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 interface IBEConstraints {

    /**
     * G*组元素的长度
     */
    int IBE_G_SIZE = 128;

    /**
     * Zr组元素的长度
     */
    int IBE_ZR_SIZE = 20;

    /**
     * 用户ID中使用的默认字符编码
     */
    String USER_STRING_ENCODING = "UTF-8";

    /**
     * 将实例持久化到输出流
     * @param out 输出流
     * @throws IOException 发生IO异常
     */
    void writeExternal(OutputStream out) throws IOException;

    /**
     * 从输入流中读取实例数据
     * @param in 输入流
     * @throws IOException 发生IO异常
     * @throws ClassNotFoundException 读取的数据无法作为类的数据
     */
    void readExternal(InputStream in) throws IOException, ClassNotFoundException;

    default byte[] toByteArray() {
        ByteArrayOutputStream out = new ByteArrayOutputStream(1024);
        try {
            writeExternal(out);
        } catch (IOException e) {
        }
        return out.toByteArray();
    }

    static <T extends IBEConstraints> T fromByteArray(byte[] data, Class<T> clazz) {
        T obj = null;
        try {
            obj = clazz.getConstructor().newInstance();
        } catch (NoSuchMethodException | SecurityException | InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
            return null;
        }
        ByteArrayInputStream in = new ByteArrayInputStream(data);
        try {
            obj.readExternal(in);
        } catch (ClassNotFoundException | IOException e) {
            return null;
        } finally {
            try {
                in.close();
            } catch (IOException e) {
            }
        }
        return obj;
    }
} 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 IBESystemParameter implements Serializable, IBEConstraints {
    private static final long serialVersionUID = 784755162095627372L;

    /**
     * 公共参数
     * The public key
     */
    protected IBEPublicParameter publicParameter;

    /**
     * 主密钥
     * The system master key, all user private keys are generated from this key.
     */
    protected byte[] masterKey;

    public IBESystemParameter() {
    }

    public IBEPublicParameter getPublicParameter() {
        return publicParameter;
    }

    public void setPublicParameter(IBEPublicParameter publicParameter) {
        this.publicParameter = publicParameter;
    }

    public byte[] getMasterKey() {
        return masterKey;
    }

    public void setMasterKey(byte[] masterKey) {
        this.masterKey = masterKey;
    }

    /*
     * (non-Javadoc)
     * @see java.lang.Object#hashCode()
     */
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + Arrays.hashCode(masterKey);
        result = prime * result + ((publicParameter == null) ? 0 : publicParameter.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 IBESystemParameter))
            return false;
        IBESystemParameter other = (IBESystemParameter) obj;
        if (!Arrays.equals(masterKey, other.masterKey))
            return false;
        if (publicParameter == null) {
            if (other.publicParameter != null)
                return false;
        } else if (!publicParameter.equals(other.publicParameter))
            return false;
        return true;
    }

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

    /*
     * (non-Javadoc)
     * @see hamaster.gradesgin.ibe.IBEConstraints#writeExternal(java.io.OutputStream)
     */
    @Override
    public void writeExternal(OutputStream out) throws IOException {
        if (masterKey == null) {
            byte[] zero = new byte[IBE_ZR_SIZE];
            Arrays.fill(zero, (byte) 0);
            out.write(zero);
        } else {
            // TODO encryption is also needed to protect the master key with a password.
            out.write(masterKey);
        }
        if (publicParameter != null)
            publicParameter.writeExternal(out);
        out.flush();
    }

    /*
     * (non-Javadoc)
     * @see hamaster.gradesgin.ibe.IBEConstraints#readExternal(java.io.InputStream)
     */
    @Override
    public void readExternal(InputStream in) throws IOException, ClassNotFoundException {
        this.masterKey = new byte[IBE_ZR_SIZE];
        if (IBE_ZR_SIZE != in.read(masterKey))
            throw new IOException("Not enough bytes for a SystemParameter");
        this.publicParameter = new IBEPublicParameter();
        publicParameter.readExternal(in);
    }
} 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 IBELibrary {
    public final static int PBC_G_SIZE = 128;
    public final static int PBC_ZR_SIZE = 20;

    private IBELibrary() {
    }

    /**
     * 生成系统参数
     * @param alphaOut 系统主密钥，长度20字节
     * @param gOut 参数g，长度128字节
     * @param g1Out 参数g1，长度128字节
     * @param hOut 参数h，长度128字节
     * @param pairingIn 椭圆曲线参数
     * @return
     */
    public final static int setup(byte[] alphaOut, byte[] gOut, byte[] g1Out, byte[] hOut, byte[] pairingIn) {
        ensureArrayCapacity(alphaOut, PBC_ZR_SIZE);
        ensureArrayCapacity(gOut, PBC_G_SIZE);
        ensureArrayCapacity(g1Out, PBC_G_SIZE);
        ensureArrayCapacity(hOut, PBC_G_SIZE);
        return IBENative.setup_str(alphaOut, gOut, g1Out, hOut, pairingIn);
    }

    /**
     * 为用户生成私钥
     * @param hIDOut 私钥hID参数，长度128字节
     * @param rIDOut 私钥rID参数，长度20字节
     * @param userIn 用户身份，如电子邮件地址
     * @param alphaIn 系统主密钥，长度20字节
     * @param gIn 参数g，长度128字节
     * @param hIn 参数h，长度128字节
     * @param pairingIn 椭圆曲线参数
     * @return
     */
    public final static int keygen(byte[] hIDOut, byte[] rIDOut, byte[] userIn, byte[] alphaIn, byte[] gIn, byte[] hIn, byte[] pairingIn) {
        ensureArrayCapacity(rIDOut, PBC_ZR_SIZE);
        ensureArrayCapacity(hIDOut, PBC_G_SIZE);
        return IBENative.keygen_str(hIDOut, rIDOut, userIn, alphaIn, gIn, hIn, pairingIn, true);
    }

    /**
     * 加密数据
     * @param cipherBufferOut 输出密文，长度384字节，按照uvw顺序排列
     * @param plainIn 明文，长度128字节
     * @param gIn 接收方参数g，长度128字节
     * @param g1In 接收方参数g1，长度128字节
     * @param hIn 接收方参数h，长度128字节
     * @param aliceIn 接收方身份，长度20字节
     * @param pairingIn 椭圆曲线参数
     * @return
     */
    public final static int encrypt(byte[] cipherBufferOut, byte[] plainIn, byte[] gIn, byte[] g1In, byte[] hIn, byte[] aliceIn, byte[] pairingIn) {
        ensureArrayCapacity(cipherBufferOut, 3 * PBC_G_SIZE);
        return IBENative.encrypt_str(cipherBufferOut, plainIn, gIn, g1In, hIn, aliceIn, pairingIn);
    }

    /**
     * 解密数据
     * @param plainBufferOut 输出明文，长度128字节
     * @param cipherIn 输入密文，长度384字节，按照uvw顺序排列
     * @param rIDIn 接收方私钥rID，长度20字节
     * @param hIDIn 接收方私钥hID，长度128字节
     * @param pairingIn 椭圆曲线参数
     * @return
     */
    public final static int decrypt(byte[] plainBufferOut, byte[] cipherIn, byte[] rIDIn, byte[] hIDIn, byte[] pairingIn) {
        ensureArrayCapacity(plainBufferOut, PBC_G_SIZE);
        return IBENative.decrypt_str(plainBufferOut, cipherIn, rIDIn, hIDIn, pairingIn);
    }

    private final static void ensureArrayCapacity(byte[] array, int min) {
        if (array == null)
            throw new InvalidKeySizeException(new StringBuilder("array size must be at least:").append(min).append(",actural:0").toString());
        if (min < 1)
            throw new IllegalArgumentException(new StringBuilder("minimum size must be above zero:").append(min).toString());
        if (array.length < min)
            throw new InvalidKeySizeException(new StringBuilder("array size must be at least:").append(min).append(",actural:").append(array.length).toString());
    }
}
import hamaster.gradesgin.ibe.IBECipherText;
import hamaster.gradesgin.ibe.IBEConstraints;
import hamaster.gradesgin.ibe.IBEPlainText;
import hamaster.gradesgin.ibe.IBEPrivateKey;
import hamaster.gradesgin.ibe.IBEPublicParameter;
import hamaster.gradesgin.ibe.IBESystemParameter;
import hamaster.gradesgin.ibs.IBSCertificate;
import hamaster.gradesgin.ibs.IBSSignature;
import hamaster.gradesgin.util.Hash;
import hamaster.gradesign.ibe.IBELibrary;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
import java.util.Date;
import java.util.Random;
package hamaster.gradesgin.ibe.core;



/**
 * 基于身份加密(IBE)的核心库，提供相关的方法
 * Core utils of IBE
 * @author <a href="mailto:wangyeee@gmail.com">Wang Ye</a>
 */
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(),