public class IBECipherText implements Serializable, IBEConstraints {
    private static final long serialVersionUID = 5766799743332486673L;

    /**
     * 密文uvw对象序列 共384字节
     * 384 bytes of (u, v, w)
     */
    private byte[] uvw;

    /**
     * 对应明文有效长度 单位字节
     * used length of plain text.
     * should this length also be encrypted???
     */
    private int length;

    public IBECipherText() {
    }

    public byte[] getUvw() {
        return uvw;
    }

    public void setUvw(byte[] uvw) {
        this.uvw = uvw;
    }

    public int getLength() {
        return length;
    }

    public void setLength(int length) {
        this.length = length;
    }

    /*
     * (non-Javadoc)
     * @see java.lang.Object#hashCode()
     */
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + length;
        result = prime * result + Arrays.hashCode(uvw);
        return result;
    }

    /*
     * (non-Javadoc)
     * @see java.lang.Object#equals(java.lang.Object)
     */
    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (!(obj instanceof IBECipherText))
            return false;
        IBECipherText other = (IBECipherText) obj;
        if (length != other.length)
            return false;
        if (!Arrays.equals(uvw, other.uvw))
            return false;
        return true;
    }

    /*
     * (non-Javadoc)
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString() {
        return "IBECipherText [uvw=" + Arrays.toString(uvw) + ", length="
               + length + "]";
    }

    /**
     * 序列化字段：<br/>
     * 密文内容 384字节<br/>
     * 明文有效长度 1字节<br/>
     * Serialize this objetc, first 384 bytes are (u,v,w) and last byte is the length of plain text(1 to 126)
     * @see hamaster.gradesgin.ibe.IBEConstraints#writeExternal(java.io.OutputStream)
     */
    @Override
    public void writeExternal(OutputStream out) throws IOException {
        byte[] uvwBuffer = new byte[IBE_G_SIZE * 3];
        Arrays.fill(uvwBuffer, (byte) 0);
        if (uvw != null)
            System.arraycopy(uvw, 0, uvwBuffer, 0, IBE_G_SIZE * 3 > uvw.length ? uvw.length : IBE_G_SIZE * 3);
        out.write(uvwBuffer);
        out.write((byte) length);
        out.flush();
        MemoryUtil.fastSecureBuffers(uvwBuffer);
    }

    /*
     * (non-Javadoc)
     * @see hamaster.gradesgin.ibe.IBEConstraints#readExternal(java.io.InputStream)
     */
    @Override
    public void readExternal(InputStream in) throws IOException,
        ClassNotFoundException {
        byte[] buffer = new byte[IBE_G_SIZE * 3];
        int size = in.read(buffer);
        if (size != buffer.length)
            throw new IOException("Not enough bytes for a CipherText");
        this.uvw = new byte[IBE_G_SIZE * 3];
        System.arraycopy(buffer, 0, uvw, 0, IBE_G_SIZE * 3);
        this.length = in.read();
        MemoryUtil.fastSecureBuffers(buffer);
    }
} public class IBEPlainText implements IBEConstraints, Serializable {
    private static final long serialVersionUID = -2705082103669151761L;

    /**
     * 明文内容 长度128字节
     * Length of plain text, max 128 bytes
     */
    private byte[] content;

    /**
     * 明文的有效长度 最大为126
     * Max length of mutable plain text, 126 bytes.
     * The first and 64th byte must be zero to avoid overflow.
     */
    private int length;

    public IBEPlainText() {
    }

    public byte[] getContent() {
        return content;
    }

    public void setContent(byte[] content) {
        this.content = content;
    }

    public void setLength(int length) {
        this.length = length;
    }

    public int getLength() {
        return length;
    }

    /*
     * (non-Javadoc)
     * @see java.lang.Object#hashCode()
     */
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + Arrays.hashCode(content);
        result = prime * result + length;
        return result;
    }

    /*
     * (non-Javadoc)
     * @see java.lang.Object#equals(java.lang.Object)
     */
    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (!(obj instanceof IBEPlainText))
            return false;
        IBEPlainText other = (IBEPlainText) obj;
        if (!Arrays.equals(content, other.content))
            return false;
        if (length != other.length)
            return false;
        return true;
    }

    /*
     * (non-Javadoc)
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString() {
        return "IBEPlainText [content=" + Arrays.toString(content)
               + ", length=" + getLength() + "]";
    }

    /**
     * 获取解密后明文中的有效内容
     * Get the 126 bytes content of decrypted plain text
     * @param plainText 要获取的明文
     * @return 包含有效内容的字节数组(Byte array containing the plain text)
     */
    public static byte[] getSignificantBytes(IBEPlainText plainText) {
        synchronized (plainText) {
            byte[] plain = new byte[plainText.getLength()];
            final int IBE_HALF = IBE_G_SIZE / 2 - 1;
            if (plainText.getLength() > IBE_HALF) {
                System.arraycopy(plainText.content, IBE_G_SIZE - plainText.getLength() - 1, plain, 0, plainText.getLength() - IBE_HALF);
                System.arraycopy(plainText.content, IBE_G_SIZE - IBE_HALF, plain, plainText.getLength() - IBE_HALF, IBE_HALF);
            } else {
                System.arraycopy(plainText.content, IBE_G_SIZE - plainText.getLength(), plain, 0, plainText.getLength());
            }
            return plain;
        }
    }

    /**
     * 通过特定长度的字节构建IBEPlainText对象
     * Construct an IBEPlainText object from certain length of bytes, the length must be from 1 to 126
     * @param significantBytes 有效字节 长度在1到126字节中间
     * @return IBEPlainText
     */
    public static IBEPlainText newIbePlainTextFormSignificantBytes(byte[] significantBytes) {
        IBEPlainText text = new IBEPlainText();
        if (significantBytes == null || significantBytes.length == 0 || significantBytes.length > IBE_G_SIZE - 2)
            throw new IllegalArgumentException("invalid plain text");
        int length = significantBytes.length;
        final int IBE_HALF = IBE_G_SIZE / 2 - 1;
        text.content = new byte[IBE_G_SIZE];
        Arrays.fill(text.content, (byte) 0);
        if (length > IBE_HALF) {
            System.arraycopy(significantBytes, 0, text.content, IBE_G_SIZE - length - 1, length - IBE_HALF);
            System.arraycopy(significantBytes, length - IBE_HALF, text.content, IBE_G_SIZE - IBE_HALF, IBE_HALF);
        } else {
            System.arraycopy(significantBytes, 0, text.content, IBE_G_SIZE - length, length);
        }
        text.setLength(length);
        return text;
    }

    /**
     * 序列化字段：<br>
     * 明文内容 128字节<br>
     * 明文有效长度 1字节<br>
     * Serialize this object, the first 128 bytes are padded plain text and the last byte is the length of byte used(1 to 126)
     * @see hamaster.gradesgin.ibe.IBEConstraints#writeExternal(java.io.OutputStream)
     */
    @Override
    public void writeExternal(OutputStream out) throws IOException {
        byte[] contentBuffer = new byte[IBE_G_SIZE];
        Arrays.fill(contentBuffer, (byte) 0);
        if (content != null)
            System.arraycopy(content, 0, contentBuffer, 0, IBE_G_SIZE > content.length ? content.length : IBE_G_SIZE);
        out.write(contentBuffer);
        out.write((byte) getLength());
        out.flush();
        MemoryUtil.immediateSecureBuffers(contentBuffer);
    }

    /*
     * (non-Javadoc)
     * @see hamaster.gradesgin.ibe.IBEConstraints#readExternal(java.io.InputStream)
     */
    @Override
    public void readExternal(InputStream in) throws IOException, ClassNotFoundException {
        byte[] buffer = new byte[IBE_G_SIZE];
        int size = in.read(buffer);
        if (size != buffer.length)
            throw new IOException("Not enough bytes for a PlainText");
        this.content = new byte[IBE_G_SIZE];
        System.arraycopy(buffer, 0, content, 0, IBE_G_SIZE);
        this.setLength(in.read());
        MemoryUtil.immediateSecureBuffers(buffer);
    }
} public class IBEPrivateKey implements Serializable, IBEConstraints, PrivateKey {
    private static final long serialVersionUID = 1569046919144264563L;

    /**
     * 私钥rID部分
     * rID part of private ley, length is 20 bytes;
     */
    protected byte[] rID;

    /**
     * 私钥hID部分
     * hID part ot private key, length is 128 bytes.
     */
    protected byte[] hID;

    /**
     * 椭圆函数参数
     * pairing
     */
    private byte[] pairing;

    /**
     * 私钥所有者身份 即对应公钥
     * the public key, e.g. email address
     */
    private String userString;

    public IBEPrivateKey() {
    }

    public byte[] getrID() {
        return rID;
    }

    public void setrID(byte[] rID) {
        this.rID = rID;
    }

    public byte[] gethID() {
        return hID;
    }

    public void sethID(byte[] hID) {
        this.hID = hID;
    }

    public String getUserString() {
        return userString;
    }

    public void setUserString(String userString) {
        this.userString = userString;
    }

    public byte[] getPairing() {
        return pairing;
    }

    public void setPairing(byte[] pairing) {
        this.pairing = pairing;
    }

    /*
     * (non-Javadoc)
     * @see java.lang.Object#hashCode()
     */
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + Arrays.hashCode(hID);
        result = prime * result + Arrays.hashCode(pairing);
        result = prime * result + Arrays.hashCode(rID);
        result = prime * result + ((userString == null) ? 0 : userString.hashCode());
        return result;
    }

    /*
     * (non-Javadoc)
     * @see java.lang.Object#equals(java.lang.Object)
     */
    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (!(obj instanceof IBEPrivateKey))
            return false;
        IBEPrivateKey other = (IBEPrivateKey) obj;
        if (!Arrays.equals(hID, other.hID))
            return false;
        if (!Arrays.equals(pairing, other.pairing))
            return false;
        if (!Arrays.equals(rID, other.rID))
            return false;
        if (userString == null) {
            if (other.userString != null)
                return false;
        } else if (!userString.equals(other.userString))
            return false;
        return true;
    }

    /*
     * (non-Javadoc)
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString() {
        return "IBEPrivateKey [rID=" + Arrays.toString(rID) + ", hID="
               + Arrays.toString(hID) + ", pairing="
               + Arrays.toString(pairing) + ", userString=" + userString + "]";
    }

    /*
     * (non-Javadoc)
     * @see java.security.Key#getAlgorithm()
     */
    @Override
    public String getAlgorithm() {
        return "IBE";
    }

    /*
     * (non-Javadoc)
     * @see java.security.Key#getFormat()
     */
    @Override
    public String getFormat() {
        return null;
    }

    /*
     * (non-Javadoc)
     * @see java.security.Key#getEncoded()
     */
    @Override
    public byte[] getEncoded() {
        return null;
    }

    /**
     * 写入顺序：<br>
     * rID 20字节<br>
     * hID 128字节<br>
     * 用户字符串长度4字节<br>
     * 用户字符串不定长度<br>
     * 椭圆参数长度4字节<br>
     * 椭圆参数不定长度
     * Serialize the private key, this implementation writes key content directly to a file, keep it private!!!
     * Sequence: rID - 20 bytes, hID - 128 bytes, length of public key - 4 bytes, public key, length of pairing - 4 bytes, pairing
     * @see hamaster.gradesgin.ibe.IBEConstraints#writeExternal(java.io.OutputStream)
     */
    @Override
    public void writeExternal(OutputStream out) throws IOException {
        byte[] encoded = getEncoded();
        if (encoded != null) {
            out.write(encoded);
            out.flush();
            return;
        }
        // 不编码，直接将私钥写入输出流
        // TODO encrypt the private key with a password.
        byte[] rBuffer = new byte[IBE_ZR_SIZE];
        Arrays.fill(rBuffer, (byte) 0);
        if (rID != null)
            System.arraycopy(rID, 0, rBuffer, 0, IBE_ZR_SIZE > rID.length ? rID.length : IBE_ZR_SIZE);
        out.write(rBuffer);
        byte[] hBuffer = new byte[IBE_G_SIZE];
        Arrays.fill(hBuffer, (byte) 0);
        if (hID != null)
            System.arraycopy(hID, 0, hBuffer, 0, IBE_G_SIZE > hID.length ? hID.length : IBE_G_SIZE);
        out.write(hBuffer);

        byte[] userBuffer = null;
        if (userString != null) {
            userBuffer = userString.getBytes(USER_STRING_ENCODING);
            out.write(intToByte(userBuffer.length));
            out.write(userBuffer);
        }
        byte[] pBuffer = new byte[IBE_G_SIZE * 4];
        Arrays.fill(pBuffer, (byte) 0);
        if (pairing != null) {
            System.arraycopy(pairing, 0, pBuffer, 0, pairing.length);
            out.write(intToByte(pairing.length));
        } else {
            out.write(intToByte(IBE_G_SIZE * 4));
        }
        out.write(pBuffer, 0, pairing == null ? pBuffer.length : pairing.length);
        out.flush();
        MemoryUtil.fastSecureBuffers(userBuffer, pBuffer);
        MemoryUtil.immediateSecureBuffers(rBuffer, hBuffer);
    }

    /*
     * (non-Javadoc)
     * @see hamaster.gradesgin.ibe.IBEConstraints#readExternal(java.io.InputStream)
     */
    @Override
    public void readExternal(InputStream in) throws IOException, ClassNotFoundException {
        // TODO 判断私钥是否是编码过的
        byte[] buffer = new byte[IBE_ZR_SIZE + IBE_G_SIZE];

        int keySize = in.read(buffer);
        if (keySize != buffer.length)
            throw new IOException("Not enough bytes for a PrivateKey");
        this.rID = new byte[IBE_ZR_SIZE];
        this.hID = new byte[IBE_G_SIZE];
        System.arraycopy(buffer, 0, rID, 0, IBE_ZR_SIZE);
        System.arraycopy(buffer, IBE_ZR_SIZE, hID, 0, IBE_G_SIZE);

        byte[] upTmp = new byte[4];
        Arrays.fill(upTmp, (byte) 0);
        if (4 != in.read(upTmp)) {
            throw new IOException("Not enough bytes for a PrivateKey");
        }
        int uSize = bytesToInt(upTmp);
        byte[] uBuffer = new byte[uSize];
        uSize = in.read(uBuffer);
        if (uSize != uBuffer.length)
            throw new IOException("Not enough bytes for a PrivateKey");
        this.userString = new String(uBuffer, USER_STRING_ENCODING);

        Arrays.fill(upTmp, (byte) 0);
        if (4 != in.read(upTmp)) {
            throw new IOException("Not enough bytes for a PrivateKey");
        }
        int pSize = bytesToInt(upTmp);
        byte[] pBuffer = new byte[pSize];
        pSize = in.read(pBuffer);
        if (pSize != pBuffer.length)
            throw new IOException("Not enough bytes for a PrivateKey pairing");
        this.pairing = null;
        if (pSize != IBE_G_SIZE * 4) {
            this.pairing = new byte[pSize];
            System.arraycopy(pBuffer, 0, pairing, 0, pSize);
        }
        MemoryUtil.fastSecureBuffers(pBuffer);
        MemoryUtil.immediateSecureBuffers(buffer);
    }
} public class IBEPublicParameter implements Serializable, IBEConstraints {
    private static final long serialVersionUID = 712976807901527482L;

    /**
     * 参数g
     * parameter G
     */
    protected byte[] paramG;

    /**
     * 参数g1
     * parameter G1
     */
    protected byte[] paramG1;

    /**
     * 参数h
     * parameter H
     */
    protected byte[] paramH;

    /**
     * 椭圆函数参数
     * the pairing
     */
    protected byte[] pairing;

    public IBEPublicParameter() {
    }

    public byte[] getParamG() {
        return paramG;
    }

    public void setParamG(byte[] paramG) {
        this.paramG = paramG;
    }

    public byte[] getParamG1() {
        return paramG1;
    }

    public void setParamG1(byte[] paramG1) {
        this.paramG1 = paramG1;
    }

    public byte[] getParamH() {
        return paramH;
    }

    public void setParamH(byte[] paramH) {
        this.paramH = paramH;
    }

    public byte[] getPairing() {
        return pairing;
    }

    public void setPairing(byte[] pairing) {
        this.pairing = pairing;
    }

    /*
     * (non-Javadoc)
     * @see java.lang.Object#hashCode()
     */
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + Arrays.hashCode(pairing);
        result = prime * result + Arrays.hashCode(paramG);
        result = prime * result + Arrays.hashCode(paramG1);
        result = prime * result + Arrays.hashCode(paramH);
        return result;
    }

    /*
     * (non-Javadoc)
     * @see java.lang.Object#equals(java.lang.Object)
     */
    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (!(obj instanceof IBEPublicParameter))
            return false;
        IBEPublicParameter other = (IBEPublicParameter) obj;
        if (!Arrays.equals(pairing, other.pairing))
            return false;
        if (!Arrays.equals(paramG, other.paramG))
            return false;
        if (!Arrays.equals(paramG1, other.paramG1))
            return false;
        if (!Arrays.equals(paramH, other.paramH))
            return false;
        return true;
    }

    /*
     * (non-Javadoc)
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString() {
        return "IBEPublicParameter [paramG=" + Arrays.toString(paramG)
               + ", paramG1=" + Arrays.toString(paramG1) + ", paramH="
               + Arrays.toString(paramH) + ", pairing="
               + new String(pairing) + "]";
    }

    /**
     * 序列化字段：<br>
     * g 128字节<br>
     * g1 128字节<br>
     * h 128字节<br>
     * 椭圆函数参数长度 4字节<br>
     * 椭圆函数参数
     * g 128 bytes, g1 128 bytes, h 128 bytes, length of pairing 4 bytes, pairing
     * @see hamaster.gradesgin.ibe.IBEConstraints#writeExternal(java.io.OutputStream)
     */
    @Override
    public void writeExternal(OutputStream out) throws IOException {
        byte[] buffer = new byte[IBE_G_SIZE];
        Arrays.fill(buffer, (byte) 0);
        if (paramG != null)
            System.arraycopy(paramG, 0, buffer, 0, IBE_G_SIZE > paramG.length ? paramG.length : IBE_G_SIZE);
        out.write(buffer);
        Arrays.fill(buffer, (byte) 0);
        if (paramG1 != null)
            System.arraycopy(paramG1, 0, buffer, 0, IBE_G_SIZE > paramG1.length ? paramG1.length : IBE_G_SIZE);
        out.write(buffer);
        Arrays.fill(buffer, (byte) 0);
        if (paramH != null)
            System.arraycopy(paramH, 0, buffer, 0, IBE_G_SIZE > paramH.length ? paramH.length : IBE_G_SIZE);
        out.write(buffer);
        int pSize = pairing == null ? IBE_G_SIZE * 4 : pairing.length;
        out.write(intToByte(pSize));
        byte[] pBuffer = new byte[IBE_G_SIZE * 4];
        Arrays.fill(pBuffer, (byte) 0);
        if (pairing != null)
            System.arraycopy(pairing, 0, pBuffer, 0, pairing.length);
        out.write(pBuffer, 0, pairing == null ? pBuffer.length : pairing.length);
        out.flush();
        MemoryUtil.fastSecureBuffers(buffer, pBuffer);
    }

    /*
     * (non-Javadoc)
     * @see hamaster.gradesgin.ibe.IBEConstraints#readExternal(java.io.InputStream)
     */
    @Override
    public void readExternal(InputStream in) throws IOException, ClassNotFoundException {
        byte[] buffer = new byte[IBE_G_SIZE * 3];
        int pSize = in.read(buffer);
        if (pSize < buffer.length) {
            // 字节数少于期望值，数据丢失
            throw new IOException("Not enough bytes for a PublicParameter");
        }
        this.paramG = new byte[IBE_G_SIZE];
        this.paramG1 = new byte[IBE_G_SIZE];
        this.paramH = new byte[IBE_G_SIZE];
        byte[] pTmp = new byte[4];
        Arrays.fill(pTmp, (byte) 0);
        if (4 != in.read(pTmp)) {
            throw new IOException("Not enough bytes for a PublicParameter");
        }
        pSize = bytesToInt(pTmp);
        this.pairing = new byte[pSize];
        pSize = in.read(pairing);
        if (pSize < pairing.length) {
            // 字节数少于期望值，数据丢失
            throw new IOException("Not enough bytes for a PublicParameter");
        }
        System.arraycopy(buffer, 0, paramG, 0, IBE_G_SIZE);
        System.arraycopy(buffer, IBE_G_SIZE, paramG1, 0, IBE_G_SIZE);
        System.arraycopy(buffer, IBE_G_SIZE * 2, paramH, 0, IBE_G_SIZE);
        MemoryUtil.fastSecureBuffers(buffer);
    }

    public static IBEPublicParameter fromByteArray(byte[] data) throws ClassNotFoundException, IOException {
        IBEPublicParameter param = new IBEPublicParameter();
        ByteArrayInputStream in = new ByteArrayInputStream(data);
        param.readExternal(in);
        return param;
    }
} public class IBEEngine {

    /**
     * 初始化一个IBE系统
     * Setup an IBE system
     * @param pairingIn 椭圆函数参数 the pairing
     * @return 系统参数 如果椭圆函数参数非法或者出现其它错误返回null
     * returns the IBESystemParameter object when success, otherwise return null
     */
    public static IBESystemParameter setup(byte[] pairingIn) {
        byte[] alphaOut = new byte[IBELibrary.PBC_ZR_SIZE];
        byte[] gOut = new byte[IBELibrary.PBC_G_SIZE];
        byte[] g1Out = new byte[IBELibrary.PBC_G_SIZE];
        byte[] hOut = new byte[IBELibrary.PBC_G_SIZE];
        int succ = IBELibrary.setup(alphaOut, gOut, g1Out, hOut, pairingIn);
        if (succ == 0) {
            IBEPublicParameter publicParameter = new IBEPublicParameter();
            publicParameter.setParamG(gOut);
            publicParameter.setParamG1(g1Out);
            publicParameter.setParamH(hOut);
            publicParameter.setPairing(pairingIn);
            IBESystemParameter parameter = new IBESystemParameter();
            parameter.setMasterKey(alphaOut);
            parameter.setPublicParameter(publicParameter);
            return parameter;
        }
        return null;
    }

    /**
     * 为一个用户生成私钥
     * Generate a private key for a user
     * @param system IBE系统 the system parameter
     * @param user 私钥请求用户 the user
     * @return 用户的私钥 the generated private key
     */
    public static IBEPrivateKey keygen(IBESystemParameter system, String user) {
        byte[] hIDOut = new byte[IBELibrary.PBC_G_SIZE];
        byte[] rIDOut = new byte[IBELibrary.PBC_ZR_SIZE];
        try {
            int succ = IBELibrary.keygen(hIDOut, rIDOut, user.getBytes(IBEConstraints.USER_STRING_ENCODING), system.getMasterKey(),
                                         system.getPublicParameter().getParamG(), system.getPublicParameter().getParamH(), system.getPublicParameter().getPairing());
            if (succ != 0)
                throw new IOException("Cannot generate private key for user:" + user);
            IBEPrivateKey privateKey = new IBEPrivateKey();
            privateKey.sethID(hIDOut);
            privateKey.setrID(rIDOut);
            privateKey.setUserString(user);
            privateKey.setPairing(system.getPublicParameter().getPairing());
            return privateKey;
        } catch (IOException e) {
            return null;
        }
    }

    /**
     * 对数据进行加密
     * encryption
     * @param publicParameter 接收方公共参数 the recipients' public key
     * @param plainText 明文 the plain text
     * @param receiver 接收着身份 the recipient
     * @return 密文 cipher text
     */
    public static IBECipherText encrypt(IBEPublicParameter publicParameter, IBEPlainText plainText, String receiver) {
        byte[] cipherBufferOut = new byte[IBELibrary.PBC_G_SIZE * 3];
        try {
            int succ = IBELibrary.encrypt(cipherBufferOut, plainText.getContent(), publicParameter.getParamG(), publicParameter.getParamG1(),
                                          publicParameter.getParamH(), receiver.getBytes(IBEConstraints.USER_STRING_ENCODING), publicParameter.getPairing());
            if (succ != 0)
                throw new IOException("Cannot encrypt messege for user:" + receiver);
            IBECipherText cipherText = new IBECipherText();
            cipherText.setUvw(cipherBufferOut);
            cipherText.setLength(plainText.getLength());
            return cipherText;
        } catch (IOException e) {
            return null;
        }
    }

    /**
     * 对密文解密
     * decryption
     * @param cipherText 密文
     * @param privateKey 接收方私钥
     * @return 解密后明文 plain text
     */
    public static IBEPlainText decrypt(IBECipherText cipherText, IBEPrivateKey privateKey) {
        byte[] plainBufferOut = new byte[IBELibrary.PBC_G_SIZE];
        int i = IBELibrary.decrypt(plainBufferOut, cipherText.getUvw(), privateKey.getrID(), privateKey.gethID(), privateKey.getPairing());
        if (i == 0) {
            IBEPlainText plainText = new IBEPlainText() {
                private static final long serialVersionUID = -2705082103669151761L;
            };
            plainText.setContent(plainBufferOut);
            plainText.setLength(cipherText.getLength());
            return plainText;
        }
        return null;
    }

    /**
     * 生成证书
     * Generate certificate
     * @param user 证书所有者 certificate owner
     * @param root 签名用根证书 如果生成根证书 则传入一个只包含椭圆函数信息的证书对象
     * the root certificate, if this paramater only contains a pairing, then this method will generate a root certificate
     * @param validAfter 有效期开始日期 the certificate effective start date
     * @param period 有效时间 单位毫秒 the certificate valid time period, in millisecond.
     * @return 生成的证书 the certificate
     */
    public static IBSCertificate generateCertificate(String user, IBSCertificate root, Date validAfter, long period) {
        IBSCertificate root0 = root;
        IBESystemParameter parameter = setup(root0.getPublicParameter().getPairing());
        IBSCertificate certificate = new IBSCertificate();
        certificate.setMasterKey(parameter.getMasterKey());
        certificate.setPublicParameter(parameter.getPublicParameter());
        certificate.setOwnerString(user);
        certificate.setNoEarlyThan(validAfter);
        certificate.setNoLateThan(new Date(period + validAfter.getTime()));
        if (root0.getMasterKey() == null)
            root0 = certificate;
        try {
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            ObjectOutputStream writer = new ObjectOutputStream(out);
            writer.writeObject(certificate);
            writer.flush();
            writer.close();
            byte[] data = out.toByteArray();
            out.close();
            byte[] hash = Hash.sha256(data);
            IBSSignature signature = sign(root0, hash, "SHA-256");
            certificate.setSignature(signature);
            return certificate;
        } catch (IOException e) {
            return null;
        }
    }

    /**
     * 进行数字签名
     * Digital signing prcess
     * @param certificate 签名证书
     * @param digest 待签名数据摘要
     * @param hash 摘要方法 e.g. SHA1 or MD5
     * @return 数字签名
     */
    public static IBSSignature sign(IBSCertificate certificate, byte[] digest, String hash) {
        IBSSignature signature = new IBSSignature();
        signature.setSignatureParameter(certificate.getPublicParameter());
        signature.setDigest(digest);
        signature.setHashAlgorithm(hash);
        signature.setSigningDate(new Date());
        try {
            IBEPrivateKey privateKey = keygen(certificate, new String(digest, IBEConstraints.USER_STRING_ENCODING));
            signature.sethID(privateKey.gethID());
            signature.setrID(privateKey.getrID());
            signature.setUserString(privateKey.getUserString());
            return signature;
        } catch (UnsupportedEncodingException e) {
            return null;
        }
    }

    /**
     * 验证数字签名
     * Verify a digital signature
     * @param signature 数字签名
     * @param digest 待验证数据摘要
     * @return 当且仅当数据一致且签名合法时验证通过 only if the verification passes it returns true
     */
    public static boolean verify(IBSSignature signature, byte[] digest) {
        if (signature == null || digest == null)
            return false;
        boolean integrity = Arrays.equals(digest, signature.getDigest());
        if (!integrity)
            return false;
        byte[] significantBytes = new byte[120];
        new Random().nextBytes(significantBytes);
        IBEPlainText plainText = IBEPlainText.newIbePlainTextFormSignificantBytes(significantBytes);
        try {
            IBECipherText cipherText = encrypt(signature.getSignatureParameter(), plainText, new String(digest, IBEConstraints.USER_STRING_ENCODING));
            IBEPlainText decrypt = decrypt(cipherText, signature);
            return decrypt.equals(plainText);
        } catch (UnsupportedEncodingException e) {
            return false;
        }
    }
} public class IBSCertificate extends IBESystemParameter implements Serializable {
    private static final long serialVersionUID = 1203770296311146389L;

    /**
     * 所有者
     */
    protected String ownerString;

    /**
     * 证书签名
     */
    protected IBSSignature signature;

    /**
     * 有效期开始日期
     */
    protected Date noEarlyThan;

    /**
     * 有效期结束日期
     */
    protected Date noLateThan;

    public IBSCertificate() {
    }

    public String getOwnerString() {
        return ownerString;
    }

    public void setOwnerString(String ownerString) {
        this.ownerString = ownerString;
    }

    public IBSSignature getSignature() {
        return signature;
    }

    public void setSignature(IBSSignature signature) {
        this.signature = signature;
    }

    public Date getNoEarlyThan() {
        return noEarlyThan;
    }

    public void setNoEarlyThan(Date noEarlyThan) {
        this.noEarlyThan = noEarlyThan;
    }

    public Date getNoLateThan() {
        return noLateThan;
    }

    public void setNoLateThan(Date noLateThan) {
        this.noLateThan = noLateThan;
    }

    /*
     * (non-Javadoc)
     * @see hamaster.gradesgin.ibe.IBESystemParameter#hashCode()
     */
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = super.hashCode();
        result = prime * result
                 + ((noEarlyThan == null) ? 0 : noEarlyThan.hashCode());
        result = prime * result
                 + ((noLateThan == null) ? 0 : noLateThan.hashCode());
        result = prime * result
                 + ((ownerString == null) ? 0 : ownerString.hashCode());
        result = prime * result
                 + ((signature == null) ? 0 : signature.hashCode());
        return result;
    }

    /*
     * (non-Javadoc)
     * @see hamaster.gradesgin.ibe.IBESystemParameter#equals(java.lang.Object)
     */
    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (!super.equals(obj))
            return false;
        if (!(obj instanceof IBSCertificate))
            return false;
        IBSCertificate other = (IBSCertificate) obj;
        if (noEarlyThan == null) {
            if (other.noEarlyThan != null)
                return false;
        } else if (!noEarlyThan.equals(other.noEarlyThan))
            return false;
        if (noLateThan == null) {
            if (other.noLateThan != null)
                return false;
        } else if (!noLateThan.equals(other.noLateThan))
            return false;
        if (ownerString == null) {
            if (other.ownerString != null)
                return false;
        } else if (!ownerString.equals(other.ownerString))
            return false;
        if (signature == null) {
            if (other.signature != null)
                return false;
        } else if (!signature.equals(other.signature))
            return false;
        return true;
    }

    /*
     * (non-Javadoc)
     * @see hamaster.gradesgin.ibe.IBESystemParameter#toString()
     */
    @Override
    public String toString() {
        return "IBSCertificate [ownerString=" + ownerString + ", signature="
               + signature + ", noEarlyThan=" + noEarlyThan + ", noLateThan="
               + noLateThan + ", publicParameter=" + publicParameter
               + ", masterKey=" + Arrays.toString(masterKey) + "]";
    }

    /**
     * 序列化字段：<br>
     * 公共参数<br>
     * 签名主密钥 20字节<br>
     * 证书有效期开始 8字节<br>
     * 证书有效期 8字节<br>
     * 所有者字符串长度 4字节<br>
     * 所有者字符串 长度由前4字节定义<br>
     * 根证书签名
     * @see hamaster.gradesgin.ibe.IBEConstraints#writeExternal(java.io.OutputStream)
     */
    @Override
    public void writeExternal(OutputStream out) throws IOException {
        publicParameter.writeExternal(out);
        byte[] mBuffer = new byte[IBE_ZR_SIZE];
        Arrays.fill(mBuffer, (byte) 0);
        if (masterKey != null)
            System.arraycopy(masterKey, 0, mBuffer, 0, IBE_ZR_SIZE);
        out.write(mBuffer);
        long start = noEarlyThan == null ? 0L : noEarlyThan.getTime();
        long end = noLateThan == null ? 0L : noLateThan.getTime();
        out.write(longToBytes(start));
        out.write(longToBytes(end - start));
        int oSize = ownerString != null ? ownerString.length() : 10;
        out.write(intToByte(oSize));
        out.write(ownerString.getBytes(USER_STRING_ENCODING));
        if (signature != null) {
            out.write((byte) 1);
            signature.writeExternal(out);
        } else {
            out.write((byte) 0);
        }
        out.flush();
        MemoryUtil.immediateSecureBuffers(mBuffer);
    }

    /*
     * (non-Javadoc)
     * @see hamaster.gradesgin.ibe.IBEConstraints#readExternal(java.io.InputStream)
     */
    @Override
    public void readExternal(InputStream in) throws IOException, ClassNotFoundException {
        this.publicParameter = new IBEPublicParameter();
        publicParameter.readExternal(in);
        this.masterKey = new byte[IBE_ZR_SIZE];
        int size = in.read(masterKey);
        if (size != masterKey.length)
            throw new IOException("Not enough bytes for a Certificate");
        byte[] spTmp = new byte[8];
        Arrays.fill(spTmp, (byte) 0);
        if (8 != in.read(spTmp))
            throw new IOException("Not enough bytes for a Certificate");
        long start = bytesToLong(spTmp);
        Arrays.fill(spTmp, (byte) 0);
        if (8 != in.read(spTmp))
            throw new IOException("Not enough bytes for a Certificate");
        long period = bytesToLong(spTmp);
        this.noEarlyThan = new Date(start);
        this.noLateThan = new Date(start + period);
        byte[] sTmp = new byte[4];
        Arrays.fill(sTmp, (byte) 0);
        if (4 != in.read(sTmp))
            throw new IOException("Not enough bytes for a Certificate");
        size = bytesToInt(sTmp);
        byte[] buffer = new byte[size];
        size = in.read(buffer);
        if (size != buffer.length)
            throw new IOException("Not enough bytes for a Certificate");
        this.ownerString = new String(buffer, 0, size, USER_STRING_ENCODING);
        size = in.read();
        if (size == 1) {
            this.signature = new IBSSignature();
            signature.readExternal(in);
        }
    }
} public class IBSSignature extends IBEPrivateKey implements Serializable, IBEConstraints {
    private static final long serialVersionUID = -4862591033031464057L;

    /**
     * 签名者参数
     */
    protected IBEPublicParameter signatureParameter;

    /**
     * 被签名数据的摘要
     */
    protected byte[] digest;

    /**
     * 摘要算法
     */
    protected String hashAlgorithm;

    /**
     * 签名日期
     */
    protected Date signingDate;

    public IBSSignature() {
    }

    public IBEPublicParameter getSignatureParameter() {
        return signatureParameter;
    }

    public void setSignatureParameter(IBEPublicParameter signatureParameter) {
        this.signatureParameter = signatureParameter;
        setPairing(signatureParameter.getPairing());
    }

    public byte[] getDigest() {
        return digest;
    }

    public void setDigest(byte[] digest) {
        this.digest = digest;
    }

    public String getHashAlgorithm() {
        return hashAlgorithm;
    }

    public void setHashAlgorithm(String hashAlgorithm) {
        this.hashAlgorithm = hashAlgorithm;
    }

    public Date getSigningDate() {
        return signingDate;
    }

    public void setSigningDate(Date signingDate) {
        this.signingDate = signingDate;
    }

    /**
     * 序列化字段：<br>
     * rID 20字节<br>
     * hID 128字节<br>
     * 摘要长度 4字节<br>
     * 摘要内容<br>
     * 签名参数<br>
     * 签名日期 8字节<br>
     * 哈希算法长度 1字节<br>
     * 哈希算法字符串
     * @see hamaster.gradesgin.ibe.IBEConstraints#writeExternal(java.io.OutputStream)
     */
    @Override
    public void writeExternal(OutputStream out) throws IOException {
        byte[] rBuffer = new byte[IBE_ZR_SIZE];
        byte[] hBuffer = new byte[IBE_G_SIZE];
        Arrays.fill(rBuffer, (byte) 0);
        Arrays.fill(hBuffer, (byte) 0);
        if (rID != null)
            System.arraycopy(rID, 0, rBuffer, 0, rID.length > IBE_ZR_SIZE ? IBE_ZR_SIZE : rID.length);
        out.write(rBuffer);
        if (hID != null)
            System.arraycopy(hID, 0, hBuffer, 0, hID.length > IBE_G_SIZE ? IBE_G_SIZE : hID.length);
        out.write(hBuffer);
        if (digest == null) {
            byte[] zero = new byte[4];
            Arrays.fill(zero, (byte) 0);
            out.write(zero);
        } else {
            out.write(intToByte(digest.length));
            out.write(digest);
        }
        signatureParameter.writeExternal(out);
        if (signingDate == null) {
            byte[] zero = new byte[8];
            Arrays.fill(zero, (byte) 0);
            out.write(zero);
        } else {
            out.write(longToBytes(signingDate.getTime()));
        }
        int aSize = hashAlgorithm == null ? 0 : hashAlgorithm.length();
        out.write((byte) aSize);
        out.write(hashAlgorithm.getBytes(USER_STRING_ENCODING));
        out.flush();
    }

    /*
     * (non-Javadoc)
     * @see hamaster.gradesgin.ibe.IBEConstraints#readExternal(java.io.InputStream)
     */
    @Override
    public void readExternal(InputStream in) throws IOException, ClassNotFoundException {
        byte[] buffer = new byte[IBE_G_SIZE + IBE_ZR_SIZE];
        int size = in.read(buffer);
        if (size != buffer.length)
            throw new IOException("Not enough bytes for a Signature");
        this.rID = new byte[IBE_ZR_SIZE];
        this.hID = new byte[IBE_G_SIZE];
        System.arraycopy(buffer, 0, rID, 0, IBE_ZR_SIZE);
        System.arraycopy(buffer, IBE_ZR_SIZE, hID, 0, IBE_G_SIZE);
        byte[] dTmp = new byte[4];
        Arrays.fill(dTmp, (byte) 0);
        if (4 != in.read(dTmp))
            throw new IOException("Not enough bytes for a Signature");
        int dSize = bytesToInt(dTmp);
        this.digest = new byte[dSize];
        dSize = in.read(digest);
        if (dSize != digest.length)
            throw new IOException("Not enough bytes for a Signature");
        setUserString(new String(digest, USER_STRING_ENCODING));
        this.signatureParameter = new IBEPublicParameter();
        signatureParameter.readExternal(in);
        byte[] sTmp = new byte[8];
        Arrays.fill(sTmp, (byte) 0);
        if (8 != in.read(sTmp))
            throw new IOException("Not enough bytes for a Signature");
        this.signingDate = new Date(bytesToLong(sTmp));
        size = in.read();
        byte[] hash = new byte[size];
        size = in.read(hash);
        if (size != hash.length)
            throw new IOException("Not enough bytes for a Signature");
        this.hashAlgorithm = new String(hash, 0, size, USER_STRING_ENCODING);
        setPairing(signatureParameter.getPairing());
    }
} public final class Hash {

    private Hash() {}

    /**
     * 计算字符串的MD5摘要
     * @param str 要计算的字符串
     * @return MD5摘要
     */
    @Deprecated
    public final static byte[] md5(String str) {
        return digest(str, "MD5");
    }

    /**
     * 计算字符串的SHA-1摘要
     * @param str 要计算的字符串
     * @return SHA-1摘要
     */
    @Deprecated
    public final static byte[] sha1(String str) {
        return digest(str, "SHA-1");
    }

    /**
     * 计算字符串的SHA-256摘要
     * @param str 要计算的字符串
     * @return SHA-256摘要
     */
    public final static byte[] sha256(String str) {
        return digest(str, "SHA-256");
    }

    /**
     * 计算字符串的SHA-512摘要
     * @param str 要计算的字符串
     * @return SHA-512摘要
     */
    public final static byte[] sha512(String str) {
        return digest(str, "SHA-512");
    }

    /**
     * 计算字节数组的MD5摘要
     * @param bytes 要计算的字节数组
     * @return MD5摘要
     */
    // There is no Deprecated annotation as this method is used to generate 16 bytes
    // array from data of arbitrary length
    public final static byte[] md5(byte[] bytes) {
        return digest(bytes, "MD5");
    }

    /**
     * 计算字节数组的SHA-1摘要
     * @param bytes 要计算的字节数组
     * @return SHA-1摘要
     */
    @Deprecated
    public final static byte[] sha1(byte[] bytes) {
        return digest(bytes, "SHA-1");
    }

    /**
     * 计算字节数组的SHA-256摘要
     * @param bytes 要计算的字节数组
     * @return SHA-256摘要
     */
    public final static byte[] sha256(byte[] bytes) {
        return digest(bytes, "SHA-256");
    }

    /**
     * 计算字节数组的SHA-512摘要
     * @param bytes 要计算的字节数组
     * @return SHA-512摘要
     */
    public final static byte[] sha512(byte[] bytes) {
        return digest(bytes, "SHA-512");
    }

    /**
     * 计算文件的MD5摘要
     * @param file 要计算的文件
     * @return 文件的MD5摘要
     * @throws IOException IO异常 如文件不存在
     */
    public final static byte[] md5(File file) throws IOException {
        return digest(new FileInputStream(file), file.length(), "MD5");
    }

    /**
     * 计算文件的SHA-1摘要
     * @param file 要计算的文件
     * @return 文件的SHA-1摘要
     * @throws IOException IO异常 如文件不存在
     */
    public final static byte[] sha1(File file) throws IOException {
        return digest(new FileInputStream(file), file.length(), "SHA-1");
    }

    /**
     * 计算文件的SHA-256摘要
     * @param file 要计算的文件
     * @return 文件的SHA-256摘要
     * @throws IOException IO异常 如文件不存在
     */
    public final static byte[] sha256_(File file) throws IOException {
        return digest(new FileInputStream(file), file.length(), "SHA-256");
    }

    /**
     * 计算文件的SHA-512摘要
     * @param file 要计算的文件
     * @return 文件的SHA-512摘要
     * @throws IOException IO异常 如文件不存在
     */
    public final static byte[] sha512(File file) throws IOException {
        return digest(new FileInputStream(file), file.length(), "SHA-512");
    }

    private final static byte[] digest(String str, String algorithm) {
        return digest(str.getBytes(), algorithm);
    }

    private final static byte[] digest(byte[] bytes, String algorithm) {
        try {
            MessageDigest md = MessageDigest.getInstance(algorithm);
            md.update(bytes);
            return md.digest();
        } catch (NoSuchAlgorithmException e) {
            return null;
        }
    }

    private final static byte[] digest(InputStream in, long length, String algorithm) throws IOException {
        try {
            MessageDigest md = MessageDigest.getInstance(algorithm);
            byte[] buffer = new byte[1024];
            int l;
            while ((l = in.read(buffer)) > 0) {
                md.update(buffer, 0, l);
            }
            return md.digest();
        } catch (NoSuchAlgorithmException e) {
            return null;
        } finally {
            in.close();
        }
    }
} public final class Hex {

    private Hex() {
    }

    /**
     * 使用十六进制编码数据
     * @param data 要编码的数据
     * @return 编码后的字符串
     */
    public final static String hex(byte[] data) {
        return hex(data, 0, data.length);
    }

    /**
     * 使用十六进制编码数据
     * @param data 要编码的数据
     * @param offset 其实偏移 0开始
     * @param count 编码字节的数量
     * @return 编码后的字符串
     */
    public final static String hex(byte[] data, int offset, int count) {
        if (offset < 0)
            throw new IllegalArgumentException(new StringBuilder("invalid offset:").append(offset).toString());
        if (count < 0)
            throw new IllegalArgumentException(new StringBuilder("invalid count:").append(offset).toString());
        if (offset > data.length - count)
            throw new ArrayIndexOutOfBoundsException(offset + count);
        ByteArrayOutputStream out = new ByteArrayOutputStream(data.length + data.length);
        PrintStream writer = new PrintStream(out);
        for (int i = offset; i < offset + count; i++) {
            writer.printf("%02x", data[i]);
        }
        return out.toString();
    }

    /**
     * 将十六进制编码的数据还原
     * @param hex 要还原的字符串
     * @return 还原后的数据
     * @throws NumberFormatException 字符串中包含无法格式化为数字的字符
     */
    public final static byte[] unhex(String hex) {
        char[] tb = hex.toUpperCase().toCharArray();
        List<Byte> bs = new ArrayList<Byte>();
        for (int i = 0; i < tb.length; i += 2) {
            String t = new String();
            t += tb[i];
            t += tb[i + 1];
            int safe = Integer.parseInt(t, 16);
            if (safe > 127)
                safe -= 256;
            bs.add(Byte.parseByte(String.valueOf(safe)));
        }
        byte[] raw = new byte[bs.size()];
        for (int i = 0; i < bs.size(); i++)
            raw[i] = bs.get(i);
        return raw;
    }

    /**
     * 将64位的long转换成8个字节的数组
     * @param l 要转换的long
     * @return 转换后的数组
     */
    public final static byte[] longToBytes(long l) {
        byte[] buffer = new byte[8];
        buffer[0] = (byte) (0xff & (l >> 56));
        buffer[1] = (byte) (0xff & (l >> 48));
        buffer[2] = (byte) (0xff & (l >> 40));
        buffer[3] = (byte) (0xff & (l >> 32));
        buffer[4] = (byte) (0xff & (l >> 24));
        buffer[5] = (byte) (0xff & (l >> 16));
        buffer[6] = (byte) (0xff & (l >> 8));
        buffer[7] = (byte) (0xff & l);
        return buffer;
    }

    /**
     * 将8个字节组装成一个long
     * @param bytes 要转换的字节数组
     * @return 组装后的long
     */
    public final static long bytesToLong(byte[] bytes) {
        return bytesToLong(bytes, 0);
    }

    /**
     * 将8个字节组装成一个long
     * @param bytes 要转换的字节数组
     * @param offset 数组中开始读取的偏移量
     * @return 组装后的long
     */
    public final static long bytesToLong(byte[] bytes, int offset) {
        if (bytes == null || offset + 8 > bytes.length)
            throw new IllegalArgumentException("invalid byte array to convert!");
        return (((long) (bytes[0 + offset] & 0xff) << 56) |
                ((long) (bytes[1 + offset] & 0xff) << 48) |
                ((long) (bytes[2 + offset] & 0xff) << 40) |
                ((long) (bytes[3 + offset] & 0xff) << 32) |
                ((long) (bytes[4 + offset] & 0xff) << 24) |
                ((long) (bytes[5 + offset] & 0xff) << 16) |
                ((long) (bytes[6 + offset] & 0xff) <<  8) |
                ((long) (bytes[7 + offset] & 0xff)));
    }

    /**
     * 将32bit的int转换为字节数组
     * @param i 要转换的int
     * @return 转换完成的数组 长度4字节
     */
    public final static byte[] intToByte(int i) {
        byte[] bt = new byte[4];
        bt[0] = (byte) ((0xff000000 & i) >> 24);
        bt[1] = (byte) ((0xff0000 & i) >> 16);
        bt[2] = (byte) ((0xff00 & i) >> 8);
        bt[3] = (byte) (0xff & i);
        return bt;
    }

    /**
     * 将4字节的数组转换成int
     * @param bytes 要转换的字节数组
     * @return 转换后的int
     */
    public final static int bytesToInt(byte[] bytes) {
        return bytesToInt(bytes,0);
    }

    /**
     * 将数组中的部分数据转换为int
     * @param bytes 要转换的数组
     * @param offset 起始偏移量 从0开始
     * @return 读取4个字节的内容 将它们转换为32bit的int并返回
     */
    public final static int bytesToInt(byte[] bytes, int offset) {
        if (bytes == null || offset + 4 > bytes.length)
            throw new IllegalArgumentException("invalid byte array to convert!");
        return (((bytes[0 + offset] & 0xff) << 24) |
                ((bytes[1 + offset] & 0xff) << 16) |
                ((bytes[2 + offset] & 0xff) <<  8) |
                (bytes[3 + offset] & 0xff));
    }
} public interface IBECapsule extends Serializable, IBEConstraints, AutoCloseable {

    /**
     * 设置加密数据
     * @param data 要加密的数据
     */
    void protect(byte[] data);

    /**
     * 把一个实现接口的类加密存储
     * @param object 要存储的类
     */
    void protect(Serializable object);

    /**
     * @return 原始数据
     */
    byte[] getData();

    /**
     * @return 原始类
     */
    Object getDataAsObject() throws ClassNotFoundException;

    /**
     * 设置加密密钥
     * @param key 密钥
     */
    void setKey(byte[] key);

    /**
     * @return 哈希算法名称
     */
    String getHashAlgorithm();

    /**
     * @return 加密算法名称
     */
    String getCrypto();

    /*
     * (non-Javadoc)
     * @see java.lang.AutoCloseable#close()
     */
    void close();
} public class IBECapsuleAESImpl implements IBECapsule {
    private static final long serialVersionUID = 7608124228314005862L;

    private final static String HASH_ALGORITHM = "SHA-512";
    private final static String CRYPTO_ALGORITHM = "AES/CBC/PKCS5Padding";

    /**
     * 明文数据
     */
    private transient byte[] data;

    /**
     * 加密密钥
     */
    private transient byte[] key;

    /**
     * 密文数据
     */
    private transient byte[] cipherText;

    /**
     * 密钥的SHA-512摘要
     */
    private transient byte[] keyHash;

    public IBECapsuleAESImpl() {
    }

    /**
     * 持久化字段格式<br>
     * 加密算法名称（长度一字节 名称最多256字节）<br>
     * 哈希算法名称（长度一字节 名称最多256字节）<br>
     * 哈希值 长度由算法确定<br>
     * 数据有效长度 4字节<br>
     * 加密数据长度 4字节<br>
     * 加密数据
     * @see hamaster.gradesgin.ibe.IBEConstraints#writeExternal(java.io.OutputStream)
     */
    @Override
    public void writeExternal(OutputStream out) throws IOException {
        ensureNotNull(out, data, key);
        byte[] key = Hash.sha256(this.key);
        byte[] iv = Hash.md5(this.key);
        byte[] keyHash = Hash.sha512(this.key);
        byte[] crypt = null;
        try {
            Cipher cipher = Cipher.getInstance(CRYPTO_ALGORITHM);
            cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, "AES"), new IvParameterSpec(iv));
            crypt = cipher.doFinal(data);
        } catch (NoSuchAlgorithmException e) {
        } catch (NoSuchPaddingException e) {
        } catch (InvalidKeyException e) {
            throw new IOException(e);
        } catch (InvalidAlgorithmParameterException e) {
        } catch (IllegalBlockSizeException e) {
            throw new IOException(e);
        } catch (BadPaddingException e) {
            throw new IOException(e);
        } finally {
            Arrays.fill(key, (byte) 0);
            Arrays.fill(iv, (byte) 0);
        }
        if (crypt == null)
            throw new IOException("Cannot encrypt data!");
        byte cl = (byte) CRYPTO_ALGORITHM.length();
        out.write(cl);
        out.write(CRYPTO_ALGORITHM.getBytes());
        out.write((byte) HASH_ALGORITHM.length());
        out.write(HASH_ALGORITHM.getBytes());
        out.write(keyHash);
        out.write(intToByte(data.length));
        out.write(intToByte(crypt.length));
        out.write(crypt);
        out.flush();
    }

    /*
     * (non-Javadoc)
     * @see hamaster.gradesgin.ibe.IBEConstraints#readExternal(java.io.InputStream)
     */
    @Override
    public void readExternal(InputStream in) throws IOException, ClassNotFoundException {
        int cLength = in.read();
        byte[] cBuffer = new byte[cLength];
        cLength = in.read(cBuffer);
        if (cLength != cBuffer.length)
            throw new IOException("Not enough bytes!");
        int hLength = in.read();
        byte[] hnBuffer = new byte[hLength];
        hLength = in.read(hnBuffer);
        if (hLength != hnBuffer.length)
            throw new IOException("Not enough bytes!");
        this.keyHash = new byte[64];
        in.read(keyHash);
        byte[] tmp = new byte[4];
        int tLength = in.read(tmp);
        if (tLength != tmp.length)
            throw new IOException("Not enough bytes!");
        int dataLength = bytesToInt(tmp);
        tLength = in.read(tmp);
        if (tLength != tmp.length)
            throw new IOException("Not enough bytes!");
        int cipherLength = bytesToInt(tmp);
        data = new byte[dataLength];
        cipherText = new byte[cipherLength];
        cipherLength = in.read(cipherText);
        if (cipherLength != cipherText.length)
            throw new IOException("Not enough bytes!");
        if (this.key != null)
            decrypt();
    }

    private void decrypt() throws IOException {
        byte[] key = Hash.sha256(this.key);
        byte[] iv = Hash.md5(this.key);
        try {
            Cipher cipher = Cipher.getInstance(CRYPTO_ALGORITHM);
            cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key, "AES"), new IvParameterSpec(iv));
            byte[] tmp = cipher.doFinal(cipherText);
            System.arraycopy(tmp, 0, data, 0, data.length);
            Arrays.fill(tmp, (byte) 0);
        } catch (NoSuchAlgorithmException e) {
        } catch (NoSuchPaddingException e) {
        } catch (InvalidKeyException e) {
            throw new IOException(e);
        } catch (InvalidAlgorithmParameterException e) {
        } catch (IllegalBlockSizeException e) {
            throw new IOException(e);
        } catch (BadPaddingException e) {
            throw new IOException(e);
        } finally {
            Arrays.fill(key, (byte) 0);
            Arrays.fill(iv, (byte) 0);
        }
    }

    /*
     * (non-Javadoc)
     * @see hamaster.gradesgin.util.IBECapsule#protect(byte[])
     */
    @Override
    public void protect(byte[] data) {
        ensureNotNull(data);
        this.data = data;
    }

    /*
     * (non-Javadoc)
     * @see hamaster.gradesgin.util.IBECapsule#protect(java.io.Serializable)
     */
    @Override
    public void protect(Serializable object) {
        ensureNotNull(object);
        try {
            ByteArrayOutputStream buffer = new ByteArrayOutputStream();
            ObjectOutputStream out = new ObjectOutputStream(buffer);
            out.writeObject(object);
            out.flush();
            buffer.flush();
            this.data = buffer.toByteArray();
            buffer.reset();
            buffer.close();
            out.close();
        } catch (IOException e) {
        }
    }

    /*
     * (non-Javadoc)
     * @see hamaster.gradesgin.util.IBECapsule#getData()
     */
    @Override
    public byte[] getData() {
        return data;
    }

    /*
     * (non-Javadoc)
     * @see hamaster.gradesgin.util.IBECapsule#getDataAsObject()
     */
    @Override
    public Object getDataAsObject() throws ClassNotFoundException {
        try {
            ByteArrayInputStream buffer = new ByteArrayInputStream(getData());
            ObjectInputStream in = new ObjectInputStream(buffer);
            Object obj = in.readObject();
            in.close();
            buffer.reset();
            buffer.close();
            return obj;
        } catch (IOException e) {
            return null;
        }
    }

    /*
     * (non-Javadoc)
     * @see hamaster.gradesgin.util.IBECapsule#setKey(byte[])
     */
    @Override
    public void setKey(byte[] key) {
        ensureNotNull(key);
        this.key = key;
        if (this.cipherText != null) {
            byte [] exc = Hash.sha512(key);
            boolean eq = Arrays.equals(exc, keyHash);
            if (!eq)
                throw new IllegalArgumentException("Invalid key");
            try {
                decrypt();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /*
     * (non-Javadoc)
     * @see hamaster.gradesgin.util.IBECapsule#getHashAlgorithm()
     */
    @Override
    public String getHashAlgorithm() {
        return HASH_ALGORITHM;
    }

    /*
     * (non-Javadoc)
     * @see hamaster.gradesgin.util.IBECapsule#getCrypto()
     */
    @Override
    public String getCrypto() {
        return CRYPTO_ALGORITHM;
    }

    /*
     * (non-Javadoc)
     * @see hamaster.gradesgin.util.IBECapsule#close()
     */
    public void close() {
        if (data != null)
            Arrays.fill(data, (byte) 0);
        if (key != null)
            Arrays.fill(key, (byte) 0);
        if (cipherText != null)
            Arrays.fill(cipherText, (byte) 0);
        if (keyHash != null)
            Arrays.fill(keyHash, (byte) 0);
    }

    private void ensureNotNull(Object ... objs) throws NullPointerException {
        if (objs == null)
            throw new NullPointerException();
        for (Object obj : objs) {
            if (obj == null)
                throw new NullPointerException();
        }
    }
} public interface Encoder {

    String encode(byte[] data);

    byte[] decode(String code);

    String name();
} public class IBECSR implements Serializable {
    private static final long serialVersionUID = -7382866034793567072L;

    final public static int APPLICATION_STATUS_ALL = 0;
    final public static int APPLICATION_STARTED = 1;
    final public static int APPLICATION_APPROVED = 2;
    final public static int APPLICATION_DENIED = 3;
    final public static int APPLICATION_ERROR = 4;
    final public static int APPLICATION_NOT_VERIFIED = 5;
    final public static int APPLICATION_PROCESSING = 6;

    /**
     * 身份描述申请序号
     */
    private Integer requestId;

    /**
     * 身份字符串
     */
    private String identityString;

    /**
     * The IBE encrypted application password.
     * This password will be used to protect generated identity description.
     */
    private byte[] password;

    /**
     * The message digest for this request.
     * It's the SHA-512 checksum for the following contents
     * <table border="1">
     * <tr>
     * <td>identityString.toUTF8Bytes</td>
     * <td>password</td>
     * <td>ibeSystemId.toBytes</td>
     * <td>applicationDate.unixEpoch.toBytes</td>
     * </tr>
     * </table>
     */
    private byte[] digest;

    /**
     * The IBE signature from key distribution server
     */
    private byte[] signature;

    /**
     * 所使用的系统
     */
    private Integer ibeSystemId;

    /**
     * 申请日期
     */
    private Date applicationDate;

    /**
     * 有效期 单位毫秒
     */
    private long period;

    public IBECSR() {
    }

    public Integer getRequestId() {
        return requestId;
    }

    public void setRequestId(Integer requestId) {
        this.requestId = requestId;
    }

    public String getIdentityString() {
        return identityString;
    }

    public void setIdentityString(String identityString) {
        this.identityString = identityString;
    }

    public Integer getIbeSystemId() {
        return ibeSystemId;
    }

    public void setIbeSystemId(Integer ibeSystemId) {
        this.ibeSystemId = ibeSystemId;
    }

    public Date getApplicationDate() {
        return applicationDate;
    }

    public void setApplicationDate(Date applicationDate) {
        this.applicationDate = applicationDate;
    }

    public long getPeriod() {
        return period;
    }

    public void setPeriod(long period) {
        this.period = period;
    }

    public byte[] getPassword() {
        return password;
    }

    public void setPassword(byte[] password) {
        this.password = password;
    }

    public byte[] getSignature() {
        return signature;
    }

    public void setSignature(byte[] signature) {
        this.signature = signature;
    }

    public byte[] getDigest() {
        byte[] message = null;
        try {
            ByteArrayOutputStream out = new ByteArrayOutputStream(1024);
            if (identityString != null)
                out.write(identityString.getBytes("UTF-8"));
            if (password != null)
                out.write(password);
            if (ibeSystemId != null)
                out.write(Hex.intToByte(ibeSystemId.intValue()));
            if (applicationDate != null)
                out.write(Hex.longToBytes(applicationDate.getTime()));
            message = out.toByteArray();
        } catch (IOException e) {
        }
        if (message == null)
            return null;
        return Hash.sha512(message);
    }

    public boolean verifyDigest(byte[] digest) {
        byte[] thisDigest = getDigest();
        if (thisDigest == null && digest == null)
            return false;
        return Arrays.equals(thisDigest, digest);
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((applicationDate == null) ? 0 : applicationDate.hashCode());
        result = prime * result + Arrays.hashCode(digest);
        result = prime * result + ((ibeSystemId == null) ? 0 : ibeSystemId.hashCode());
        result = prime * result + ((identityString == null) ? 0 : identityString.hashCode());
        result = prime * result + Arrays.hashCode(password);
        result = prime * result + (int) (period ^ (period >>> 32));
        result = prime * result + ((requestId == null) ? 0 : requestId.hashCode());
        result = prime * result + Arrays.hashCode(signature);
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        IBECSR other = (IBECSR) obj;
        if (applicationDate == null) {
            if (other.applicationDate != null)
                return false;
        } else if (!applicationDate.equals(other.applicationDate))
            return false;
        if (!Arrays.equals(digest, other.digest))
            return false;
        if (ibeSystemId == null) {
            if (other.ibeSystemId != null)
                return false;
        } else if (!ibeSystemId.equals(other.ibeSystemId))
            return false;
        if (identityString == null) {
            if (other.identityString != null)
                return false;
        } else if (!identityString.equals(other.identityString))
            return false;
        if (!Arrays.equals(password, other.password))
            return false;
        if (period != other.period)
            return false;
        if (requestId == null) {
            if (other.requestId != null)
                return false;
        } else if (!requestId.equals(other.requestId))
            return false;
        if (!Arrays.equals(signature, other.signature))
            return false;
        return true;
    }

    @Override
    public String toString() {
        return "IBECSR [requestId=" + requestId + ", identityString=" + identityString + ", password="
                + Arrays.toString(password) + ", digest=" + Arrays.toString(digest) + ", signature="
                + Arrays.toString(signature) + ", ibeSystemId=" + ibeSystemId + ", applicationDate=" + applicationDate
                + ", period=" + period + "]";
    }
} public class IdentityDescription implements Serializable, SecureConstraints {
    private static final long serialVersionUID = -9068795518061465393L;

    /**
     * 用户私钥
     */
    private IBEPrivateKey privateKey;

    /**
     * 用户签名证书
     */
    private IBSCertificate certificate;

    /**
     * 用户所属于的IBE系统的公共参数
     */
    private IBEPublicParameter systemPublicParameter;

    public IdentityDescription() {
    }

    /**
     * <pre>将身份描述信息转换为字节表示形式：
     * 系统公共参数
     * 用户私钥（不包含所有者身份和椭圆函数参数）
     * 签名证书</pre>
     * @return 字节形式表示的身份描述信息
     */
    public byte[] toByteArray() {
        ByteArrayOutputStream out = new SecureByteArrayOutputStream();
        byte[] id = null;
        try {
            systemPublicParameter.writeExternal(out);
            out.write(privateKey.getrID());
            out.write(privateKey.gethID());
            certificate.writeExternal(out);
            id = out.toByteArray();
        } catch (IOException e) {
        } finally {
            try {
                out.close();
            } catch (IOException e) {
            }
        }
        return id;
    }

    public IBEPrivateKey getPrivateKey() {
        return privateKey;
    }

    public void setPrivateKey(IBEPrivateKey privateKey) {
        this.privateKey = privateKey;
    }

    public IBSCertificate getCertificate() {
        return certificate;
    }

    public void setCertificate(IBSCertificate certificate) {
        this.certificate = certificate;
    }

    public IBEPublicParameter getSystemPublicParameter() {
        return systemPublicParameter;
    }

    public void setSystemPublicParameter(IBEPublicParameter systemPublicParameter) {
        this.systemPublicParameter = systemPublicParameter;
    }
} public class SimpleRESTResponse implements Serializable {
    private static final long serialVersionUID = -8931817682359207120L;

    private int resultCode;

    private String message;

    private Object payload;

    public SimpleRESTResponse() {
    }

    public int getResultCode() {
        return resultCode;
    }

    public void setResultCode(int resultCode) {
        this.resultCode = resultCode;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((message == null) ? 0 : message.hashCode());
        result = prime * result + ((payload == null) ? 0 : payload.hashCode());
        result = prime * result + resultCode;
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        SimpleRESTResponse other = (SimpleRESTResponse) obj;
        if (message == null) {
            if (other.message != null)
                return false;
        } else if (!message.equals(other.message))
            return false;
        if (payload == null) {
            if (other.payload != null)
                return false;
        } else if (!payload.equals(other.payload))
            return false;
        if (resultCode != other.resultCode)
            return false;
        return true;
    }

    @Override
    public String toString() {
        return "SimpleRESTResponse [resultCode=" + resultCode + ", message=" + message + "]";
    }

    public Object getPayload() {
        return payload;
    }

    public void setPayload(Object payload) {
        this.payload = payload;
    }
} @Entity
@Table(name = "IBE_IDENTITY_DESCRIPTION")
public class IdentityDescriptionEntity implements Serializable {
    private static final long serialVersionUID = 5131049791994128188L;

    /**
     * 身份描述ID主键
     */
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "IBE_ID")
    private Integer ibeId;

    /**
     * 所有者名称 值与证书的ownerString字段一致
     */
    @Column(unique = true, nullable = false, name = "ID_OWNER")
    private String idOwner;

    /**
     * 用户所属于的IBE系统
     */
    @ManyToOne(optional = false, fetch = FetchType.LAZY)
    @JoinColumn(name = "SYSTEM")
    private IBESystemEntity system;

    /**
     * 以字节形式存储的加密后的身份描述信息
     */
    @Lob
    @Column(nullable = false, name = "ENCRYPTED_ID")
    private byte[] encryptedIdentityDescription;

    public IdentityDescriptionEntity() {
    }

    public Integer getIbeId() {
        return ibeId;
    }

    public void setIbeId(Integer ibeId) {
        this.ibeId = ibeId;
    }

    public String getIdOwner() {
        return idOwner;
    }

    public void setIdOwner(String idOwner) {
        this.idOwner = idOwner;
    }

    @JsonIgnore
    public IBESystemEntity getSystem() {
        return system;
    }

    public void setSystem(IBESystemEntity system) {
        this.system = system;
    }

    public byte[] getEncryptedIdentityDescription() {
        return encryptedIdentityDescription;
    }

    public void setEncryptedIdentityDescription(byte[] encryptedIdentityDescription) {
        this.encryptedIdentityDescription = encryptedIdentityDescription;
    }

    /**
     * 获取密码保护的IdentityDescription对象
     * 加密方式为AES256_CBC_PKCS5Padding
     * @param aesKey 加密用的密钥
     * @return IdentityDescription对象
     */
    public IdentityDescription getIdentityDescription(byte[] aesKey) {
        if (encryptedIdentityDescription == null)
            return null;
        synchronized (this) {
            IdentityDescription identityDescription;
            IBECapsule capsule = new IBECapsuleAESImpl();
            capsule.setKey(aesKey);
            try {
                ByteArrayInputStream bin = new SecureByteArrayInputStream(encryptedIdentityDescription);
                capsule.readExternal(bin);
                identityDescription = (IdentityDescription) capsule.getDataAsObject();
                bin.close();
            } catch (IOException e) {
                e.printStackTrace();
                return null;
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
                return null;
            }
            return identityDescription;
        }
    }

    /**
     * 使用密码加密<code>IdentityDescription</code>
     * @param identityDescription 要加密的<code>IdentityDescription<code>
     * @param aesKey 加密用密码 可能会被处理后再加密
     */
    public void setIdentityDescription(IdentityDescription identityDescription, byte[] aesKey) {
        synchronized (this) {
            ByteArrayOutputStream bout = new SecureByteArrayOutputStream();
            IBECapsule capsule = new IBECapsuleAESImpl();
            capsule.setKey(aesKey);
            capsule.protect(identityDescription);
            try {
                capsule.writeExternal(bout);
                bout.flush();
                if (encryptedIdentityDescription != null)
                    MemoryUtil.fastSecureBuffers(encryptedIdentityDescription);
                this.encryptedIdentityDescription = bout.toByteArray();
                bout.close();
            } catch (IOException e) {
            }
        }
    }

    /*
     * (non-Javadoc)
     * @see java.lang.Object#hashCode()
     */
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + Arrays.hashCode(encryptedIdentityDescription);
        result = prime * result + ((ibeId == null) ? 0 : ibeId.hashCode());
        result = prime * result + ((idOwner == null) ? 0 : idOwner.hashCode());
        result = prime * result + ((system == null) ? 0 : system.hashCode());
        return result;
    }

    /*
     * (non-Javadoc)
     * @see java.lang.Object#equals(java.lang.Object)
     */
    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (!(obj instanceof IdentityDescriptionEntity))
            return false;
        IdentityDescriptionEntity other = (IdentityDescriptionEntity) obj;
        if (!Arrays.equals(encryptedIdentityDescription,
                           other.encryptedIdentityDescription))
            return false;
        if (ibeId == null) {
            if (other.ibeId != null)
                return false;
        } else if (!ibeId.equals(other.ibeId))
            return false;
        if (idOwner == null) {
            if (other.idOwner != null)
                return false;
        } else if (!idOwner.equals(other.idOwner))
            return false;
        if (system == null) {
            if (other.system != null)
                return false;
        } else if (!system.equals(other.system))
            return false;
        return true;
    }

    /*
     * (non-Javadoc)
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString() {
        return "IdentityDescriptionEntity [ibeId=" + ibeId + ", idOwner="
               + idOwner + ", system=" + system
               + ", encryptedIdentityDescription="
               + Arrays.toString(encryptedIdentityDescription) + "]";
    }
}
import static java.util.Objects.requireNonNull;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.attribute.PosixFilePermission;
import java.nio.file.attribute.PosixFilePermissions;
import java.security.SecureRandom;
import java.util.Date;
import java.util.Map;
import java.util.Properties;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.commons.lang3.SystemUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import hamaster.gradesgin.ibe.IBECipherText;
import hamaster.gradesgin.ibe.IBEPlainText;
import hamaster.gradesgin.ibe.IBEPrivateKey;
import hamaster.gradesgin.ibe.IBEPublicParameter;
import hamaster.gradesgin.ibe.core.IBEEngine;
import hamaster.gradesgin.ibs.IBSCertificate;
import hamaster.gradesgin.ibs.IBSSignature;
import hamaster.gradesgin.util.Hash;
import hamaster.gradesgin.util.Hex;
import hamaster.gradesgin.util.IBECapsule;
import hamaster.gradesgin.util.IBECapsuleAESImpl;
import hamaster.gradesign.keydist.client.Encoder;
import hamaster.gradesign.keygen.IBECSR;
import hamaster.gradesign.keygen.IdentityDescription;
import hamaster.gradesign.keygen.SimpleRESTResponse;
import hamaster.gradesign.keygen.entity.IdentityDescriptionEntity;
package hamaster.gradesign.keydist.daemon;





@Service
public class KeyGenClient {

    @Value("${hamaster.gradesign.keydist.genserver}")
    private String keyGenServereURL;

    @Value("${hamaster.gradesign.keydist.system}")
    private String systemIDStr;

    @Value("${hamaster.gradesign.keydist.server_id}")
    private String serverID;

    @Value("${hamaster.gradesign.keydist.server_key_valid:1000000000000}")
    private Long serverKeyValidPeriod;

    @Value("${hamaster.gradesign.keydist.server_key_dir}")
    private String serverKeyLocation;

    private final static String SERVER_KEY_FILE = "ibedist.key";
    private final static String SERVER_KEY_FILE_CONTENT = "content";
    private final static String SERVER_KEY_FILE_CRYPT_KEY = "key";

    private Integer currentSystemID;
    private IBSCertificate serverCertificate;
    private IBEPrivateKey serverPrivateKey;
    private Encoder base64;