diff options
Diffstat (limited to 'bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece')
14 files changed, 3137 insertions, 0 deletions
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/BCMcElieceCCA2PrivateKey.java b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/BCMcElieceCCA2PrivateKey.java new file mode 100644 index 0000000..72400de --- /dev/null +++ b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/BCMcElieceCCA2PrivateKey.java @@ -0,0 +1,307 @@ +package org.bouncycastle.pqc.jcajce.provider.mceliece; + +import java.io.IOException; +import java.security.PrivateKey; + +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.DERNull; +import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import org.bouncycastle.crypto.CipherParameters; +import org.bouncycastle.pqc.asn1.McElieceCCA2PrivateKey; +import org.bouncycastle.pqc.crypto.mceliece.McElieceCCA2KeyPairGenerator; +import org.bouncycastle.pqc.crypto.mceliece.McElieceCCA2Parameters; +import org.bouncycastle.pqc.crypto.mceliece.McElieceCCA2PrivateKeyParameters; +import org.bouncycastle.pqc.jcajce.spec.McElieceCCA2PrivateKeySpec; +import org.bouncycastle.pqc.math.linearalgebra.GF2Matrix; +import org.bouncycastle.pqc.math.linearalgebra.GF2mField; +import org.bouncycastle.pqc.math.linearalgebra.Permutation; +import org.bouncycastle.pqc.math.linearalgebra.PolynomialGF2mSmallM; + +/** + * This class implements a McEliece CCA2 private key and is usually instantiated + * by the {@link McElieceCCA2KeyPairGenerator} or {@link McElieceCCA2KeyFactorySpi}. + * + * @see McElieceCCA2KeyPairGenerator + */ +public class BCMcElieceCCA2PrivateKey + implements CipherParameters, PrivateKey +{ + + + /** + * + */ + private static final long serialVersionUID = 1L; + + // the OID of the algorithm + private String oid; + + // the length of the code + private int n; + + // the dimension of the code, k>=n-mt + private int k; + + // the finte field GF(2^m) + private GF2mField field; + + // the irreducible Goppa polynomial + private PolynomialGF2mSmallM goppaPoly; + + // the permutation + private Permutation p; + + // the canonical check matrix + private GF2Matrix h; + + // the matrix used to compute square roots in (GF(2^m))^t + private PolynomialGF2mSmallM[] qInv; + + private McElieceCCA2Parameters mcElieceCCA2Params; + + /** + * Constructor (used by the {@link McElieceCCA2KeyPairGenerator}). + * + * @param n the length of the code + * @param k the dimension of the code + * @param field the field polynomial + * @param gp the irreducible Goppa polynomial + * @param p the permutation + * @param h the canonical check matrix + * @param qInv the matrix used to compute square roots in + * <tt>(GF(2^m))^t</tt> + */ + public BCMcElieceCCA2PrivateKey(String oid, int n, int k, GF2mField field, + PolynomialGF2mSmallM gp, Permutation p, GF2Matrix h, + PolynomialGF2mSmallM[] qInv) + { + this.oid = oid; + this.n = n; + this.k = k; + this.field = field; + this.goppaPoly = gp; + this.p = p; + this.h = h; + this.qInv = qInv; + } + + /** + * Constructor (used by the {@link McElieceCCA2KeyFactorySpi}). + * + * @param keySpec a {@link McElieceCCA2PrivateKeySpec} + */ + public BCMcElieceCCA2PrivateKey(McElieceCCA2PrivateKeySpec keySpec) + { + this(keySpec.getOIDString(), keySpec.getN(), keySpec.getK(), keySpec.getField(), keySpec + .getGoppaPoly(), keySpec.getP(), keySpec.getH(), keySpec + .getQInv()); + } + + public BCMcElieceCCA2PrivateKey(McElieceCCA2PrivateKeyParameters params) + { + this(params.getOIDString(), params.getN(), params.getK(), params.getField(), params.getGoppaPoly(), + params.getP(), params.getH(), params.getQInv()); + this.mcElieceCCA2Params = params.getParameters(); + } + + /** + * Return the name of the algorithm. + * + * @return "McEliece" + */ + public String getAlgorithm() + { + return "McEliece"; + } + + /** + * @return the length of the code + */ + public int getN() + { + return n; + } + + /** + * @return the dimension of the code + */ + public int getK() + { + return k; + } + + /** + * @return the degree of the Goppa polynomial (error correcting capability) + */ + public int getT() + { + return goppaPoly.getDegree(); + } + + /** + * @return the finite field + */ + public GF2mField getField() + { + return field; + } + + /** + * @return the irreducible Goppa polynomial + */ + public PolynomialGF2mSmallM getGoppaPoly() + { + return goppaPoly; + } + + /** + * @return the permutation vector + */ + public Permutation getP() + { + return p; + } + + /** + * @return the canonical check matrix + */ + public GF2Matrix getH() + { + return h; + } + + /** + * @return the matrix used to compute square roots in <tt>(GF(2^m))^t</tt> + */ + public PolynomialGF2mSmallM[] getQInv() + { + return qInv; + } + + /** + * @return a human readable form of the key + */ + public String toString() + { + String result = ""; + result += " extension degree of the field : " + n + "\n"; + result += " dimension of the code : " + k + "\n"; + result += " irreducible Goppa polynomial : " + goppaPoly + "\n"; + return result; + } + + /** + * Compare this key with another object. + * + * @param other the other object + * @return the result of the comparison + */ + public boolean equals(Object other) + { + if (other == null || !(other instanceof BCMcElieceCCA2PrivateKey)) + { + return false; + } + + BCMcElieceCCA2PrivateKey otherKey = (BCMcElieceCCA2PrivateKey)other; + + return (n == otherKey.n) && (k == otherKey.k) + && field.equals(otherKey.field) + && goppaPoly.equals(otherKey.goppaPoly) && p.equals(otherKey.p) + && h.equals(otherKey.h); + } + + /** + * @return the hash code of this key + */ + public int hashCode() + { + return k + n + field.hashCode() + goppaPoly.hashCode() + p.hashCode() + + h.hashCode(); + } + + /** + * @return the OID of the algorithm + */ + public String getOIDString() + { + return oid; + } + + /** + * @return the OID to encode in the SubjectPublicKeyInfo structure + */ + protected ASN1ObjectIdentifier getOID() + { + return new ASN1ObjectIdentifier(McElieceCCA2KeyFactorySpi.OID); + } + + /** + * @return the algorithm parameters to encode in the SubjectPublicKeyInfo + * structure + */ + protected ASN1Primitive getAlgParams() + { + return null; // FIXME: needed at all? + } + + + /** + * Return the keyData to encode in the SubjectPublicKeyInfo structure. + * <p/> + * The ASN.1 definition of the key structure is + * <p/> + * <pre> + * McEliecePrivateKey ::= SEQUENCE { + * m INTEGER -- extension degree of the field + * k INTEGER -- dimension of the code + * field OCTET STRING -- field polynomial + * goppaPoly OCTET STRING -- irreducible Goppa polynomial + * p OCTET STRING -- permutation vector + * matrixH OCTET STRING -- canonical check matrix + * sqRootMatrix SEQUENCE OF OCTET STRING -- square root matrix + * } + * </pre> + * + * @return the keyData to encode in the SubjectPublicKeyInfo structure + */ + public byte[] getEncoded() + { + McElieceCCA2PrivateKey privateKey = new McElieceCCA2PrivateKey(new ASN1ObjectIdentifier(oid), n, k, field, goppaPoly, p, h, qInv); + PrivateKeyInfo pki; + try + { + AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(this.getOID(), DERNull.INSTANCE); + pki = new PrivateKeyInfo(algorithmIdentifier, privateKey); + } + catch (IOException e) + { + e.printStackTrace(); + return null; + } + try + { + byte[] encoded = pki.getEncoded(); + return encoded; + } + catch (IOException e) + { + e.printStackTrace(); + return null; + } + } + + public String getFormat() + { + // TODO Auto-generated method stub + return null; + } + + public McElieceCCA2Parameters getMcElieceCCA2Parameters() + { + return mcElieceCCA2Params; + } + +} diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/BCMcElieceCCA2PublicKey.java b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/BCMcElieceCCA2PublicKey.java new file mode 100644 index 0000000..3646933 --- /dev/null +++ b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/BCMcElieceCCA2PublicKey.java @@ -0,0 +1,227 @@ +package org.bouncycastle.pqc.jcajce.provider.mceliece; + + +import java.io.IOException; +import java.security.PublicKey; + +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.DERNull; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; +import org.bouncycastle.crypto.CipherParameters; +import org.bouncycastle.pqc.asn1.McElieceCCA2PublicKey; +import org.bouncycastle.pqc.crypto.mceliece.McElieceCCA2KeyPairGenerator; +import org.bouncycastle.pqc.crypto.mceliece.McElieceCCA2Parameters; +import org.bouncycastle.pqc.crypto.mceliece.McElieceCCA2PublicKeyParameters; +import org.bouncycastle.pqc.jcajce.spec.McElieceCCA2PublicKeySpec; +import org.bouncycastle.pqc.math.linearalgebra.GF2Matrix; + +/** + * This class implements a McEliece CCA2 public key and is usually instantiated + * by the {@link McElieceCCA2KeyPairGenerator} or {@link McElieceCCA2KeyFactorySpi}. + */ +public class BCMcElieceCCA2PublicKey + implements CipherParameters, PublicKey +{ + + /** + * + */ + private static final long serialVersionUID = 1L; + + // the OID of the algorithm + private String oid; + + // the length of the code + private int n; + + // the error correction capability of the code + private int t; + + // the generator matrix + private GF2Matrix g; + + private McElieceCCA2Parameters McElieceCCA2Params; + + /** + * Constructor (used by the {@link McElieceCCA2KeyPairGenerator}). + * + * @param n the length of the code + * @param t the error correction capability of the code + * @param g the generator matrix + */ + public BCMcElieceCCA2PublicKey(String oid, int n, int t, GF2Matrix g) + { + this.oid = oid; + this.n = n; + this.t = t; + this.g = g; + } + + /** + * Constructor (used by the {@link McElieceCCA2KeyFactorySpi}). + * + * @param keySpec a {@link McElieceCCA2PublicKeySpec} + */ + public BCMcElieceCCA2PublicKey(McElieceCCA2PublicKeySpec keySpec) + { + this(keySpec.getOIDString(), keySpec.getN(), keySpec.getT(), keySpec.getMatrixG()); + } + + public BCMcElieceCCA2PublicKey(McElieceCCA2PublicKeyParameters params) + { + this(params.getOIDString(), params.getN(), params.getT(), params.getMatrixG()); + this.McElieceCCA2Params = params.getParameters(); + } + + /** + * Return the name of the algorithm. + * + * @return "McEliece" + */ + public String getAlgorithm() + { + return "McEliece"; + } + + /** + * @return the length of the code + */ + public int getN() + { + return n; + } + + /** + * @return the dimension of the code + */ + public int getK() + { + return g.getNumRows(); + } + + /** + * @return the error correction capability of the code + */ + public int getT() + { + return t; + } + + /** + * @return the generator matrix + */ + public GF2Matrix getG() + { + return g; + } + + /** + * @return a human readable form of the key + */ + public String toString() + { + String result = "McEliecePublicKey:\n"; + result += " length of the code : " + n + "\n"; + result += " error correction capability: " + t + "\n"; + result += " generator matrix : " + g.toString(); + return result; + } + + /** + * Compare this key with another object. + * + * @param other the other object + * @return the result of the comparison + */ + public boolean equals(Object other) + { + if (other == null || !(other instanceof BCMcElieceCCA2PublicKey)) + { + return false; + } + + BCMcElieceCCA2PublicKey otherKey = (BCMcElieceCCA2PublicKey)other; + + return (n == otherKey.n) && (t == otherKey.t) && (g.equals(otherKey.g)); + } + + /** + * @return the hash code of this key + */ + public int hashCode() + { + return n + t + g.hashCode(); + } + + /** + * @return the OID of the algorithm + */ + public String getOIDString() + { + return oid; + } + + /** + * @return the OID to encode in the SubjectPublicKeyInfo structure + */ + protected ASN1ObjectIdentifier getOID() + { + return new ASN1ObjectIdentifier(McElieceCCA2KeyFactorySpi.OID); + } + + /** + * @return the algorithm parameters to encode in the SubjectPublicKeyInfo + * structure + */ + protected ASN1Primitive getAlgParams() + { + return null; // FIXME: needed at all? + } + + /** + * Return the keyData to encode in the SubjectPublicKeyInfo structure. + * <p/> + * The ASN.1 definition of the key structure is + * <p/> + * <pre> + * McEliecePublicKey ::= SEQUENCE { + * n Integer -- length of the code + * t Integer -- error correcting capability + * matrixG OctetString -- generator matrix as octet string + * } + * </pre> + * + * @return the keyData to encode in the SubjectPublicKeyInfo structure + */ + public byte[] getEncoded() + { + McElieceCCA2PublicKey key = new McElieceCCA2PublicKey(new ASN1ObjectIdentifier(oid), n, t, g); + AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(this.getOID(), DERNull.INSTANCE); + + try + { + SubjectPublicKeyInfo subjectPublicKeyInfo = new SubjectPublicKeyInfo(algorithmIdentifier, key); + + return subjectPublicKeyInfo.getEncoded(); + } + catch (IOException e) + { + return null; + } + + } + + public String getFormat() + { + // TODO Auto-generated method stub + return null; + } + + public McElieceCCA2Parameters getMcElieceCCA2Parameters() + { + return McElieceCCA2Params; + } + +} diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/BCMcEliecePrivateKey.java b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/BCMcEliecePrivateKey.java new file mode 100644 index 0000000..be93b31 --- /dev/null +++ b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/BCMcEliecePrivateKey.java @@ -0,0 +1,334 @@ +package org.bouncycastle.pqc.jcajce.provider.mceliece; + +import java.io.IOException; +import java.security.PrivateKey; + +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.DERNull; +import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import org.bouncycastle.crypto.CipherParameters; +import org.bouncycastle.pqc.asn1.McEliecePrivateKey; +import org.bouncycastle.pqc.crypto.mceliece.McElieceKeyPairGenerator; +import org.bouncycastle.pqc.crypto.mceliece.McElieceParameters; +import org.bouncycastle.pqc.crypto.mceliece.McEliecePrivateKeyParameters; +import org.bouncycastle.pqc.jcajce.spec.McEliecePrivateKeySpec; +import org.bouncycastle.pqc.math.linearalgebra.GF2Matrix; +import org.bouncycastle.pqc.math.linearalgebra.GF2mField; +import org.bouncycastle.pqc.math.linearalgebra.Permutation; +import org.bouncycastle.pqc.math.linearalgebra.PolynomialGF2mSmallM; + +/** + * This class implements a McEliece private key and is usually instantiated by + * the {@link McElieceKeyPairGenerator} or {@link McElieceKeyFactorySpi}. + */ +public class BCMcEliecePrivateKey + implements CipherParameters, PrivateKey +{ + + /** + * + */ + private static final long serialVersionUID = 1L; + + // the OID of the algorithm + private String oid; + + // the length of the code + private int n; + + // the dimension of the code, where <tt>k >= n - mt</tt> + private int k; + + // the underlying finite field + private GF2mField field; + + // the irreducible Goppa polynomial + private PolynomialGF2mSmallM goppaPoly; + + // the matrix S^-1 + private GF2Matrix sInv; + + // the permutation P1 used to generate the systematic check matrix + private Permutation p1; + + // the permutation P2 used to compute the public generator matrix + private Permutation p2; + + // the canonical check matrix of the code + private GF2Matrix h; + + // the matrix used to compute square roots in <tt>(GF(2^m))^t</tt> + private PolynomialGF2mSmallM[] qInv; + + private McElieceParameters mcElieceParams; + + + /** + * Constructor (used by the {@link McElieceKeyPairGenerator}). + * + * @param oid + * @param n the length of the code + * @param k the dimension of the code + * @param field the field polynomial defining the finite field + * <tt>GF(2<sup>m</sup>)</tt> + * @param goppaPoly the irreducible Goppa polynomial + * @param sInv the matrix <tt>S<sup>-1</sup></tt> + * @param p1 the permutation used to generate the systematic check + * matrix + * @param p2 the permutation used to compute the public generator + * matrix + * @param h the canonical check matrix + * @param qInv the matrix used to compute square roots in + * <tt>(GF(2<sup>m</sup>))<sup>t</sup></tt> + */ + public BCMcEliecePrivateKey(String oid, int n, int k, GF2mField field, + PolynomialGF2mSmallM goppaPoly, GF2Matrix sInv, Permutation p1, + Permutation p2, GF2Matrix h, PolynomialGF2mSmallM[] qInv) + { + this.oid = oid; + this.n = n; + this.k = k; + this.field = field; + this.goppaPoly = goppaPoly; + this.sInv = sInv; + this.p1 = p1; + this.p2 = p2; + this.h = h; + this.qInv = qInv; + } + + /** + * Constructor (used by the {@link McElieceKeyFactorySpi}). + * + * @param keySpec a {@link McEliecePrivateKeySpec} + */ + public BCMcEliecePrivateKey(McEliecePrivateKeySpec keySpec) + { + this(keySpec.getOIDString(), keySpec.getN(), keySpec.getK(), keySpec.getField(), keySpec + .getGoppaPoly(), keySpec.getSInv(), keySpec.getP1(), keySpec + .getP2(), keySpec.getH(), keySpec.getQInv()); + } + + public BCMcEliecePrivateKey(McEliecePrivateKeyParameters params) + { + this(params.getOIDString(), params.getN(), params.getK(), params.getField(), params.getGoppaPoly(), + params.getSInv(), params.getP1(), params.getP2(), params.getH(), params.getQInv()); + + this.mcElieceParams = params.getParameters(); + } + + + /** + * Return the name of the algorithm. + * + * @return "McEliece" + */ + public String getAlgorithm() + { + return "McEliece"; + } + + /** + * @return the length of the code + */ + public int getN() + { + return n; + } + + /** + * @return the dimension of the code + */ + public int getK() + { + return k; + } + + /** + * @return the finite field + */ + public GF2mField getField() + { + return field; + } + + /** + * @return the irreducible Goppa polynomial + */ + public PolynomialGF2mSmallM getGoppaPoly() + { + return goppaPoly; + } + + /** + * @return the k x k random binary non-singular matrix S + */ + public GF2Matrix getSInv() + { + return sInv; + } + + /** + * @return the permutation used to generate the systematic check matrix + */ + public Permutation getP1() + { + return p1; + } + + /** + * @return the permutation used to compute the public generator matrix + */ + public Permutation getP2() + { + return p2; + } + + /** + * @return the canonical check matrix + */ + public GF2Matrix getH() + { + return h; + } + + /** + * @return the matrix for computing square roots in <tt>(GF(2^m))^t</tt> + */ + public PolynomialGF2mSmallM[] getQInv() + { + return qInv; + } + + /** + * @return the OID of the algorithm + */ + public String getOIDString() + { + return oid; + } + + /** + * @return a human readable form of the key + */ + public String toString() + { + String result = " length of the code : " + n + "\n"; + result += " dimension of the code : " + k + "\n"; + result += " irreducible Goppa polynomial: " + goppaPoly + "\n"; + result += " (k x k)-matrix S^-1 : " + sInv + "\n"; + result += " permutation P1 : " + p1 + "\n"; + result += " permutation P2 : " + p2; + return result; + } + + /** + * Compare this key with another object. + * + * @param other the other object + * @return the result of the comparison + */ + public boolean equals(Object other) + { + if (!(other instanceof BCMcEliecePrivateKey)) + { + return false; + } + BCMcEliecePrivateKey otherKey = (BCMcEliecePrivateKey)other; + + return (n == otherKey.n) && (k == otherKey.k) + && field.equals(otherKey.field) + && goppaPoly.equals(otherKey.goppaPoly) + && sInv.equals(otherKey.sInv) && p1.equals(otherKey.p1) + && p2.equals(otherKey.p2) && h.equals(otherKey.h); + } + + /** + * @return the hash code of this key + */ + public int hashCode() + { + return k + n + field.hashCode() + goppaPoly.hashCode() + + sInv.hashCode() + p1.hashCode() + p2.hashCode() + + h.hashCode(); + } + + /** + * @return the OID to encode in the SubjectPublicKeyInfo structure + */ + protected ASN1ObjectIdentifier getOID() + { + return new ASN1ObjectIdentifier(McElieceKeyFactorySpi.OID); + } + + /** + * @return the algorithm parameters to encode in the SubjectPublicKeyInfo + * structure + */ + protected ASN1Primitive getAlgParams() + { + return null; // FIXME: needed at all? + } + + /** + * Return the key data to encode in the SubjectPublicKeyInfo structure. + * <p/> + * The ASN.1 definition of the key structure is + * <p/> + * <pre> + * McEliecePrivateKey ::= SEQUENCE { + * n INTEGER -- length of the code + * k INTEGER -- dimension of the code + * fieldPoly OCTET STRING -- field polynomial defining GF(2ˆm) + * goppaPoly OCTET STRING -- irreducible Goppa polynomial + * sInv OCTET STRING -- matrix Sˆ-1 + * p1 OCTET STRING -- permutation P1 + * p2 OCTET STRING -- permutation P2 + * h OCTET STRING -- canonical check matrix + * qInv SEQUENCE OF OCTET STRING -- matrix used to compute square roots + * } + * </pre> + * + * @return the key data to encode in the SubjectPublicKeyInfo structure + */ + public byte[] getEncoded() + { + McEliecePrivateKey privateKey = new McEliecePrivateKey(new ASN1ObjectIdentifier(oid), n, k, field, goppaPoly, sInv, p1, p2, h, qInv); + PrivateKeyInfo pki; + try + { + AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(this.getOID(), DERNull.INSTANCE); + pki = new PrivateKeyInfo(algorithmIdentifier, privateKey); + } + catch (IOException e) + { + e.printStackTrace(); + return null; + } + try + { + byte[] encoded = pki.getEncoded(); + return encoded; + } + catch (IOException e) + { + e.printStackTrace(); + return null; + } + } + + public String getFormat() + { + // TODO Auto-generated method stub + return null; + } + + public McElieceParameters getMcElieceParameters() + { + return mcElieceParams; + } + + +} diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/BCMcEliecePublicKey.java b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/BCMcEliecePublicKey.java new file mode 100644 index 0000000..4e278c9 --- /dev/null +++ b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/BCMcEliecePublicKey.java @@ -0,0 +1,231 @@ +package org.bouncycastle.pqc.jcajce.provider.mceliece; + +import java.io.IOException; +import java.security.PublicKey; + +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.DERNull; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; +import org.bouncycastle.crypto.CipherParameters; +import org.bouncycastle.pqc.asn1.McEliecePublicKey; +import org.bouncycastle.pqc.crypto.mceliece.McElieceKeyPairGenerator; +import org.bouncycastle.pqc.crypto.mceliece.McElieceParameters; +import org.bouncycastle.pqc.crypto.mceliece.McEliecePublicKeyParameters; +import org.bouncycastle.pqc.jcajce.spec.McEliecePublicKeySpec; +import org.bouncycastle.pqc.math.linearalgebra.GF2Matrix; + +/** + * This class implements a McEliece public key and is usually instantiated by + * the {@link McElieceKeyPairGenerator} or {@link McElieceKeyFactorySpi}. + */ +public class BCMcEliecePublicKey + implements CipherParameters, PublicKey +{ + + /** + * + */ + private static final long serialVersionUID = 1L; + + // the OID of the algorithm + private String oid; + + /** + * the length of the code + */ + private int n; + + /** + * the error correction capability of the code + */ + private int t; + + /** + * the generator matrix + */ + private GF2Matrix g; + + private McElieceParameters McElieceParams; + + /** + * Constructor (used by the {@link McElieceKeyPairGenerator}). + * + * @param oid + * @param n the length of the code + * @param t the error correction capability of the code + * @param g the generator matrix + */ + public BCMcEliecePublicKey(String oid, int n, int t, GF2Matrix g) + { + this.oid = oid; + this.n = n; + this.t = t; + this.g = g; + } + + /** + * Constructor (used by the {@link McElieceKeyFactorySpi}). + * + * @param keySpec a {@link McEliecePublicKeySpec} + */ + public BCMcEliecePublicKey(McEliecePublicKeySpec keySpec) + { + this(keySpec.getOIDString(), keySpec.getN(), keySpec.getT(), keySpec.getG()); + } + + public BCMcEliecePublicKey(McEliecePublicKeyParameters params) + { + this(params.getOIDString(), params.getN(), params.getT(), params.getG()); + this.McElieceParams = params.getParameters(); + } + + /** + * Return the name of the algorithm. + * + * @return "McEliece" + */ + public String getAlgorithm() + { + return "McEliece"; + } + + /** + * @return the length of the code + */ + public int getN() + { + return n; + } + + /** + * @return the dimension of the code + */ + public int getK() + { + return g.getNumRows(); + } + + /** + * @return the error correction capability of the code + */ + public int getT() + { + return t; + } + + /** + * @return the generator matrix + */ + public GF2Matrix getG() + { + return g; + } + + /** + * @return a human readable form of the key + */ + public String toString() + { + String result = "McEliecePublicKey:\n"; + result += " length of the code : " + n + "\n"; + result += " error correction capability: " + t + "\n"; + result += " generator matrix : " + g.toString(); + return result; + } + + /** + * Compare this key with another object. + * + * @param other the other object + * @return the result of the comparison + */ + public boolean equals(Object other) + { + if (!(other instanceof BCMcEliecePublicKey)) + { + return false; + } + BCMcEliecePublicKey otherKey = (BCMcEliecePublicKey)other; + + return (n == otherKey.n) && (t == otherKey.t) && g.equals(otherKey.g); + } + + /** + * @return the hash code of this key + */ + public int hashCode() + { + return n + t + g.hashCode(); + } + + + /** + * @return the OID of the algorithm + */ + public String getOIDString() + { + return oid; + } + + /** + * @return the OID to encode in the SubjectPublicKeyInfo structure + */ + protected ASN1ObjectIdentifier getOID() + { + return new ASN1ObjectIdentifier(McElieceKeyFactorySpi.OID); + } + + /** + * @return the algorithm parameters to encode in the SubjectPublicKeyInfo + * structure + */ + protected ASN1Primitive getAlgParams() + { + return null; // FIXME: needed at all? + } + + + /** + * Return the keyData to encode in the SubjectPublicKeyInfo structure. + * <p/> + * The ASN.1 definition of the key structure is + * <p/> + * <pre> + * McEliecePublicKey ::= SEQUENCE { + * n Integer -- length of the code + * t Integer -- error correcting capability + * matrixG OctetString -- generator matrix as octet string + * } + * </pre> + * + * @return the keyData to encode in the SubjectPublicKeyInfo structure + */ + public byte[] getEncoded() + { + McEliecePublicKey key = new McEliecePublicKey(new ASN1ObjectIdentifier(oid), n, t, g); + AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(this.getOID(), DERNull.INSTANCE); + + try + { + SubjectPublicKeyInfo subjectPublicKeyInfo = new SubjectPublicKeyInfo(algorithmIdentifier, key); + + return subjectPublicKeyInfo.getEncoded(); + } + catch (IOException e) + { + return null; + } + } + + public String getFormat() + { + return null; + } + + public McElieceParameters getMcElieceParameters() + { + return McElieceParams; + } +} diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceCCA2KeyFactorySpi.java b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceCCA2KeyFactorySpi.java new file mode 100644 index 0000000..c6ca7c2 --- /dev/null +++ b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceCCA2KeyFactorySpi.java @@ -0,0 +1,346 @@ +package org.bouncycastle.pqc.jcajce.provider.mceliece; + +import java.io.IOException; +import java.math.BigInteger; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.KeyFactorySpi; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.KeySpec; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.X509EncodedKeySpec; + +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; +import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; +import org.bouncycastle.pqc.asn1.McElieceCCA2PrivateKey; +import org.bouncycastle.pqc.asn1.McElieceCCA2PublicKey; +import org.bouncycastle.pqc.jcajce.spec.McElieceCCA2PrivateKeySpec; +import org.bouncycastle.pqc.jcajce.spec.McElieceCCA2PublicKeySpec; + +/** + * This class is used to translate between McEliece CCA2 keys and key + * specifications. + * + * @see BCMcElieceCCA2PrivateKey + * @see McElieceCCA2PrivateKeySpec + * @see BCMcElieceCCA2PublicKey + * @see McElieceCCA2PublicKeySpec + */ +public class McElieceCCA2KeyFactorySpi + extends KeyFactorySpi +{ + + /** + * The OID of the algorithm. + */ + public static final String OID = "1.3.6.1.4.1.8301.3.1.3.4.2"; + + /** + * Converts, if possible, a key specification into a + * {@link BCMcElieceCCA2PublicKey}. Currently, the following key + * specifications are supported: {@link McElieceCCA2PublicKeySpec}, + * {@link X509EncodedKeySpec}. + * + * @param keySpec the key specification + * @return the McEliece CCA2 public key + * @throws InvalidKeySpecException if the key specification is not supported. + */ + public PublicKey generatePublic(KeySpec keySpec) + throws InvalidKeySpecException + { + if (keySpec instanceof McElieceCCA2PublicKeySpec) + { + return new BCMcElieceCCA2PublicKey( + (McElieceCCA2PublicKeySpec)keySpec); + } + else if (keySpec instanceof X509EncodedKeySpec) + { + // get the DER-encoded Key according to X.509 from the spec + byte[] encKey = ((X509EncodedKeySpec)keySpec).getEncoded(); + + // decode the SubjectPublicKeyInfo data structure to the pki object + SubjectPublicKeyInfo pki; + try + { + pki = SubjectPublicKeyInfo.getInstance(ASN1Primitive.fromByteArray(encKey)); + } + catch (IOException e) + { + throw new InvalidKeySpecException(e.toString()); + } + + + try + { + // --- Build and return the actual key. + ASN1Primitive innerType = pki.parsePublicKey(); + ASN1Sequence publicKey = (ASN1Sequence)innerType; + + // decode oidString (but we don't need it right now) + String oidString = ((ASN1ObjectIdentifier)publicKey.getObjectAt(0)) + .toString(); + + // decode <n> + BigInteger bigN = ((ASN1Integer)publicKey.getObjectAt(1)).getValue(); + int n = bigN.intValue(); + + // decode <t> + BigInteger bigT = ((ASN1Integer)publicKey.getObjectAt(2)).getValue(); + int t = bigT.intValue(); + + // decode <matrixG> + byte[] matrixG = ((ASN1OctetString)publicKey.getObjectAt(3)).getOctets(); + + return new BCMcElieceCCA2PublicKey(new McElieceCCA2PublicKeySpec( + OID, n, t, matrixG)); + } + catch (IOException cce) + { + throw new InvalidKeySpecException( + "Unable to decode X509EncodedKeySpec: " + + cce.getMessage()); + } + } + + throw new InvalidKeySpecException("Unsupported key specification: " + + keySpec.getClass() + "."); + } + + /** + * Converts, if possible, a key specification into a + * {@link BCMcElieceCCA2PrivateKey}. Currently, the following key + * specifications are supported: {@link McElieceCCA2PrivateKeySpec}, + * {@link PKCS8EncodedKeySpec}. + * + * @param keySpec the key specification + * @return the McEliece CCA2 private key + * @throws InvalidKeySpecException if the KeySpec is not supported. + */ + public PrivateKey generatePrivate(KeySpec keySpec) + throws InvalidKeySpecException + { + if (keySpec instanceof McElieceCCA2PrivateKeySpec) + { + return new BCMcElieceCCA2PrivateKey( + (McElieceCCA2PrivateKeySpec)keySpec); + } + else if (keySpec instanceof PKCS8EncodedKeySpec) + { + // get the DER-encoded Key according to PKCS#8 from the spec + byte[] encKey = ((PKCS8EncodedKeySpec)keySpec).getEncoded(); + + // decode the PKCS#8 data structure to the pki object + PrivateKeyInfo pki; + + try + { + pki = PrivateKeyInfo.getInstance(ASN1Primitive.fromByteArray(encKey)); + } + catch (IOException e) + { + throw new InvalidKeySpecException("Unable to decode PKCS8EncodedKeySpec: " + e); + } + + try + { + // get the inner type inside the BIT STRING + ASN1Primitive innerType = pki.parsePrivateKey().toASN1Primitive(); + + // build and return the actual key + ASN1Sequence privKey = (ASN1Sequence)innerType; + + // decode oidString (but we don't need it right now) + String oidString = ((ASN1ObjectIdentifier)privKey.getObjectAt(0)) + .toString(); + + // decode <n> + BigInteger bigN = ((ASN1Integer)privKey.getObjectAt(1)).getValue(); + int n = bigN.intValue(); + + // decode <k> + BigInteger bigK = ((ASN1Integer)privKey.getObjectAt(2)).getValue(); + int k = bigK.intValue(); + + + // decode <fieldPoly> + byte[] encFieldPoly = ((ASN1OctetString)privKey.getObjectAt(3)) + .getOctets(); + // decode <goppaPoly> + byte[] encGoppaPoly = ((ASN1OctetString)privKey.getObjectAt(4)) + .getOctets(); + // decode <p> + byte[] encP = ((ASN1OctetString)privKey.getObjectAt(5)).getOctets(); + // decode <h> + byte[] encH = ((ASN1OctetString)privKey.getObjectAt(6)).getOctets(); + // decode <qInv> + ASN1Sequence qSeq = (ASN1Sequence)privKey.getObjectAt(7); + byte[][] encQInv = new byte[qSeq.size()][]; + for (int i = 0; i < qSeq.size(); i++) + { + encQInv[i] = ((ASN1OctetString)qSeq.getObjectAt(i)).getOctets(); + } + + return new BCMcElieceCCA2PrivateKey( + new McElieceCCA2PrivateKeySpec(OID, n, k, encFieldPoly, + encGoppaPoly, encP, encH, encQInv)); + + } + catch (IOException cce) + { + throw new InvalidKeySpecException( + "Unable to decode PKCS8EncodedKeySpec."); + } + } + + throw new InvalidKeySpecException("Unsupported key specification: " + + keySpec.getClass() + "."); + } + + /** + * Converts, if possible, a given key into a key specification. Currently, + * the following key specifications are supported: + * <ul> + * <li>for McElieceCCA2PublicKey: {@link X509EncodedKeySpec}, + * {@link McElieceCCA2PublicKeySpec}</li> + * <li>for McElieceCCA2PrivateKey: {@link PKCS8EncodedKeySpec}, + * {@link McElieceCCA2PrivateKeySpec}</li>. + * </ul> + * + * @param key the key + * @param keySpec the key specification + * @return the specification of the McEliece CCA2 key + * @throws InvalidKeySpecException if the key type or the key specification is not + * supported. + * @see BCMcElieceCCA2PrivateKey + * @see McElieceCCA2PrivateKeySpec + * @see BCMcElieceCCA2PublicKey + * @see McElieceCCA2PublicKeySpec + */ + public KeySpec getKeySpec(Key key, Class keySpec) + throws InvalidKeySpecException + { + if (key instanceof BCMcElieceCCA2PrivateKey) + { + if (PKCS8EncodedKeySpec.class.isAssignableFrom(keySpec)) + { + return new PKCS8EncodedKeySpec(key.getEncoded()); + } + else if (McElieceCCA2PrivateKeySpec.class + .isAssignableFrom(keySpec)) + { + BCMcElieceCCA2PrivateKey privKey = (BCMcElieceCCA2PrivateKey)key; + return new McElieceCCA2PrivateKeySpec(OID, privKey.getN(), privKey + .getK(), privKey.getField(), privKey.getGoppaPoly(), + privKey.getP(), privKey.getH(), privKey.getQInv()); + } + } + else if (key instanceof BCMcElieceCCA2PublicKey) + { + if (X509EncodedKeySpec.class.isAssignableFrom(keySpec)) + { + return new X509EncodedKeySpec(key.getEncoded()); + } + else if (McElieceCCA2PublicKeySpec.class + .isAssignableFrom(keySpec)) + { + BCMcElieceCCA2PublicKey pubKey = (BCMcElieceCCA2PublicKey)key; + return new McElieceCCA2PublicKeySpec(OID, pubKey.getN(), pubKey + .getT(), pubKey.getG()); + } + } + else + { + throw new InvalidKeySpecException("Unsupported key type: " + + key.getClass() + "."); + } + + throw new InvalidKeySpecException("Unknown key specification: " + + keySpec + "."); + } + + /** + * Translates a key into a form known by the FlexiProvider. Currently, only + * the following "source" keys are supported: {@link BCMcElieceCCA2PrivateKey}, + * {@link BCMcElieceCCA2PublicKey}. + * + * @param key the key + * @return a key of a known key type + * @throws InvalidKeyException if the key type is not supported. + */ + public Key translateKey(Key key) + throws InvalidKeyException + { + if ((key instanceof BCMcElieceCCA2PrivateKey) + || (key instanceof BCMcElieceCCA2PublicKey)) + { + return key; + } + throw new InvalidKeyException("Unsupported key type."); + + } + + + public PublicKey generatePublic(SubjectPublicKeyInfo pki) + throws InvalidKeySpecException + { + // get the inner type inside the BIT STRING + try + { + ASN1Primitive innerType = pki.parsePublicKey(); + McElieceCCA2PublicKey key = McElieceCCA2PublicKey.getInstance((ASN1Sequence)innerType); + return new BCMcElieceCCA2PublicKey(key.getOID().getId(), key.getN(), key.getT(), key.getG()); + } + catch (IOException cce) + { + throw new InvalidKeySpecException("Unable to decode X509EncodedKeySpec"); + } + } + + + public PrivateKey generatePrivate(PrivateKeyInfo pki) + throws InvalidKeySpecException + { + // get the inner type inside the BIT STRING + try + { + ASN1Primitive innerType = pki.parsePrivateKey().toASN1Primitive(); + McElieceCCA2PrivateKey key = McElieceCCA2PrivateKey.getInstance(innerType); + return new BCMcElieceCCA2PrivateKey(key.getOID().getId(), key.getN(), key.getK(), key.getField(), key.getGoppaPoly(), key.getP(), key.getH(), key.getQInv()); + } + catch (IOException cce) + { + throw new InvalidKeySpecException("Unable to decode PKCS8EncodedKeySpec"); + } + } + + protected PublicKey engineGeneratePublic(KeySpec keySpec) + throws InvalidKeySpecException + { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + protected PrivateKey engineGeneratePrivate(KeySpec keySpec) + throws InvalidKeySpecException + { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + protected KeySpec engineGetKeySpec(Key key, Class tClass) + throws InvalidKeySpecException + { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + protected Key engineTranslateKey(Key key) + throws InvalidKeyException + { + return null; //To change body of implemented methods use File | Settings | File Templates. + } +} diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceCCA2KeysToParams.java b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceCCA2KeysToParams.java new file mode 100644 index 0000000..03e7c1b --- /dev/null +++ b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceCCA2KeysToParams.java @@ -0,0 +1,47 @@ +package org.bouncycastle.pqc.jcajce.provider.mceliece; + +import java.security.InvalidKeyException; +import java.security.PrivateKey; +import java.security.PublicKey; + +import org.bouncycastle.crypto.params.AsymmetricKeyParameter; +import org.bouncycastle.pqc.crypto.mceliece.McElieceCCA2PrivateKeyParameters; +import org.bouncycastle.pqc.crypto.mceliece.McElieceCCA2PublicKeyParameters; + +/** + * utility class for converting jce/jca McElieceCCA2 objects + * objects into their org.bouncycastle.crypto counterparts. + */ +public class McElieceCCA2KeysToParams +{ + + + static public AsymmetricKeyParameter generatePublicKeyParameter( + PublicKey key) + throws InvalidKeyException + { + if (key instanceof BCMcElieceCCA2PublicKey) + { + BCMcElieceCCA2PublicKey k = (BCMcElieceCCA2PublicKey)key; + + return new McElieceCCA2PublicKeyParameters(k.getOIDString(), k.getN(), k.getT(), k.getG(), k.getMcElieceCCA2Parameters()); + } + + throw new InvalidKeyException("can't identify McElieceCCA2 public key: " + key.getClass().getName()); + } + + + static public AsymmetricKeyParameter generatePrivateKeyParameter( + PrivateKey key) + throws InvalidKeyException + { + if (key instanceof BCMcElieceCCA2PrivateKey) + { + BCMcElieceCCA2PrivateKey k = (BCMcElieceCCA2PrivateKey)key; + return new McElieceCCA2PrivateKeyParameters(k.getOIDString(), k.getN(), k.getK(), k.getField(), k.getGoppaPoly(), + k.getP(), k.getH(), k.getQInv(), k.getMcElieceCCA2Parameters()); + } + + throw new InvalidKeyException("can't identify McElieceCCA2 private key."); + } +} diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceCCA2Primitives.java b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceCCA2Primitives.java new file mode 100644 index 0000000..2650fff --- /dev/null +++ b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceCCA2Primitives.java @@ -0,0 +1,131 @@ +package org.bouncycastle.pqc.jcajce.provider.mceliece; + +import org.bouncycastle.pqc.crypto.mceliece.McElieceCCA2PrivateKeyParameters; +import org.bouncycastle.pqc.crypto.mceliece.McElieceCCA2PublicKeyParameters; +import org.bouncycastle.pqc.math.linearalgebra.GF2Matrix; +import org.bouncycastle.pqc.math.linearalgebra.GF2Vector; +import org.bouncycastle.pqc.math.linearalgebra.GF2mField; +import org.bouncycastle.pqc.math.linearalgebra.GoppaCode; +import org.bouncycastle.pqc.math.linearalgebra.Permutation; +import org.bouncycastle.pqc.math.linearalgebra.PolynomialGF2mSmallM; +import org.bouncycastle.pqc.math.linearalgebra.Vector; + +/** + * Core operations for the CCA-secure variants of McEliece. + */ +public final class McElieceCCA2Primitives +{ + + /** + * Default constructor (private). + */ + private McElieceCCA2Primitives() + { + } + + /** + * The McEliece encryption primitive. + * + * @param pubKey the public key + * @param m the message vector + * @param z the error vector + * @return <tt>m*G + z</tt> + */ + public static GF2Vector encryptionPrimitive(BCMcElieceCCA2PublicKey pubKey, + GF2Vector m, GF2Vector z) + { + + GF2Matrix matrixG = pubKey.getG(); + Vector mG = matrixG.leftMultiplyLeftCompactForm(m); + return (GF2Vector)mG.add(z); + } + + public static GF2Vector encryptionPrimitive(McElieceCCA2PublicKeyParameters pubKey, + GF2Vector m, GF2Vector z) + { + + GF2Matrix matrixG = pubKey.getMatrixG(); + Vector mG = matrixG.leftMultiplyLeftCompactForm(m); + return (GF2Vector)mG.add(z); + } + + /** + * The McEliece decryption primitive. + * + * @param privKey the private key + * @param c the ciphertext vector <tt>c = m*G + z</tt> + * @return the message vector <tt>m</tt> and the error vector <tt>z</tt> + */ + public static GF2Vector[] decryptionPrimitive( + BCMcElieceCCA2PrivateKey privKey, GF2Vector c) + { + + // obtain values from private key + int k = privKey.getK(); + Permutation p = privKey.getP(); + GF2mField field = privKey.getField(); + PolynomialGF2mSmallM gp = privKey.getGoppaPoly(); + GF2Matrix h = privKey.getH(); + PolynomialGF2mSmallM[] q = privKey.getQInv(); + + // compute inverse permutation P^-1 + Permutation pInv = p.computeInverse(); + + // multiply c with permutation P^-1 + GF2Vector cPInv = (GF2Vector)c.multiply(pInv); + + // compute syndrome of cP^-1 + GF2Vector syndVec = (GF2Vector)h.rightMultiply(cPInv); + + // decode syndrome + GF2Vector errors = GoppaCode.syndromeDecode(syndVec, field, gp, q); + GF2Vector mG = (GF2Vector)cPInv.add(errors); + + // multiply codeword and error vector with P + mG = (GF2Vector)mG.multiply(p); + errors = (GF2Vector)errors.multiply(p); + + // extract plaintext vector (last k columns of mG) + GF2Vector m = mG.extractRightVector(k); + + // return vectors + return new GF2Vector[]{m, errors}; + } + + public static GF2Vector[] decryptionPrimitive( + McElieceCCA2PrivateKeyParameters privKey, GF2Vector c) + { + + // obtain values from private key + int k = privKey.getK(); + Permutation p = privKey.getP(); + GF2mField field = privKey.getField(); + PolynomialGF2mSmallM gp = privKey.getGoppaPoly(); + GF2Matrix h = privKey.getH(); + PolynomialGF2mSmallM[] q = privKey.getQInv(); + + // compute inverse permutation P^-1 + Permutation pInv = p.computeInverse(); + + // multiply c with permutation P^-1 + GF2Vector cPInv = (GF2Vector)c.multiply(pInv); + + // compute syndrome of cP^-1 + GF2Vector syndVec = (GF2Vector)h.rightMultiply(cPInv); + + // decode syndrome + GF2Vector errors = GoppaCode.syndromeDecode(syndVec, field, gp, q); + GF2Vector mG = (GF2Vector)cPInv.add(errors); + + // multiply codeword and error vector with P + mG = (GF2Vector)mG.multiply(p); + errors = (GF2Vector)errors.multiply(p); + + // extract plaintext vector (last k columns of mG) + GF2Vector m = mG.extractRightVector(k); + + // return vectors + return new GF2Vector[]{m, errors}; + } + +} diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceFujisakiCipherSpi.java b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceFujisakiCipherSpi.java new file mode 100644 index 0000000..5320c22 --- /dev/null +++ b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceFujisakiCipherSpi.java @@ -0,0 +1,253 @@ +package org.bouncycastle.pqc.jcajce.provider.mceliece; + +import java.io.ByteArrayOutputStream; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.spec.AlgorithmParameterSpec; + +import javax.crypto.BadPaddingException; +import javax.crypto.IllegalBlockSizeException; + +import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; +import org.bouncycastle.asn1.x509.X509ObjectIdentifiers; +import org.bouncycastle.crypto.CipherParameters; +import org.bouncycastle.crypto.Digest; +import org.bouncycastle.crypto.digests.SHA1Digest; +import org.bouncycastle.crypto.digests.SHA224Digest; +import org.bouncycastle.crypto.digests.SHA256Digest; +import org.bouncycastle.crypto.digests.SHA384Digest; +import org.bouncycastle.crypto.digests.SHA512Digest; +import org.bouncycastle.crypto.params.ParametersWithRandom; +import org.bouncycastle.pqc.crypto.mceliece.McElieceCCA2KeyParameters; +import org.bouncycastle.pqc.crypto.mceliece.McElieceFujisakiCipher; +import org.bouncycastle.pqc.jcajce.provider.util.AsymmetricHybridCipher; + +public class McElieceFujisakiCipherSpi + extends AsymmetricHybridCipher + implements PKCSObjectIdentifiers, X509ObjectIdentifiers +{ + // TODO digest needed? + private Digest digest; + private McElieceFujisakiCipher cipher; + + /** + * buffer to store the input data + */ + private ByteArrayOutputStream buf; + + + protected McElieceFujisakiCipherSpi(Digest digest, McElieceFujisakiCipher cipher) + { + this.digest = digest; + this.cipher = cipher; + buf = new ByteArrayOutputStream(); + + } + + /** + * Continue a multiple-part encryption or decryption operation. + * + * @param input byte array containing the next part of the input + * @param inOff index in the array where the input starts + * @param inLen length of the input + * @return the processed byte array. + */ + public byte[] update(byte[] input, int inOff, int inLen) + { + buf.write(input, inOff, inLen); + return new byte[0]; + } + + + /** + * Encrypts or decrypts data in a single-part operation, or finishes a + * multiple-part operation. The data is encrypted or decrypted, depending on + * how this cipher was initialized. + * + * @param input the input buffer + * @param inOff the offset in input where the input starts + * @param inLen the input length + * @return the new buffer with the result + * @throws BadPaddingException on deryption errors. + */ + public byte[] doFinal(byte[] input, int inOff, int inLen) + throws BadPaddingException + { + update(input, inOff, inLen); + byte[] data = buf.toByteArray(); + buf.reset(); + if (opMode == ENCRYPT_MODE) + { + + try + { + return cipher.messageEncrypt(data); + } + catch (Exception e) + { + e.printStackTrace(); + } + + } + else if (opMode == DECRYPT_MODE) + { + + try + { + return cipher.messageDecrypt(data); + } + catch (Exception e) + { + e.printStackTrace(); + } + + } + return null; + } + + + protected int encryptOutputSize(int inLen) + { + return 0; + } + + protected int decryptOutputSize(int inLen) + { + return 0; + } + + protected void initCipherEncrypt(Key key, AlgorithmParameterSpec params, + SecureRandom sr) + throws InvalidKeyException, + InvalidAlgorithmParameterException + { + + CipherParameters param; + param = McElieceCCA2KeysToParams.generatePublicKeyParameter((PublicKey)key); + + param = new ParametersWithRandom(param, sr); + digest.reset(); + cipher.init(true, param); + + } + + protected void initCipherDecrypt(Key key, AlgorithmParameterSpec params) + throws InvalidKeyException, InvalidAlgorithmParameterException + { + + CipherParameters param; + param = McElieceCCA2KeysToParams.generatePrivateKeyParameter((PrivateKey)key); + + digest.reset(); + cipher.init(false, param); + } + + public String getName() + { + return "McElieceFujisakiCipher"; + } + + public int getKeySize(Key key) + throws InvalidKeyException + { + McElieceCCA2KeyParameters mcElieceCCA2KeyParameters; + if (key instanceof PublicKey) + { + mcElieceCCA2KeyParameters = (McElieceCCA2KeyParameters)McElieceCCA2KeysToParams.generatePublicKeyParameter((PublicKey)key); + } + else + { + mcElieceCCA2KeyParameters = (McElieceCCA2KeyParameters)McElieceCCA2KeysToParams.generatePrivateKeyParameter((PrivateKey)key); + + } + + + return cipher.getKeySize(mcElieceCCA2KeyParameters); + } + + public byte[] messageEncrypt(byte[] input) + throws IllegalBlockSizeException, BadPaddingException, NoSuchAlgorithmException + { + byte[] output = null; + try + { + output = cipher.messageEncrypt(input); + } + catch (Exception e) + { + e.printStackTrace(); + } + return output; + } + + + public byte[] messageDecrypt(byte[] input) + throws IllegalBlockSizeException, BadPaddingException, NoSuchAlgorithmException + { + byte[] output = null; + try + { + output = cipher.messageDecrypt(input); + } + catch (Exception e) + { + e.printStackTrace(); + } + return output; + } + + + ////////////////////////////////////////////////////////////////////////////////// + + static public class McElieceFujisaki + extends McElieceFujisakiCipherSpi + { + public McElieceFujisaki() + { + super(new SHA1Digest(), new McElieceFujisakiCipher()); + } + } + + static public class McElieceFujisaki224 + extends McElieceFujisakiCipherSpi + { + public McElieceFujisaki224() + { + super(new SHA224Digest(), new McElieceFujisakiCipher()); + } + } + + static public class McElieceFujisaki256 + extends McElieceFujisakiCipherSpi + { + public McElieceFujisaki256() + { + super(new SHA256Digest(), new McElieceFujisakiCipher()); + } + } + + static public class McElieceFujisaki384 + extends McElieceFujisakiCipherSpi + { + public McElieceFujisaki384() + { + super(new SHA384Digest(), new McElieceFujisakiCipher()); + } + } + + static public class McElieceFujisaki512 + extends McElieceFujisakiCipherSpi + { + public McElieceFujisaki512() + { + super(new SHA512Digest(), new McElieceFujisakiCipher()); + } + } + + +} diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceKeyFactorySpi.java b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceKeyFactorySpi.java new file mode 100644 index 0000000..c1df9e9 --- /dev/null +++ b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceKeyFactorySpi.java @@ -0,0 +1,343 @@ +package org.bouncycastle.pqc.jcajce.provider.mceliece; + +import java.io.IOException; +import java.math.BigInteger; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.KeyFactorySpi; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.KeySpec; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.X509EncodedKeySpec; + +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; +import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; +import org.bouncycastle.pqc.asn1.McEliecePrivateKey; +import org.bouncycastle.pqc.asn1.McEliecePublicKey; +import org.bouncycastle.pqc.jcajce.spec.McEliecePrivateKeySpec; +import org.bouncycastle.pqc.jcajce.spec.McEliecePublicKeySpec; + +/** + * This class is used to translate between McEliece keys and key specifications. + * + * @see BCMcEliecePrivateKey + * @see McEliecePrivateKeySpec + * @see BCMcEliecePublicKey + * @see McEliecePublicKeySpec + */ +public class McElieceKeyFactorySpi + extends KeyFactorySpi +{ + /** + * The OID of the algorithm. + */ + public static final String OID = "1.3.6.1.4.1.8301.3.1.3.4.1"; + + /** + * Converts, if possible, a key specification into a + * {@link BCMcEliecePublicKey}. Currently, the following key specifications + * are supported: {@link McEliecePublicKeySpec}, {@link X509EncodedKeySpec}. + * + * @param keySpec the key specification + * @return the McEliece public key + * @throws InvalidKeySpecException if the key specification is not supported. + */ + public PublicKey generatePublic(KeySpec keySpec) + throws InvalidKeySpecException + { + if (keySpec instanceof McEliecePublicKeySpec) + { + return new BCMcEliecePublicKey((McEliecePublicKeySpec)keySpec); + } + else if (keySpec instanceof X509EncodedKeySpec) + { + // get the DER-encoded Key according to X.509 from the spec + byte[] encKey = ((X509EncodedKeySpec)keySpec).getEncoded(); + + // decode the SubjectPublicKeyInfo data structure to the pki object + SubjectPublicKeyInfo pki; + try + { + pki = SubjectPublicKeyInfo.getInstance(ASN1Primitive.fromByteArray(encKey)); + } + catch (IOException e) + { + throw new InvalidKeySpecException(e.toString()); + } + + try + { + // --- Build and return the actual key. + ASN1Primitive innerType = pki.parsePublicKey(); + ASN1Sequence publicKey = (ASN1Sequence)innerType; + + // decode oidString (but we don't need it right now) + String oidString = ((ASN1ObjectIdentifier)publicKey.getObjectAt(0)) + .toString(); + + // decode <n> + BigInteger bigN = ((ASN1Integer)publicKey.getObjectAt(1)).getValue(); + int n = bigN.intValue(); + + // decode <t> + BigInteger bigT = ((ASN1Integer)publicKey.getObjectAt(2)).getValue(); + int t = bigT.intValue(); + + // decode <matrixG> + byte[] matrixG = ((ASN1OctetString)publicKey.getObjectAt(3)).getOctets(); + + + return new BCMcEliecePublicKey(new McEliecePublicKeySpec(OID, t, n, + matrixG)); + } + catch (IOException cce) + { + throw new InvalidKeySpecException( + "Unable to decode X509EncodedKeySpec: " + + cce.getMessage()); + } + } + + throw new InvalidKeySpecException("Unsupported key specification: " + + keySpec.getClass() + "."); + } + + /** + * Converts, if possible, a key specification into a + * {@link BCMcEliecePrivateKey}. Currently, the following key specifications + * are supported: {@link McEliecePrivateKeySpec}, + * {@link PKCS8EncodedKeySpec}. + * + * @param keySpec the key specification + * @return the McEliece private key + * @throws InvalidKeySpecException if the KeySpec is not supported. + */ + public PrivateKey generatePrivate(KeySpec keySpec) + throws InvalidKeySpecException + { + if (keySpec instanceof McEliecePrivateKeySpec) + { + return new BCMcEliecePrivateKey((McEliecePrivateKeySpec)keySpec); + } + else if (keySpec instanceof PKCS8EncodedKeySpec) + { + // get the DER-encoded Key according to PKCS#8 from the spec + byte[] encKey = ((PKCS8EncodedKeySpec)keySpec).getEncoded(); + + // decode the PKCS#8 data structure to the pki object + PrivateKeyInfo pki; + + try + { + pki = PrivateKeyInfo.getInstance(ASN1Primitive.fromByteArray(encKey)); + } + catch (IOException e) + { + throw new InvalidKeySpecException("Unable to decode PKCS8EncodedKeySpec: " + e); + } + + try + { + ASN1Primitive innerType = pki.parsePrivateKey().toASN1Primitive(); + + // build and return the actual key + ASN1Sequence privKey = (ASN1Sequence)innerType; + + // decode oidString (but we don't need it right now) + String oidString = ((ASN1ObjectIdentifier)privKey.getObjectAt(0)) + .toString(); + + // decode <n> + BigInteger bigN = ((ASN1Integer)privKey.getObjectAt(1)).getValue(); + int n = bigN.intValue(); + + // decode <k> + BigInteger bigK = ((ASN1Integer)privKey.getObjectAt(2)).getValue(); + int k = bigK.intValue(); + + // decode <fieldPoly> + byte[] encFieldPoly = ((ASN1OctetString)privKey.getObjectAt(3)) + .getOctets(); + // decode <goppaPoly> + byte[] encGoppaPoly = ((ASN1OctetString)privKey.getObjectAt(4)) + .getOctets(); + + // decode <sInv> + byte[] encSInv = ((ASN1OctetString)privKey.getObjectAt(5)).getOctets(); + // decode <p1> + byte[] encP1 = ((ASN1OctetString)privKey.getObjectAt(6)).getOctets(); + // decode <p2> + byte[] encP2 = ((ASN1OctetString)privKey.getObjectAt(7)).getOctets(); + + //decode <h> + byte[] encH = ((ASN1OctetString)privKey.getObjectAt(8)).getOctets(); + + // decode <qInv> + ASN1Sequence qSeq = (ASN1Sequence)privKey.getObjectAt(9); + byte[][] encQInv = new byte[qSeq.size()][]; + for (int i = 0; i < qSeq.size(); i++) + { + encQInv[i] = ((ASN1OctetString)qSeq.getObjectAt(i)).getOctets(); + } + + return new BCMcEliecePrivateKey(new McEliecePrivateKeySpec(OID, n, k, + encFieldPoly, encGoppaPoly, encSInv, encP1, encP2, + encH, encQInv)); + + } + catch (IOException cce) + { + throw new InvalidKeySpecException( + "Unable to decode PKCS8EncodedKeySpec."); + } + } + + throw new InvalidKeySpecException("Unsupported key specification: " + + keySpec.getClass() + "."); + } + + /** + * Converts, if possible, a given key into a key specification. Currently, + * the following key specifications are supported: + * <ul> + * <li>for McEliecePublicKey: {@link X509EncodedKeySpec}, + * {@link McEliecePublicKeySpec}</li> + * <li>for McEliecePrivateKey: {@link PKCS8EncodedKeySpec}, + * {@link McEliecePrivateKeySpec}</li>. + * </ul> + * + * @param key the key + * @param keySpec the key specification + * @return the specification of the McEliece key + * @throws InvalidKeySpecException if the key type or the key specification is not + * supported. + * @see BCMcEliecePrivateKey + * @see McEliecePrivateKeySpec + * @see BCMcEliecePublicKey + * @see McEliecePublicKeySpec + */ + public KeySpec getKeySpec(Key key, Class keySpec) + throws InvalidKeySpecException + { + if (key instanceof BCMcEliecePrivateKey) + { + if (PKCS8EncodedKeySpec.class.isAssignableFrom(keySpec)) + { + return new PKCS8EncodedKeySpec(key.getEncoded()); + } + else if (McEliecePrivateKeySpec.class.isAssignableFrom(keySpec)) + { + BCMcEliecePrivateKey privKey = (BCMcEliecePrivateKey)key; + return new McEliecePrivateKeySpec(OID, privKey.getN(), privKey + .getK(), privKey.getField(), privKey.getGoppaPoly(), + privKey.getSInv(), privKey.getP1(), privKey.getP2(), + privKey.getH(), privKey.getQInv()); + } + } + else if (key instanceof BCMcEliecePublicKey) + { + if (X509EncodedKeySpec.class.isAssignableFrom(keySpec)) + { + return new X509EncodedKeySpec(key.getEncoded()); + } + else if (McEliecePublicKeySpec.class.isAssignableFrom(keySpec)) + { + BCMcEliecePublicKey pubKey = (BCMcEliecePublicKey)key; + return new McEliecePublicKeySpec(OID, pubKey.getN(), pubKey.getT(), + pubKey.getG()); + } + } + else + { + throw new InvalidKeySpecException("Unsupported key type: " + + key.getClass() + "."); + } + + throw new InvalidKeySpecException("Unknown key specification: " + + keySpec + "."); + } + + /** + * Translates a key into a form known by the FlexiProvider. Currently, only + * the following "source" keys are supported: {@link BCMcEliecePrivateKey}, + * {@link BCMcEliecePublicKey}. + * + * @param key the key + * @return a key of a known key type + * @throws InvalidKeyException if the key type is not supported. + */ + public Key translateKey(Key key) + throws InvalidKeyException + { + if ((key instanceof BCMcEliecePrivateKey) + || (key instanceof BCMcEliecePublicKey)) + { + return key; + } + throw new InvalidKeyException("Unsupported key type."); + + } + + public PublicKey generatePublic(SubjectPublicKeyInfo pki) + throws InvalidKeySpecException + { + // get the inner type inside the BIT STRING + try + { + ASN1Primitive innerType = pki.parsePublicKey(); + McEliecePublicKey key = McEliecePublicKey.getInstance(innerType); + return new BCMcEliecePublicKey(key.getOID().getId(), key.getN(), key.getT(), key.getG()); + } + catch (IOException cce) + { + throw new InvalidKeySpecException("Unable to decode X509EncodedKeySpec"); + } + } + + public PrivateKey generatePrivate(PrivateKeyInfo pki) + throws InvalidKeySpecException + { + // get the inner type inside the BIT STRING + try + { + ASN1Primitive innerType = pki.parsePrivateKey().toASN1Primitive(); + McEliecePrivateKey key = McEliecePrivateKey.getInstance(innerType); + return new BCMcEliecePrivateKey(key.getOID().getId(), key.getN(), key.getK(), key.getField(), key.getGoppaPoly(), key.getSInv(), key.getP1(), key.getP2(), key.getH(), key.getQInv()); + } + catch (IOException cce) + { + throw new InvalidKeySpecException("Unable to decode PKCS8EncodedKeySpec"); + } + } + + protected PublicKey engineGeneratePublic(KeySpec keySpec) + throws InvalidKeySpecException + { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + protected PrivateKey engineGeneratePrivate(KeySpec keySpec) + throws InvalidKeySpecException + { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + protected KeySpec engineGetKeySpec(Key key, Class tClass) + throws InvalidKeySpecException + { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + protected Key engineTranslateKey(Key key) + throws InvalidKeyException + { + return null; //To change body of implemented methods use File | Settings | File Templates. + } +} diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceKeyPairGeneratorSpi.java b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceKeyPairGeneratorSpi.java new file mode 100644 index 0000000..75008fe --- /dev/null +++ b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceKeyPairGeneratorSpi.java @@ -0,0 +1,146 @@ +package org.bouncycastle.pqc.jcajce.provider.mceliece; + +import java.security.InvalidAlgorithmParameterException; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.SecureRandom; +import java.security.spec.AlgorithmParameterSpec; + +import org.bouncycastle.crypto.AsymmetricCipherKeyPair; +import org.bouncycastle.pqc.crypto.mceliece.McElieceCCA2KeyGenerationParameters; +import org.bouncycastle.pqc.crypto.mceliece.McElieceCCA2KeyPairGenerator; +import org.bouncycastle.pqc.crypto.mceliece.McElieceCCA2Parameters; +import org.bouncycastle.pqc.crypto.mceliece.McElieceCCA2PrivateKeyParameters; +import org.bouncycastle.pqc.crypto.mceliece.McElieceCCA2PublicKeyParameters; +import org.bouncycastle.pqc.crypto.mceliece.McElieceKeyGenerationParameters; +import org.bouncycastle.pqc.crypto.mceliece.McElieceKeyPairGenerator; +import org.bouncycastle.pqc.crypto.mceliece.McElieceParameters; +import org.bouncycastle.pqc.crypto.mceliece.McEliecePrivateKeyParameters; +import org.bouncycastle.pqc.crypto.mceliece.McEliecePublicKeyParameters; +import org.bouncycastle.pqc.jcajce.spec.ECCKeyGenParameterSpec; +import org.bouncycastle.pqc.jcajce.spec.McElieceCCA2ParameterSpec; + +public abstract class McElieceKeyPairGeneratorSpi + extends KeyPairGenerator +{ + public McElieceKeyPairGeneratorSpi( + String algorithmName) + { + super(algorithmName); + } + + /** + * + * + * + */ + + public static class McElieceCCA2 + extends McElieceKeyPairGeneratorSpi + { + + McElieceCCA2KeyPairGenerator kpg; + + + public McElieceCCA2() + { + super("McElieceCCA-2"); + } + + public McElieceCCA2(String s) + { + super(s); + } + + public void initialize(AlgorithmParameterSpec params) + throws InvalidAlgorithmParameterException + { + kpg = new McElieceCCA2KeyPairGenerator(); + super.initialize(params); + ECCKeyGenParameterSpec ecc = (ECCKeyGenParameterSpec)params; + + McElieceCCA2KeyGenerationParameters mccca2KGParams = new McElieceCCA2KeyGenerationParameters(new SecureRandom(), new McElieceCCA2Parameters(ecc.getM(), ecc.getT())); + kpg.init(mccca2KGParams); + } + + public void initialize(int keySize, SecureRandom random) + { + McElieceCCA2ParameterSpec paramSpec = new McElieceCCA2ParameterSpec(); + + // call the initializer with the chosen parameters + try + { + this.initialize(paramSpec); + } + catch (InvalidAlgorithmParameterException ae) + { + } + } + + public KeyPair generateKeyPair() + { + AsymmetricCipherKeyPair generateKeyPair = kpg.generateKeyPair(); + McElieceCCA2PrivateKeyParameters sk = (McElieceCCA2PrivateKeyParameters)generateKeyPair.getPrivate(); + McElieceCCA2PublicKeyParameters pk = (McElieceCCA2PublicKeyParameters)generateKeyPair.getPublic(); + + return new KeyPair(new BCMcElieceCCA2PublicKey(pk), new BCMcElieceCCA2PrivateKey(sk)); + + } + + } + + /** + * + * + * + */ + + public static class McEliece + extends McElieceKeyPairGeneratorSpi + { + + McElieceKeyPairGenerator kpg; + + + public McEliece() + { + super("McEliece"); + } + + public void initialize(AlgorithmParameterSpec params) + throws InvalidAlgorithmParameterException + { + kpg = new McElieceKeyPairGenerator(); + super.initialize(params); + ECCKeyGenParameterSpec ecc = (ECCKeyGenParameterSpec)params; + + McElieceKeyGenerationParameters mccKGParams = new McElieceKeyGenerationParameters(new SecureRandom(), new McElieceParameters(ecc.getM(), ecc.getT())); + kpg.init(mccKGParams); + } + + public void initialize(int keySize, SecureRandom random) + { + ECCKeyGenParameterSpec paramSpec = new ECCKeyGenParameterSpec(); + + // call the initializer with the chosen parameters + try + { + this.initialize(paramSpec); + } + catch (InvalidAlgorithmParameterException ae) + { + } + } + + public KeyPair generateKeyPair() + { + AsymmetricCipherKeyPair generateKeyPair = kpg.generateKeyPair(); + McEliecePrivateKeyParameters sk = (McEliecePrivateKeyParameters)generateKeyPair.getPrivate(); + McEliecePublicKeyParameters pk = (McEliecePublicKeyParameters)generateKeyPair.getPublic(); + + return new KeyPair(new BCMcEliecePublicKey(pk), new BCMcEliecePrivateKey(sk)); + } + + } + +} diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceKeysToParams.java b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceKeysToParams.java new file mode 100644 index 0000000..23686b8 --- /dev/null +++ b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceKeysToParams.java @@ -0,0 +1,47 @@ +package org.bouncycastle.pqc.jcajce.provider.mceliece; + +import java.security.InvalidKeyException; +import java.security.PrivateKey; +import java.security.PublicKey; + +import org.bouncycastle.crypto.params.AsymmetricKeyParameter; +import org.bouncycastle.pqc.crypto.mceliece.McEliecePrivateKeyParameters; +import org.bouncycastle.pqc.crypto.mceliece.McEliecePublicKeyParameters; + +/** + * utility class for converting jce/jca McEliece objects + * objects into their org.bouncycastle.crypto counterparts. + */ +public class McElieceKeysToParams +{ + + + static public AsymmetricKeyParameter generatePublicKeyParameter( + PublicKey key) + throws InvalidKeyException + { + if (key instanceof BCMcEliecePublicKey) + { + BCMcEliecePublicKey k = (BCMcEliecePublicKey)key; + + return new McEliecePublicKeyParameters(k.getOIDString(), k.getN(), k.getT(), k.getG(), k.getMcElieceParameters()); + } + + throw new InvalidKeyException("can't identify McEliece public key: " + key.getClass().getName()); + } + + + static public AsymmetricKeyParameter generatePrivateKeyParameter( + PrivateKey key) + throws InvalidKeyException + { + if (key instanceof BCMcEliecePrivateKey) + { + BCMcEliecePrivateKey k = (BCMcEliecePrivateKey)key; + return new McEliecePrivateKeyParameters(k.getOIDString(), k.getN(), k.getK(), k.getField(), k.getGoppaPoly(), + k.getSInv(), k.getP1(), k.getP2(), k.getH(), k.getQInv(), k.getMcElieceParameters()); + } + + throw new InvalidKeyException("can't identify McEliece private key."); + } +} diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceKobaraImaiCipherSpi.java b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceKobaraImaiCipherSpi.java new file mode 100644 index 0000000..36c6231 --- /dev/null +++ b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceKobaraImaiCipherSpi.java @@ -0,0 +1,307 @@ +package org.bouncycastle.pqc.jcajce.provider.mceliece; + +import java.io.ByteArrayOutputStream; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.spec.AlgorithmParameterSpec; + +import javax.crypto.BadPaddingException; +import javax.crypto.IllegalBlockSizeException; + +import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; +import org.bouncycastle.asn1.x509.X509ObjectIdentifiers; +import org.bouncycastle.crypto.CipherParameters; +import org.bouncycastle.crypto.Digest; +import org.bouncycastle.crypto.digests.SHA1Digest; +import org.bouncycastle.crypto.digests.SHA224Digest; +import org.bouncycastle.crypto.digests.SHA256Digest; +import org.bouncycastle.crypto.digests.SHA384Digest; +import org.bouncycastle.crypto.digests.SHA512Digest; +import org.bouncycastle.crypto.params.ParametersWithRandom; +import org.bouncycastle.pqc.crypto.mceliece.McElieceCCA2KeyParameters; +import org.bouncycastle.pqc.crypto.mceliece.McElieceKobaraImaiCipher; +import org.bouncycastle.pqc.jcajce.provider.util.AsymmetricHybridCipher; + +public class McElieceKobaraImaiCipherSpi + extends AsymmetricHybridCipher + implements PKCSObjectIdentifiers, X509ObjectIdentifiers +{ + + // TODO digest needed? + private Digest digest; + private McElieceKobaraImaiCipher cipher; + + /** + * buffer to store the input data + */ + private ByteArrayOutputStream buf = new ByteArrayOutputStream(); + + + public McElieceKobaraImaiCipherSpi() + { + buf = new ByteArrayOutputStream(); + } + + protected McElieceKobaraImaiCipherSpi(Digest digest, McElieceKobaraImaiCipher cipher) + { + this.digest = digest; + this.cipher = cipher; + buf = new ByteArrayOutputStream(); + } + + /** + * Continue a multiple-part encryption or decryption operation. + * + * @param input byte array containing the next part of the input + * @param inOff index in the array where the input starts + * @param inLen length of the input + * @return the processed byte array. + */ + public byte[] update(byte[] input, int inOff, int inLen) + { + buf.write(input, inOff, inLen); + return new byte[0]; + } + + + /** + * Encrypts or decrypts data in a single-part operation, or finishes a + * multiple-part operation. The data is encrypted or decrypted, depending on + * how this cipher was initialized. + * + * @param input the input buffer + * @param inOff the offset in input where the input starts + * @param inLen the input length + * @return the new buffer with the result + * @throws BadPaddingException if this cipher is in decryption mode, and (un)padding has + * been requested, but the decrypted data is not bounded by + * the appropriate padding bytes + */ + public byte[] doFinal(byte[] input, int inOff, int inLen) + throws BadPaddingException + { + update(input, inOff, inLen); + if (opMode == ENCRYPT_MODE) + { + + try + { + return cipher.messageEncrypt(this.pad()); + } + catch (Exception e) + { + e.printStackTrace(); + } + + } + else if (opMode == DECRYPT_MODE) + { + byte[] inputOfDecr = buf.toByteArray(); + buf.reset(); + + try + { + return unpad(cipher.messageDecrypt(inputOfDecr)); + } + catch (Exception e) + { + e.printStackTrace(); + } + + } + return null; + } + + protected int encryptOutputSize(int inLen) + { + return 0; + } + + protected int decryptOutputSize(int inLen) + { + return 0; + } + + protected void initCipherEncrypt(Key key, AlgorithmParameterSpec params, + SecureRandom sr) + throws InvalidKeyException, + InvalidAlgorithmParameterException + { + + buf.reset(); + CipherParameters param; + param = McElieceCCA2KeysToParams.generatePublicKeyParameter((PublicKey)key); + + param = new ParametersWithRandom(param, sr); + digest.reset(); + cipher.init(true, param); + } + + protected void initCipherDecrypt(Key key, AlgorithmParameterSpec params) + throws InvalidKeyException, InvalidAlgorithmParameterException + { + + buf.reset(); + CipherParameters param; + param = McElieceCCA2KeysToParams.generatePrivateKeyParameter((PrivateKey)key); + + digest.reset(); + cipher.init(false, param); + } + + public String getName() + { + return "McElieceKobaraImaiCipher"; + } + + public int getKeySize(Key key) + throws InvalidKeyException + { + McElieceCCA2KeyParameters mcElieceCCA2KeyParameters; + if (key instanceof PublicKey) + { + mcElieceCCA2KeyParameters = (McElieceCCA2KeyParameters)McElieceCCA2KeysToParams.generatePublicKeyParameter((PublicKey)key); + return cipher.getKeySize(mcElieceCCA2KeyParameters); + } + else if (key instanceof PrivateKey) + { + mcElieceCCA2KeyParameters = (McElieceCCA2KeyParameters)McElieceCCA2KeysToParams.generatePrivateKeyParameter((PrivateKey)key); + return cipher.getKeySize(mcElieceCCA2KeyParameters); + } + else + { + throw new InvalidKeyException(); + } + + + } + + /** + * Pad and return the message stored in the message buffer. + * + * @return the padded message + */ + private byte[] pad() + { + buf.write(0x01); + byte[] result = buf.toByteArray(); + buf.reset(); + return result; + } + + /** + * Unpad a message. + * + * @param pmBytes the padded message + * @return the message + * @throws BadPaddingException if the padded message is invalid. + */ + private byte[] unpad(byte[] pmBytes) + throws BadPaddingException + { + // find first non-zero byte + int index; + for (index = pmBytes.length - 1; index >= 0 && pmBytes[index] == 0; index--) + { + ; + } + + // check if padding byte is valid + if (pmBytes[index] != 0x01) + { + throw new BadPaddingException("invalid ciphertext"); + } + + // extract and return message + byte[] mBytes = new byte[index]; + System.arraycopy(pmBytes, 0, mBytes, 0, index); + return mBytes; + } + + + public byte[] messageEncrypt() + throws IllegalBlockSizeException, BadPaddingException, NoSuchAlgorithmException + { + byte[] output = null; + try + { + output = cipher.messageEncrypt((this.pad())); + } + catch (Exception e) + { + e.printStackTrace(); + } + return output; + } + + + public byte[] messageDecrypt() + throws IllegalBlockSizeException, BadPaddingException, NoSuchAlgorithmException + { + byte[] output = null; + byte[] inputOfDecr = buf.toByteArray(); + buf.reset(); + try + { + output = unpad(cipher.messageDecrypt(inputOfDecr)); + } + catch (Exception e) + { + e.printStackTrace(); + } + return output; + } + + + static public class McElieceKobaraImai + extends McElieceKobaraImaiCipherSpi + { + public McElieceKobaraImai() + { + super(new SHA1Digest(), new McElieceKobaraImaiCipher()); + } + } + + static public class McElieceKobaraImai224 + extends McElieceKobaraImaiCipherSpi + { + public McElieceKobaraImai224() + { + super(new SHA224Digest(), new McElieceKobaraImaiCipher()); + } + } + + static public class McElieceKobaraImai256 + extends McElieceKobaraImaiCipherSpi + { + public McElieceKobaraImai256() + { + super(new SHA256Digest(), new McElieceKobaraImaiCipher()); + } + } + + static public class McElieceKobaraImai384 + extends McElieceKobaraImaiCipherSpi + { + public McElieceKobaraImai384() + { + super(new SHA384Digest(), new McElieceKobaraImaiCipher()); + } + } + + static public class McElieceKobaraImai512 + extends McElieceKobaraImaiCipherSpi + { + public McElieceKobaraImai512() + { + super(new SHA512Digest(), new McElieceKobaraImaiCipher()); + } + } + + +} diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McEliecePKCSCipherSpi.java b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McEliecePKCSCipherSpi.java new file mode 100644 index 0000000..583acbb --- /dev/null +++ b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McEliecePKCSCipherSpi.java @@ -0,0 +1,171 @@ +package org.bouncycastle.pqc.jcajce.provider.mceliece; + +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.spec.AlgorithmParameterSpec; + +import javax.crypto.BadPaddingException; +import javax.crypto.IllegalBlockSizeException; + +import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; +import org.bouncycastle.asn1.x509.X509ObjectIdentifiers; +import org.bouncycastle.crypto.CipherParameters; +import org.bouncycastle.crypto.Digest; +import org.bouncycastle.crypto.digests.SHA1Digest; +import org.bouncycastle.crypto.digests.SHA224Digest; +import org.bouncycastle.crypto.digests.SHA256Digest; +import org.bouncycastle.crypto.digests.SHA384Digest; +import org.bouncycastle.crypto.digests.SHA512Digest; +import org.bouncycastle.crypto.params.ParametersWithRandom; +import org.bouncycastle.pqc.crypto.mceliece.McElieceKeyParameters; +import org.bouncycastle.pqc.crypto.mceliece.McEliecePKCSCipher; +import org.bouncycastle.pqc.jcajce.provider.util.AsymmetricBlockCipher; + +public class McEliecePKCSCipherSpi + extends AsymmetricBlockCipher + implements PKCSObjectIdentifiers, X509ObjectIdentifiers +{ + // TODO digest needed? + private Digest digest; + private McEliecePKCSCipher cipher; + + public McEliecePKCSCipherSpi(Digest digest, McEliecePKCSCipher cipher) + { + this.digest = digest; + this.cipher = cipher; + } + + protected void initCipherEncrypt(Key key, AlgorithmParameterSpec params, + SecureRandom sr) + throws InvalidKeyException, + InvalidAlgorithmParameterException + { + + CipherParameters param; + param = McElieceKeysToParams.generatePublicKeyParameter((PublicKey)key); + + param = new ParametersWithRandom(param, sr); + digest.reset(); + cipher.init(true, param); + this.maxPlainTextSize = cipher.maxPlainTextSize; + this.cipherTextSize = cipher.cipherTextSize; + } + + protected void initCipherDecrypt(Key key, AlgorithmParameterSpec params) + throws InvalidKeyException, InvalidAlgorithmParameterException + { + CipherParameters param; + param = McElieceKeysToParams.generatePrivateKeyParameter((PrivateKey)key); + + digest.reset(); + cipher.init(false, param); + this.maxPlainTextSize = cipher.maxPlainTextSize; + this.cipherTextSize = cipher.cipherTextSize; + } + + protected byte[] messageEncrypt(byte[] input) + throws IllegalBlockSizeException, BadPaddingException + { + byte[] output = null; + try + { + output = cipher.messageEncrypt(input); + } + catch (Exception e) + { + e.printStackTrace(); + } + return output; + } + + protected byte[] messageDecrypt(byte[] input) + throws IllegalBlockSizeException, BadPaddingException + { + byte[] output = null; + try + { + output = cipher.messageDecrypt(input); + } + catch (Exception e) + { + e.printStackTrace(); + } + return output; + } + + public String getName() + { + return "McEliecePKCS"; + } + + public int getKeySize(Key key) + throws InvalidKeyException + { + McElieceKeyParameters mcElieceKeyParameters; + if (key instanceof PublicKey) + { + mcElieceKeyParameters = (McElieceKeyParameters)McElieceKeysToParams.generatePublicKeyParameter((PublicKey)key); + } + else + { + mcElieceKeyParameters = (McElieceKeyParameters)McElieceKeysToParams.generatePrivateKeyParameter((PrivateKey)key); + + } + + + return cipher.getKeySize(mcElieceKeyParameters); + } + + ////////////////////////////////////////////////////////////////////////////////// + + static public class McEliecePKCS + extends McEliecePKCSCipherSpi + { + public McEliecePKCS() + { + super(new SHA1Digest(), new McEliecePKCSCipher()); + } + } + + static public class McEliecePKCS224 + extends McEliecePKCSCipherSpi + { + public McEliecePKCS224() + { + super(new SHA224Digest(), new McEliecePKCSCipher()); + } + } + + static public class McEliecePKCS256 + extends McEliecePKCSCipherSpi + { + public McEliecePKCS256() + { + super(new SHA256Digest(), new McEliecePKCSCipher()); + } + } + + static public class McEliecePKCS384 + extends McEliecePKCSCipherSpi + { + public McEliecePKCS384() + { + super(new SHA384Digest(), new McEliecePKCSCipher()); + } + } + + static public class McEliecePKCS512 + extends McEliecePKCSCipherSpi + { + public McEliecePKCS512() + { + super(new SHA512Digest(), new McEliecePKCSCipher()); + } + } + + +} diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McEliecePointchevalCipherSpi.java b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McEliecePointchevalCipherSpi.java new file mode 100644 index 0000000..c9c67ea --- /dev/null +++ b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McEliecePointchevalCipherSpi.java @@ -0,0 +1,247 @@ +package org.bouncycastle.pqc.jcajce.provider.mceliece; + +import java.io.ByteArrayOutputStream; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.spec.AlgorithmParameterSpec; + +import javax.crypto.BadPaddingException; +import javax.crypto.IllegalBlockSizeException; + +import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; +import org.bouncycastle.asn1.x509.X509ObjectIdentifiers; +import org.bouncycastle.crypto.CipherParameters; +import org.bouncycastle.crypto.Digest; +import org.bouncycastle.crypto.digests.SHA1Digest; +import org.bouncycastle.crypto.digests.SHA224Digest; +import org.bouncycastle.crypto.digests.SHA256Digest; +import org.bouncycastle.crypto.digests.SHA384Digest; +import org.bouncycastle.crypto.digests.SHA512Digest; +import org.bouncycastle.crypto.params.ParametersWithRandom; +import org.bouncycastle.pqc.crypto.mceliece.McElieceCCA2KeyParameters; +import org.bouncycastle.pqc.crypto.mceliece.McEliecePointchevalCipher; +import org.bouncycastle.pqc.jcajce.provider.util.AsymmetricHybridCipher; + +public class McEliecePointchevalCipherSpi + extends AsymmetricHybridCipher + implements PKCSObjectIdentifiers, X509ObjectIdentifiers +{ + // TODO digest needed? + private Digest digest; + private McEliecePointchevalCipher cipher; + + /** + * buffer to store the input data + */ + private ByteArrayOutputStream buf = new ByteArrayOutputStream(); + + + protected McEliecePointchevalCipherSpi(Digest digest, McEliecePointchevalCipher cipher) + { + this.digest = digest; + this.cipher = cipher; + buf = new ByteArrayOutputStream(); + } + + /** + * Continue a multiple-part encryption or decryption operation. + * + * @param input byte array containing the next part of the input + * @param inOff index in the array where the input starts + * @param inLen length of the input + * @return the processed byte array. + */ + public byte[] update(byte[] input, int inOff, int inLen) + { + buf.write(input, inOff, inLen); + return new byte[0]; + } + + + /** + * Encrypts or decrypts data in a single-part operation, or finishes a + * multiple-part operation. The data is encrypted or decrypted, depending on + * how this cipher was initialized. + * + * @param input the input buffer + * @param inOff the offset in input where the input starts + * @param inLen the input length + * @return the new buffer with the result + * @throws BadPaddingException on deryption errors. + */ + public byte[] doFinal(byte[] input, int inOff, int inLen) + throws BadPaddingException + { + update(input, inOff, inLen); + byte[] data = buf.toByteArray(); + buf.reset(); + if (opMode == ENCRYPT_MODE) + { + + try + { + return cipher.messageEncrypt(data); + } + catch (Exception e) + { + e.printStackTrace(); + } + + } + else if (opMode == DECRYPT_MODE) + { + + try + { + return cipher.messageDecrypt(data); + } + catch (Exception e) + { + e.printStackTrace(); + } + + } + return null; + } + + protected int encryptOutputSize(int inLen) + { + return 0; + } + + protected int decryptOutputSize(int inLen) + { + return 0; + } + + protected void initCipherEncrypt(Key key, AlgorithmParameterSpec params, + SecureRandom sr) + throws InvalidKeyException, + InvalidAlgorithmParameterException + { + CipherParameters param; + param = McElieceCCA2KeysToParams.generatePublicKeyParameter((PublicKey)key); + + param = new ParametersWithRandom(param, sr); + digest.reset(); + cipher.init(true, param); + } + + protected void initCipherDecrypt(Key key, AlgorithmParameterSpec params) + throws InvalidKeyException, InvalidAlgorithmParameterException + { + CipherParameters param; + param = McElieceCCA2KeysToParams.generatePrivateKeyParameter((PrivateKey)key); + + digest.reset(); + cipher.init(false, param); + } + + public String getName() + { + return "McEliecePointchevalCipher"; + } + + + public int getKeySize(Key key) + throws InvalidKeyException + { + McElieceCCA2KeyParameters mcElieceCCA2KeyParameters; + if (key instanceof PublicKey) + { + mcElieceCCA2KeyParameters = (McElieceCCA2KeyParameters)McElieceCCA2KeysToParams.generatePublicKeyParameter((PublicKey)key); + } + else + { + mcElieceCCA2KeyParameters = (McElieceCCA2KeyParameters)McElieceCCA2KeysToParams.generatePrivateKeyParameter((PrivateKey)key); + } + + return cipher.getKeySize(mcElieceCCA2KeyParameters); + } + + public byte[] messageEncrypt(byte[] input) + throws IllegalBlockSizeException, BadPaddingException, NoSuchAlgorithmException + { + byte[] output = null; + try + { + output = cipher.messageEncrypt(input); + } + catch (Exception e) + { + e.printStackTrace(); + } + return output; + } + + + public byte[] messageDecrypt(byte[] input) + throws IllegalBlockSizeException, BadPaddingException, NoSuchAlgorithmException + { + byte[] output = null; + try + { + output = cipher.messageDecrypt(input); + } + catch (Exception e) + { + e.printStackTrace(); + } + return output; + } + + + //////////////////////////////////////////////////////////////////////////////////77 + + static public class McEliecePointcheval + extends McEliecePointchevalCipherSpi + { + public McEliecePointcheval() + { + super(new SHA1Digest(), new McEliecePointchevalCipher()); + } + } + + static public class McEliecePointcheval224 + extends McEliecePointchevalCipherSpi + { + public McEliecePointcheval224() + { + super(new SHA224Digest(), new McEliecePointchevalCipher()); + } + } + + static public class McEliecePointcheval256 + extends McEliecePointchevalCipherSpi + { + public McEliecePointcheval256() + { + super(new SHA256Digest(), new McEliecePointchevalCipher()); + } + } + + static public class McEliecePointcheval384 + extends McEliecePointchevalCipherSpi + { + public McEliecePointcheval384() + { + super(new SHA384Digest(), new McEliecePointchevalCipher()); + } + } + + static public class McEliecePointcheval512 + extends McEliecePointchevalCipherSpi + { + public McEliecePointcheval512() + { + super(new SHA512Digest(), new McEliecePointchevalCipher()); + } + } + + +} |