diff --git a/java/ext/apache/.classpath b/java/ext/apache/.classpath
new file mode 100644
index 0000000..fb50116
--- /dev/null
+++ b/java/ext/apache/.classpath
@@ -0,0 +1,6 @@
+
+
+ * Released into the public domain
+ *
+ * @author Jordan Zimmerman - jordan@jordanzimmerman.com
+ * @see SRPFactory Full Documentation
+ * @version 1.1
+ */
+public class SRPAuthenticationFailedException extends IOException
+{
+ public SRPAuthenticationFailedException()
+ {
+ super();
+ }
+
+ public SRPAuthenticationFailedException(String message)
+ {
+ super(message);
+ }
+}
diff --git a/java/ext/jordanzimmerman/src/com/jordanzimmerman/SRPClientSession.java b/java/ext/jordanzimmerman/src/com/jordanzimmerman/SRPClientSession.java
new file mode 100755
index 0000000..531c7cb
--- /dev/null
+++ b/java/ext/jordanzimmerman/src/com/jordanzimmerman/SRPClientSession.java
@@ -0,0 +1,179 @@
+package com.jordanzimmerman;
+
+import java.math.BigInteger;
+
+/**
+ * Manages a client SRP session
+ *
+ * Released into the public domain
+ *
+ * @author Jordan Zimmerman - jordan@jordanzimmerman.com
+ * @see SRPFactory Full Documentation
+ * @version 1.4 Make sure safeguards are checked: abort if B == 0 (mod N) or u == 0 - 2/27/07
+ * @version 1.3 Updated to use the SRP-6 spec - 2/21/07
+ * @version 1.2
+ */
+public class SRPClientSession
+{
+ protected SRPClientSession ()
+ {
+
+ }
+
+ /**
+ * @param constants constants to use
+ * @param password password as passed to {@link SRPFactory#makeVerifier(byte[])}
+ */
+ public SRPClientSession(SRPConstants constants, byte[] password)
+ {
+ fConstants = constants;
+ fPassword = password;
+ }
+
+ /**
+ * Once the server sends the salt (value s in the docs), call this method to save the value
+ *
+ * @param salt salt from the server
+ */
+ public void setSalt_s(BigInteger salt)
+ {
+ fPrivateKey_x = SRPUtils.makePrivateKey(fPassword, salt);
+ fRandom_a = SRPUtils.random(fConstants);
+ fCommonValue_S = null;
+ fEvidenceValue_M1 = null;
+ fSessionKey_K = null;
+
+ // A = g^a
+ fPublicKey_A = fConstants.primitiveRoot_g.modPow(fRandom_a, fConstants.largePrime_N);
+ }
+
+ public void setSalt_s(byte[] v)
+ { setSalt_s(new BigInteger(v)); }
+
+ /**
+ * Returns the public key (value A in the docs). This should be passed to the server
+ *
+ * @return A
+ */
+ public BigInteger getPublicKey_A()
+ {
+ return fPublicKey_A;
+ }
+
+ public byte[] getPublicKey_A_()
+ { return getPublicKey_A().toByteArray(); }
+
+
+ /**
+ * Call to save the public key (value B in the docs) when received from the server
+ *
+ * @param publicKey_B B
+ * @throws SRPAuthenticationFailedException if B is invalid
+ */
+ public void setServerPublicKey_B(BigInteger publicKey_B) throws SRPAuthenticationFailedException
+ {
+ if ( fPublicKey_A == null )
+ {
+ throw new IllegalStateException("setSalt_s() has not been called yet.");
+ }
+
+ if ( publicKey_B.mod(fConstants.largePrime_N).equals(BigInteger.ZERO) )
+ {
+ throw new SRPAuthenticationFailedException("B%N == 0");
+ }
+
+ BigInteger SRP6_u = SRPUtils.calc_u(fPublicKey_A, publicKey_B);
+ if ( SRP6_u.mod(fConstants.largePrime_N).equals(BigInteger.ZERO) )
+ {
+ throw new SRPAuthenticationFailedException("u%N == 0");
+ }
+
+ // S = (B - 3(g^x))^(a + ux)
+ BigInteger three_g_pow_x = fConstants.srp6Multiplier_k.multiply(fConstants.primitiveRoot_g.modPow(fPrivateKey_x, fConstants.largePrime_N));
+ BigInteger B_minus_g_pow_x = publicKey_B.subtract(three_g_pow_x);
+ BigInteger ux = SRP6_u.multiply(fPrivateKey_x);
+ fCommonValue_S = B_minus_g_pow_x.modPow(fRandom_a.add(ux), fConstants.largePrime_N).mod(fConstants.largePrime_N);
+ fEvidenceValue_M1 = SRPUtils.calcM1(fPublicKey_A, publicKey_B, fCommonValue_S);
+
+ // the MD5 output is the same as the AES key length
+ fSessionKey_K = SRPUtils.hashToBytesMD5(fCommonValue_S);
+ }
+
+ public void setServerPublicKey_B(byte[] v) throws SRPAuthenticationFailedException
+ { setServerPublicKey_B(new BigInteger(v)); }
+
+ /**
+ * After the session key has been computed, use this method to return the evidence value to send to the server (value M[1] in the docs).
+ *
+ * @return M(1)
+ */
+ public BigInteger getEvidenceValue_M1()
+ {
+ if ( fEvidenceValue_M1 == null )
+ {
+ throw new IllegalStateException("computeCommonValue_S() has not been called yet.");
+ }
+
+ return fEvidenceValue_M1;
+ }
+
+ public byte[] getEvidenceValue_M1_()
+ { return getEvidenceValue_M1().toByteArray(); }
+
+ /**
+ * When the server sends M(2), call this method to validate the number.
+ *
+ * @param evidenceValueFromServer_M2 M(2) from the server.
+ * @throws SRPAuthenticationFailedException if M(2) is incorrect
+ */
+ public void validateServerEvidenceValue_M2(BigInteger evidenceValueFromServer_M2) throws SRPAuthenticationFailedException
+ {
+ if ( fEvidenceValue_M1 == null )
+ {
+ throw new IllegalStateException("computeCommonValue_S() has not been called yet.");
+ }
+
+ BigInteger M2 = SRPUtils.calcM2(fPublicKey_A, fEvidenceValue_M1, fCommonValue_S);
+ if ( !evidenceValueFromServer_M2.equals(M2) )
+ {
+ throw new SRPAuthenticationFailedException("M(2) is incorrect");
+ }
+ }
+
+ public void validateServerEvidenceValue_M2(byte[] v) throws SRPAuthenticationFailedException
+ { validateServerEvidenceValue_M2(new BigInteger(v)); }
+
+ /**
+ * Returns the session common value which is the pre-hashed version of K
+ *
+ * @return common value
+ */
+ public BigInteger getSessionCommonValue()
+ {
+ return fCommonValue_S;
+ }
+
+ /**
+ * The 16 byte session key suitable for encryption
+ *
+ * @return session key - K
+ */
+ public byte[] getSessionKey_K()
+ {
+ return fSessionKey_K;
+ }
+
+ SRPConstants getConstants()
+ {
+ return fConstants;
+ }
+
+ protected SRPConstants fConstants;
+ protected byte[] fPassword;
+ protected BigInteger fPrivateKey_x;
+ protected BigInteger fRandom_a;
+ protected BigInteger fPublicKey_A;
+ protected BigInteger fCommonValue_S;
+ protected byte[] fSessionKey_K;
+ protected BigInteger fEvidenceValue_M1;
+}
diff --git a/java/ext/jordanzimmerman/src/com/jordanzimmerman/SRPConstants.java b/java/ext/jordanzimmerman/src/com/jordanzimmerman/SRPConstants.java
new file mode 100755
index 0000000..4bbadaf
--- /dev/null
+++ b/java/ext/jordanzimmerman/src/com/jordanzimmerman/SRPConstants.java
@@ -0,0 +1,48 @@
+package com.jordanzimmerman;
+
+import java.math.BigInteger;
+import java.io.Serializable;
+
+/**
+ * POJO for holding the prime number and primitve root.
+ *
+ * SRP attempts to eliminate many of the security problems involved in a client/server user authentication.
+ * I don't understand the math, but the ideas are farily simple. On the server, store a mathematically generated number that is
+ * based on a user chosen password and a randomly generated "salt". Both the client and server maintain a predetermined prime
+ * number "N" and a "primitive root" based on N called "g". The nature of all these numbers allows an authentication without
+ * the server needing to save the password. The client asks for the salt that was created, then a series of calculations
+ * are performed with the client and server exchanging the calculated values. At the end of this, both the client and server
+ * can safely know that authentication has occurred.
+ *
+ *
+ * From the SRP website, SRP assures:
+ *
+ *
+ * Using this library:
+ * For all interactions, you obtain an {@link SRPFactory} via one of the static getInstance() methods. The no-args version uses
+ * default values for the prime number and primitive root. The other version allows you to specify values for these.
+ *
+ * The first activity is to generate a "verifier" for a password. Given a password P, this is accomplished via the {@link SRPFactory#makeVerifier(byte[])}
+ * method. E.g.
+
+ *
+ * The second activity is a client/server session. On the server, allocate a {@link SRPServerSessionRunner} loaded with
+ * a session from {@link SRPFactory#newServerSession(SRPVerifier)}. On the client, allocate a {@link SRPClientSessionRunner}
+ * loaded with a session from {@link SRPFactory#newClientSession(byte[])}. Once you have a Session Runner, you can pass it to an
+ * {@link SRPInputStream} and an {@link SRPOutputStream}. For each of these streams, call both {@link SRPInputStream#authenticate(SRPRunner, SRPOutputStream)}
+ * and {@link SRPOutputStream#authenticate(SRPRunner, SRPInputStream)}. Once authenticated, use them as you would any I/O stream. All I/O
+ * on these streams are encrypted using AES with the SRP session key as the encryption key.
+ *
+ *
+ * Stream Protocol
+ * Once authentication is complete, the streams use the following protocol to send data:
+ *
+ * IMPORTANT: This library relies on JCE
+ *
+ *
+ * Released into the public domain
+ *
+ * @author Jordan Zimmerman - jordan@jordanzimmerman.com
+ * @version 1.4 a) Updated to use the SRP-6a spec. b) Updated Javadoc. 2/27/07
+ * @version 1.3 Updated to use the SRP-6 spec 2/21/07
+ * @version 1.2
+ */
+public class SRPFactory
+{
+ /**
+ * Utility for generating a verifier (using default constants)
+ *
+ * @param args args[0] is the Password
+ */
+ public static void main(String[] args)
+ {
+ SRPVerifier verifier = SRPFactory.getInstance().makeVerifier(args[0].getBytes());
+ System.out.println("v: " + verifier.verifier_v.toString(16));
+ System.out.println("s: " + verifier.salt_s.toString(16));
+ }
+
+ /**
+ * Return a factory that uses default constants
+ *
+ * @return the factory
+ */
+ public static SRPFactory getInstance()
+ {
+ return new SRPFactory(DEFAULT_CONSTANTS);
+ }
+
+ /**
+ * Return a factory that uses the given constants
+ *
+ * @param constants prime number constants
+ * @return the factory
+ */
+ public static SRPFactory getInstance(SRPConstants constants)
+ {
+ return new SRPFactory(constants);
+ }
+
+ /**
+ * Create a new "verifier" (v in the SRP docs). A random salt value is created.
+ *
+ * @param password bytes of the password. Client will need this same password later on for a client session.
+ *
+ * @return the verifier
+ */
+ public SRPVerifier makeVerifier(byte[] password)
+ {
+ return SRPUtils.makeVerifier(fConstants, password);
+ }
+
+ /**
+ * Start a new client session.
+ *
+ * @param password The same password that was passed to {@link #makeVerifier(byte[])}
+ *
+ * @return the client session. Normally, this is passed directly to a new {@link SRPClientSessionRunner}
+ */
+ public SRPClientSession newClientSession(byte[] password)
+ {
+ return new SRPClientSession(fConstants, password);
+ }
+
+ /**
+ * Start a new server session.
+ *
+ * @param verifier The same verifier that was returned by {@link #makeVerifier(byte[])}
+ *
+ * @return the server session. Normally, this is passed directly to a new {@link SRPServerSessionRunner}
+ */
+ public SRPServerSession newServerSession(SRPVerifier verifier)
+ {
+ return new SRPServerSession(fConstants, verifier);
+ }
+
+ private SRPFactory(SRPConstants constants)
+ {
+ fConstants = constants;
+ }
+
+ public static final SRPConstants DEFAULT_CONSTANTS = new SRPConstants
+ (
+ new BigInteger("115b8b692e0e045692cf280b436735c77a5a9e8a9e7ed56c965f87db5b2a2ece3", 16),
+ new BigInteger("2")
+ );
+
+ private SRPConstants fConstants;
+}
diff --git a/java/ext/jordanzimmerman/src/com/jordanzimmerman/SRPServerSession.java b/java/ext/jordanzimmerman/src/com/jordanzimmerman/SRPServerSession.java
new file mode 100755
index 0000000..25d82f7
--- /dev/null
+++ b/java/ext/jordanzimmerman/src/com/jordanzimmerman/SRPServerSession.java
@@ -0,0 +1,166 @@
+package com.jordanzimmerman;
+
+import java.math.BigInteger;
+
+/**
+ * Manages a server SRP session
+ *
+ *
+ * Released into the public domain
+ *
+ * @author Jordan Zimmerman - jordan@jordanzimmerman.com
+ * @see SRPFactory Full Documentation
+ * @version 1.4 Make sure safeguards are checked: abort if A == 0 (mod N) or u == 0 - 2/27/07
+ * @version 1.3 Updated to use the SRP-6 spec 2/21/07
+ * @version 1.2
+ */
+public class SRPServerSession
+{
+ /**
+ * @param constants constants to use
+ * @param verifier the verifier as returned from {@link SRPFactory#makeVerifier(byte[])}
+ */
+ public SRPServerSession(SRPConstants constants, SRPVerifier verifier)
+ {
+ fConstants = constants;
+ fVerifier = verifier;
+ fRandom_b = SRPUtils.random(fConstants);
+ fSRP6_u = null;
+ fPublicKey_A = null;
+ fCommonValue_S = null;
+ fEvidenceValue_M1 = null;
+ fSessionKey_K = null;
+
+ // B = 3v + g^b
+ fPublicKey_B = fVerifier.verifier_v.multiply(constants.srp6Multiplier_k).add(fConstants.primitiveRoot_g.modPow(fRandom_b, fConstants.largePrime_N));
+ }
+
+ /**
+ * When the client sends the public key (value A in the docs) call this method to store the value
+ *
+ * @param publicKey_A A
+ * @throws SRPAuthenticationFailedException if A is invalid
+ */
+ public void setClientPublicKey_A(BigInteger publicKey_A) throws SRPAuthenticationFailedException
+ {
+ if ( publicKey_A.mod(fConstants.largePrime_N).equals(BigInteger.ZERO) )
+ {
+ throw new SRPAuthenticationFailedException("A%N == 0");
+ }
+
+ fPublicKey_A = publicKey_A;
+ fSRP6_u = SRPUtils.calc_u(fPublicKey_A, fPublicKey_B);
+ if ( fSRP6_u.mod(fConstants.largePrime_N).equals(BigInteger.ZERO) )
+ {
+ throw new SRPAuthenticationFailedException("u%N == 0");
+ }
+ }
+
+ public void setClientPublicKey_A(byte[] publicKey) throws SRPAuthenticationFailedException
+ { setClientPublicKey_A(new BigInteger(publicKey)); }
+
+ /**
+ * Returns the public key that should be sent to the client (value B in the docs).
+ *
+ * @return B
+ */
+ public BigInteger getPublicKey_B()
+ {
+ return fPublicKey_B;
+ }
+
+ /**
+ * Call to calculate the common session key (S/K in the docs)
+ */
+ public void computeCommonValue_S()
+ {
+ if ( fPublicKey_A == null )
+ {
+ throw new IllegalStateException("setClientPublicKey_A() has not been called yet.");
+ }
+
+ // S = (A · v^u)^b
+ fCommonValue_S = fPublicKey_A.multiply(fVerifier.verifier_v.modPow(fSRP6_u, fConstants.largePrime_N)).modPow(fRandom_b, fConstants.largePrime_N);
+ fEvidenceValue_M1 = SRPUtils.calcM1(fPublicKey_A, fPublicKey_B, fCommonValue_S);
+
+ // the MD5 output is the same as the AES key length
+ fSessionKey_K = SRPUtils.hashToBytesMD5(fCommonValue_S);
+ }
+
+ /**
+ * When M(1) is received from the client, call this method to validate it
+ *
+ * @param evidenceValueFromClient_M1 M(1) as recevied from the client
+ * @throws SRPAuthenticationFailedException if M(1) is incorrect
+ */
+ public void validateClientEvidenceValue_M1(BigInteger evidenceValueFromClient_M1) throws SRPAuthenticationFailedException
+ {
+ if ( fEvidenceValue_M1 == null )
+ {
+ throw new IllegalStateException("computeCommonValue_S() has not been called yet.");
+ }
+
+ if ( !fEvidenceValue_M1.equals(evidenceValueFromClient_M1) )
+ {
+ throw new SRPAuthenticationFailedException("M(1) incorrect");
+ }
+ }
+
+ public void validateClientEvidenceValue_M1(byte[] evidenceValueFromClient_M1) throws SRPAuthenticationFailedException
+ { validateClientEvidenceValue_M1(new BigInteger(evidenceValueFromClient_M1)); }
+
+ /**
+ * Return the value M(2) that should be sent to the client
+ *
+ * @return M(2)
+ */
+ public BigInteger getEvidenceValue_M2()
+ {
+ if ( fEvidenceValue_M1 == null )
+ {
+ throw new IllegalStateException("computeCommonValue_S() has not been called yet.");
+ }
+
+ return SRPUtils.calcM2(fPublicKey_A, fEvidenceValue_M1, fCommonValue_S);
+ }
+
+ /**
+ * Returns the session common value which is the pre-hashed version of K
+ *
+ * @return common value
+ */
+ public BigInteger getSessionCommonValue()
+ {
+ return fCommonValue_S;
+ }
+
+ /**
+ * The 16 byte session key suitable for encryption
+ *
+ * @return session key - K
+ */
+ public byte[] getSessionKey_K()
+ {
+ return fSessionKey_K;
+ }
+
+ SRPConstants getConstants()
+ {
+ return fConstants;
+ }
+
+ public SRPVerifier getVerifier()
+ {
+ return fVerifier;
+ }
+
+ private SRPConstants fConstants;
+ private SRPVerifier fVerifier;
+ private BigInteger fRandom_b;
+ private BigInteger fSRP6_u;
+ private BigInteger fPublicKey_A;
+ private BigInteger fPublicKey_B;
+ private BigInteger fCommonValue_S;
+ private byte[] fSessionKey_K;
+ private BigInteger fEvidenceValue_M1;
+}
diff --git a/java/ext/jordanzimmerman/src/com/jordanzimmerman/SRPUtils.java b/java/ext/jordanzimmerman/src/com/jordanzimmerman/SRPUtils.java
new file mode 100755
index 0000000..6744f01
--- /dev/null
+++ b/java/ext/jordanzimmerman/src/com/jordanzimmerman/SRPUtils.java
@@ -0,0 +1,286 @@
+package com.jordanzimmerman;
+
+import java.math.BigInteger;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.nio.ByteBuffer;
+
+/**
+ * Various utilities
+
+ if ( !N.isProbablePrime(10) )
+ {
+ throw new IllegalArgumentException("isProbablePrime(10) failed for " + N.toString(16));
+ }
+
+ BigInteger n_minus_one_div_2 = N.subtract(BigInteger.ONE).divide(TWO);
+
+ if ( !n_minus_one_div_2.isProbablePrime(10) )
+ {
+ throw new IllegalArgumentException("(N-1)/2 is not prime for " + N.toString(16));
+ }
+
+ if( g.modPow(n_minus_one_div_2, N).add(BigInteger.ONE).compareTo(N) != 0)
+ {
+ throw new IllegalArgumentException("Not a primitive root: " + g.toString(16));
+ }
+ }
+
+ /**
+ * Make a verifier. First, x is generated via x = H(s, P) where H is a hash() function, s is random salt, and P is the password.
+ * The verifier is then v = g^x
+ *
+ * @param constants the constants to use
+ * @param password the password to process
+ * @return the verifier
+ */
+ static SRPVerifier makeVerifier(SRPConstants constants, byte[] password)
+ {
+ BigInteger salt = random(constants);
+ BigInteger x = makePrivateKey(password, salt);
+ BigInteger v = constants.primitiveRoot_g.modPow(x, constants.largePrime_N);
+
+ return new SRPVerifier(v, salt);
+ }
+
+ /**
+ * Make a new private key via x = H(s, P) where H is a hash() function, s is random salt, and P is the password.
+ *
+ * @param password the password
+ * @param salt random salt
+ * @return the private key
+ */
+ static BigInteger makePrivateKey(byte[] password, BigInteger salt)
+ {
+ BigInteger passwordInt = new BigInteger(password);
+ return hash(combine(passwordInt, salt));
+ }
+
+ /**
+ * Combine two integers into one. This method uses a novel combining method rather than simple concatenation. My assumption is
+ * that it will add an additional level of security as a malicious party would not be able to guess this method. The bytes from
+ * each value are interleaved in pairs. If the first value of the pair is odd, two bytes are taken from the second value. Any
+ * remaining bytes are appended at the end.
+ *
+ * @param a first value to combine
+ * @param b second value to combine
+ * @return combined value
+ */
+ /*
+ static BigInteger combine(BigInteger a, BigInteger b)
+ {
+ ByteBuffer abuf = ByteBuffer.wrap(a.toByteArray());
+ ByteBuffer bbuf = ByteBuffer.wrap(b.toByteArray());
+ byte[] combined = new byte[abuf.capacity() + bbuf.capacity()];
+ ByteBuffer combinedbuf = ByteBuffer.wrap(combined);
+
+ abuf.rewind();
+ bbuf.rewind();
+ combinedbuf.clear();
+
+ while ( abuf.hasRemaining() && bbuf.hasRemaining() )
+ {
+ byte abyte = abuf.get();
+ combinedbuf.put(abyte);
+ byte bbyte = bbuf.get();
+ combinedbuf.put(bbyte);
+ if ( ((abyte & 1) == 0) && bbuf.hasRemaining() )
+ {
+ bbyte = bbuf.get();
+ combinedbuf.put(bbyte);
+ }
+ }
+
+ while ( abuf.hasRemaining() )
+ {
+ byte x = abuf.get();
+ combinedbuf.put(x);
+ }
+
+ while ( bbuf.hasRemaining() )
+ {
+ byte x = bbuf.get();
+ combinedbuf.put(x);
+ }
+
+ return new BigInteger(combined);
+ }
+ */
+ static BigInteger combine(BigInteger a, BigInteger b)
+ {
+ byte[] abuf = a.toByteArray();
+ byte[] bbuf = b.toByteArray();
+ byte[] cbuf = new byte[abuf.length + bbuf.length];
+
+ int ai = 0;
+ int bi = 0;
+ int ci = 0;
+ int al = abuf.length;
+ int bl = bbuf.length;
+
+ while ( ai < al && bi < bl )
+ {
+ byte abyte = abuf[ai++];
+ cbuf[ci++] = abyte;
+ byte bbyte = bbuf[bi++];
+ cbuf[ci++] = bbyte;
+
+ if ( ((abyte & 1) == 0) && bi < bl )
+ {
+ cbuf[ci++] = bbuf[bi++];
+ }
+ }
+
+ while ( ai < al )
+ {
+ cbuf[ci++] = abuf[ai++];
+ }
+
+ while ( bi < bl )
+ {
+ cbuf[ci++] = bbuf[bi++];
+ }
+
+ return new BigInteger(cbuf);
+ }
+
+
+ /**
+ * hash a big int. Use SHA 256.
+ *
+ * @param i int to hash
+ * @return the hash
+ */
+ static BigInteger hash(BigInteger i)
+ {
+ return new BigInteger(hashToBytes(i));
+ }
+
+ /**
+ * hash a big int. Use SHA 256.
+ *
+ * @param i int to hash
+ * @return the hash
+ */
+ static byte[] hashToBytes(BigInteger i)
+ {
+ Hash256i d = new Hash256i();
+ byte[] b = i.toByteArray();
+ return d.hash(b);
+ }
+
+ /**
+ * hash a big int. Use MD5.
+ *
+ * @param i int to hash
+ * @return the hash
+ */
+ static byte[] hashToBytesMD5(BigInteger i)
+ {
+ /*
+ try
+ {
+ MessageDigest sha = MessageDigest.getInstance("MD5");
+ byte[] b = i.toByteArray();
+ sha.update(b, 0, b.length);
+ return sha.digest();
+ }
+ catch ( NoSuchAlgorithmException e )
+ {
+ throw new UnsupportedOperationException(e);
+ }
+ */
+ return hashToBytesForAES(i);
+ }
+
+ static byte[] hashToBytesForAES(BigInteger i)
+ {
+ return hashToBytes(i);
+ }
+
+
+ /**
+ * Return a random number that satsifies: 1 < r < n
+ *
+ * @param constants constants to use
+ * @return the random number
+ */
+ static BigInteger random(SRPConstants constants)
+ {
+ int numberOfBytes = (constants.largePrime_N.bitLength() + (constants.largePrime_N.bitLength() - 1)) / 8;
+ byte[] b = new byte[numberOfBytes];
+ fRandom.nextBytes(b);
+ BigInteger i = new BigInteger(b);
+
+ // random numbers must be: 1 < r < n
+ BigInteger max = constants.largePrime_N.subtract(TWO);
+ return i.mod(max).add(TWO);
+ }
+
+ /**
+ * Calculate M(1) - H(A, B, K)
+ *
+ * @param publicKey_A generated public key - A
+ * @param publicKey_B generated public key - B
+ * @param commonValue_S the session common value - S
+ * @return M(1)
+ */
+ static BigInteger calcM1(BigInteger publicKey_A, BigInteger publicKey_B, BigInteger commonValue_S)
+ {
+ return hash(combine(combine(publicKey_A, publicKey_B), commonValue_S));
+ }
+
+ /**
+ * Calculate M(1) - H(A, M[1], K)
+ *
+ * @param publicKey_A generated public key - A
+ * @param evidenceValue_M1 generated hash - M(1)
+ * @param commonValue_S the session common value - S
+ * @return M(1)
+ */
+ static BigInteger calcM2(BigInteger publicKey_A, BigInteger evidenceValue_M1, BigInteger commonValue_S)
+ {
+ return hash(combine(combine(publicKey_A, evidenceValue_M1), commonValue_S));
+ }
+
+ /**
+ * Return the SRP-6 version of u - H(A, B)
+ *
+ * @param A Public Key A
+ * @param B Public Key B
+ * @return u
+ */
+ static BigInteger calc_u(BigInteger A, BigInteger B)
+ {
+ return hash(combine(A, B));
+ }
+
+ private SRPUtils()
+ {
+ }
+
+ private static final BigInteger TWO = BigInteger.valueOf(2);
+
+ private static final SecureRandom fRandom = new SecureRandom();
+}
diff --git a/java/ext/jordanzimmerman/src/com/jordanzimmerman/SRPVerifier.java b/java/ext/jordanzimmerman/src/com/jordanzimmerman/SRPVerifier.java
new file mode 100755
index 0000000..05a7abe
--- /dev/null
+++ b/java/ext/jordanzimmerman/src/com/jordanzimmerman/SRPVerifier.java
@@ -0,0 +1,32 @@
+package com.jordanzimmerman;
+
+import java.math.BigInteger;
+import java.io.Serializable;
+
+/**
+ * POJO for holding the random salt and verifier
+ * The constructor can convert a JSON text into a Java object. The
+ *
+ * A
+ * The generic
+ * The texts produced by the
+ * Warning: This method assumes that the data structure is acyclical.
+ *
+ * @return a printable, displayable, transmittable
+ * representation of the array.
+ */
+ public String toString() {
+ try {
+ return '[' + this.join(",") + ']';
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+
+ /**
+ * Make a prettyprinted JSON text of this JSONArray.
+ * Warning: This method assumes that the data structure is acyclical.
+ * @param indentFactor The number of spaces to add to each level of
+ * indentation.
+ * @return a printable, displayable, transmittable
+ * representation of the object, beginning
+ * with
+ * Warning: This method assumes that the data structure is acyclical.
+ *
+ * @return The writer.
+ * @throws JSONException
+ */
+ public Writer write(Writer writer) throws JSONException {
+ return this.write(writer, 0, 0);
+ }
+
+ /**
+ * Write the contents of the JSONArray as JSON text to a writer. For
+ * compactness, no whitespace is added.
+ *
+ * Warning: This method assumes that the data structure is acyclical.
+ *
+ * @param indentFactor
+ * The number of spaces to add to each level of indentation.
+ * @param indent
+ * The indention of the top level.
+ * @return The writer.
+ * @throws JSONException
+ */
+ Writer write(Writer writer, int indentFactor, int indent)
+ throws JSONException {
+ try {
+ boolean commanate = false;
+ int length = this.length();
+ writer.write('[');
+
+ if (length == 1) {
+ JSONObject.writeValue(writer, this.myArrayList.get(0),
+ indentFactor, indent);
+ } else if (length != 0) {
+ final int newindent = indent + indentFactor;
+
+ for (int i = 0; i < length; i += 1) {
+ if (commanate) {
+ writer.write(',');
+ }
+ if (indentFactor > 0) {
+ writer.write('\n');
+ }
+ JSONObject.indent(writer, newindent);
+ JSONObject.writeValue(writer, this.myArrayList.get(i),
+ indentFactor, newindent);
+ commanate = true;
+ }
+ if (indentFactor > 0) {
+ writer.write('\n');
+ }
+ JSONObject.indent(writer, indent);
+ }
+ writer.write(']');
+ return writer;
+ } catch (IOException e) {
+ throw new JSONException(e);
+ }
+ }
+}
diff --git a/java/ext/json/src/org/json/JSONException.java b/java/ext/json/src/org/json/JSONException.java
new file mode 100755
index 0000000..289b602
--- /dev/null
+++ b/java/ext/json/src/org/json/JSONException.java
@@ -0,0 +1,28 @@
+package org.json;
+
+/**
+ * The JSONException is thrown by the JSON.org classes when things are amiss.
+ * @author JSON.org
+ * @version 2010-12-24
+ */
+public class JSONException extends Exception {
+ private static final long serialVersionUID = 0;
+ private Throwable cause;
+
+ /**
+ * Constructs a JSONException with an explanatory message.
+ * @param message Detail about the reason for the exception.
+ */
+ public JSONException(String message) {
+ super(message);
+ }
+
+ public JSONException(Throwable cause) {
+ super(cause.getMessage());
+ this.cause = cause;
+ }
+
+ public Throwable getCause() {
+ return this.cause;
+ }
+}
diff --git a/java/ext/json/src/org/json/JSONObject.java b/java/ext/json/src/org/json/JSONObject.java
new file mode 100755
index 0000000..637a807
--- /dev/null
+++ b/java/ext/json/src/org/json/JSONObject.java
@@ -0,0 +1,1606 @@
+package org.json;
+
+/*
+Copyright (c) 2002 JSON.org
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+The Software shall be used for Good, not Evil.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+*/
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.io.Writer;
+/*
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+*/
+import java.util.Collection;
+//import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Iterator;
+//import java.util.Locale;
+import java.util.Map;
+//import java.util.ResourceBundle;
+
+/**
+ * A JSONObject is an unordered collection of name/value pairs. Its external
+ * form is a string wrapped in curly braces with colons between the names and
+ * values, and commas between the values and names. The internal form is an
+ * object having
+ * The generic
+ * The
+ * The texts produced by the
+ * Warning: This method assumes that the data structure is acyclical.
+ *
+ * @return a printable, displayable, portable, transmittable
+ * representation of the object, beginning
+ * with
+ * Warning: This method assumes that the data structure is acyclical.
+ * @param indentFactor The number of spaces to add to each level of
+ * indentation.
+ * @return a printable, displayable, portable, transmittable
+ * representation of the object, beginning
+ * with
+ * Warning: This method assumes that the data structure is acyclical.
+ * @param value The value to be serialized.
+ * @return a printable, displayable, transmittable
+ * representation of the object, beginning
+ * with
+ * Warning: This method assumes that the data structure is acyclical.
+ *
+ * @return The writer.
+ * @throws JSONException
+ */
+ public Writer write(Writer writer) throws JSONException {
+ return this.write(writer, 0, 0);
+ }
+
+
+ static final Writer writeValue(Writer writer, Object value,
+ int indentFactor, int indent) throws JSONException, IOException {
+ if (value == null || value.equals(null)) {
+ writer.write("null");
+ } else if (value instanceof JSONObject) {
+ ((JSONObject) value).write(writer, indentFactor, indent);
+ } else if (value instanceof JSONArray) {
+ ((JSONArray) value).write(writer, indentFactor, indent);
+ } else if (value instanceof Map) {
+ new JSONObject((Map) value).write(writer, indentFactor, indent);
+ } else if (value instanceof Collection) {
+ new JSONArray((Collection) value).write(writer, indentFactor,
+ indent);
+ } else if (value.getClass().isArray()) {
+ new JSONArray(value).write(writer, indentFactor, indent);
+ } else if (value instanceof Number) {
+ writer.write(numberToString((Number) value));
+ } else if (value instanceof Boolean) {
+ writer.write(value.toString());
+ } else if (value instanceof JSONString) {
+ Object o;
+ try {
+ o = ((JSONString) value).toJSONString();
+ } catch (Exception e) {
+ throw new JSONException(e);
+ }
+ writer.write(o != null ? o.toString() : quote(value.toString()));
+ } else {
+ quote(value.toString(), writer);
+ }
+ return writer;
+ }
+
+ static final void indent(Writer writer, int indent) throws IOException {
+ for (int i = 0; i < indent; i += 1) {
+ writer.write(' ');
+ }
+ }
+
+ /**
+ * Write the contents of the JSONObject as JSON text to a writer. For
+ * compactness, no whitespace is added.
+ *
+ * Warning: This method assumes that the data structure is acyclical.
+ *
+ * @return The writer.
+ * @throws JSONException
+ */
+ Writer write(Writer writer, int indentFactor, int indent)
+ throws JSONException {
+ try {
+ boolean commanate = false;
+ final int length = this.length();
+ Iterator keys = this.keys();
+ writer.write('{');
+
+ if (length == 1) {
+ Object key = keys.next();
+ writer.write(quote(key.toString()));
+ writer.write(':');
+ if (indentFactor > 0) {
+ writer.write(' ');
+ }
+ writeValue(writer, this.map.get(key), indentFactor, indent);
+ } else if (length != 0) {
+ final int newindent = indent + indentFactor;
+ while (keys.hasNext()) {
+ Object key = keys.next();
+ if (commanate) {
+ writer.write(',');
+ }
+ if (indentFactor > 0) {
+ writer.write('\n');
+ }
+ indent(writer, newindent);
+ writer.write(quote(key.toString()));
+ writer.write(':');
+ if (indentFactor > 0) {
+ writer.write(' ');
+ }
+ writeValue(writer, this.map.get(key), indentFactor,
+ newindent);
+ commanate = true;
+ }
+ if (indentFactor > 0) {
+ writer.write('\n');
+ }
+ indent(writer, indent);
+ }
+ writer.write('}');
+ return writer;
+ } catch (IOException exception) {
+ throw new JSONException(exception);
+ }
+ }
+}
diff --git a/java/ext/json/src/org/json/JSONString.java b/java/ext/json/src/org/json/JSONString.java
new file mode 100755
index 0000000..1f2d77d
--- /dev/null
+++ b/java/ext/json/src/org/json/JSONString.java
@@ -0,0 +1,18 @@
+package org.json;
+/**
+ * The
+ * A JSONStringer instance provides a
+ * The first method called must be
+ * This can sometimes be easier than using a JSONObject to build a string.
+ * @author JSON.org
+ * @version 2008-09-18
+ */
+public class JSONStringer extends JSONWriter {
+ /**
+ * Make a fresh JSONStringer. It can be used to build one JSON text.
+ */
+ public JSONStringer() {
+ super(new StringWriter());
+ }
+
+ /**
+ * Return the JSON text. This method is used to obtain the product of the
+ * JSONStringer instance. It will return
+ * A JSONWriter instance provides a
+ * The first method called must be
+ * This can sometimes be easier than using a JSONObject to build a string.
+ * @author JSON.org
+ * @version 2011-11-24
+ */
+public class JSONWriter {
+ private static final int maxdepth = 200;
+
+ /**
+ * The comma flag determines if a comma should be output before the next
+ * value.
+ */
+ private boolean comma;
+
+ /**
+ * The current mode. Values:
+ * 'a' (array),
+ * 'd' (done),
+ * 'i' (initial),
+ * 'k' (key),
+ * 'o' (object).
+ */
+ protected char mode;
+
+ /**
+ * The object/array stack.
+ */
+ private final JSONObject stack[];
+
+ /**
+ * The stack top index. A value of 0 indicates that the stack is empty.
+ */
+ private int top;
+
+ /**
+ * The writer that will receive the output.
+ */
+ protected Writer writer;
+
+ /**
+ * Make a fresh JSONWriter. It can be used to build one JSON text.
+ */
+ public JSONWriter(Writer w) {
+ this.comma = false;
+ this.mode = 'i';
+ this.stack = new JSONObject[maxdepth];
+ this.top = 0;
+ this.writer = w;
+ }
+
+ /**
+ * Append a value.
+ * @param string A string value.
+ * @return this
+ * @throws JSONException If the value is out of sequence.
+ */
+ private JSONWriter append(String string) throws JSONException {
+ if (string == null) {
+ throw new JSONException("Null pointer");
+ }
+ if (this.mode == 'o' || this.mode == 'a') {
+ try {
+ if (this.comma && this.mode == 'a') {
+ this.writer.write(',');
+ }
+ this.writer.write(string);
+ } catch (IOException e) {
+ throw new JSONException(e);
+ }
+ if (this.mode == 'o') {
+ this.mode = 'k';
+ }
+ this.comma = true;
+ return this;
+ }
+ throw new JSONException("Value out of sequence.");
+ }
+
+ /**
+ * Begin appending a new array. All values until the balancing
+ *
+Thanks, may your castles never deflate!
+
+Organisations
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+and associated documentation files (the "Software"), to deal in the Software without restriction,
+including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial
+portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+
diff --git a/java/ext/lcrypto-jdk15on-148/bin/META-INF/MANIFEST.MF b/java/ext/lcrypto-jdk15on-148/bin/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..5e94951
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/bin/META-INF/MANIFEST.MF
@@ -0,0 +1,3 @@
+Manifest-Version: 1.0
+Class-Path:
+
diff --git a/java/ext/lcrypto-jdk15on-148/index.html b/java/ext/lcrypto-jdk15on-148/index.html
new file mode 100644
index 0000000..6899828
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/index.html
@@ -0,0 +1,121 @@
+
+
+The Legion also gratefully acknowledges the contributions made to this
+package by others (see here
+for the current list).
+
+The package is organised so that it
+contains a light-weight API suitable for use in any environment
+(including the newly released J2ME) with the additional infrastructure
+to conform the algorithms to the JCE framework.
+
+Except where otherwise stated, this software is distributed under a license based on the MIT X Consortium license. To view the license, see here. The OpenPGP library also includes a modified BZIP2 library which is licensed under the Apache Software License, Version 2.0.
+
+The current release notes for this package are
+here.
+
+The current specifications for this package are
+here.
+
+The current api documentation for this package is
+here.
+
+ *
+ * Released into the public domain
+ *
+ * @author Jordan Zimmerman - jordan@jordanzimmerman.com
+ * @see SRPFactory Full Documentation
+ * @version 1.3 Updated to use the SRP-6a spec - k = H(N, g) 2/27/07
+ * @version 1.2 Updated to use the SRP-6 spec 2/21/07
+ * @version 1.1
+ */
+public class SRPConstants implements Serializable
+{
+ /**
+ * NOTE: this constructor validates the values passed via {@link SRPUtils#validateConstants(java.math.BigInteger,java.math.BigInteger)}
+ *
+ * @param largePrime a very large prime number
+ * @param primitiveRoot a primitive root that relates to the prime number.
+ */
+ public SRPConstants(BigInteger largePrime, BigInteger primitiveRoot)
+ {
+ SRPUtils.validateConstants(largePrime, primitiveRoot);
+
+ this.largePrime_N = largePrime;
+ this.primitiveRoot_g = primitiveRoot;
+ this.srp6Multiplier_k = SRPUtils.hash(SRPUtils.combine(this.largePrime_N, this.primitiveRoot_g));
+ }
+
+ /**
+ * N
+ */
+ public final BigInteger largePrime_N;
+
+ /**
+ * g
+ */
+ public final BigInteger primitiveRoot_g;
+
+ /**
+ * k from SRP-6
+ */
+ public final BigInteger srp6Multiplier_k;
+}
diff --git a/java/ext/jordanzimmerman/src/com/jordanzimmerman/SRPFactory.java b/java/ext/jordanzimmerman/src/com/jordanzimmerman/SRPFactory.java
new file mode 100755
index 0000000..22c115e
--- /dev/null
+++ b/java/ext/jordanzimmerman/src/com/jordanzimmerman/SRPFactory.java
@@ -0,0 +1,164 @@
+package com.jordanzimmerman;
+
+import java.math.BigInteger;
+
+/**
+ * An implementation of SRP-6a - Secure Remote Password Protocol. See http://srp.stanford.edu
+ * and http://srp.stanford.edu/ndss.html. The improvements described in
+ * SRP-6: Improvements and Refinements to the Secure Remote Password Protocol have been incorporated.
+ *
+ *
+ *
+ * For general use, you should only need to directly use these three classes: {@link SRPFactory}, {@link SRPInputStream}
+ * and {@link SRPOutputStream}. Besides these three, you will use two POJOs: {@link SRPConstants} and {@link SRPVerifier}
+ *
+ * This value should be stored away referenced via a username.
+ *
+ SRPFactory.getInstance().makeVerifier(P);
+
+ * The SRPInputStream/SRPOutStream authenticate using, essentially, the protocol as specified here: http://srp.stanford.edu/design.html.
+ * All values are sent as {@link java.math.BigInteger#toString(int)} with a radix of 16. The only difference is that the method to combine values is
+ * unique to this library (see {@link SRPUtils#combine(java.math.BigInteger, java.math.BigInteger)}). If at any point authentication
+ * fails, the stream is closed.
+ *
+
+ *
+ [data size][newline]
+ [data]
+
+ * "data size" is the number of bytes in the data block. The size is specified as radix 16 BigInteger. The data block is
+ * encrypted via AES using K as the key. K is an MD5 hash of S. A new data block is sent each time flush() is called on the
+ * output stream.
+ *
+ *
+ * Released into the public domain
+ *
+ * @author Jordan Zimmerman - jordan@jordanzimmerman.com
+ * @see SRPFactory Full Documentation
+ * @version 1.2 Updated to use the SRP-6 spec 2/21/07
+ * @version 1.1
+ */
+class SRPUtils
+{
+ /**
+ * Validates the given constants. Throws {@link IllegalArgumentException} if the values are not valid.
+ * NOTE: due to prime number calculations, this method can be slow.
+ *
+ * @param N large prime
+ * @param g primitve root of N
+ */
+ static void validateConstants(BigInteger N, BigInteger g)
+ {
+ // Developed from "SRP JavaScript Demo" from http://srp.stanford.edu
+ *
+ * Released into the public domain
+ *
+ * @author Jordan Zimmerman - jordan@jordanzimmerman.com
+ * @see SRPFactory Full Documentation
+ * @version 1.1
+ */
+public class SRPVerifier implements Serializable
+{
+ public SRPVerifier(BigInteger verifier, BigInteger salt)
+ {
+ this.verifier_v = verifier;
+ this.salt_s = salt;
+ }
+
+ /**
+ * v
+ */
+ public final BigInteger verifier_v;
+
+ /**
+ * s
+ */
+ public final BigInteger salt_s;
+}
diff --git a/java/ext/json/.classpath b/java/ext/json/.classpath
new file mode 100644
index 0000000..e2b1764
--- /dev/null
+++ b/java/ext/json/.classpath
@@ -0,0 +1,16 @@
+
+get
and opt
+ * methods for accessing the values by index, and put
methods for
+ * adding or replacing values. The values can be any of these types:
+ * Boolean
, JSONArray
, JSONObject
,
+ * Number
, String
, or the
+ * JSONObject.NULL object
.
+ * toString
method converts to JSON text.
+ * get
method returns a value if one can be found, and throws an
+ * exception if one cannot be found. An opt
method returns a
+ * default value instead of throwing an exception, and so is useful for
+ * obtaining optional values.
+ * get()
and opt()
methods return an
+ * object which you can cast or query for type. There are also typed
+ * get
and opt
methods that do type checking and type
+ * coercion for you.
+ * toString
methods strictly conform to
+ * JSON syntax rules. The constructors are more forgiving in the texts they will
+ * accept:
+ *
+ *
+ *
+ * @author JSON.org
+ * @version 2012-04-20
+ */
+public class JSONArray {
+
+
+ /**
+ * The arrayList where the JSONArray's properties are kept.
+ */
+ private final ArrayList myArrayList;
+
+
+ /**
+ * Construct an empty JSONArray.
+ */
+ public JSONArray() {
+ this.myArrayList = new ArrayList();
+ }
+
+ /**
+ * Construct a JSONArray from a JSONTokener.
+ * @param x A JSONTokener
+ * @throws JSONException If there is a syntax error.
+ */
+ public JSONArray(JSONTokener x) throws JSONException {
+ this();
+ if (x.nextClean() != '[') {
+ throw x.syntaxError("A JSONArray text must start with '['");
+ }
+ if (x.nextClean() != ']') {
+ x.back();
+ for (;;) {
+ if (x.nextClean() == ',') {
+ x.back();
+ this.myArrayList.add(JSONObject.NULL);
+ } else {
+ x.back();
+ this.myArrayList.add(x.nextValue());
+ }
+ switch (x.nextClean()) {
+ case ';':
+ case ',':
+ if (x.nextClean() == ']') {
+ return;
+ }
+ x.back();
+ break;
+ case ']':
+ return;
+ default:
+ throw x.syntaxError("Expected a ',' or ']'");
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Construct a JSONArray from a source JSON text.
+ * @param source A string that begins with
+ * ,
(comma) may appear just
+ * before the closing bracket.null
value will be inserted when there is ,
+ * (comma) elision.'
(single
+ * quote).{ } [ ] / \ : , = ; #
and if they do not look like numbers and
+ * if they are not the reserved words true
, false
, or
+ * null
.;
(semicolon) as
+ * well as by ,
(comma).[
(left bracket)
+ * and ends with ]
(right bracket).
+ * @throws JSONException If there is a syntax error.
+ */
+ public JSONArray(String source) throws JSONException {
+ this(new JSONTokener(source));
+ }
+
+
+ /**
+ * Construct a JSONArray from a Collection.
+ * @param collection A Collection.
+ */
+ public JSONArray(Collection collection) {
+ this.myArrayList = new ArrayList();
+ if (collection != null) {
+ Iterator iter = collection.iterator();
+ while (iter.hasNext()) {
+ this.myArrayList.add(JSONObject.wrap(iter.next()));
+ }
+ }
+ }
+
+
+ /**
+ * Construct a JSONArray from an array
+ * @throws JSONException If not an array.
+ */
+ public JSONArray(Object array) throws JSONException {
+ this();
+ throw new JSONException("not supported");
+/*
+ if (array.getClass().isArray()) {
+ int length = Array.getLength(array);
+ for (int i = 0; i < length; i += 1) {
+ this.put(JSONObject.wrap(Array.get(array, i)));
+ }
+ } else {
+ throw new JSONException(
+"JSONArray initial value should be a string or collection or array.");
+ }
+ */
+ }
+
+ /**
+ * Get the object value associated with an index.
+ * @param index
+ * The index must be between 0 and length() - 1.
+ * @return An object value.
+ * @throws JSONException If there is no value for the index.
+ */
+ public Object get(int index) throws JSONException {
+ Object object = this.opt(index);
+ if (object == null) {
+ throw new JSONException("JSONArray[" + index + "] not found.");
+ }
+ return object;
+ }
+
+
+ /**
+ * Get the boolean value associated with an index.
+ * The string values "true" and "false" are converted to boolean.
+ *
+ * @param index The index must be between 0 and length() - 1.
+ * @return The truth.
+ * @throws JSONException If there is no value for the index or if the
+ * value is not convertible to boolean.
+ */
+ public boolean getBoolean(int index) throws JSONException {
+ Object object = this.get(index);
+ if (object.equals(Boolean.FALSE) ||
+ (object instanceof String &&
+ ((String)object).equalsIgnoreCase("false"))) {
+ return false;
+ } else if (object.equals(Boolean.TRUE) ||
+ (object instanceof String &&
+ ((String)object).equalsIgnoreCase("true"))) {
+ return true;
+ }
+ throw new JSONException("JSONArray[" + index + "] is not a boolean.");
+ }
+
+
+ /**
+ * Get the double value associated with an index.
+ *
+ * @param index The index must be between 0 and length() - 1.
+ * @return The value.
+ * @throws JSONException If the key is not found or if the value cannot
+ * be converted to a number.
+ */
+ public double getDouble(int index) throws JSONException {
+ Object object = this.get(index);
+ try {
+ return object instanceof Number
+ ? ((Number)object).doubleValue()
+ : Double.parseDouble((String)object);
+ } catch (Exception e) {
+ throw new JSONException("JSONArray[" + index +
+ "] is not a number.");
+ }
+ }
+
+
+ /**
+ * Get the int value associated with an index.
+ *
+ * @param index The index must be between 0 and length() - 1.
+ * @return The value.
+ * @throws JSONException If the key is not found or if the value is not a number.
+ */
+ public int getInt(int index) throws JSONException {
+ Object object = this.get(index);
+ try {
+ return object instanceof Number
+ ? ((Number)object).intValue()
+ : Integer.parseInt((String)object);
+ } catch (Exception e) {
+ throw new JSONException("JSONArray[" + index +
+ "] is not a number.");
+ }
+ }
+
+
+ /**
+ * Get the JSONArray associated with an index.
+ * @param index The index must be between 0 and length() - 1.
+ * @return A JSONArray value.
+ * @throws JSONException If there is no value for the index. or if the
+ * value is not a JSONArray
+ */
+ public JSONArray getJSONArray(int index) throws JSONException {
+ Object object = this.get(index);
+ if (object instanceof JSONArray) {
+ return (JSONArray)object;
+ }
+ throw new JSONException("JSONArray[" + index +
+ "] is not a JSONArray.");
+ }
+
+
+ /**
+ * Get the JSONObject associated with an index.
+ * @param index subscript
+ * @return A JSONObject value.
+ * @throws JSONException If there is no value for the index or if the
+ * value is not a JSONObject
+ */
+ public JSONObject getJSONObject(int index) throws JSONException {
+ Object object = this.get(index);
+ if (object instanceof JSONObject) {
+ return (JSONObject)object;
+ }
+ throw new JSONException("JSONArray[" + index +
+ "] is not a JSONObject.");
+ }
+
+
+ /**
+ * Get the long value associated with an index.
+ *
+ * @param index The index must be between 0 and length() - 1.
+ * @return The value.
+ * @throws JSONException If the key is not found or if the value cannot
+ * be converted to a number.
+ */
+ public long getLong(int index) throws JSONException {
+ Object object = this.get(index);
+ try {
+ return object instanceof Number
+ ? ((Number)object).longValue()
+ : Long.parseLong((String)object);
+ } catch (Exception e) {
+ throw new JSONException("JSONArray[" + index +
+ "] is not a number.");
+ }
+ }
+
+
+ /**
+ * Get the string associated with an index.
+ * @param index The index must be between 0 and length() - 1.
+ * @return A string value.
+ * @throws JSONException If there is no string value for the index.
+ */
+ public String getString(int index) throws JSONException {
+ Object object = this.get(index);
+ if (object instanceof String) {
+ return (String)object;
+ }
+ throw new JSONException("JSONArray[" + index + "] not a string.");
+ }
+
+
+ /**
+ * Determine if the value is null.
+ * @param index The index must be between 0 and length() - 1.
+ * @return true if the value at the index is null, or if there is no value.
+ */
+ public boolean isNull(int index) {
+ return JSONObject.NULL.equals(this.opt(index));
+ }
+
+
+ /**
+ * Make a string from the contents of this JSONArray. The
+ * separator
string is inserted between each element.
+ * Warning: This method assumes that the data structure is acyclical.
+ * @param separator A string that will be inserted between the elements.
+ * @return a string.
+ * @throws JSONException If the array contains an invalid number.
+ */
+ public String join(String separator) throws JSONException {
+ int len = this.length();
+ StringBuffer sb = new StringBuffer();
+
+ for (int i = 0; i < len; i += 1) {
+ if (i > 0) {
+ sb.append(separator);
+ }
+ sb.append(JSONObject.valueToString(this.myArrayList.get(i)));
+ }
+ return sb.toString();
+ }
+
+
+ /**
+ * Get the number of elements in the JSONArray, included nulls.
+ *
+ * @return The length (or size).
+ */
+ public int length() {
+ return this.myArrayList.size();
+ }
+
+
+ /**
+ * Get the optional object value associated with an index.
+ * @param index The index must be between 0 and length() - 1.
+ * @return An object value, or null if there is no
+ * object at that index.
+ */
+ public Object opt(int index) {
+ return (index < 0 || index >= this.length())
+ ? null
+ : this.myArrayList.get(index);
+ }
+
+
+ /**
+ * Get the optional boolean value associated with an index.
+ * It returns false if there is no value at that index,
+ * or if the value is not Boolean.TRUE or the String "true".
+ *
+ * @param index The index must be between 0 and length() - 1.
+ * @return The truth.
+ */
+ public boolean optBoolean(int index) {
+ return this.optBoolean(index, false);
+ }
+
+
+ /**
+ * Get the optional boolean value associated with an index.
+ * It returns the defaultValue if there is no value at that index or if
+ * it is not a Boolean or the String "true" or "false" (case insensitive).
+ *
+ * @param index The index must be between 0 and length() - 1.
+ * @param defaultValue A boolean default.
+ * @return The truth.
+ */
+ public boolean optBoolean(int index, boolean defaultValue) {
+ try {
+ return this.getBoolean(index);
+ } catch (Exception e) {
+ return defaultValue;
+ }
+ }
+
+
+ /**
+ * Get the optional double value associated with an index.
+ * NaN is returned if there is no value for the index,
+ * or if the value is not a number and cannot be converted to a number.
+ *
+ * @param index The index must be between 0 and length() - 1.
+ * @return The value.
+ */
+ public double optDouble(int index) {
+ return this.optDouble(index, Double.NaN);
+ }
+
+
+ /**
+ * Get the optional double value associated with an index.
+ * The defaultValue is returned if there is no value for the index,
+ * or if the value is not a number and cannot be converted to a number.
+ *
+ * @param index subscript
+ * @param defaultValue The default value.
+ * @return The value.
+ */
+ public double optDouble(int index, double defaultValue) {
+ try {
+ return this.getDouble(index);
+ } catch (Exception e) {
+ return defaultValue;
+ }
+ }
+
+
+ /**
+ * Get the optional int value associated with an index.
+ * Zero is returned if there is no value for the index,
+ * or if the value is not a number and cannot be converted to a number.
+ *
+ * @param index The index must be between 0 and length() - 1.
+ * @return The value.
+ */
+ public int optInt(int index) {
+ return this.optInt(index, 0);
+ }
+
+
+ /**
+ * Get the optional int value associated with an index.
+ * The defaultValue is returned if there is no value for the index,
+ * or if the value is not a number and cannot be converted to a number.
+ * @param index The index must be between 0 and length() - 1.
+ * @param defaultValue The default value.
+ * @return The value.
+ */
+ public int optInt(int index, int defaultValue) {
+ try {
+ return this.getInt(index);
+ } catch (Exception e) {
+ return defaultValue;
+ }
+ }
+
+
+ /**
+ * Get the optional JSONArray associated with an index.
+ * @param index subscript
+ * @return A JSONArray value, or null if the index has no value,
+ * or if the value is not a JSONArray.
+ */
+ public JSONArray optJSONArray(int index) {
+ Object o = this.opt(index);
+ return o instanceof JSONArray ? (JSONArray)o : null;
+ }
+
+
+ /**
+ * Get the optional JSONObject associated with an index.
+ * Null is returned if the key is not found, or null if the index has
+ * no value, or if the value is not a JSONObject.
+ *
+ * @param index The index must be between 0 and length() - 1.
+ * @return A JSONObject value.
+ */
+ public JSONObject optJSONObject(int index) {
+ Object o = this.opt(index);
+ return o instanceof JSONObject ? (JSONObject)o : null;
+ }
+
+
+ /**
+ * Get the optional long value associated with an index.
+ * Zero is returned if there is no value for the index,
+ * or if the value is not a number and cannot be converted to a number.
+ *
+ * @param index The index must be between 0 and length() - 1.
+ * @return The value.
+ */
+ public long optLong(int index) {
+ return this.optLong(index, 0);
+ }
+
+
+ /**
+ * Get the optional long value associated with an index.
+ * The defaultValue is returned if there is no value for the index,
+ * or if the value is not a number and cannot be converted to a number.
+ * @param index The index must be between 0 and length() - 1.
+ * @param defaultValue The default value.
+ * @return The value.
+ */
+ public long optLong(int index, long defaultValue) {
+ try {
+ return this.getLong(index);
+ } catch (Exception e) {
+ return defaultValue;
+ }
+ }
+
+
+ /**
+ * Get the optional string value associated with an index. It returns an
+ * empty string if there is no value at that index. If the value
+ * is not a string and is not null, then it is coverted to a string.
+ *
+ * @param index The index must be between 0 and length() - 1.
+ * @return A String value.
+ */
+ public String optString(int index) {
+ return this.optString(index, "");
+ }
+
+
+ /**
+ * Get the optional string associated with an index.
+ * The defaultValue is returned if the key is not found.
+ *
+ * @param index The index must be between 0 and length() - 1.
+ * @param defaultValue The default value.
+ * @return A String value.
+ */
+ public String optString(int index, String defaultValue) {
+ Object object = this.opt(index);
+ return JSONObject.NULL.equals(object)
+ ? defaultValue : object
+ .toString();
+ }
+
+
+ /**
+ * Append a boolean value. This increases the array's length by one.
+ *
+ * @param value A boolean value.
+ * @return this.
+ */
+ public JSONArray put(boolean value) {
+ this.put(value ? Boolean.TRUE : Boolean.FALSE);
+ return this;
+ }
+
+
+ /**
+ * Put a value in the JSONArray, where the value will be a
+ * JSONArray which is produced from a Collection.
+ * @param value A Collection value.
+ * @return this.
+ */
+ public JSONArray put(Collection value) {
+ this.put(new JSONArray(value));
+ return this;
+ }
+
+
+ /**
+ * Append a double value. This increases the array's length by one.
+ *
+ * @param value A double value.
+ * @throws JSONException if the value is not finite.
+ * @return this.
+ */
+ public JSONArray put(double value) throws JSONException {
+ Double d = new Double(value);
+ JSONObject.testValidity(d);
+ this.put(d);
+ return this;
+ }
+
+
+ /**
+ * Append an int value. This increases the array's length by one.
+ *
+ * @param value An int value.
+ * @return this.
+ */
+ public JSONArray put(int value) {
+ this.put(new Integer(value));
+ return this;
+ }
+
+
+ /**
+ * Append an long value. This increases the array's length by one.
+ *
+ * @param value A long value.
+ * @return this.
+ */
+ public JSONArray put(long value) {
+ this.put(new Long(value));
+ return this;
+ }
+
+
+ /**
+ * Put a value in the JSONArray, where the value will be a
+ * JSONObject which is produced from a Map.
+ * @param value A Map value.
+ * @return this.
+ */
+ public JSONArray put(Map value) {
+ this.put(new JSONObject(value));
+ return this;
+ }
+
+
+ /**
+ * Append an object value. This increases the array's length by one.
+ * @param value An object value. The value should be a
+ * Boolean, Double, Integer, JSONArray, JSONObject, Long, or String, or the
+ * JSONObject.NULL object.
+ * @return this.
+ */
+ public JSONArray put(Object value) {
+ this.myArrayList.add(value);
+ return this;
+ }
+
+
+ /**
+ * Put or replace a boolean value in the JSONArray. If the index is greater
+ * than the length of the JSONArray, then null elements will be added as
+ * necessary to pad it out.
+ * @param index The subscript.
+ * @param value A boolean value.
+ * @return this.
+ * @throws JSONException If the index is negative.
+ */
+ public JSONArray put(int index, boolean value) throws JSONException {
+ this.put(index, value ? Boolean.TRUE : Boolean.FALSE);
+ return this;
+ }
+
+
+ /**
+ * Put a value in the JSONArray, where the value will be a
+ * JSONArray which is produced from a Collection.
+ * @param index The subscript.
+ * @param value A Collection value.
+ * @return this.
+ * @throws JSONException If the index is negative or if the value is
+ * not finite.
+ */
+ public JSONArray put(int index, Collection value) throws JSONException {
+ this.put(index, new JSONArray(value));
+ return this;
+ }
+
+
+ /**
+ * Put or replace a double value. If the index is greater than the length of
+ * the JSONArray, then null elements will be added as necessary to pad
+ * it out.
+ * @param index The subscript.
+ * @param value A double value.
+ * @return this.
+ * @throws JSONException If the index is negative or if the value is
+ * not finite.
+ */
+ public JSONArray put(int index, double value) throws JSONException {
+ this.put(index, new Double(value));
+ return this;
+ }
+
+
+ /**
+ * Put or replace an int value. If the index is greater than the length of
+ * the JSONArray, then null elements will be added as necessary to pad
+ * it out.
+ * @param index The subscript.
+ * @param value An int value.
+ * @return this.
+ * @throws JSONException If the index is negative.
+ */
+ public JSONArray put(int index, int value) throws JSONException {
+ this.put(index, new Integer(value));
+ return this;
+ }
+
+
+ /**
+ * Put or replace a long value. If the index is greater than the length of
+ * the JSONArray, then null elements will be added as necessary to pad
+ * it out.
+ * @param index The subscript.
+ * @param value A long value.
+ * @return this.
+ * @throws JSONException If the index is negative.
+ */
+ public JSONArray put(int index, long value) throws JSONException {
+ this.put(index, new Long(value));
+ return this;
+ }
+
+
+ /**
+ * Put a value in the JSONArray, where the value will be a
+ * JSONObject that is produced from a Map.
+ * @param index The subscript.
+ * @param value The Map value.
+ * @return this.
+ * @throws JSONException If the index is negative or if the the value is
+ * an invalid number.
+ */
+ public JSONArray put(int index, Map value) throws JSONException {
+ this.put(index, new JSONObject(value));
+ return this;
+ }
+
+
+ /**
+ * Put or replace an object value in the JSONArray. If the index is greater
+ * than the length of the JSONArray, then null elements will be added as
+ * necessary to pad it out.
+ * @param index The subscript.
+ * @param value The value to put into the array. The value should be a
+ * Boolean, Double, Integer, JSONArray, JSONObject, Long, or String, or the
+ * JSONObject.NULL object.
+ * @return this.
+ * @throws JSONException If the index is negative or if the the value is
+ * an invalid number.
+ */
+ public JSONArray put(int index, Object value) throws JSONException {
+ JSONObject.testValidity(value);
+ if (index < 0) {
+ throw new JSONException("JSONArray[" + index + "] not found.");
+ }
+ if (index < this.length()) {
+ this.myArrayList.set(index, value);
+ } else {
+ while (index != this.length()) {
+ this.put(JSONObject.NULL);
+ }
+ this.put(value);
+ }
+ return this;
+ }
+
+
+ /**
+ * Remove an index and close the hole.
+ * @param index The index of the element to be removed.
+ * @return The value that was associated with the index,
+ * or null if there was no value.
+ */
+ public Object remove(int index) {
+ Object o = this.opt(index);
+ this.myArrayList.remove(index);
+ return o;
+ }
+
+
+ /**
+ * Produce a JSONObject by combining a JSONArray of names with the values
+ * of this JSONArray.
+ * @param names A JSONArray containing a list of key strings. These will be
+ * paired with the values.
+ * @return A JSONObject, or null if there are no names or if this JSONArray
+ * has no values.
+ * @throws JSONException If any of the names are null.
+ */
+ public JSONObject toJSONObject(JSONArray names) throws JSONException {
+ if (names == null || names.length() == 0 || this.length() == 0) {
+ return null;
+ }
+ JSONObject jo = new JSONObject();
+ for (int i = 0; i < names.length(); i += 1) {
+ jo.put(names.getString(i), this.opt(i));
+ }
+ return jo;
+ }
+
+
+ /**
+ * Make a JSON text of this JSONArray. For compactness, no
+ * unnecessary whitespace is added. If it is not possible to produce a
+ * syntactically correct JSON text then null will be returned instead. This
+ * could occur if the array contains an invalid number.
+ * [
(left bracket) and ending
+ * with ]
(right bracket).
+ * @throws JSONException
+ */
+ public String toString(int indentFactor) throws JSONException {
+ StringWriter sw = new StringWriter();
+ synchronized (sw.getBuffer()) {
+ return this.write(sw, indentFactor, 0).toString();
+ }
+ }
+
+ /**
+ * Write the contents of the JSONArray as JSON text to a writer. For
+ * compactness, no whitespace is added.
+ * get
and opt
methods for accessing the
+ * values by name, and put
methods for adding or replacing values
+ * by name. The values can be any of these types: Boolean
,
+ * JSONArray
, JSONObject
, Number
,
+ * String
, or the JSONObject.NULL
object. A JSONObject
+ * constructor can be used to convert an external form JSON text into an
+ * internal form whose values can be retrieved with the get
and
+ * opt
methods, or to convert values into a JSON text using the
+ * put
and toString
methods. A get
method
+ * returns a value if one can be found, and throws an exception if one cannot be
+ * found. An opt
method returns a default value instead of throwing
+ * an exception, and so is useful for obtaining optional values.
+ * get()
and opt()
methods return an
+ * object, which you can cast or query for type. There are also typed
+ * get
and opt
methods that do type checking and type
+ * coercion for you. The opt methods differ from the get methods in that they do
+ * not throw. Instead, they return a specified value, such as null.
+ * put
methods add or replace values in an object. For example,
+ *
+ *
+ * myString = new JSONObject().put("JSON", "Hello, World!").toString();
+ *
+ *
+ * produces the string {"JSON": "Hello, World"}
.
+ * toString
methods strictly conform to
+ * the JSON syntax rules. The constructors are more forgiving in the texts they
+ * will accept:
+ *
+ *
+ *
+ * @author JSON.org
+ * @version 2012-07-02
+ */
+public class JSONObject {
+
+ /**
+ * JSONObject.NULL is equivalent to the value that JavaScript calls null,
+ * whilst Java's null is equivalent to the value that JavaScript calls
+ * undefined.
+ */
+ private static final class Null {
+
+ /**
+ * There is only intended to be a single instance of the NULL object,
+ * so the clone method returns itself.
+ * @return NULL.
+ */
+ protected final Object clone() {
+ return this;
+ }
+
+ /**
+ * A Null object is equal to the null value and to itself.
+ * @param object An object to test for nullness.
+ * @return true if the object parameter is the JSONObject.NULL object
+ * or null.
+ */
+ public boolean equals(Object object) {
+ return object == null || object == this;
+ }
+
+ /**
+ * Get the "null" string value.
+ * @return The string "null".
+ */
+ public String toString() {
+ return "null";
+ }
+ }
+
+
+ /**
+ * The map where the JSONObject's properties are kept.
+ */
+ private final Map map;
+
+
+ /**
+ * It is sometimes more convenient and less ambiguous to have a
+ * ,
(comma) may appear just
+ * before the closing brace.'
(single
+ * quote).{ } [ ] / \ : , = ; #
and if they do not look like numbers and
+ * if they are not the reserved words true
, false
, or
+ * null
.=
or =>
as well as by
+ * :
.;
(semicolon) as
+ * well as by ,
(comma).NULL
object than to use Java's null
value.
+ * JSONObject.NULL.equals(null)
returns true
.
+ * JSONObject.NULL.toString()
returns "null"
.
+ */
+ public static final Object NULL = new Null();
+
+
+ /**
+ * Construct an empty JSONObject.
+ */
+ public JSONObject() {
+ this.map = new HashMap();
+ }
+
+
+ /**
+ * Construct a JSONObject from a subset of another JSONObject.
+ * An array of strings is used to identify the keys that should be copied.
+ * Missing keys are ignored.
+ * @param jo A JSONObject.
+ * @param names An array of strings.
+ * @throws JSONException
+ * @exception JSONException If a value is a non-finite number or if a name is duplicated.
+ */
+ public JSONObject(JSONObject jo, String[] names) {
+ this();
+ for (int i = 0; i < names.length; i += 1) {
+ try {
+ this.putOnce(names[i], jo.opt(names[i]));
+ } catch (Exception ignore) {
+ }
+ }
+ }
+
+
+ /**
+ * Construct a JSONObject from a JSONTokener.
+ * @param x A JSONTokener object containing the source string.
+ * @throws JSONException If there is a syntax error in the source string
+ * or a duplicated key.
+ */
+ public JSONObject(JSONTokener x) throws JSONException {
+ this();
+ char c;
+ String key;
+
+ if (x.nextClean() != '{') {
+ throw x.syntaxError("A JSONObject text must begin with '{'");
+ }
+ for (;;) {
+ c = x.nextClean();
+ switch (c) {
+ case 0:
+ throw x.syntaxError("A JSONObject text must end with '}'");
+ case '}':
+ return;
+ default:
+ x.back();
+ key = x.nextValue().toString();
+ }
+
+// The key is followed by ':'. We will also tolerate '=' or '=>'.
+
+ c = x.nextClean();
+ if (c == '=') {
+ if (x.next() != '>') {
+ x.back();
+ }
+ } else if (c != ':') {
+ throw x.syntaxError("Expected a ':' after a key");
+ }
+ this.putOnce(key, x.nextValue());
+
+// Pairs are separated by ','. We will also tolerate ';'.
+
+ switch (x.nextClean()) {
+ case ';':
+ case ',':
+ if (x.nextClean() == '}') {
+ return;
+ }
+ x.back();
+ break;
+ case '}':
+ return;
+ default:
+ throw x.syntaxError("Expected a ',' or '}'");
+ }
+ }
+ }
+
+
+ /**
+ * Construct a JSONObject from a Map.
+ *
+ * @param map A map object that can be used to initialize the contents of
+ * the JSONObject.
+ * @throws JSONException
+ */
+ public JSONObject(Map map) {
+ this.map = new HashMap();
+ if (map != null) {
+ Iterator i = map.entrySet().iterator();
+ while (i.hasNext()) {
+ Map.Entry e = (Map.Entry)i.next();
+ Object value = e.getValue();
+ if (value != null) {
+ this.map.put(e.getKey(), wrap(value));
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Construct a JSONObject from an Object using bean getters.
+ * It reflects on all of the public methods of the object.
+ * For each of the methods with no parameters and a name starting
+ * with "get"
or "is"
followed by an uppercase letter,
+ * the method is invoked, and a key and the value returned from the getter method
+ * are put into the new JSONObject.
+ *
+ * The key is formed by removing the "get"
or "is"
prefix.
+ * If the second remaining character is not upper case, then the first
+ * character is converted to lower case.
+ *
+ * For example, if an object has a method named "getName"
, and
+ * if the result of calling object.getName()
is "Larry Fine"
,
+ * then the JSONObject will contain "name": "Larry Fine"
.
+ *
+ * @param bean An object that has getter methods that should be used
+ * to make a JSONObject.
+ */
+ /*
+ public JSONObject(Object bean) {
+ this();
+ this.populateMap(bean);
+ }
+ */
+
+ /**
+ * Construct a JSONObject from an Object, using reflection to find the
+ * public members. The resulting JSONObject's keys will be the strings
+ * from the names array, and the values will be the field values associated
+ * with those keys in the object. If a key is not found or not visible,
+ * then it will not be copied into the new JSONObject.
+ * @param object An object that has fields that should be used to make a
+ * JSONObject.
+ * @param names An array of strings, the names of the fields to be obtained
+ * from the object.
+ */
+ /*
+ public JSONObject(Object object, String names[]) {
+ this();
+ Class c = object.getClass();
+ for (int i = 0; i < names.length; i += 1) {
+ String name = names[i];
+ try {
+ this.putOpt(name, c.getField(name).get(object));
+ } catch (Exception ignore) {
+ }
+ }
+ }
+ */
+
+
+ /**
+ * Construct a JSONObject from a source JSON text string.
+ * This is the most commonly used JSONObject constructor.
+ * @param source A string beginning
+ * with {
(left brace) and ending
+ * with }
(right brace).
+ * @exception JSONException If there is a syntax error in the source
+ * string or a duplicated key.
+ */
+ public JSONObject(String source) throws JSONException {
+ this(new JSONTokener(source));
+ }
+
+
+ /**
+ * Construct a JSONObject from a ResourceBundle.
+ * @param baseName The ResourceBundle base name.
+ * @param locale The Locale to load the ResourceBundle for.
+ * @throws JSONException If any JSONExceptions are detected.
+ */
+ /*
+ public JSONObject(String baseName, Locale locale) throws JSONException {
+ this();
+ ResourceBundle bundle = ResourceBundle.getBundle(baseName, locale,
+ Thread.currentThread().getContextClassLoader());
+
+// Iterate through the keys in the bundle.
+
+ Enumeration keys = bundle.getKeys();
+ while (keys.hasMoreElements()) {
+ Object key = keys.nextElement();
+ if (key instanceof String) {
+
+// Go through the path, ensuring that there is a nested JSONObject for each
+// segment except the last. Add the value using the last segment's name into
+// the deepest nested JSONObject.
+
+ String[] path = ((String)key).split("\\.");
+ int last = path.length - 1;
+ JSONObject target = this;
+ for (int i = 0; i < last; i += 1) {
+ String segment = path[i];
+ JSONObject nextTarget = target.optJSONObject(segment);
+ if (nextTarget == null) {
+ nextTarget = new JSONObject();
+ target.put(segment, nextTarget);
+ }
+ target = nextTarget;
+ }
+ target.put(path[last], bundle.getString((String)key));
+ }
+ }
+ }
+
+*/
+ /**
+ * Accumulate values under a key. It is similar to the put method except
+ * that if there is already an object stored under the key then a
+ * JSONArray is stored under the key to hold all of the accumulated values.
+ * If there is already a JSONArray, then the new value is appended to it.
+ * In contrast, the put method replaces the previous value.
+ *
+ * If only one value is accumulated that is not a JSONArray, then the
+ * result will be the same as using put. But if multiple values are
+ * accumulated, then the result will be like append.
+ * @param key A key string.
+ * @param value An object to be accumulated under the key.
+ * @return this.
+ * @throws JSONException If the value is an invalid number
+ * or if the key is null.
+ */
+ public JSONObject accumulate(
+ String key,
+ Object value
+ ) throws JSONException {
+ testValidity(value);
+ Object object = this.opt(key);
+ if (object == null) {
+ this.put(key, value instanceof JSONArray
+ ? new JSONArray().put(value)
+ : value);
+ } else if (object instanceof JSONArray) {
+ ((JSONArray)object).put(value);
+ } else {
+ this.put(key, new JSONArray().put(object).put(value));
+ }
+ return this;
+ }
+
+
+ /**
+ * Append values to the array under a key. If the key does not exist in the
+ * JSONObject, then the key is put in the JSONObject with its value being a
+ * JSONArray containing the value parameter. If the key was already
+ * associated with a JSONArray, then the value parameter is appended to it.
+ * @param key A key string.
+ * @param value An object to be accumulated under the key.
+ * @return this.
+ * @throws JSONException If the key is null or if the current value
+ * associated with the key is not a JSONArray.
+ */
+ public JSONObject append(String key, Object value) throws JSONException {
+ testValidity(value);
+ Object object = this.opt(key);
+ if (object == null) {
+ this.put(key, new JSONArray().put(value));
+ } else if (object instanceof JSONArray) {
+ this.put(key, ((JSONArray)object).put(value));
+ } else {
+ throw new JSONException("JSONObject[" + key +
+ "] is not a JSONArray.");
+ }
+ return this;
+ }
+
+
+ /**
+ * Produce a string from a double. The string "null" will be returned if
+ * the number is not finite.
+ * @param d A double.
+ * @return A String.
+ */
+ public static String doubleToString(double d) {
+ if (Double.isInfinite(d) || Double.isNaN(d)) {
+ return "null";
+ }
+
+// Shave off trailing zeros and decimal point, if possible.
+
+ String string = Double.toString(d);
+ if (string.indexOf('.') > 0 && string.indexOf('e') < 0 &&
+ string.indexOf('E') < 0) {
+ while (string.endsWith("0")) {
+ string = string.substring(0, string.length() - 1);
+ }
+ if (string.endsWith(".")) {
+ string = string.substring(0, string.length() - 1);
+ }
+ }
+ return string;
+ }
+
+
+ /**
+ * Get the value object associated with a key.
+ *
+ * @param key A key string.
+ * @return The object associated with the key.
+ * @throws JSONException if the key is not found.
+ */
+ public Object get(String key) throws JSONException {
+ if (key == null) {
+ throw new JSONException("Null key.");
+ }
+ Object object = this.opt(key);
+ if (object == null) {
+ throw new JSONException("JSONObject[" + quote(key) +
+ "] not found.");
+ }
+ return object;
+ }
+
+
+ /**
+ * Get the boolean value associated with a key.
+ *
+ * @param key A key string.
+ * @return The truth.
+ * @throws JSONException
+ * if the value is not a Boolean or the String "true" or "false".
+ */
+ public boolean getBoolean(String key) throws JSONException {
+ Object object = this.get(key);
+ if (object.equals(Boolean.FALSE) ||
+ (object instanceof String &&
+ ((String)object).equalsIgnoreCase("false"))) {
+ return false;
+ } else if (object.equals(Boolean.TRUE) ||
+ (object instanceof String &&
+ ((String)object).equalsIgnoreCase("true"))) {
+ return true;
+ }
+ throw new JSONException("JSONObject[" + quote(key) +
+ "] is not a Boolean.");
+ }
+
+
+ /**
+ * Get the double value associated with a key.
+ * @param key A key string.
+ * @return The numeric value.
+ * @throws JSONException if the key is not found or
+ * if the value is not a Number object and cannot be converted to a number.
+ */
+ public double getDouble(String key) throws JSONException {
+ Object object = this.get(key);
+ try {
+ return object instanceof Number
+ ? ((Number)object).doubleValue()
+ : Double.parseDouble((String)object);
+ } catch (Exception e) {
+ throw new JSONException("JSONObject[" + quote(key) +
+ "] is not a number.");
+ }
+ }
+
+
+ /**
+ * Get the int value associated with a key.
+ *
+ * @param key A key string.
+ * @return The integer value.
+ * @throws JSONException if the key is not found or if the value cannot
+ * be converted to an integer.
+ */
+ public int getInt(String key) throws JSONException {
+ Object object = this.get(key);
+ try {
+ return object instanceof Number
+ ? ((Number)object).intValue()
+ : Integer.parseInt((String)object);
+ } catch (Exception e) {
+ throw new JSONException("JSONObject[" + quote(key) +
+ "] is not an int.");
+ }
+ }
+
+
+ /**
+ * Get the JSONArray value associated with a key.
+ *
+ * @param key A key string.
+ * @return A JSONArray which is the value.
+ * @throws JSONException if the key is not found or
+ * if the value is not a JSONArray.
+ */
+ public JSONArray getJSONArray(String key) throws JSONException {
+ Object object = this.get(key);
+ if (object instanceof JSONArray) {
+ return (JSONArray)object;
+ }
+ throw new JSONException("JSONObject[" + quote(key) +
+ "] is not a JSONArray.");
+ }
+
+
+ /**
+ * Get the JSONObject value associated with a key.
+ *
+ * @param key A key string.
+ * @return A JSONObject which is the value.
+ * @throws JSONException if the key is not found or
+ * if the value is not a JSONObject.
+ */
+ public JSONObject getJSONObject(String key) throws JSONException {
+ Object object = this.get(key);
+ if (object instanceof JSONObject) {
+ return (JSONObject)object;
+ }
+ throw new JSONException("JSONObject[" + quote(key) +
+ "] is not a JSONObject.");
+ }
+
+
+ /**
+ * Get the long value associated with a key.
+ *
+ * @param key A key string.
+ * @return The long value.
+ * @throws JSONException if the key is not found or if the value cannot
+ * be converted to a long.
+ */
+ public long getLong(String key) throws JSONException {
+ Object object = this.get(key);
+ try {
+ return object instanceof Number
+ ? ((Number)object).longValue()
+ : Long.parseLong((String)object);
+ } catch (Exception e) {
+ throw new JSONException("JSONObject[" + quote(key) +
+ "] is not a long.");
+ }
+ }
+
+
+ /**
+ * Get an array of field names from a JSONObject.
+ *
+ * @return An array of field names, or null if there are no names.
+ */
+ public static String[] getNames(JSONObject jo) {
+ int length = jo.length();
+ if (length == 0) {
+ return null;
+ }
+ Iterator iterator = jo.keys();
+ String[] names = new String[length];
+ int i = 0;
+ while (iterator.hasNext()) {
+ names[i] = (String)iterator.next();
+ i += 1;
+ }
+ return names;
+ }
+
+
+ /**
+ * Get an array of field names from an Object.
+ *
+ * @return An array of field names, or null if there are no names.
+ */
+ /*
+ public static String[] getNames(Object object) {
+ if (object == null) {
+ return null;
+ }
+ Class klass = object.getClass();
+ Field[] fields = klass.getFields();
+ int length = fields.length;
+ if (length == 0) {
+ return null;
+ }
+ String[] names = new String[length];
+ for (int i = 0; i < length; i += 1) {
+ names[i] = fields[i].getName();
+ }
+ return names;
+ }
+ */
+
+ /**
+ * Get the string associated with a key.
+ *
+ * @param key A key string.
+ * @return A string which is the value.
+ * @throws JSONException if there is no string value for the key.
+ */
+ public String getString(String key) throws JSONException {
+ Object object = this.get(key);
+ if (object instanceof String) {
+ return (String)object;
+ }
+ throw new JSONException("JSONObject[" + quote(key) +
+ "] not a string.");
+ }
+
+
+ /**
+ * Determine if the JSONObject contains a specific key.
+ * @param key A key string.
+ * @return true if the key exists in the JSONObject.
+ */
+ public boolean has(String key) {
+ return this.map.containsKey(key);
+ }
+
+
+ /**
+ * Increment a property of a JSONObject. If there is no such property,
+ * create one with a value of 1. If there is such a property, and if
+ * it is an Integer, Long, Double, or Float, then add one to it.
+ * @param key A key string.
+ * @return this.
+ * @throws JSONException If there is already a property with this name
+ * that is not an Integer, Long, Double, or Float.
+ */
+ public JSONObject increment(String key) throws JSONException {
+ Object value = this.opt(key);
+ if (value == null) {
+ this.put(key, 1);
+ } else if (value instanceof Integer) {
+ this.put(key, ((Integer)value).intValue() + 1);
+ } else if (value instanceof Long) {
+ this.put(key, ((Long)value).longValue() + 1);
+ } else if (value instanceof Double) {
+ this.put(key, ((Double)value).doubleValue() + 1);
+ } else if (value instanceof Float) {
+ this.put(key, ((Float)value).floatValue() + 1);
+ } else {
+ throw new JSONException("Unable to increment [" + quote(key) + "].");
+ }
+ return this;
+ }
+
+
+ /**
+ * Determine if the value associated with the key is null or if there is
+ * no value.
+ * @param key A key string.
+ * @return true if there is no value associated with the key or if
+ * the value is the JSONObject.NULL object.
+ */
+ public boolean isNull(String key) {
+ return JSONObject.NULL.equals(this.opt(key));
+ }
+
+
+ /**
+ * Get an enumeration of the keys of the JSONObject.
+ *
+ * @return An iterator of the keys.
+ */
+ public Iterator keys() {
+ return this.map.keySet().iterator();
+ }
+
+
+ /**
+ * Get the number of keys stored in the JSONObject.
+ *
+ * @return The number of keys in the JSONObject.
+ */
+ public int length() {
+ return this.map.size();
+ }
+
+
+ /**
+ * Produce a JSONArray containing the names of the elements of this
+ * JSONObject.
+ * @return A JSONArray containing the key strings, or null if the JSONObject
+ * is empty.
+ */
+ public JSONArray names() {
+ JSONArray ja = new JSONArray();
+ Iterator keys = this.keys();
+ while (keys.hasNext()) {
+ ja.put(keys.next());
+ }
+ return ja.length() == 0 ? null : ja;
+ }
+
+ /**
+ * Produce a string from a Number.
+ * @param number A Number
+ * @return A String.
+ * @throws JSONException If n is a non-finite number.
+ */
+ public static String numberToString(Number number)
+ throws JSONException {
+ if (number == null) {
+ throw new JSONException("Null pointer");
+ }
+ testValidity(number);
+
+// Shave off trailing zeros and decimal point, if possible.
+
+ String string = number.toString();
+ if (string.indexOf('.') > 0 && string.indexOf('e') < 0 &&
+ string.indexOf('E') < 0) {
+ while (string.endsWith("0")) {
+ string = string.substring(0, string.length() - 1);
+ }
+ if (string.endsWith(".")) {
+ string = string.substring(0, string.length() - 1);
+ }
+ }
+ return string;
+ }
+
+
+ /**
+ * Get an optional value associated with a key.
+ * @param key A key string.
+ * @return An object which is the value, or null if there is no value.
+ */
+ public Object opt(String key) {
+ return key == null ? null : this.map.get(key);
+ }
+
+
+ /**
+ * Get an optional boolean associated with a key.
+ * It returns false if there is no such key, or if the value is not
+ * Boolean.TRUE or the String "true".
+ *
+ * @param key A key string.
+ * @return The truth.
+ */
+ public boolean optBoolean(String key) {
+ return this.optBoolean(key, false);
+ }
+
+
+ /**
+ * Get an optional boolean associated with a key.
+ * It returns the defaultValue if there is no such key, or if it is not
+ * a Boolean or the String "true" or "false" (case insensitive).
+ *
+ * @param key A key string.
+ * @param defaultValue The default.
+ * @return The truth.
+ */
+ public boolean optBoolean(String key, boolean defaultValue) {
+ try {
+ return this.getBoolean(key);
+ } catch (Exception e) {
+ return defaultValue;
+ }
+ }
+
+
+ /**
+ * Get an optional double associated with a key,
+ * or NaN if there is no such key or if its value is not a number.
+ * If the value is a string, an attempt will be made to evaluate it as
+ * a number.
+ *
+ * @param key A string which is the key.
+ * @return An object which is the value.
+ */
+ public double optDouble(String key) {
+ return this.optDouble(key, Double.NaN);
+ }
+
+
+ /**
+ * Get an optional double associated with a key, or the
+ * defaultValue if there is no such key or if its value is not a number.
+ * If the value is a string, an attempt will be made to evaluate it as
+ * a number.
+ *
+ * @param key A key string.
+ * @param defaultValue The default.
+ * @return An object which is the value.
+ */
+ public double optDouble(String key, double defaultValue) {
+ try {
+ return this.getDouble(key);
+ } catch (Exception e) {
+ return defaultValue;
+ }
+ }
+
+
+ /**
+ * Get an optional int value associated with a key,
+ * or zero if there is no such key or if the value is not a number.
+ * If the value is a string, an attempt will be made to evaluate it as
+ * a number.
+ *
+ * @param key A key string.
+ * @return An object which is the value.
+ */
+ public int optInt(String key) {
+ return this.optInt(key, 0);
+ }
+
+
+ /**
+ * Get an optional int value associated with a key,
+ * or the default if there is no such key or if the value is not a number.
+ * If the value is a string, an attempt will be made to evaluate it as
+ * a number.
+ *
+ * @param key A key string.
+ * @param defaultValue The default.
+ * @return An object which is the value.
+ */
+ public int optInt(String key, int defaultValue) {
+ try {
+ return this.getInt(key);
+ } catch (Exception e) {
+ return defaultValue;
+ }
+ }
+
+
+ /**
+ * Get an optional JSONArray associated with a key.
+ * It returns null if there is no such key, or if its value is not a
+ * JSONArray.
+ *
+ * @param key A key string.
+ * @return A JSONArray which is the value.
+ */
+ public JSONArray optJSONArray(String key) {
+ Object o = this.opt(key);
+ return o instanceof JSONArray ? (JSONArray)o : null;
+ }
+
+
+ /**
+ * Get an optional JSONObject associated with a key.
+ * It returns null if there is no such key, or if its value is not a
+ * JSONObject.
+ *
+ * @param key A key string.
+ * @return A JSONObject which is the value.
+ */
+ public JSONObject optJSONObject(String key) {
+ Object object = this.opt(key);
+ return object instanceof JSONObject ? (JSONObject)object : null;
+ }
+
+
+ /**
+ * Get an optional long value associated with a key,
+ * or zero if there is no such key or if the value is not a number.
+ * If the value is a string, an attempt will be made to evaluate it as
+ * a number.
+ *
+ * @param key A key string.
+ * @return An object which is the value.
+ */
+ public long optLong(String key) {
+ return this.optLong(key, 0);
+ }
+
+
+ /**
+ * Get an optional long value associated with a key,
+ * or the default if there is no such key or if the value is not a number.
+ * If the value is a string, an attempt will be made to evaluate it as
+ * a number.
+ *
+ * @param key A key string.
+ * @param defaultValue The default.
+ * @return An object which is the value.
+ */
+ public long optLong(String key, long defaultValue) {
+ try {
+ return this.getLong(key);
+ } catch (Exception e) {
+ return defaultValue;
+ }
+ }
+
+
+ /**
+ * Get an optional string associated with a key.
+ * It returns an empty string if there is no such key. If the value is not
+ * a string and is not null, then it is converted to a string.
+ *
+ * @param key A key string.
+ * @return A string which is the value.
+ */
+ public String optString(String key) {
+ return this.optString(key, "");
+ }
+
+
+ /**
+ * Get an optional string associated with a key.
+ * It returns the defaultValue if there is no such key.
+ *
+ * @param key A key string.
+ * @param defaultValue The default.
+ * @return A string which is the value.
+ */
+ public String optString(String key, String defaultValue) {
+ Object object = this.opt(key);
+ return NULL.equals(object) ? defaultValue : object.toString();
+ }
+
+
+ /*
+ private void populateMap(Object bean) {
+ Class klass = bean.getClass();
+
+// If klass is a System class then set includeSuperClass to false.
+
+ boolean includeSuperClass = klass.getClassLoader() != null;
+
+ Method[] methods = includeSuperClass
+ ? klass.getMethods()
+ : klass.getDeclaredMethods();
+ for (int i = 0; i < methods.length; i += 1) {
+ try {
+ Method method = methods[i];
+ if (Modifier.isPublic(method.getModifiers())) {
+ String name = method.getName();
+ String key = "";
+ if (name.startsWith("get")) {
+ if ("getClass".equals(name) ||
+ "getDeclaringClass".equals(name)) {
+ key = "";
+ } else {
+ key = name.substring(3);
+ }
+ } else if (name.startsWith("is")) {
+ key = name.substring(2);
+ }
+ if (key.length() > 0 &&
+ Character.isUpperCase(key.charAt(0)) &&
+ method.getParameterTypes().length == 0) {
+ if (key.length() == 1) {
+ key = key.toLowerCase();
+ } else if (!Character.isUpperCase(key.charAt(1))) {
+ key = key.substring(0, 1).toLowerCase() +
+ key.substring(1);
+ }
+
+ Object result = method.invoke(bean, (Object[])null);
+ if (result != null) {
+ this.map.put(key, wrap(result));
+ }
+ }
+ }
+ } catch (Exception ignore) {
+ }
+ }
+ }
+ */
+
+ /**
+ * Put a key/boolean pair in the JSONObject.
+ *
+ * @param key A key string.
+ * @param value A boolean which is the value.
+ * @return this.
+ * @throws JSONException If the key is null.
+ */
+ public JSONObject put(String key, boolean value) throws JSONException {
+ this.put(key, value ? Boolean.TRUE : Boolean.FALSE);
+ return this;
+ }
+
+
+ /**
+ * Put a key/value pair in the JSONObject, where the value will be a
+ * JSONArray which is produced from a Collection.
+ * @param key A key string.
+ * @param value A Collection value.
+ * @return this.
+ * @throws JSONException
+ */
+ public JSONObject put(String key, Collection value) throws JSONException {
+ this.put(key, new JSONArray(value));
+ return this;
+ }
+
+
+ /**
+ * Put a key/double pair in the JSONObject.
+ *
+ * @param key A key string.
+ * @param value A double which is the value.
+ * @return this.
+ * @throws JSONException If the key is null or if the number is invalid.
+ */
+ public JSONObject put(String key, double value) throws JSONException {
+ this.put(key, new Double(value));
+ return this;
+ }
+
+
+ /**
+ * Put a key/int pair in the JSONObject.
+ *
+ * @param key A key string.
+ * @param value An int which is the value.
+ * @return this.
+ * @throws JSONException If the key is null.
+ */
+ public JSONObject put(String key, int value) throws JSONException {
+ this.put(key, new Integer(value));
+ return this;
+ }
+
+
+ /**
+ * Put a key/long pair in the JSONObject.
+ *
+ * @param key A key string.
+ * @param value A long which is the value.
+ * @return this.
+ * @throws JSONException If the key is null.
+ */
+ public JSONObject put(String key, long value) throws JSONException {
+ this.put(key, new Long(value));
+ return this;
+ }
+
+
+ /**
+ * Put a key/value pair in the JSONObject, where the value will be a
+ * JSONObject which is produced from a Map.
+ * @param key A key string.
+ * @param value A Map value.
+ * @return this.
+ * @throws JSONException
+ */
+ public JSONObject put(String key, Map value) throws JSONException {
+ this.put(key, new JSONObject(value));
+ return this;
+ }
+
+
+ /**
+ * Put a key/value pair in the JSONObject. If the value is null,
+ * then the key will be removed from the JSONObject if it is present.
+ * @param key A key string.
+ * @param value An object which is the value. It should be of one of these
+ * types: Boolean, Double, Integer, JSONArray, JSONObject, Long, String,
+ * or the JSONObject.NULL object.
+ * @return this.
+ * @throws JSONException If the value is non-finite number
+ * or if the key is null.
+ */
+ public JSONObject put(String key, Object value) throws JSONException {
+ if (key == null) {
+ throw new JSONException("Null key.");
+ }
+ if (value != null) {
+ testValidity(value);
+ this.map.put(key, value);
+ } else {
+ this.remove(key);
+ }
+ return this;
+ }
+
+
+ /**
+ * Put a key/value pair in the JSONObject, but only if the key and the
+ * value are both non-null, and only if there is not already a member
+ * with that name.
+ * @param key
+ * @param value
+ * @return his.
+ * @throws JSONException if the key is a duplicate
+ */
+ public JSONObject putOnce(String key, Object value) throws JSONException {
+ if (key != null && value != null) {
+ if (this.opt(key) != null) {
+ throw new JSONException("Duplicate key \"" + key + "\"");
+ }
+ this.put(key, value);
+ }
+ return this;
+ }
+
+
+ /**
+ * Put a key/value pair in the JSONObject, but only if the
+ * key and the value are both non-null.
+ * @param key A key string.
+ * @param value An object which is the value. It should be of one of these
+ * types: Boolean, Double, Integer, JSONArray, JSONObject, Long, String,
+ * or the JSONObject.NULL object.
+ * @return this.
+ * @throws JSONException If the value is a non-finite number.
+ */
+ public JSONObject putOpt(String key, Object value) throws JSONException {
+ if (key != null && value != null) {
+ this.put(key, value);
+ }
+ return this;
+ }
+
+
+ /**
+ * Produce a string in double quotes with backslash sequences in all the
+ * right places. A backslash will be inserted within , producing <\/,
+ * allowing JSON text to be delivered in HTML. In JSON text, a string
+ * cannot contain a control character or an unescaped quote or backslash.
+ * @param string A String
+ * @return A String correctly formatted for insertion in a JSON text.
+ */
+ public static String quote(String string) {
+ StringWriter sw = new StringWriter();
+// synchronized (sw.getBuffer()) {
+ try {
+ return quote(string, sw).toString();
+ } catch (IOException ignored) {
+ // will never happen - we are writing to a string writer
+ return "";
+ }
+// }
+ }
+
+ public static Writer quote(String string, Writer w) throws IOException {
+ if (string == null || string.length() == 0) {
+ w.write("\"\"");
+ return w;
+ }
+
+ char b;
+ char c = 0;
+ String hhhh;
+ int i;
+ int len = string.length();
+
+ w.write('"');
+ for (i = 0; i < len; i += 1) {
+ b = c;
+ c = string.charAt(i);
+ switch (c) {
+ case '\\':
+ case '"':
+ w.write('\\');
+ w.write(c);
+ break;
+ case '/':
+ if (b == '<') {
+ w.write('\\');
+ }
+ w.write(c);
+ break;
+ case '\b':
+ w.write("\\b");
+ break;
+ case '\t':
+ w.write("\\t");
+ break;
+ case '\n':
+ w.write("\\n");
+ break;
+ case '\f':
+ w.write("\\f");
+ break;
+ case '\r':
+ w.write("\\r");
+ break;
+ default:
+ if (c < ' ' || (c >= '\u0080' && c < '\u00a0')
+ || (c >= '\u2000' && c < '\u2100')) {
+ hhhh = "000" + Integer.toHexString(c);
+ w.write("\\u" + hhhh.substring(hhhh.length() - 4));
+ } else {
+ w.write(c);
+ }
+ }
+ }
+ w.write('"');
+ return w;
+ }
+
+ /**
+ * Remove a name and its value, if present.
+ * @param key The name to be removed.
+ * @return The value that was associated with the name,
+ * or null if there was no value.
+ */
+ public Object remove(String key) {
+ return this.map.remove(key);
+ }
+
+ /**
+ * Try to convert a string into a number, boolean, or null. If the string
+ * can't be converted, return the string.
+ * @param string A String.
+ * @return A simple JSON value.
+ */
+ public static Object stringToValue(String string) {
+ Double d;
+ if (string.equals("")) {
+ return string;
+ }
+ if (string.equalsIgnoreCase("true")) {
+ return Boolean.TRUE;
+ }
+ if (string.equalsIgnoreCase("false")) {
+ return Boolean.FALSE;
+ }
+ if (string.equalsIgnoreCase("null")) {
+ return JSONObject.NULL;
+ }
+
+ /*
+ * If it might be a number, try converting it.
+ * If a number cannot be produced, then the value will just
+ * be a string. Note that the plus and implied string
+ * conventions are non-standard. A JSON parser may accept
+ * non-JSON forms as long as it accepts all correct JSON forms.
+ */
+
+ char b = string.charAt(0);
+ if ((b >= '0' && b <= '9') || b == '.' || b == '-' || b == '+') {
+ try {
+ if (string.indexOf('.') > -1 ||
+ string.indexOf('e') > -1 || string.indexOf('E') > -1) {
+ d = Double.valueOf(string);
+ if (!d.isInfinite() && !d.isNaN()) {
+ return d;
+ }
+ } else {
+ Long myLong = new Long(string);
+ if (myLong.longValue() == myLong.intValue()) {
+ return new Integer(myLong.intValue());
+ } else {
+ return myLong;
+ }
+ }
+ } catch (Exception ignore) {
+ }
+ }
+ return string;
+ }
+
+
+ /**
+ * Throw an exception if the object is a NaN or infinite number.
+ * @param o The object to test.
+ * @throws JSONException If o is a non-finite number.
+ */
+ public static void testValidity(Object o) throws JSONException {
+ if (o != null) {
+ if (o instanceof Double) {
+ if (((Double)o).isInfinite() || ((Double)o).isNaN()) {
+ throw new JSONException(
+ "JSON does not allow non-finite numbers.");
+ }
+ } else if (o instanceof Float) {
+ if (((Float)o).isInfinite() || ((Float)o).isNaN()) {
+ throw new JSONException(
+ "JSON does not allow non-finite numbers.");
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Produce a JSONArray containing the values of the members of this
+ * JSONObject.
+ * @param names A JSONArray containing a list of key strings. This
+ * determines the sequence of the values in the result.
+ * @return A JSONArray of values.
+ * @throws JSONException If any of the values are non-finite numbers.
+ */
+ public JSONArray toJSONArray(JSONArray names) throws JSONException {
+ if (names == null || names.length() == 0) {
+ return null;
+ }
+ JSONArray ja = new JSONArray();
+ for (int i = 0; i < names.length(); i += 1) {
+ ja.put(this.opt(names.getString(i)));
+ }
+ return ja;
+ }
+
+ /**
+ * Make a JSON text of this JSONObject. For compactness, no whitespace
+ * is added. If this would not result in a syntactically correct JSON text,
+ * then null will be returned instead.
+ * {
(left brace) and ending
+ * with }
(right brace).
+ */
+ public String toString() {
+ try {
+ return this.toString(0);
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+
+ /**
+ * Make a prettyprinted JSON text of this JSONObject.
+ * {
(left brace) and ending
+ * with }
(right brace).
+ * @throws JSONException If the object contains an invalid number.
+ */
+ public String toString(int indentFactor) throws JSONException {
+ StringWriter w = new StringWriter();
+// synchronized (w.getBuffer()) {
+ return this.write(w, indentFactor, 0).toString();
+// }
+ }
+
+ /**
+ * Make a JSON text of an Object value. If the object has an
+ * value.toJSONString() method, then that method will be used to produce
+ * the JSON text. The method is required to produce a strictly
+ * conforming text. If the object does not contain a toJSONString
+ * method (which is the most common case), then a text will be
+ * produced by other means. If the value is an array or Collection,
+ * then a JSONArray will be made from it and its toJSONString method
+ * will be called. If the value is a MAP, then a JSONObject will be made
+ * from it and its toJSONString method will be called. Otherwise, the
+ * value's toString method will be called, and the result will be quoted.
+ *
+ * {
(left brace) and ending
+ * with }
(right brace).
+ * @throws JSONException If the value is or contains an invalid number.
+ */
+ public static String valueToString(Object value) throws JSONException {
+ if (value == null || value.equals(null)) {
+ return "null";
+ }
+ if (value instanceof JSONString) {
+ Object object;
+ try {
+ object = ((JSONString)value).toJSONString();
+ } catch (Exception e) {
+ throw new JSONException(e);
+ }
+ if (object instanceof String) {
+ return (String)object;
+ }
+ throw new JSONException("Bad value from toJSONString: " + object);
+ }
+ if (value instanceof Number) {
+ return numberToString((Number) value);
+ }
+ if (value instanceof Boolean || value instanceof JSONObject ||
+ value instanceof JSONArray) {
+ return value.toString();
+ }
+ if (value instanceof Map) {
+ return new JSONObject((Map)value).toString();
+ }
+ if (value instanceof Collection) {
+ return new JSONArray((Collection)value).toString();
+ }
+ if (value.getClass().isArray()) {
+ return new JSONArray(value).toString();
+ }
+ return quote(value.toString());
+ }
+
+ /**
+ * Wrap an object, if necessary. If the object is null, return the NULL
+ * object. If it is an array or collection, wrap it in a JSONArray. If
+ * it is a map, wrap it in a JSONObject. If it is a standard property
+ * (Double, String, et al) then it is already wrapped. Otherwise, if it
+ * comes from one of the java packages, turn it into a string. And if
+ * it doesn't, try to wrap it in a JSONObject. If the wrapping fails,
+ * then null is returned.
+ *
+ * @param object The object to wrap
+ * @return The wrapped value
+ */
+ public static Object wrap(Object object) {
+ try {
+ if (object == null) {
+ return NULL;
+ }
+ if (object instanceof JSONObject || object instanceof JSONArray ||
+ NULL.equals(object) || object instanceof JSONString ||
+ object instanceof Byte || object instanceof Character ||
+ object instanceof Short || object instanceof Integer ||
+ object instanceof Long || object instanceof Boolean ||
+ object instanceof Float || object instanceof Double ||
+ object instanceof String || object instanceof Enum) {
+ return object;
+ }
+
+ if (object instanceof Collection) {
+ return new JSONArray((Collection)object);
+ }
+ if (object.getClass().isArray()) {
+ return new JSONArray(object);
+ }
+ if (object instanceof Map) {
+ return new JSONObject((Map)object);
+ }
+
+ /*
+ Package objectPackage = object.getClass().getPackage();
+ String objectPackageName = objectPackage != null
+ ? objectPackage.getName()
+ : "";
+ if (
+ objectPackageName.startsWith("java.") ||
+ objectPackageName.startsWith("javax.") ||
+ object.getClass().getClassLoader() == null
+ ) {
+ return object.toString();
+ }
+ */
+
+ return null;
+// return new JSONObject(object);
+ } catch(Exception exception) {
+ return null;
+ }
+ }
+
+
+ /**
+ * Write the contents of the JSONObject as JSON text to a writer.
+ * For compactness, no whitespace is added.
+ * JSONString
interface allows a toJSONString()
+ * method so that a class can change the behavior of
+ * JSONObject.toString()
, JSONArray.toString()
,
+ * and JSONWriter.value(
Object)
. The
+ * toJSONString
method will be used instead of the default behavior
+ * of using the Object's toString()
method and quoting the result.
+ */
+public interface JSONString {
+ /**
+ * The toJSONString
method allows a class to produce its own JSON
+ * serialization.
+ *
+ * @return A strictly syntactically correct JSON text.
+ */
+ public String toJSONString();
+}
diff --git a/java/ext/json/src/org/json/JSONStringer.java b/java/ext/json/src/org/json/JSONStringer.java
new file mode 100755
index 0000000..2ae7d88
--- /dev/null
+++ b/java/ext/json/src/org/json/JSONStringer.java
@@ -0,0 +1,78 @@
+package org.json;
+
+import java.io.StringWriter;
+
+/*
+Copyright (c) 2006 JSON.org
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+The Software shall be used for Good, not Evil.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+*/
+
+/**
+ * JSONStringer provides a quick and convenient way of producing JSON text.
+ * The texts produced strictly conform to JSON syntax rules. No whitespace is
+ * added, so the results are ready for transmission or storage. Each instance of
+ * JSONStringer can produce one JSON text.
+ * value
method for appending
+ * values to the
+ * text, and a key
+ * method for adding keys before values in objects. There are array
+ * and endArray
methods that make and bound array values, and
+ * object
and endObject
methods which make and bound
+ * object values. All of these methods return the JSONWriter instance,
+ * permitting cascade style. For example,
+ * myString = new JSONStringer()
+ * .object()
+ * .key("JSON")
+ * .value("Hello, World!")
+ * .endObject()
+ * .toString();
which produces the string
+ * {"JSON":"Hello, World!"}
+ * array
or object
.
+ * There are no methods for adding commas or colons. JSONStringer adds them for
+ * you. Objects and arrays can be nested up to 20 levels deep.
+ * null
if there was a
+ * problem in the construction of the JSON text (such as the calls to
+ * array
were not properly balanced with calls to
+ * endArray
).
+ * @return The JSON text.
+ */
+ public String toString() {
+ return this.mode == 'd' ? this.writer.toString() : null;
+ }
+}
diff --git a/java/ext/json/src/org/json/JSONTokener.java b/java/ext/json/src/org/json/JSONTokener.java
new file mode 100755
index 0000000..fdd261e
--- /dev/null
+++ b/java/ext/json/src/org/json/JSONTokener.java
@@ -0,0 +1,433 @@
+package org.json;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.io.StringReader;
+
+/*
+Copyright (c) 2002 JSON.org
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+The Software shall be used for Good, not Evil.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+*/
+
+/**
+ * A JSONTokener takes a source string and extracts characters and tokens from
+ * it. It is used by the JSONObject and JSONArray constructors to parse
+ * JSON source strings.
+ * @author JSON.org
+ * @version 2012-02-16
+ */
+public class JSONTokener {
+
+ private long character;
+ private boolean eof;
+ private long index;
+ private long line;
+ private char previous;
+ private Reader reader;
+ private boolean usePrevious;
+
+
+ /**
+ * Construct a JSONTokener from a Reader.
+ *
+ * @param reader A reader.
+ */
+ public JSONTokener(Reader reader) {
+ this.reader = reader;
+ this.eof = false;
+ this.usePrevious = false;
+ this.previous = 0;
+ this.index = 0;
+ this.character = 1;
+ this.line = 1;
+ }
+
+
+ /**
+ * Construct a JSONTokener from a string.
+ *
+ * @param s A source string.
+ */
+ public JSONTokener(String s) {
+ this(new StringReader(s));
+ }
+
+
+ /**
+ * Back up one character. This provides a sort of lookahead capability,
+ * so that you can test for a digit or letter before attempting to parse
+ * the next number or identifier.
+ */
+ public void back() throws JSONException {
+ if (this.usePrevious || this.index <= 0) {
+ throw new JSONException("Stepping back two steps is not supported");
+ }
+ this.index -= 1;
+ this.character -= 1;
+ this.usePrevious = true;
+ this.eof = false;
+ }
+
+
+ /**
+ * Get the hex value of a character (base16).
+ * @param c A character between '0' and '9' or between 'A' and 'F' or
+ * between 'a' and 'f'.
+ * @return An int between 0 and 15, or -1 if c was not a hex digit.
+ */
+ public static int dehexchar(char c) {
+ if (c >= '0' && c <= '9') {
+ return c - '0';
+ }
+ if (c >= 'A' && c <= 'F') {
+ return c - ('A' - 10);
+ }
+ if (c >= 'a' && c <= 'f') {
+ return c - ('a' - 10);
+ }
+ return -1;
+ }
+
+ public boolean end() {
+ return this.eof && !this.usePrevious;
+ }
+
+
+ /**
+ * Determine if the source string still contains characters that next()
+ * can consume.
+ * @return true if not yet at the end of the source.
+ */
+ public boolean more() throws JSONException {
+ this.next();
+ if (this.end()) {
+ return false;
+ }
+ this.back();
+ return true;
+ }
+
+
+ /**
+ * Get the next character in the source string.
+ *
+ * @return The next character, or 0 if past the end of the source string.
+ */
+ public char next() throws JSONException {
+ int c;
+ if (this.usePrevious) {
+ this.usePrevious = false;
+ c = this.previous;
+ } else {
+ try {
+ c = this.reader.read();
+ } catch (IOException exception) {
+ throw new JSONException(exception);
+ }
+
+ if (c <= 0) { // End of stream
+ this.eof = true;
+ c = 0;
+ }
+ }
+ this.index += 1;
+ if (this.previous == '\r') {
+ this.line += 1;
+ this.character = c == '\n' ? 0 : 1;
+ } else if (c == '\n') {
+ this.line += 1;
+ this.character = 0;
+ } else {
+ this.character += 1;
+ }
+ this.previous = (char) c;
+ return this.previous;
+ }
+
+
+ /**
+ * Consume the next character, and check that it matches a specified
+ * character.
+ * @param c The character to match.
+ * @return The character.
+ * @throws JSONException if the character does not match.
+ */
+ public char next(char c) throws JSONException {
+ char n = this.next();
+ if (n != c) {
+ throw this.syntaxError("Expected '" + c + "' and instead saw '" +
+ n + "'");
+ }
+ return n;
+ }
+
+
+ /**
+ * Get the next n characters.
+ *
+ * @param n The number of characters to take.
+ * @return A string of n characters.
+ * @throws JSONException
+ * Substring bounds error if there are not
+ * n characters remaining in the source string.
+ */
+ public String next(int n) throws JSONException {
+ if (n == 0) {
+ return "";
+ }
+
+ char[] chars = new char[n];
+ int pos = 0;
+
+ while (pos < n) {
+ chars[pos] = this.next();
+ if (this.end()) {
+ throw this.syntaxError("Substring bounds error");
+ }
+ pos += 1;
+ }
+ return new String(chars);
+ }
+
+
+ /**
+ * Get the next char in the string, skipping whitespace.
+ * @throws JSONException
+ * @return A character, or 0 if there are no more characters.
+ */
+ public char nextClean() throws JSONException {
+ for (;;) {
+ char c = this.next();
+ if (c == 0 || c > ' ') {
+ return c;
+ }
+ }
+ }
+
+
+ /**
+ * Return the characters up to the next close quote character.
+ * Backslash processing is done. The formal JSON format does not
+ * allow strings in single quotes, but an implementation is allowed to
+ * accept them.
+ * @param quote The quoting character, either
+ * "
(double quote) or
+ * '
(single quote).
+ * @return A String.
+ * @throws JSONException Unterminated string.
+ */
+ public String nextString(char quote) throws JSONException {
+ char c;
+ StringBuffer sb = new StringBuffer();
+ for (;;) {
+ c = this.next();
+ switch (c) {
+ case 0:
+ case '\n':
+ case '\r':
+ throw this.syntaxError("Unterminated string");
+ case '\\':
+ c = this.next();
+ switch (c) {
+ case 'b':
+ sb.append('\b');
+ break;
+ case 't':
+ sb.append('\t');
+ break;
+ case 'n':
+ sb.append('\n');
+ break;
+ case 'f':
+ sb.append('\f');
+ break;
+ case 'r':
+ sb.append('\r');
+ break;
+ case 'u':
+ sb.append((char)Integer.parseInt(this.next(4), 16));
+ break;
+ case '"':
+ case '\'':
+ case '\\':
+ case '/':
+ sb.append(c);
+ break;
+ default:
+ throw this.syntaxError("Illegal escape.");
+ }
+ break;
+ default:
+ if (c == quote) {
+ return sb.toString();
+ }
+ sb.append(c);
+ }
+ }
+ }
+
+
+ /**
+ * Get the text up but not including the specified character or the
+ * end of line, whichever comes first.
+ * @param delimiter A delimiter character.
+ * @return A string.
+ */
+ public String nextTo(char delimiter) throws JSONException {
+ StringBuffer sb = new StringBuffer();
+ for (;;) {
+ char c = this.next();
+ if (c == delimiter || c == 0 || c == '\n' || c == '\r') {
+ if (c != 0) {
+ this.back();
+ }
+ return sb.toString().trim();
+ }
+ sb.append(c);
+ }
+ }
+
+
+ /**
+ * Get the text up but not including one of the specified delimiter
+ * characters or the end of line, whichever comes first.
+ * @param delimiters A set of delimiter characters.
+ * @return A string, trimmed.
+ */
+ public String nextTo(String delimiters) throws JSONException {
+ char c;
+ StringBuffer sb = new StringBuffer();
+ for (;;) {
+ c = this.next();
+ if (delimiters.indexOf(c) >= 0 || c == 0 ||
+ c == '\n' || c == '\r') {
+ if (c != 0) {
+ this.back();
+ }
+ return sb.toString().trim();
+ }
+ sb.append(c);
+ }
+ }
+
+
+ /**
+ * Get the next value. The value can be a Boolean, Double, Integer,
+ * JSONArray, JSONObject, Long, or String, or the JSONObject.NULL object.
+ * @throws JSONException If syntax error.
+ *
+ * @return An object.
+ */
+ public Object nextValue() throws JSONException {
+ char c = this.nextClean();
+ String string;
+
+ switch (c) {
+ case '"':
+ case '\'':
+ return this.nextString(c);
+ case '{':
+ this.back();
+ return new JSONObject(this);
+ case '[':
+ this.back();
+ return new JSONArray(this);
+ }
+
+ /*
+ * Handle unquoted text. This could be the values true, false, or
+ * null, or it can be a number. An implementation (such as this one)
+ * is allowed to also accept non-standard forms.
+ *
+ * Accumulate characters until we reach the end of the text or a
+ * formatting character.
+ */
+
+ StringBuffer sb = new StringBuffer();
+ while (c >= ' ' && ",:]}/\\\"[{;=#".indexOf(c) < 0) {
+ sb.append(c);
+ c = this.next();
+ }
+ this.back();
+
+ string = sb.toString().trim();
+ if ("".equals(string)) {
+ throw this.syntaxError("Missing value");
+ }
+ return JSONObject.stringToValue(string);
+ }
+
+
+ /**
+ * Skip characters until the next character is the requested character.
+ * If the requested character is not found, no characters are skipped.
+ * @param to A character to skip to.
+ * @return The requested character, or zero if the requested character
+ * is not found.
+ */
+ public char skipTo(char to) throws JSONException {
+ char c;
+ try {
+ long startIndex = this.index;
+ long startCharacter = this.character;
+ long startLine = this.line;
+ this.reader.mark(1000000);
+ do {
+ c = this.next();
+ if (c == 0) {
+ this.reader.reset();
+ this.index = startIndex;
+ this.character = startCharacter;
+ this.line = startLine;
+ return c;
+ }
+ } while (c != to);
+ } catch (IOException exc) {
+ throw new JSONException(exc);
+ }
+
+ this.back();
+ return c;
+ }
+
+
+ /**
+ * Make a JSONException to signal a syntax error.
+ *
+ * @param message The error message.
+ * @return A JSONException object, suitable for throwing
+ */
+ public JSONException syntaxError(String message) {
+ return new JSONException(message + this.toString());
+ }
+
+
+ /**
+ * Make a printable string of this JSONTokener.
+ *
+ * @return " at {index} [character {character} line {line}]"
+ */
+ public String toString() {
+ return " at " + this.index + " [character " + this.character + " line " +
+ this.line + "]";
+ }
+}
diff --git a/java/ext/json/src/org/json/JSONWriter.java b/java/ext/json/src/org/json/JSONWriter.java
new file mode 100755
index 0000000..855b2bd
--- /dev/null
+++ b/java/ext/json/src/org/json/JSONWriter.java
@@ -0,0 +1,327 @@
+package org.json;
+
+import java.io.IOException;
+import java.io.Writer;
+
+/*
+Copyright (c) 2006 JSON.org
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+The Software shall be used for Good, not Evil.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+*/
+
+/**
+ * JSONWriter provides a quick and convenient way of producing JSON text.
+ * The texts produced strictly conform to JSON syntax rules. No whitespace is
+ * added, so the results are ready for transmission or storage. Each instance of
+ * JSONWriter can produce one JSON text.
+ * value
method for appending
+ * values to the
+ * text, and a key
+ * method for adding keys before values in objects. There are array
+ * and endArray
methods that make and bound array values, and
+ * object
and endObject
methods which make and bound
+ * object values. All of these methods return the JSONWriter instance,
+ * permitting a cascade style. For example,
+ * new JSONWriter(myWriter)
+ * .object()
+ * .key("JSON")
+ * .value("Hello, World!")
+ * .endObject();
which writes
+ * {"JSON":"Hello, World!"}
+ * array
or object
.
+ * There are no methods for adding commas or colons. JSONWriter adds them for
+ * you. Objects and arrays can be nested up to 20 levels deep.
+ * endArray
will be appended to this array. The
+ * endArray
method must be called to mark the array's end.
+ * @return this
+ * @throws JSONException If the nesting is too deep, or if the object is
+ * started in the wrong place (for example as a key or after the end of the
+ * outermost array or object).
+ */
+ public JSONWriter array() throws JSONException {
+ if (this.mode == 'i' || this.mode == 'o' || this.mode == 'a') {
+ this.push(null);
+ this.append("[");
+ this.comma = false;
+ return this;
+ }
+ throw new JSONException("Misplaced array.");
+ }
+
+ /**
+ * End something.
+ * @param mode Mode
+ * @param c Closing character
+ * @return this
+ * @throws JSONException If unbalanced.
+ */
+ private JSONWriter end(char mode, char c) throws JSONException {
+ if (this.mode != mode) {
+ throw new JSONException(mode == 'a'
+ ? "Misplaced endArray."
+ : "Misplaced endObject.");
+ }
+ this.pop(mode);
+ try {
+ this.writer.write(c);
+ } catch (IOException e) {
+ throw new JSONException(e);
+ }
+ this.comma = true;
+ return this;
+ }
+
+ /**
+ * End an array. This method most be called to balance calls to
+ * array
.
+ * @return this
+ * @throws JSONException If incorrectly nested.
+ */
+ public JSONWriter endArray() throws JSONException {
+ return this.end('a', ']');
+ }
+
+ /**
+ * End an object. This method most be called to balance calls to
+ * object
.
+ * @return this
+ * @throws JSONException If incorrectly nested.
+ */
+ public JSONWriter endObject() throws JSONException {
+ return this.end('k', '}');
+ }
+
+ /**
+ * Append a key. The key will be associated with the next value. In an
+ * object, every value must be preceded by a key.
+ * @param string A key string.
+ * @return this
+ * @throws JSONException If the key is out of place. For example, keys
+ * do not belong in arrays or if the key is null.
+ */
+ public JSONWriter key(String string) throws JSONException {
+ if (string == null) {
+ throw new JSONException("Null key.");
+ }
+ if (this.mode == 'k') {
+ try {
+ this.stack[this.top - 1].putOnce(string, Boolean.TRUE);
+ if (this.comma) {
+ this.writer.write(',');
+ }
+ this.writer.write(JSONObject.quote(string));
+ this.writer.write(':');
+ this.comma = false;
+ this.mode = 'o';
+ return this;
+ } catch (IOException e) {
+ throw new JSONException(e);
+ }
+ }
+ throw new JSONException("Misplaced key.");
+ }
+
+
+ /**
+ * Begin appending a new object. All keys and values until the balancing
+ * endObject
will be appended to this object. The
+ * endObject
method must be called to mark the object's end.
+ * @return this
+ * @throws JSONException If the nesting is too deep, or if the object is
+ * started in the wrong place (for example as a key or after the end of the
+ * outermost array or object).
+ */
+ public JSONWriter object() throws JSONException {
+ if (this.mode == 'i') {
+ this.mode = 'o';
+ }
+ if (this.mode == 'o' || this.mode == 'a') {
+ this.append("{");
+ this.push(new JSONObject());
+ this.comma = false;
+ return this;
+ }
+ throw new JSONException("Misplaced object.");
+
+ }
+
+
+ /**
+ * Pop an array or object scope.
+ * @param c The scope to close.
+ * @throws JSONException If nesting is wrong.
+ */
+ private void pop(char c) throws JSONException {
+ if (this.top <= 0) {
+ throw new JSONException("Nesting error.");
+ }
+ char m = this.stack[this.top - 1] == null ? 'a' : 'k';
+ if (m != c) {
+ throw new JSONException("Nesting error.");
+ }
+ this.top -= 1;
+ this.mode = this.top == 0
+ ? 'd'
+ : this.stack[this.top - 1] == null
+ ? 'a'
+ : 'k';
+ }
+
+ /**
+ * Push an array or object scope.
+ * @param c The scope to open.
+ * @throws JSONException If nesting is too deep.
+ */
+ private void push(JSONObject jo) throws JSONException {
+ if (this.top >= maxdepth) {
+ throw new JSONException("Nesting too deep.");
+ }
+ this.stack[this.top] = jo;
+ this.mode = jo == null ? 'a' : 'k';
+ this.top += 1;
+ }
+
+
+ /**
+ * Append either the value true
or the value
+ * false
.
+ * @param b A boolean.
+ * @return this
+ * @throws JSONException
+ */
+ public JSONWriter value(boolean b) throws JSONException {
+ return this.append(b ? "true" : "false");
+ }
+
+ /**
+ * Append a double value.
+ * @param d A double.
+ * @return this
+ * @throws JSONException If the number is not finite.
+ */
+ public JSONWriter value(double d) throws JSONException {
+ return this.value(new Double(d));
+ }
+
+ /**
+ * Append a long value.
+ * @param l A long.
+ * @return this
+ * @throws JSONException
+ */
+ public JSONWriter value(long l) throws JSONException {
+ return this.append(Long.toString(l));
+ }
+
+
+ /**
+ * Append an object value.
+ * @param object The object to append. It can be null, or a Boolean, Number,
+ * String, JSONObject, or JSONArray, or an object that implements JSONString.
+ * @return this
+ * @throws JSONException If the value is out of sequence.
+ */
+ public JSONWriter value(Object object) throws JSONException {
+ return this.append(JSONObject.valueToString(object));
+ }
+}
diff --git a/java/ext/json/src/org/json/README b/java/ext/json/src/org/json/README
new file mode 100755
index 0000000..b77c71a
--- /dev/null
+++ b/java/ext/json/src/org/json/README
@@ -0,0 +1,68 @@
+JSON in Java [package org.json]
+
+Douglas Crockford
+douglas@crockford.com
+
+2011-02-02
+
+
+JSON is a light-weight, language independent, data interchange format.
+See http://www.JSON.org/
+
+The files in this package implement JSON encoders/decoders in Java.
+It also includes the capability to convert between JSON and XML, HTTP
+headers, Cookies, and CDL.
+
+This is a reference implementation. There is a large number of JSON packages
+in Java. Perhaps someday the Java community will standardize on one. Until
+then, choose carefully.
+
+The license includes this restriction: "The software shall be used for good,
+not evil." If your conscience cannot live with that, then choose a different
+package.
+
+The package compiles on Java 1.2 thru Java 1.4.
+
+
+JSONObject.java: The JSONObject can parse text from a String or a JSONTokener
+to produce a map-like object. The object provides methods for manipulating its
+contents, and for producing a JSON compliant object serialization.
+
+JSONArray.java: The JSONObject can parse text from a String or a JSONTokener
+to produce a vector-like object. The object provides methods for manipulating
+its contents, and for producing a JSON compliant array serialization.
+
+JSONTokener.java: The JSONTokener breaks a text into a sequence of individual
+tokens. It can be constructed from a String, Reader, or InputStream.
+
+JSONException.java: The JSONException is the standard exception type thrown
+by this package.
+
+
+JSONString.java: The JSONString interface requires a toJSONString method,
+allowing an object to provide its own serialization.
+
+JSONStringer.java: The JSONStringer provides a convenient facility for
+building JSON strings.
+
+JSONWriter.java: The JSONWriter provides a convenient facility for building
+JSON text through a writer.
+
+
+CDL.java: CDL provides support for converting between JSON and comma
+delimited lists.
+
+Cookie.java: Cookie provides support for converting between JSON and cookies.
+
+CookieList.java: CookieList provides support for converting between JSON and
+cookie lists.
+
+HTTP.java: HTTP provides support for converting between JSON and HTTP headers.
+
+HTTPTokener.java: HTTPTokener extends JSONTokener for parsing HTTP headers.
+
+XML.java: XML provides support for converting between JSON and XML.
+
+JSONML.java: JSONML provides support for converting between JSONML and XML.
+
+XMLTokener.java: XMLTokener extends JSONTokener for parsing XML text.
diff --git a/java/ext/lcrypto-jdk15on-148/.classpath b/java/ext/lcrypto-jdk15on-148/.classpath
new file mode 100644
index 0000000..e2b1764
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/.classpath
@@ -0,0 +1,16 @@
+
+
+
+People
+
+
+
+
diff --git a/java/ext/lcrypto-jdk15on-148/LICENSE.html b/java/ext/lcrypto-jdk15on-148/LICENSE.html
new file mode 100644
index 0000000..c317e74
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/LICENSE.html
@@ -0,0 +1,22 @@
+
+
+
+Copyright (c) 2000-2011 The Legion Of The Bouncy Castle (http://www.bouncycastle.org)
+The Bouncy Castle Crypto Package
+
+
+
+
+
+
To view some examples, look at the test programs in the packages: +
org.bouncycastle.crypto.test +
org.bouncycastle.jce.provider.test +
org.bouncycastle.cms.test +
org.bouncycastle.mail.smime.test +
org.bouncycastle.openpgp.test + +
org.bouncycastle.tsp.test + +
There are also some specific example programs for dealing with Attribute Certificates, PKCS12, SMIME and OpenPGP. They can be found in: +
org.bouncycastle.jce.examples +
org.bouncycastle.mail.smime.examples +
org.bouncycastle.openpgp.examples + +
org.bouncycastle.x509.examples +
Finally there are also code examples from Beginning Cryptography with Java which demonstrate both the use of the JCE/JCA and also some of the Bouncy Castle APIs.
+
+Note 1:The JCE classes are only distributed with the JDK 1.1, JDK 1.2, and JDK 1.3 JCE releases. The
+JDK 1.0, J2ME, and the JDK 1.1, JDK 1.2, JDK 1.3, JDK 1.4, and JDK 1.5 lightweight releases only include the
+Bouncy Castle lightweight cryptography API.
+Note 2:The regression test for Diffie-Hellman is quite slow.
+
+The src and test/src directory are for JDK 1.5. +
++Compatibility classes for other VMs are as follows: +
+The clean room JCE, which will compile with everything from JDK 1.1 and up is in the jce/src directory. +
++The build scripts that come with the full distribution allow creation of the different releases by using the tree under src and test/src, excluding classes that are not appropriate and copying in the required compatibility classes from the directories containing compatibility classes appropriate for the distribution. +
++If you want to try create a build for yourself, using your own environment, the best way to do it is to start with the build for the distribution you are interested in, make sure that builds, and then modify your build scripts to do the required exclusions and file copies for your setup, otherwise you are likely to get class not found exceptions. The final caveat to this is that as the j2me distribution includes some compatibility classes starting in the java package, you need to use an obfuscator to change the package names before attempting to import a midlet using the BC API. +
++For those who are interested, there are 2 mailing lists +for participation in this project. To subscribe use the +links below and include the word subscribe in the message body. (To unsubscribe, replace subscribe with +unsubscribe in the message body) +
+
+If you want to provide feedback, offers of jobs (or more importantly +beer) directly to the members of The Legion +then please use +feedback-crypto@bouncycastle.org +
+Enjoy! + + diff --git a/java/ext/lcrypto-jdk15on-148/releasenotes.html b/java/ext/lcrypto-jdk15on-148/releasenotes.html new file mode 100644 index 0000000..1af7401 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/releasenotes.html @@ -0,0 +1,1434 @@ + +
+++ +
+
+Okay, so we have had to do another release. The issue we have run into is that we probably didn't go far enough in 1.46, but we are now confident that moving from this release to 2.0 should be largely just getting rid of deprecated methods. While this release does change a lot it is relatively straight forward to do a port and we have a porting guide which explains the important ones. The area there has been the most change in is the ASN.1 library which was in bad need of a rewrite after 10 years of patching. On the bright side the rewrite did allow us to eliminate a few problems and bugs in the ASN.1 library, so we have some hope anyone porting to it will also have similar benefits. As with 1.46 the other point of emphasis has been making sure interface support is available for operations across the major APIs, so the lightweight API or some local role your own methods can be used instead for doing encryption and signing. +
+ ++Baring security patches we expect 1.46 will be the last of the 1.* releases. The next release of +BC will be version 2.0. For this reason a lot of things in 1.46 that relate to CMS have been deprecated and +new methods have been added to the CMS and certificate handling APIs which provide greater flexibility +in how digest and signature algorithms get used. It is now possible to use the lightweight API or a simple +custom API with CMS and for certificate generation. In addition a lot of methods and some classes that were +deprecated for reasons of been confusing, or in some cases just plan wrong, have been removed. +
++So there are four things useful to know about this release: +
+Concerning the PKCS12 fix: in a few cases this may cause some backward +compatibility issues - if this happens to you, drop us a line at +feedback-crypto@bouncycastle.org +and we will help you get it sorted out. + +
+
+
+The J2ME is only supported under Windows. +
+If you are trying to use the lightweight provider in a JDK 1.0 applet, you +need to change the package names for java.math.BigInteger, java.lang.IllegalStateException, and java.security.SecureRandom +
+The RSA test under JDK 1.0 and J2ME takes a while to run... + + diff --git a/java/ext/lcrypto-jdk15on-148/specifications.html b/java/ext/lcrypto-jdk15on-148/specifications.html new file mode 100644 index 0000000..a26ad50 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/specifications.html @@ -0,0 +1,815 @@ + +
+++ +
+Except where otherwise stated, this software is distributed under a license +based on the MIT X +Consortium license. To view the license, see here. +The OpenPGP library also includes a modified BZIP2 library which +is licensed under the Apache Software License, Version 2.0. + +
+If you have the full package you will have six jar files, bcprov*.jar +which contains the BC provider, jce-*.jar which contains +the JCE provider, clean room API, and bcmail*.jar which contains the +mail API. +
+Note: if you are using JDK 1.0, you will just find a class hierarchy in +the classes directory. +
+To view examples, look at the test programs in the packages: +
+To verify the packages, run the following Java programs with the +appropriate classpath: +
+Some of the algorithms in the Bouncy Castle APIs are patented in some +places. It is upon the user of the library to be aware of what the +legal situation is in their own situation, however we have been asked +to specifically mention the patent below, in the following terms, at +the request of the patent holder. Algorithms that appear here are only +distributed in the -ext- versions of the provider. +
+The IDEA encryption algorithm is patented in the USA, Japan, and Europe +including at least Austria, France, Germany, Italy, Netherlands, Spain, Sweden, +Switzerland and the United Kingdom. Non-commercial use is free, however +any commercial products that make use of IDEA are liable for royalties. +Please see +www.mediacrypt.com for +further details. + +
+This API has been specifically developed for those circumstances +where the rich API and integration requirements of the JCE are +not required. +
+However as a result, the light-weight API requires more effort +and understanding on the part of a developer to initialise and +utilise the algorithms. + +
To utilise the light-weight API in a program, the fundamentals +are as follows; + +
+
+ /*
+ * This will use a supplied key, and encrypt the data
+ * This is the equivalent of DES/CBC/PKCS5Padding
+ */
+ BlockCipher engine = new DESEngine();
+ BufferedBlockCipher cipher = new PaddedBlockCipher(new CBCCipher(engine));
+
+ byte[] key = keyString.getBytes();
+ byte[] input = inputString.getBytes();
+
+ cipher.init(true, new KeyParameter(key));
+
+ byte[] cipherText = new byte[cipher.getOutputSize(input.length)];
+
+ int outputLen = cipher.processBytes(input, 0, input.length, cipherText, 0);
+ try
+ {
+ cipher.doFinal(cipherText, outputLen);
+ }
+ catch (CryptoException ce)
+ {
+ System.err.println(ce);
+ System.exit(1);
+ }
+
+
+
+The light-weight API has built in support for the following: + +
+The base interface is BlockCipher and has the following +implementations which match the modes the block cipher can +be operated in. +
+
Name | Constructor | Notes |
---|---|---|
BufferedBlockCipher | BlockCipher | |
CBCBlockCipher | BlockCipher | |
CFBBlockCipher | BlockCipher, block size (in bits) | |
CCMBlockCipher | BlockCipher | Packet mode - requires all data up front. |
EAXBlockCipher | BlockCipher | |
OFBBlockCipher | BlockCipher, block size (in bits) | |
SICBlockCipher | BlockCipher, block size (in bits) | Also known as CTR mode |
OpenPGPCFBBlockCipher | BlockCipher | |
GOFBBlockCipher | BlockCipher | GOST OFB mode |
+BufferedBlockCipher has a further sub-classes +
+
Name | Constructor | Notes |
---|---|---|
PaddedBufferedBlockCipher | BlockCipher | a buffered block cipher that can use padding - default PKCS5/7 padding |
CTSBlockCipher | BlockCipher | Cipher Text Stealing |
The following paddings can be used with the PaddedBufferedBlockCipher. +
+
Name | Description |
---|---|
PKCS7Padding | PKCS7/PKCS5 padding |
ISO10126d2Padding | ISO 10126-2 padding |
X932Padding | X9.23 padding |
ISO7816d4Padding | ISO 7816-4 padding (ISO 9797-1 scheme 2) |
ZeroBytePadding | Pad with Zeros (not recommended) |
The following cipher engines are implemented that can be +used with the above modes. +
+
Name | KeySizes (in bits) | Block Size | Notes |
---|---|---|---|
AESEngine | 0 .. 256 | 128 bit | |
AESWrapEngine | 0 .. 256 | 128 bit | Implements FIPS AES key wrapping |
BlowfishEngine | 0 .. 448 | 64 bit | |
CamelliaEngine | 128, 192, 256 | 128 bit | |
CamelliaWrapEngine | 128, 192, 256 | 128 bit | |
CAST5Engine | 0 .. 128 | 64 bit | |
CAST6Engine | 0 .. 256 | 128 bit | |
DESEngine | 64 | 64 bit | |
DESedeEngine | 128, 192 | 64 bit | |
DESedeWrapEngine | 128, 192 | 64 bit | Implements Draft IETF DESede key wrapping |
GOST28147Engine | 256 | 64 bit | Has a range of S-boxes |
IDEAEngine | 128 | 64 bit | |
NoekeonEngine | 128 | 128 bit | |
RC2Engine | 0 .. 1024 | 64 bit | |
RC532Engine | 0 .. 128 | 64 bit | Uses a 32 bit word |
RC564Engine | 0 .. 128 | 128 bit | Uses a 64 bit word |
RC6Engine | 0 .. 256 | 128 bit | |
RijndaelEngine | 0 .. 256 | 128 bit, 160 bit, 192 bit, 224 bit, 256 bit | |
SEEDEngine | 128 | 128 bit | |
SEEDWrapEngine | 128 | 128 bit | |
SerpentEngine | 128, 192, 256 | 128 bit | |
SkipjackEngine | 0 .. 128 | 64 bit | |
TEAEngine | 128 | 64 bit | |
TwofishEngine | 128, 192, 256 | 128 bit | |
XTEAEngine | 128 | 64 bit |
+The base interface is StreamCipher and has the following +implementations which match the modes the stream cipher can +be operated in. + +
+
Name | Constructor | Notes |
---|---|---|
BlockStreamCipher | BlockCipher |
The following cipher engines are implemented that can be +used with the above modes. +
+ +
Name | KeySizes (in bits) | Notes |
---|---|---|
RC4Engine | 40 .. 2048 | |
HC128Engine | 128 | |
HC256Engine | 256 | |
Salsa20Engine | 128/256 | |
ISAACEngine | 32 .. 8192 | |
VMPCEngine | 8 .. 6144 | |
Grainv1Engine | 80 | 64 bit IV |
Grain128Engine | 128 | 96 bit IV |
+The base interface is AsymmetricBlockCipher and has the following +implementations which match the modes the cipher can be operated in. + +
+
Name | Constructor | Notes |
---|---|---|
BufferedAsymmetricBlockCipher | AsymmetricBlockCipher | |
OAEPEncoding | AsymmetricBlockCipher | |
PKCS1Encoding | AsymmetricBlockCipher | |
ISO9796d1Encoding | AsymmetricBlockCipher | ISO9796-1 |
The following cipher engines are implemented that can be +used with the above modes. +
+
Name | KeySizes (in bits) | Notes |
---|---|---|
RSAEngine | any multiple of 8 large enough for the encoding. | |
ElGamalEngine | any multiple of 8 large enough for the encoding. |
+The base interface is Digest and has the following +implementations +
+
Name | Output (in bits) | Notes |
---|---|---|
MD2Digest | 128 | |
MD4Digest | 128 | |
MD5Digest | 128 | |
RipeMD128Digest | 128 | basic RipeMD |
RipeMD160Digest | 160 | enhanced version of RipeMD |
RipeMD256Digest | 256 | expanded version of RipeMD128 |
RipeMD320Digest | 320 | expanded version of RipeMD160 |
SHA1Digest | 160 | |
SHA224Digest | 224 | FIPS 180-2 |
SHA256Digest | 256 | FIPS 180-2 |
SHA384Digest | 384 | FIPS 180-2 |
SHA512Digest | 512 | FIPS 180-2 |
SHA3Digest | 224, 256, 288, 384, 512 | |
TigerDigest | 192 | The Tiger Digest. |
GOST3411Digest | 256 | The GOST-3411 Digest. |
WhirlpoolDigest | 512 | The Whirlpool Digest. |
+The base interface is Mac and has the following +implementations +
+
Name | Output (in bits) | Notes |
---|---|---|
CBCBlockCipherMac | blocksize/2 unless specified | |
CFBBlockCipherMac | blocksize/2, in CFB 8 mode, unless specified | |
HMac | digest length |
+The base class is PBEParametersGenerator and has the following +sub-classes +
+
Name | Constructor | Notes |
---|---|---|
PKCS5S1ParametersGenerator | Digest | |
PKCS5S2ParametersGenerator | Uses SHA1/Hmac as defined | |
PKCS12ParametersGenerator | Digest | |
OpenSSLPBEParametersGenerator | Uses MD5 as defined |
+Two versions of Diffie-Hellman key agreement are supported, the basic +version, and one for use with long term public keys. Two versions of +key agreement using Elliptic Curve cryptography are also supported, +standard Diffie-Hellman key agreement and standard key agreement with +co-factors. +
+The agreement APIs are in the org.bouncycastle.crypto.agreement package. +Classes for generating Diffie-Hellman parameters can be found in the +org.bouncycastle.crypto.params and org.bouncycastle.crypto.generators packages. +
+ +
+The IES cipher is based on the one described in IEEE P1363a (draft 10), for +use with either traditional Diffie-Hellman or Elliptic Curve Diffie-Hellman. +
+Note: At the moment this is still a draft, don't use it for anything +that may be subject to long term storage, the key values produced may well +change as the draft is finalised. +
+
+DSA, ECDSA, ISO-9796-2, GOST-3410-94, GOST-3410-2001, DSTU-4145-2002, and RSA-PSS are supported by the org.bouncycastle.crypto.signers +package. Note: as these are light weight classes, if you need to use SHA1 or GOST-3411 +(as defined in the relevant standards) you'll also need to make use of the appropriate +digest class in conjunction with these. +Classes for generating DSA and ECDSA parameters can be found in the +org.bouncycastle.crypto.params and org.bouncycastle.crypto.generators packages. +
+ +
The light-weight API has direct interfaces into a package capable of +reading and writing DER-encoded ASN.1 objects and for the generation +of X.509 V3 certificate objects and PKCS12 files. BER InputStream and +OutputStream classes are provided as well. + +
The Bouncy Castle provider is a JCE compliant provider that +is a wrapper built on top of the light-weight API. + +
+The advantage for writing application code that uses the +provider interface to cryptographic algorithms is that the +actual provider used can be selected at run time. This +is extremely valuable for applications that may wish to +make use of a provider that has underlying hardware for +cryptographic computation, or where an application may have +been developed in an environment with cryptographic export +controls. + +
To utilise the JCE provider in a program, the fundamentals +are as follows; + +
+
+ /*
+ * This will generate a random key, and encrypt the data
+ */
+ Key key;
+ KeyGenerator keyGen;
+ Cipher encrypt;
+
+ Security.addProvider(new BouncyCastleProvider());
+
+ try
+ {
+ // "BC" is the name of the BouncyCastle provider
+ keyGen = KeyGenerator.getInstance("DES", "BC");
+ keyGen.init(new SecureRandom());
+
+ key = keyGen.generateKey();
+
+ encrypt = Cipher.getInstance("DES/CBC/PKCS5Padding", "BC");
+ }
+ catch (Exception e)
+ {
+ System.err.println(e);
+ System.exit(1);
+ }
+
+ encrypt.init(Cipher.ENCRYPT_MODE, key);
+
+ bOut = new ByteArrayOutputStream();
+ cOut = new CipherOutputStream(bOut, encrypt);
+
+ cOut.write("plaintext".getBytes());
+ cOut.close();
+
+ // bOut now contains the cipher text
+
+
++The provider can also be configured as part of your environment via static registration +by adding an entry to the java.security properties file (found in $JAVA_HOME/jre/lib/security/java.security, where $JAVA_HOME is the location of your JDK/JRE distribution). You'll find detailed +instructions in the file but basically it comes down to adding a line: +
+
+ security.provider.<n>=org.bouncycastle.jce.provider.BouncyCastleProvider
+
+
+Where <n> is the preference you want the provider at (1 being the most prefered). +
Where you put the jar is up to mostly up to you, although with jdk1.3 and +jdk1.4 the best (and in some cases only) place to have it is in $JAVA_HOME/jre/lib/ext. Note: under Windows there will normally be a JRE and a JDK install of Java if you think you have installed it correctly and it still doesn't work chances are you have added the provider to the installation not being used. +
+Note: with JDK 1.4 and later you will need to have installed the unrestricted policy
+files to take full advantage of the provider. If you do not install the policy files you are likely
+to get something like the following:
+
+
+ java.lang.SecurityException: Unsupported keysize or algorithm parameters
+ at javax.crypto.Cipher.init(DashoA6275)
+
+
+The policy files can be found at the same place you downloaded the JDK.
+
+
Modes: +
+Where (n) is a multiple of 8 that gives the blocksize in bits, +eg, OFB8. Note that OFB and CFB mode can be used with plain text that +is not an exact multiple of the block size if NoPadding has been specified. +
+ +Padding Schemes: +
+When placed together this gives a specification for an algorithm +as; +
+Note: default key sizes are in bold. +
+
Name | KeySizes (in bits) | Block Size | Notes |
---|---|---|---|
AES | 0 .. 256 (192) | 128 bit | |
AESWrap | 0 .. 256 (192) | 128 bit | A FIPS AES key wrapper |
Blowfish | 0 .. 448 (448) | 64 bit | |
Camellia | 128, 192, 256 | 128 bit | |
CamelliaWrap | 128, 192, 256 | 128 bit | |
CAST5 | 0 .. 128(128) | 64 bit | |
CAST6 | 0 .. 256(256) | 128 bit | |
DES | 64 | 64 bit | |
DESede | 128, 192 | 64 bit | |
DESedeWrap | 128, 192 | 128 bit | A Draft IETF DESede key wrapper |
GOST28147 | 256 | 64 bit | |
IDEA | 128 (128) | 64 bit | Only included in extended provider jar. |
Noekeon | 128(128) | 128 bit | |
RC2 | 0 .. 1024 (128) | 64 bit | |
RC5 | 0 .. 128 (128) | 64 bit | Uses a 32 bit word |
RC5-64 | 0 .. 256 (256) | 128 bit | Uses a 64 bit word |
RC6 | 0 .. 256 (128) | 128 bit | |
Rijndael | 0 .. 256 (192) | 128 bit | |
SEED | 128(128) | 128 bit | |
SEEDWrap | 128(128) | 128 bit | |
Serpent | 128, 192, 256 (256) | 128 bit | |
Skipjack | 0 .. 128 (128) | 64 bit | |
TEA | 128 (128) | 64 bit | |
Twofish | 128, 192, 256 (256) | 128 bit | |
XTEA | 128 (128) | 64 bit |
+Note: default key sizes are in bold. +
+
Name | KeySizes (in bits) | Notes |
---|---|---|
RC4 | 40 .. 2048 bits (128) | |
HC128 | (128) | |
HC256 | (256) | |
Salsa20 | 128/256(128) | |
VMPC | 128/6144(128) | |
Grainv1 | 80 | 64 bit IV |
Grain128 | 128 | 96 bit IV |
Encoding: +
Note: except as indicated in PKCS 1v2 we recommend you use OAEP, as +mandated in X9.44. + +
+When placed together with RSA this gives a specification for an algorithm +as; +
Name | KeySizes (in bits) | Notes |
---|---|---|
RSA | any multiple of 8 bits large enough for the encryption(2048) | |
ElGamal | any multiple of 8 bits large enough for the encryption(1024) |
+Diffie-Hellman key agreement is supported using the "DH", "ECDH", and +"ECDHC" (ECDH with cofactors) key agreement instances. +
+Note: with basic "DH" only the basic algorithm fits in with the JCE API, if +you're using long-term public keys you may want to look at the light-weight +API. +
+
+An implementation of ECIES (stream mode) as described in IEEE P 1363a. +
+Note: At the moment this is still a draft, don't use it for anything +that may be subject to long term storage, the key values produced may well +change as the draft is finalised. +
+
+
Name | Output (in bits) | Notes |
---|---|---|
GOST3411 | 256 | |
MD2 | 128 | |
MD4 | 128 | |
MD5 | 128 | |
RipeMD128 | 128 | basic RipeMD |
RipeMD160 | 160 | enhanced version of RipeMD |
RipeMD256Digest | 256 | expanded version of RipeMD128 |
RipeMD320Digest | 320 | expanded version of RipeMD160 |
SHA1 | 160 | |
SHA-224 | 224 | FIPS 180-2 |
SHA-256 | 256 | FIPS 180-2 |
SHA-384 | 384 | FIPS 180-2 |
SHA-512 | 512 | FIPS 180-2 |
SHA3-224 | 224 | |
SHA3-256 | 256 | |
SHA3-384 | 384 | |
SHA3-512 | 512 | |
Tiger | 192 | |
Whirlpool | 512 |
Name | Output (in bits) | Notes |
---|---|---|
Any MAC based on a block cipher, CBC (the default) and CFB modes. | half the cipher's block size (usually 32 bits) | |
VMPC-MAC | 128 | |
HMac-MD2 | 128 | |
HMac-MD4 | 128 | |
HMac-MD5 | 128 | |
HMac-RipeMD128 | 128 | |
HMac-RipeMD160 | 160 | |
HMac-SHA1 | 160 | |
HMac-SHA224 | 224 | |
HMac-SHA256 | 256 | |
HMac-SHA384 | 384 | |
HMac-SHA512 | 512 | |
HMac-Tiger | 192 |
Examples: +
Schemes: +
Schemes: +
+Defined in Bouncy Castle JCE Provider +
Name | Key Generation Scheme | Key Length (in bits) |
---|---|---|
PBEWithMD2AndDES | PKCS5 Scheme 1 | 64 |
PBEWithMD2AndRC2 | PKCS5 Scheme 1 | 128 |
PBEWithMD5AndDES | PKCS5 Scheme 1 | 64 |
PBEWithMD5AndRC2 | PKCS5 Scheme 1 | 128 |
PBEWithSHA1AndDES | PKCS5 Scheme 1 | 64 |
PBEWithSHA1AndRC2 | PKCS5 Scheme 1 | 128 |
PBEWithSHAAnd2-KeyTripleDES-CBC | PKCS12 | 128 |
PBEWithSHAAnd3-KeyTripleDES-CBC | PKCS12 | 192 |
PBEWithSHAAnd128BitRC2-CBC | PKCS12 | 128 |
PBEWithSHAAnd40BitRC2-CBC | PKCS12 | 40 |
PBEWithSHAAnd128BitRC4 | PKCS12 | 128 |
PBEWithSHAAnd40BitRC4 | PKCS12 | 40 |
PBEWithSHAAndTwofish-CBC | PKCS12 | 256 |
PBEWithSHAAndIDEA-CBC | PKCS12 | 128 |
+The Bouncy Castle provider will read X.509 certficates (v2 or v3) as per the examples in +the java.security.cert.CertificateFactory class. They can be provided either +in the normal PEM encoded format, or as DER binaries. +
+The CertificiateFactory will also read X.509 CRLs (v2) from either PEM or DER encodings. +
+In addition to the classes in the org.bouncycastle.asn1.x509 package for certificate +generation a more JCE "friendly" class is provided in the package org.bouncycastle.x509. The JCE "friendly" class supports RSA, DSA, and EC-DSA. +
+
+The Bouncy Castle package has three implementation of a keystore. +
+The first "BKS" is a keystore that will work with the keytool in the same +fashion as the Sun "JKS" keystore. The keystore is resistent to tampering +but not inspection. +
+The second, Keystore.BouncyCastle, or Keystore.UBER will only work with the keytool +if the password is provided on the command line, as the entire keystore +is encrypted +with a PBE based on SHA1 and Twofish. PBEWithSHAAndTwofish-CBC. +This makes the entire keystore resistant to tampering and inspection, +and forces verification. +The Sun JDK provided keytool will attempt to load a keystore even if no +password is given, +this is impossible for this version. (One might wonder about going to all +this trouble and then having the password on the command line! New keytool +anyone?). +
+In the first case, the keys are encrypted with 3-Key-TripleDES. +
+The third is a PKCS12 compatible keystore. PKCS12 provides a slightly +different situation from the regular key store, the keystore password is +currently the only password used for storing keys. Otherwise it supports +all the functionality required for it to be used with the keytool. In some +situations other libraries always expect to be dealing with Sun certificates, +if this is the case use PKCS12-DEF, and the certificates produced by the +key store will be made using the default provider. In the default case PKCS12 uses 3DES for key protection and 40 bit RC2 for protecting the certificates. It is also possible to use 3DES for both by using PKCS12-3DES-3DES or PKCS12-DEF-3DES-3DES as the KeyStore type. +
+There is an example program that produces PKCS12 files suitable for +loading into browsers. It is in the package +org.bouncycastle.jce.examples. +
+
+
+There are no classes for supporting EC in the JDK prior to JDK 1.5. If you are using +an earlier JDK you can find classes for using EC in the following +packages: +
+ application/pkcs7-signature;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.pkcs7_signature + application/pkcs7-mime;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.pkcs7_mime + application/x-pkcs7-signature;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.x_pkcs7_signature + application/x-pkcs7-mime;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.x_pkcs7_mime + multipart/signed;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.multipart_signed ++ +
+ import javax.activation.MailcapCommandMap; + import javax.activation.CommandMap; + + public static void setDefaultMailcap() + { + MailcapCommandMap _mailcap = + (MailcapCommandMap)CommandMap.getDefaultCommandMap(); + + _mailcap.addMailcap("application/pkcs7-signature;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.pkcs7_signature"); + _mailcap.addMailcap("application/pkcs7-mime;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.pkcs7_mime"); + _mailcap.addMailcap("application/x-pkcs7-signature;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.x_pkcs7_signature"); + _mailcap.addMailcap("application/x-pkcs7-mime;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.x_pkcs7_mime"); + _mailcap.addMailcap("multipart/signed;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.multipart_signed"); + + CommandMap.setDefaultCommandMap(_mailcap); + } ++ + + diff --git a/java/ext/lcrypto-jdk15on-148/src/META-INF/MANIFEST.MF b/java/ext/lcrypto-jdk15on-148/src/META-INF/MANIFEST.MF new file mode 100644 index 0000000..5e94951 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/META-INF/MANIFEST.MF @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +Class-Path: + diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/LICENSE.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/LICENSE.java new file mode 100644 index 0000000..6a77691 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/LICENSE.java @@ -0,0 +1,63 @@ +package org.bc; + +/** + * The Bouncy Castle License + * + * Copyright (c) 2000-2012 The Legion Of The Bouncy Castle (http://www.bouncycastle.org) + *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial + * portions of the Software. + *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ +public class LICENSE +{ + public static String licenseText = + "Copyright (c) 2000-2012 The Legion Of The Bouncy Castle (http://www.bouncycastle.org) " + + System.getProperty("line.separator") + + System.getProperty("line.separator") + + "Permission is hereby granted, free of charge, to any person obtaining a copy of this software " + + System.getProperty("line.separator") + + "and associated documentation files (the \"Software\"), to deal in the Software without restriction, " + + System.getProperty("line.separator") + + "including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, " + + System.getProperty("line.separator") + + "and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so," + + System.getProperty("line.separator") + + "subject to the following conditions:" + + System.getProperty("line.separator") + + System.getProperty("line.separator") + + "The above copyright notice and this permission notice shall be included in all copies or substantial" + + System.getProperty("line.separator") + + "portions of the Software." + + System.getProperty("line.separator") + + System.getProperty("line.separator") + + "THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED," + + System.getProperty("line.separator") + + "INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR" + + System.getProperty("line.separator") + + "PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE" + + System.getProperty("line.separator") + + "LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR" + + System.getProperty("line.separator") + + "OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER" + + System.getProperty("line.separator") + + "DEALINGS IN THE SOFTWARE."; + + public static void main( + String[] args) + { + System.out.println(licenseText); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ASN1ApplicationSpecificParser.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ASN1ApplicationSpecificParser.java new file mode 100644 index 0000000..4b82819 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ASN1ApplicationSpecificParser.java @@ -0,0 +1,10 @@ +package org.bc.asn1; + +import java.io.IOException; + +public interface ASN1ApplicationSpecificParser + extends ASN1Encodable, InMemoryRepresentable +{ + ASN1Encodable readObject() + throws IOException; +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ASN1Boolean.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ASN1Boolean.java new file mode 100644 index 0000000..5844a74 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ASN1Boolean.java @@ -0,0 +1,15 @@ +package org.bc.asn1; + +public class ASN1Boolean + extends DERBoolean +{ + public ASN1Boolean(boolean value) + { + super(value); + } + + ASN1Boolean(byte[] value) + { + super(value); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ASN1Choice.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ASN1Choice.java new file mode 100644 index 0000000..58e6058 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ASN1Choice.java @@ -0,0 +1,14 @@ +package org.bc.asn1; + +/** + * Marker interface for CHOICE objects - if you implement this in a role your + * own object any attempt to tag the object implicitly will convert the tag to + * an explicit one as the encoding rules require. + *
+ * If you use this interface your class should also implement the getInstance + * pattern which takes a tag object and the tagging mode used. + */ +public interface ASN1Choice +{ + // marker interface +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ASN1Encodable.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ASN1Encodable.java new file mode 100644 index 0000000..4838910 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ASN1Encodable.java @@ -0,0 +1,6 @@ +package org.bc.asn1; + +public interface ASN1Encodable +{ + ASN1Primitive toASN1Primitive(); +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ASN1EncodableVector.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ASN1EncodableVector.java new file mode 100644 index 0000000..21ab9d7 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ASN1EncodableVector.java @@ -0,0 +1,36 @@ +package org.bc.asn1; + +import java.util.Enumeration; +import java.util.Vector; + +public class ASN1EncodableVector +{ + Vector v = new Vector(); + + public ASN1EncodableVector() + { + } + + public void add(ASN1Encodable obj) + { + v.addElement(obj); + } + + public void addAll(ASN1EncodableVector other) + { + for (Enumeration en = other.v.elements(); en.hasMoreElements();) + { + v.addElement(en.nextElement()); + } + } + + public ASN1Encodable get(int i) + { + return (ASN1Encodable)v.elementAt(i); + } + + public int size() + { + return v.size(); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ASN1Encoding.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ASN1Encoding.java new file mode 100644 index 0000000..c3a4fd6 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ASN1Encoding.java @@ -0,0 +1,8 @@ +package org.bc.asn1; + +public interface ASN1Encoding +{ + static final String DER = "DER"; + static final String DL = "DL"; + static final String BER = "BER"; +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ASN1Enumerated.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ASN1Enumerated.java new file mode 100644 index 0000000..01b1df2 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ASN1Enumerated.java @@ -0,0 +1,22 @@ +package org.bc.asn1; + +import java.math.BigInteger; + +public class ASN1Enumerated + extends DEREnumerated +{ + ASN1Enumerated(byte[] bytes) + { + super(bytes); + } + + public ASN1Enumerated(BigInteger value) + { + super(value); + } + + public ASN1Enumerated(int value) + { + super(value); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ASN1Exception.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ASN1Exception.java new file mode 100644 index 0000000..449232b --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ASN1Exception.java @@ -0,0 +1,25 @@ +package org.bc.asn1; + +import java.io.IOException; + +public class ASN1Exception + extends IOException +{ + private Throwable cause; + + ASN1Exception(String message) + { + super(message); + } + + ASN1Exception(String message, Throwable cause) + { + super(message); + this.cause = cause; + } + + public Throwable getCause() + { + return cause; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ASN1GeneralizedTime.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ASN1GeneralizedTime.java new file mode 100644 index 0000000..f099ee8 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ASN1GeneralizedTime.java @@ -0,0 +1,22 @@ +package org.bc.asn1; + +import java.util.Date; + +public class ASN1GeneralizedTime + extends DERGeneralizedTime +{ + ASN1GeneralizedTime(byte[] bytes) + { + super(bytes); + } + + public ASN1GeneralizedTime(Date time) + { + super(time); + } + + public ASN1GeneralizedTime(String time) + { + super(time); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ASN1Generator.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ASN1Generator.java new file mode 100644 index 0000000..d489550 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ASN1Generator.java @@ -0,0 +1,15 @@ +package org.bc.asn1; + +import java.io.OutputStream; + +public abstract class ASN1Generator +{ + protected OutputStream _out; + + public ASN1Generator(OutputStream out) + { + _out = out; + } + + public abstract OutputStream getRawOutputStream(); +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ASN1InputStream.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ASN1InputStream.java new file mode 100644 index 0000000..7296476 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ASN1InputStream.java @@ -0,0 +1,466 @@ +package org.bc.asn1; + +import java.io.ByteArrayInputStream; +import java.io.EOFException; +import java.io.FilterInputStream; +import java.io.IOException; +import java.io.InputStream; + +import org.bc.util.io.Streams; + +/** + * a general purpose ASN.1 decoder - note: this class differs from the + * others in that it returns null after it has read the last object in + * the stream. If an ASN.1 NULL is encountered a DER/BER Null object is + * returned. + */ +public class ASN1InputStream + extends FilterInputStream + implements BERTags +{ + private final int limit; + private final boolean lazyEvaluate; + + private final byte[][] tmpBuffers; + + public ASN1InputStream( + InputStream is) + { + this(is, StreamUtil.findLimit(is)); + } + + /** + * Create an ASN1InputStream based on the input byte array. The length of DER objects in + * the stream is automatically limited to the length of the input array. + * + * @param input array containing ASN.1 encoded data. + */ + public ASN1InputStream( + byte[] input) + { + this(new ByteArrayInputStream(input), input.length); + } + + /** + * Create an ASN1InputStream based on the input byte array. The length of DER objects in + * the stream is automatically limited to the length of the input array. + * + * @param input array containing ASN.1 encoded data. + * @param lazyEvaluate true if parsing inside constructed objects can be delayed. + */ + public ASN1InputStream( + byte[] input, + boolean lazyEvaluate) + { + this(new ByteArrayInputStream(input), input.length, lazyEvaluate); + } + + /** + * Create an ASN1InputStream where no DER object will be longer than limit. + * + * @param input stream containing ASN.1 encoded data. + * @param limit maximum size of a DER encoded object. + */ + public ASN1InputStream( + InputStream input, + int limit) + { + this(input, limit, false); + } + + /** + * Create an ASN1InputStream where no DER object will be longer than limit, and constructed + * objects such as sequences will be parsed lazily. + * + * @param input stream containing ASN.1 encoded data. + * @param lazyEvaluate true if parsing inside constructed objects can be delayed. + */ + public ASN1InputStream( + InputStream input, + boolean lazyEvaluate) + { + this(input, StreamUtil.findLimit(input), lazyEvaluate); + } + + /** + * Create an ASN1InputStream where no DER object will be longer than limit, and constructed + * objects such as sequences will be parsed lazily. + * + * @param input stream containing ASN.1 encoded data. + * @param limit maximum size of a DER encoded object. + * @param lazyEvaluate true if parsing inside constructed objects can be delayed. + */ + public ASN1InputStream( + InputStream input, + int limit, + boolean lazyEvaluate) + { + super(input); + this.limit = limit; + this.lazyEvaluate = lazyEvaluate; + this.tmpBuffers = new byte[11][]; + } + + int getLimit() + { + return limit; + } + + protected int readLength() + throws IOException + { + return readLength(this, limit); + } + + protected void readFully( + byte[] bytes) + throws IOException + { + if (Streams.readFully(this, bytes) != bytes.length) + { + throw new EOFException("EOF encountered in middle of object"); + } + } + + /** + * build an object given its tag and the number of bytes to construct it from. + */ + protected ASN1Primitive buildObject( + int tag, + int tagNo, + int length) + throws IOException + { + boolean isConstructed = (tag & CONSTRUCTED) != 0; + + DefiniteLengthInputStream defIn = new DefiniteLengthInputStream(this, length); + + if ((tag & APPLICATION) != 0) + { + return new DERApplicationSpecific(isConstructed, tagNo, defIn.toByteArray()); + } + + if ((tag & TAGGED) != 0) + { + return new ASN1StreamParser(defIn).readTaggedObject(isConstructed, tagNo); + } + + if (isConstructed) + { + // TODO There are other tags that may be constructed (e.g. BIT_STRING) + switch (tagNo) + { + case OCTET_STRING: + // + // yes, people actually do this... + // + ASN1EncodableVector v = buildDEREncodableVector(defIn); + ASN1OctetString[] strings = new ASN1OctetString[v.size()]; + + for (int i = 0; i != strings.length; i++) + { + strings[i] = (ASN1OctetString)v.get(i); + } + + return new BEROctetString(strings); + case SEQUENCE: + if (lazyEvaluate) + { + return new LazyEncodedSequence(defIn.toByteArray()); + } + else + { + return DERFactory.createSequence(buildDEREncodableVector(defIn)); + } + case SET: + return DERFactory.createSet(buildDEREncodableVector(defIn)); + case EXTERNAL: + return new DERExternal(buildDEREncodableVector(defIn)); + default: + throw new IOException("unknown tag " + tagNo + " encountered"); + } + } + + return createPrimitiveDERObject(tagNo, defIn, tmpBuffers); + } + + ASN1EncodableVector buildEncodableVector() + throws IOException + { + ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1Primitive o; + + while ((o = readObject()) != null) + { + v.add(o); + } + + return v; + } + + ASN1EncodableVector buildDEREncodableVector( + DefiniteLengthInputStream dIn) throws IOException + { + return new ASN1InputStream(dIn).buildEncodableVector(); + } + + public ASN1Primitive readObject() + throws IOException + { + int tag = read(); + if (tag <= 0) + { + if (tag == 0) + { + throw new IOException("unexpected end-of-contents marker"); + } + + return null; + } + + // + // calculate tag number + // + int tagNo = readTagNumber(this, tag); + + boolean isConstructed = (tag & CONSTRUCTED) != 0; + + // + // calculate length + // + int length = readLength(); + + if (length < 0) // indefinite length method + { + if (!isConstructed) + { + throw new IOException("indefinite length primitive encoding encountered"); + } + + IndefiniteLengthInputStream indIn = new IndefiniteLengthInputStream(this, limit); + ASN1StreamParser sp = new ASN1StreamParser(indIn, limit); + + if ((tag & APPLICATION) != 0) + { + return new BERApplicationSpecificParser(tagNo, sp).getLoadedObject(); + } + + if ((tag & TAGGED) != 0) + { + return new BERTaggedObjectParser(true, tagNo, sp).getLoadedObject(); + } + + // TODO There are other tags that may be constructed (e.g. BIT_STRING) + switch (tagNo) + { + case OCTET_STRING: + return new BEROctetStringParser(sp).getLoadedObject(); + case SEQUENCE: + return new BERSequenceParser(sp).getLoadedObject(); + case SET: + return new BERSetParser(sp).getLoadedObject(); + case EXTERNAL: + return new DERExternalParser(sp).getLoadedObject(); + default: + throw new IOException("unknown BER object encountered"); + } + } + else + { + try + { + return buildObject(tag, tagNo, length); + } + catch (IllegalArgumentException e) + { + throw new ASN1Exception("corrupted stream detected", e); + } + } + } + + static int readTagNumber(InputStream s, int tag) + throws IOException + { + int tagNo = tag & 0x1f; + + // + // with tagged object tag number is bottom 5 bits, or stored at the start of the content + // + if (tagNo == 0x1f) + { + tagNo = 0; + + int b = s.read(); + + // X.690-0207 8.1.2.4.2 + // "c) bits 7 to 1 of the first subsequent octet shall not all be zero." + if ((b & 0x7f) == 0) // Note: -1 will pass + { + throw new IOException("corrupted stream - invalid high tag number found"); + } + + while ((b >= 0) && ((b & 0x80) != 0)) + { + tagNo |= (b & 0x7f); + tagNo <<= 7; + b = s.read(); + } + + if (b < 0) + { + throw new EOFException("EOF found inside tag value."); + } + + tagNo |= (b & 0x7f); + } + + return tagNo; + } + + static int readLength(InputStream s, int limit) + throws IOException + { + int length = s.read(); + if (length < 0) + { + throw new EOFException("EOF found when length expected"); + } + + if (length == 0x80) + { + return -1; // indefinite-length encoding + } + + if (length > 127) + { + int size = length & 0x7f; + + // Note: The invalid long form "0xff" (see X.690 8.1.3.5c) will be caught here + if (size > 4) + { + throw new IOException("DER length more than 4 bytes: " + size); + } + + length = 0; + for (int i = 0; i < size; i++) + { + int next = s.read(); + + if (next < 0) + { + throw new EOFException("EOF found reading length"); + } + + length = (length << 8) + next; + } + + if (length < 0) + { + throw new IOException("corrupted stream - negative length found"); + } + + if (length >= limit) // after all we must have read at least 1 byte + { + throw new IOException("corrupted stream - out of bounds length found"); + } + } + + return length; + } + + private static byte[] getBuffer(DefiniteLengthInputStream defIn, byte[][] tmpBuffers) + throws IOException + { + int len = defIn.getRemaining(); + if (defIn.getRemaining() < tmpBuffers.length) + { + byte[] buf = tmpBuffers[len]; + + if (buf == null) + { + buf = tmpBuffers[len] = new byte[len]; + } + + Streams.readFully(defIn, buf); + + return buf; + } + else + { + return defIn.toByteArray(); + } + } + + private static char[] getBMPCharBuffer(DefiniteLengthInputStream defIn) + throws IOException + { + int len = defIn.getRemaining() / 2; + char[] buf = new char[len]; + int totalRead = 0; + while (totalRead < len) + { + int ch1 = defIn.read(); + if (ch1 < 0) + { + break; + } + int ch2 = defIn.read(); + if (ch2 < 0) + { + break; + } + buf[totalRead++] = (char)((ch1 << 8) | (ch2 & 0xff)); + } + + return buf; + } + + static ASN1Primitive createPrimitiveDERObject( + int tagNo, + DefiniteLengthInputStream defIn, + byte[][] tmpBuffers) + throws IOException + { + switch (tagNo) + { + case BIT_STRING: + return DERBitString.fromInputStream(defIn.getRemaining(), defIn); + case BMP_STRING: + return new DERBMPString(getBMPCharBuffer(defIn)); + case BOOLEAN: + return ASN1Boolean.fromOctetString(getBuffer(defIn, tmpBuffers)); + case ENUMERATED: + return ASN1Enumerated.fromOctetString(getBuffer(defIn, tmpBuffers)); + case GENERALIZED_TIME: + return new ASN1GeneralizedTime(defIn.toByteArray()); + case GENERAL_STRING: + return new DERGeneralString(defIn.toByteArray()); + case IA5_STRING: + return new DERIA5String(defIn.toByteArray()); + case INTEGER: + return new ASN1Integer(defIn.toByteArray()); + case NULL: + return DERNull.INSTANCE; // actual content is ignored (enforce 0 length?) + case NUMERIC_STRING: + return new DERNumericString(defIn.toByteArray()); + case OBJECT_IDENTIFIER: + return ASN1ObjectIdentifier.fromOctetString(getBuffer(defIn, tmpBuffers)); + case OCTET_STRING: + return new DEROctetString(defIn.toByteArray()); + case PRINTABLE_STRING: + return new DERPrintableString(defIn.toByteArray()); + case T61_STRING: + return new DERT61String(defIn.toByteArray()); + case UNIVERSAL_STRING: + return new DERUniversalString(defIn.toByteArray()); + case UTC_TIME: + return new ASN1UTCTime(defIn.toByteArray()); + case UTF8_STRING: + return new DERUTF8String(defIn.toByteArray()); + case VISIBLE_STRING: + return new DERVisibleString(defIn.toByteArray()); + default: + throw new IOException("unknown tag " + tagNo + " encountered"); + } + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ASN1Integer.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ASN1Integer.java new file mode 100644 index 0000000..0dbbecb --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ASN1Integer.java @@ -0,0 +1,22 @@ +package org.bc.asn1; + +import java.math.BigInteger; + +public class ASN1Integer + extends DERInteger +{ + ASN1Integer(byte[] bytes) + { + super(bytes); + } + + public ASN1Integer(BigInteger value) + { + super(value); + } + + public ASN1Integer(long value) + { + super(value); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ASN1Null.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ASN1Null.java new file mode 100644 index 0000000..3a6e3c1 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ASN1Null.java @@ -0,0 +1,67 @@ +package org.bc.asn1; + +import java.io.IOException; + +/** + * A NULL object. + */ +public abstract class ASN1Null + extends ASN1Primitive +{ + /** + * @deprecated use DERNull.INSTANCE + */ + public ASN1Null() + { + } + + public static ASN1Null getInstance(Object o) + { + if (o instanceof ASN1Null) + { + return (ASN1Null)o; + } + + if (o != null) + { + try + { + return ASN1Null.getInstance(ASN1Primitive.fromByteArray((byte[])o)); + } + catch (IOException e) + { + throw new IllegalArgumentException("failed to construct NULL from byte[]: " + e.getMessage()); + } + catch (ClassCastException e) + { + throw new IllegalArgumentException("unknown object in getInstance(): " + o.getClass().getName()); + } + } + + return null; + } + + public int hashCode() + { + return -1; + } + + boolean asn1Equals( + ASN1Primitive o) + { + if (!(o instanceof ASN1Null)) + { + return false; + } + + return true; + } + + abstract void encode(ASN1OutputStream out) + throws IOException; + + public String toString() + { + return "NULL"; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ASN1Object.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ASN1Object.java new file mode 100644 index 0000000..00ca164 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ASN1Object.java @@ -0,0 +1,97 @@ +package org.bc.asn1; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +public abstract class ASN1Object + implements ASN1Encodable +{ + /** + * Return the default BER or DER encoding for this object. + * + * @return BER/DER byte encoded object. + * @throws java.io.IOException on encoding error. + */ + public byte[] getEncoded() + throws IOException + { + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + ASN1OutputStream aOut = new ASN1OutputStream(bOut); + + aOut.writeObject(this); + + return bOut.toByteArray(); + } + + /** + * Return either the default for "BER" or a DER encoding if "DER" is specified. + * + * @param encoding name of encoding to use. + * @return byte encoded object. + * @throws IOException on encoding error. + */ + public byte[] getEncoded( + String encoding) + throws IOException + { + if (encoding.equals(ASN1Encoding.DER)) + { + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + DEROutputStream dOut = new DEROutputStream(bOut); + + dOut.writeObject(this); + + return bOut.toByteArray(); + } + else if (encoding.equals(ASN1Encoding.DL)) + { + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + DLOutputStream dOut = new DLOutputStream(bOut); + + dOut.writeObject(this); + + return bOut.toByteArray(); + } + + return this.getEncoded(); + } + + public int hashCode() + { + return this.toASN1Primitive().hashCode(); + } + + public boolean equals( + Object o) + { + if (this == o) + { + return true; + } + + if (!(o instanceof ASN1Encodable)) + { + return false; + } + + ASN1Encodable other = (ASN1Encodable)o; + + return this.toASN1Primitive().equals(other.toASN1Primitive()); + } + + /** + * @deprecated use toASN1Primitive() + * @return the underlying primitive type. + */ + public ASN1Primitive toASN1Object() + { + return this.toASN1Primitive(); + } + + protected static boolean hasEncodedTagValue(Object obj, int tagValue) + { + return (obj instanceof byte[]) && ((byte[])obj)[0] == tagValue; + } + + public abstract ASN1Primitive toASN1Primitive(); +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ASN1ObjectIdentifier.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ASN1ObjectIdentifier.java new file mode 100644 index 0000000..9858577 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ASN1ObjectIdentifier.java @@ -0,0 +1,37 @@ +package org.bc.asn1; + +public class ASN1ObjectIdentifier + extends DERObjectIdentifier +{ + public ASN1ObjectIdentifier(String identifier) + { + super(identifier); + } + + ASN1ObjectIdentifier(byte[] bytes) + { + super(bytes); + } + + /** + * Return an OID that creates a branch under the current one. + * + * @param branchID node numbers for the new branch. + * @return the OID for the new created branch. + */ + public ASN1ObjectIdentifier branch(String branchID) + { + return new ASN1ObjectIdentifier(getId() + "." + branchID); + } + + /** + * Return true if this oid is an extension of the passed in branch, stem. + * @param stem the arc or branch that is a possible parent. + * @return true if the branch is on the passed in stem, false otherwise. + */ + public boolean on(ASN1ObjectIdentifier stem) + { + String id = getId(), stemId = stem.getId(); + return id.length() > stemId.length() && id.charAt(stemId.length()) == '.' && id.startsWith(stemId); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ASN1OctetString.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ASN1OctetString.java new file mode 100644 index 0000000..6b04c5e --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ASN1OctetString.java @@ -0,0 +1,146 @@ +package org.bc.asn1; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; + +import org.bc.util.Arrays; +import org.bc.util.encoders.Hex; + +public abstract class ASN1OctetString + extends ASN1Primitive + implements ASN1OctetStringParser +{ + byte[] string; + + /** + * return an Octet String from a tagged object. + * + * @param obj the tagged object holding the object we want. + * @param explicit true if the object is meant to be explicitly + * tagged false otherwise. + * @exception IllegalArgumentException if the tagged object cannot + * be converted. + */ + public static ASN1OctetString getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + ASN1Primitive o = obj.getObject(); + + if (explicit || o instanceof ASN1OctetString) + { + return getInstance(o); + } + else + { + return BEROctetString.fromSequence(ASN1Sequence.getInstance(o)); + } + } + + /** + * return an Octet String from the given object. + * + * @param obj the object we want converted. + * @exception IllegalArgumentException if the object cannot be converted. + */ + public static ASN1OctetString getInstance( + Object obj) + { + if (obj == null || obj instanceof ASN1OctetString) + { + return (ASN1OctetString)obj; + } + else if (obj instanceof byte[]) + { + try + { + return ASN1OctetString.getInstance(ASN1Primitive.fromByteArray((byte[])obj)); + } + catch (IOException e) + { + throw new IllegalArgumentException("failed to construct OCTET STRING from byte[]: " + e.getMessage()); + } + } + else if (obj instanceof ASN1Encodable) + { + ASN1Primitive primitive = ((ASN1Encodable)obj).toASN1Primitive(); + + if (primitive instanceof ASN1OctetString) + { + return (ASN1OctetString)primitive; + } + } + + throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); + } + + /** + * @param string the octets making up the octet string. + */ + public ASN1OctetString( + byte[] string) + { + if (string == null) + { + throw new NullPointerException("string cannot be null"); + } + this.string = string; + } + + public InputStream getOctetStream() + { + return new ByteArrayInputStream(string); + } + + public ASN1OctetStringParser parser() + { + return this; + } + + public byte[] getOctets() + { + return string; + } + + public int hashCode() + { + return Arrays.hashCode(this.getOctets()); + } + + boolean asn1Equals( + ASN1Primitive o) + { + if (!(o instanceof ASN1OctetString)) + { + return false; + } + + ASN1OctetString other = (ASN1OctetString)o; + + return Arrays.areEqual(string, other.string); + } + + public ASN1Primitive getLoadedObject() + { + return this.toASN1Primitive(); + } + + ASN1Primitive toDERObject() + { + return new DEROctetString(string); + } + + ASN1Primitive toDLObject() + { + return new DEROctetString(string); + } + + abstract void encode(ASN1OutputStream out) + throws IOException; + + public String toString() + { + return "#"+new String(Hex.encode(string)); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ASN1OctetStringParser.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ASN1OctetStringParser.java new file mode 100644 index 0000000..a804726 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ASN1OctetStringParser.java @@ -0,0 +1,9 @@ +package org.bc.asn1; + +import java.io.InputStream; + +public interface ASN1OctetStringParser + extends ASN1Encodable, InMemoryRepresentable +{ + public InputStream getOctetStream(); +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ASN1OutputStream.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ASN1OutputStream.java new file mode 100644 index 0000000..957db9f --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ASN1OutputStream.java @@ -0,0 +1,194 @@ +package org.bc.asn1; + +import java.io.IOException; +import java.io.OutputStream; + +/** + * Stream that produces output based on the default encoding for the passed in objects. + */ +public class ASN1OutputStream +{ + private OutputStream os; + + public ASN1OutputStream( + OutputStream os) + { + this.os = os; + } + + void writeLength( + int length) + throws IOException + { + if (length > 127) + { + int size = 1; + int val = length; + + while ((val >>>= 8) != 0) + { + size++; + } + + write((byte)(size | 0x80)); + + for (int i = (size - 1) * 8; i >= 0; i -= 8) + { + write((byte)(length >> i)); + } + } + else + { + write((byte)length); + } + } + + void write(int b) + throws IOException + { + os.write(b); + } + + void write(byte[] bytes) + throws IOException + { + os.write(bytes); + } + + void write(byte[] bytes, int off, int len) + throws IOException + { + os.write(bytes, off, len); + } + + void writeEncoded( + int tag, + byte[] bytes) + throws IOException + { + write(tag); + writeLength(bytes.length); + write(bytes); + } + + void writeTag(int flags, int tagNo) + throws IOException + { + if (tagNo < 31) + { + write(flags | tagNo); + } + else + { + write(flags | 0x1f); + if (tagNo < 128) + { + write(tagNo); + } + else + { + byte[] stack = new byte[5]; + int pos = stack.length; + + stack[--pos] = (byte)(tagNo & 0x7F); + + do + { + tagNo >>= 7; + stack[--pos] = (byte)(tagNo & 0x7F | 0x80); + } + while (tagNo > 127); + + write(stack, pos, stack.length - pos); + } + } + } + + void writeEncoded(int flags, int tagNo, byte[] bytes) + throws IOException + { + writeTag(flags, tagNo); + writeLength(bytes.length); + write(bytes); + } + + protected void writeNull() + throws IOException + { + os.write(BERTags.NULL); + os.write(0x00); + } + + public void writeObject( + ASN1Encodable obj) + throws IOException + { + if (obj != null) + { + obj.toASN1Primitive().encode(this); + } + else + { + throw new IOException("null object detected"); + } + } + + void writeImplicitObject(ASN1Primitive obj) + throws IOException + { + if (obj != null) + { + obj.encode(new ImplicitOutputStream(os)); + } + else + { + throw new IOException("null object detected"); + } + } + + public void close() + throws IOException + { + os.close(); + } + + public void flush() + throws IOException + { + os.flush(); + } + + ASN1OutputStream getDERSubStream() + { + return new DEROutputStream(os); + } + + ASN1OutputStream getDLSubStream() + { + return new DLOutputStream(os); + } + + private class ImplicitOutputStream + extends ASN1OutputStream + { + private boolean first = true; + + public ImplicitOutputStream(OutputStream os) + { + super(os); + } + + public void write(int b) + throws IOException + { + if (first) + { + first = false; + } + else + { + super.write(b); + } + } + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ASN1ParsingException.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ASN1ParsingException.java new file mode 100644 index 0000000..cc40dbd --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ASN1ParsingException.java @@ -0,0 +1,23 @@ +package org.bc.asn1; + +public class ASN1ParsingException + extends IllegalStateException +{ + private Throwable cause; + + public ASN1ParsingException(String message) + { + super(message); + } + + public ASN1ParsingException(String message, Throwable cause) + { + super(message); + this.cause = cause; + } + + public Throwable getCause() + { + return cause; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ASN1Primitive.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ASN1Primitive.java new file mode 100644 index 0000000..6a2a1a4 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ASN1Primitive.java @@ -0,0 +1,69 @@ +package org.bc.asn1; + +import java.io.IOException; + +public abstract class ASN1Primitive + extends ASN1Object +{ + ASN1Primitive() + { + + } + + /** + * Create a base ASN.1 object from a byte stream. + * + * @param data the byte stream to parse. + * @return the base ASN.1 object represented by the byte stream. + * @exception IOException if there is a problem parsing the data. + */ + public static ASN1Primitive fromByteArray(byte[] data) + throws IOException + { + ASN1InputStream aIn = new ASN1InputStream(data); + + try + { + return aIn.readObject(); + } + catch (ClassCastException e) + { + throw new IOException("cannot recognise object in stream"); + } + } + + public final boolean equals(Object o) + { + if (this == o) + { + return true; + } + + return (o instanceof ASN1Encodable) && asn1Equals(((ASN1Encodable)o).toASN1Primitive()); + } + + public ASN1Primitive toASN1Primitive() + { + return this; + } + + ASN1Primitive toDERObject() + { + return this; + } + + ASN1Primitive toDLObject() + { + return this; + } + + public abstract int hashCode(); + + abstract boolean isConstructed(); + + abstract int encodedLength() throws IOException; + + abstract void encode(ASN1OutputStream out) throws IOException; + + abstract boolean asn1Equals(ASN1Primitive o); +} \ No newline at end of file diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ASN1Sequence.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ASN1Sequence.java new file mode 100644 index 0000000..b079ee1 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ASN1Sequence.java @@ -0,0 +1,323 @@ +package org.bc.asn1; + +import java.io.IOException; +import java.util.Enumeration; +import java.util.Vector; + +public abstract class ASN1Sequence + extends ASN1Primitive +{ + protected Vector seq = new Vector(); + + /** + * return an ASN1Sequence from the given object. + * + * @param obj the object we want converted. + * @exception IllegalArgumentException if the object cannot be converted. + */ + public static ASN1Sequence getInstance( + Object obj) + { + if (obj == null || obj instanceof ASN1Sequence) + { + return (ASN1Sequence)obj; + } + else if (obj instanceof ASN1SequenceParser) + { + return ASN1Sequence.getInstance(((ASN1SequenceParser)obj).toASN1Primitive()); + } + else if (obj instanceof byte[]) + { + try + { + return ASN1Sequence.getInstance(fromByteArray((byte[])obj)); + } + catch (IOException e) + { + throw new IllegalArgumentException("failed to construct sequence from byte[]: " + e.getMessage()); + } + } + else if (obj instanceof ASN1Encodable) + { + ASN1Primitive primitive = ((ASN1Encodable)obj).toASN1Primitive(); + + if (primitive instanceof ASN1Sequence) + { + return (ASN1Sequence)primitive; + } + } + + throw new IllegalArgumentException("unknown object in getInstance: " + obj.getClass().getName()); + } + + /** + * Return an ASN1 sequence from a tagged object. There is a special + * case here, if an object appears to have been explicitly tagged on + * reading but we were expecting it to be implicitly tagged in the + * normal course of events it indicates that we lost the surrounding + * sequence - so we need to add it back (this will happen if the tagged + * object is a sequence that contains other sequences). If you are + * dealing with implicitly tagged sequences you really should + * be using this method. + * + * @param obj the tagged object. + * @param explicit true if the object is meant to be explicitly tagged, + * false otherwise. + * @exception IllegalArgumentException if the tagged object cannot + * be converted. + */ + public static ASN1Sequence getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + if (explicit) + { + if (!obj.isExplicit()) + { + throw new IllegalArgumentException("object implicit - explicit expected."); + } + + return ASN1Sequence.getInstance(obj.getObject().toASN1Primitive()); + } + else + { + // + // constructed object which appears to be explicitly tagged + // when it should be implicit means we have to add the + // surrounding sequence. + // + if (obj.isExplicit()) + { + if (obj instanceof BERTaggedObject) + { + return new BERSequence(obj.getObject()); + } + else + { + return new DLSequence(obj.getObject()); + } + } + else + { + if (obj.getObject() instanceof ASN1Sequence) + { + return (ASN1Sequence)obj.getObject(); + } + } + } + + throw new IllegalArgumentException("unknown object in getInstance: " + obj.getClass().getName()); + } + + /** + * create an empty sequence + */ + protected ASN1Sequence() + { + } + + /** + * create a sequence containing one object + */ + protected ASN1Sequence( + ASN1Encodable obj) + { + seq.addElement(obj); + } + + /** + * create a sequence containing a vector of objects. + */ + protected ASN1Sequence( + ASN1EncodableVector v) + { + for (int i = 0; i != v.size(); i++) + { + seq.addElement(v.get(i)); + } + } + + /** + * create a sequence containing a vector of objects. + */ + protected ASN1Sequence( + ASN1Encodable[] array) + { + for (int i = 0; i != array.length; i++) + { + seq.addElement(array[i]); + } + } + + public ASN1Encodable[] toArray() + { + ASN1Encodable[] values = new ASN1Encodable[this.size()]; + + for (int i = 0; i != this.size(); i++) + { + values[i] = this.getObjectAt(i); + } + + return values; + } + + public Enumeration getObjects() + { + return seq.elements(); + } + + public ASN1SequenceParser parser() + { + final ASN1Sequence outer = this; + + return new ASN1SequenceParser() + { + private final int max = size(); + + private int index; + + public ASN1Encodable readObject() throws IOException + { + if (index == max) + { + return null; + } + + ASN1Encodable obj = getObjectAt(index++); + if (obj instanceof ASN1Sequence) + { + return ((ASN1Sequence)obj).parser(); + } + if (obj instanceof ASN1Set) + { + return ((ASN1Set)obj).parser(); + } + + return obj; + } + + public ASN1Primitive getLoadedObject() + { + return outer; + } + + public ASN1Primitive toASN1Primitive() + { + return outer; + } + }; + } + + /** + * return the object at the sequence position indicated by index. + * + * @param index the sequence number (starting at zero) of the object + * @return the object at the sequence position indicated by index. + */ + public ASN1Encodable getObjectAt( + int index) + { + return (ASN1Encodable)seq.elementAt(index); + } + + /** + * return the number of objects in this sequence. + * + * @return the number of objects in this sequence. + */ + public int size() + { + return seq.size(); + } + + public int hashCode() + { + Enumeration e = this.getObjects(); + int hashCode = size(); + + while (e.hasMoreElements()) + { + Object o = getNext(e); + hashCode *= 17; + + hashCode ^= o.hashCode(); + } + + return hashCode; + } + + boolean asn1Equals( + ASN1Primitive o) + { + if (!(o instanceof ASN1Sequence)) + { + return false; + } + + ASN1Sequence other = (ASN1Sequence)o; + + if (this.size() != other.size()) + { + return false; + } + + Enumeration s1 = this.getObjects(); + Enumeration s2 = other.getObjects(); + + while (s1.hasMoreElements()) + { + ASN1Encodable obj1 = getNext(s1); + ASN1Encodable obj2 = getNext(s2); + + ASN1Primitive o1 = obj1.toASN1Primitive(); + ASN1Primitive o2 = obj2.toASN1Primitive(); + + if (o1 == o2 || o1.equals(o2)) + { + continue; + } + + return false; + } + + return true; + } + + private ASN1Encodable getNext(Enumeration e) + { + ASN1Encodable encObj = (ASN1Encodable)e.nextElement(); + + return encObj; + } + + ASN1Primitive toDERObject() + { + ASN1Sequence derSeq = new DERSequence(); + + derSeq.seq = this.seq; + + return derSeq; + } + + ASN1Primitive toDLObject() + { + ASN1Sequence dlSeq = new DLSequence(); + + dlSeq.seq = this.seq; + + return dlSeq; + } + + boolean isConstructed() + { + return true; + } + + abstract void encode(ASN1OutputStream out) + throws IOException; + + public String toString() + { + return seq.toString(); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ASN1SequenceParser.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ASN1SequenceParser.java new file mode 100644 index 0000000..c26dbf9 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ASN1SequenceParser.java @@ -0,0 +1,10 @@ +package org.bc.asn1; + +import java.io.IOException; + +public interface ASN1SequenceParser + extends ASN1Encodable, InMemoryRepresentable +{ + ASN1Encodable readObject() + throws IOException; +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ASN1Set.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ASN1Set.java new file mode 100644 index 0000000..806b891 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ASN1Set.java @@ -0,0 +1,460 @@ +package org.bc.asn1; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.Enumeration; +import java.util.Vector; + +abstract public class ASN1Set + extends ASN1Primitive +{ + private Vector set = new Vector(); + private boolean isSorted = false; + + /** + * return an ASN1Set from the given object. + * + * @param obj the object we want converted. + * @exception IllegalArgumentException if the object cannot be converted. + */ + public static ASN1Set getInstance( + Object obj) + { + if (obj == null || obj instanceof ASN1Set) + { + return (ASN1Set)obj; + } + else if (obj instanceof ASN1SetParser) + { + return ASN1Set.getInstance(((ASN1SetParser)obj).toASN1Primitive()); + } + else if (obj instanceof byte[]) + { + try + { + return ASN1Set.getInstance(ASN1Primitive.fromByteArray((byte[])obj)); + } + catch (IOException e) + { + throw new IllegalArgumentException("failed to construct set from byte[]: " + e.getMessage()); + } + } + else if (obj instanceof ASN1Encodable) + { + ASN1Primitive primitive = ((ASN1Encodable)obj).toASN1Primitive(); + + if (primitive instanceof ASN1Set) + { + return (ASN1Set)primitive; + } + } + + throw new IllegalArgumentException("unknown object in getInstance: " + obj.getClass().getName()); + } + + /** + * Return an ASN1 set from a tagged object. There is a special + * case here, if an object appears to have been explicitly tagged on + * reading but we were expecting it to be implicitly tagged in the + * normal course of events it indicates that we lost the surrounding + * set - so we need to add it back (this will happen if the tagged + * object is a sequence that contains other sequences). If you are + * dealing with implicitly tagged sets you really should + * be using this method. + * + * @param obj the tagged object. + * @param explicit true if the object is meant to be explicitly tagged + * false otherwise. + * @exception IllegalArgumentException if the tagged object cannot + * be converted. + */ + public static ASN1Set getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + if (explicit) + { + if (!obj.isExplicit()) + { + throw new IllegalArgumentException("object implicit - explicit expected."); + } + + return (ASN1Set)obj.getObject(); + } + else + { + // + // constructed object which appears to be explicitly tagged + // and it's really implicit means we have to add the + // surrounding set. + // + if (obj.isExplicit()) + { + if (obj instanceof BERTaggedObject) + { + return new BERSet(obj.getObject()); + } + else + { + return new DLSet(obj.getObject()); + } + } + else + { + if (obj.getObject() instanceof ASN1Set) + { + return (ASN1Set)obj.getObject(); + } + + // + // in this case the parser returns a sequence, convert it + // into a set. + // + if (obj.getObject() instanceof ASN1Sequence) + { + ASN1Sequence s = (ASN1Sequence)obj.getObject(); + + if (obj instanceof BERTaggedObject) + { + return new BERSet(s.toArray()); + } + else + { + return new DLSet(s.toArray()); + } + } + } + } + + throw new IllegalArgumentException("unknown object in getInstance: " + obj.getClass().getName()); + } + + protected ASN1Set() + { + } + + /** + * create a sequence containing one object + */ + protected ASN1Set( + ASN1Encodable obj) + { + set.addElement(obj); + } + + /** + * create a sequence containing a vector of objects. + */ + protected ASN1Set( + ASN1EncodableVector v, + boolean doSort) + { + for (int i = 0; i != v.size(); i++) + { + set.addElement(v.get(i)); + } + + if (doSort) + { + this.sort(); + } + } + + /** + * create a sequence containing a vector of objects. + */ + protected ASN1Set( + ASN1Encodable[] array, + boolean doSort) + { + for (int i = 0; i != array.length; i++) + { + set.addElement(array[i]); + } + + if (doSort) + { + this.sort(); + } + } + + public Enumeration getObjects() + { + return set.elements(); + } + + /** + * return the object at the set position indicated by index. + * + * @param index the set number (starting at zero) of the object + * @return the object at the set position indicated by index. + */ + public ASN1Encodable getObjectAt( + int index) + { + return (ASN1Encodable)set.elementAt(index); + } + + /** + * return the number of objects in this set. + * + * @return the number of objects in this set. + */ + public int size() + { + return set.size(); + } + + public ASN1Encodable[] toArray() + { + ASN1Encodable[] values = new ASN1Encodable[this.size()]; + + for (int i = 0; i != this.size(); i++) + { + values[i] = this.getObjectAt(i); + } + + return values; + } + + public ASN1SetParser parser() + { + final ASN1Set outer = this; + + return new ASN1SetParser() + { + private final int max = size(); + + private int index; + + public ASN1Encodable readObject() throws IOException + { + if (index == max) + { + return null; + } + + ASN1Encodable obj = getObjectAt(index++); + if (obj instanceof ASN1Sequence) + { + return ((ASN1Sequence)obj).parser(); + } + if (obj instanceof ASN1Set) + { + return ((ASN1Set)obj).parser(); + } + + return obj; + } + + public ASN1Primitive getLoadedObject() + { + return outer; + } + + public ASN1Primitive toASN1Primitive() + { + return outer; + } + }; + } + + public int hashCode() + { + Enumeration e = this.getObjects(); + int hashCode = size(); + + while (e.hasMoreElements()) + { + Object o = getNext(e); + hashCode *= 17; + + hashCode ^= o.hashCode(); + } + + return hashCode; + } + + ASN1Primitive toDERObject() + { + if (isSorted) + { + ASN1Set derSet = new DERSet(); + + derSet.set = this.set; + + return derSet; + } + else + { + Vector v = new Vector(); + + for (int i = 0; i != set.size(); i++) + { + v.addElement(set.elementAt(i)); + } + + ASN1Set derSet = new DERSet(); + + derSet.set = v; + + derSet.sort(); + + return derSet; + } + } + + ASN1Primitive toDLObject() + { + ASN1Set derSet = new DLSet(); + + derSet.set = this.set; + + return derSet; + } + + boolean asn1Equals( + ASN1Primitive o) + { + if (!(o instanceof ASN1Set)) + { + return false; + } + + ASN1Set other = (ASN1Set)o; + + if (this.size() != other.size()) + { + return false; + } + + Enumeration s1 = this.getObjects(); + Enumeration s2 = other.getObjects(); + + while (s1.hasMoreElements()) + { + ASN1Encodable obj1 = getNext(s1); + ASN1Encodable obj2 = getNext(s2); + + ASN1Primitive o1 = obj1.toASN1Primitive(); + ASN1Primitive o2 = obj2.toASN1Primitive(); + + if (o1 == o2 || o1.equals(o2)) + { + continue; + } + + return false; + } + + return true; + } + + private ASN1Encodable getNext(Enumeration e) + { + ASN1Encodable encObj = (ASN1Encodable)e.nextElement(); + + // unfortunately null was allowed as a substitute for DER null + if (encObj == null) + { + return DERNull.INSTANCE; + } + + return encObj; + } + + /** + * return true if a <= b (arrays are assumed padded with zeros). + */ + private boolean lessThanOrEqual( + byte[] a, + byte[] b) + { + int len = Math.min(a.length, b.length); + for (int i = 0; i != len; ++i) + { + if (a[i] != b[i]) + { + return (a[i] & 0xff) < (b[i] & 0xff); + } + } + return len == a.length; + } + + private byte[] getEncoded( + ASN1Encodable obj) + { + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + ASN1OutputStream aOut = new ASN1OutputStream(bOut); + + try + { + aOut.writeObject(obj); + } + catch (IOException e) + { + throw new IllegalArgumentException("cannot encode object added to SET"); + } + + return bOut.toByteArray(); + } + + protected void sort() + { + if (!isSorted) + { + isSorted = true; + if (set.size() > 1) + { + boolean swapped = true; + int lastSwap = set.size() - 1; + + while (swapped) + { + int index = 0; + int swapIndex = 0; + byte[] a = getEncoded((ASN1Encodable)set.elementAt(0)); + + swapped = false; + + while (index != lastSwap) + { + byte[] b = getEncoded((ASN1Encodable)set.elementAt(index + 1)); + + if (lessThanOrEqual(a, b)) + { + a = b; + } + else + { + Object o = set.elementAt(index); + + set.setElementAt(set.elementAt(index + 1), index); + set.setElementAt(o, index + 1); + + swapped = true; + swapIndex = index; + } + + index++; + } + + lastSwap = swapIndex; + } + } + } + } + + boolean isConstructed() + { + return true; + } + + abstract void encode(ASN1OutputStream out) + throws IOException; + + public String toString() + { + return set.toString(); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ASN1SetParser.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ASN1SetParser.java new file mode 100644 index 0000000..7a29ee9 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ASN1SetParser.java @@ -0,0 +1,10 @@ +package org.bc.asn1; + +import java.io.IOException; + +public interface ASN1SetParser + extends ASN1Encodable, InMemoryRepresentable +{ + public ASN1Encodable readObject() + throws IOException; +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ASN1StreamParser.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ASN1StreamParser.java new file mode 100644 index 0000000..07b589f --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ASN1StreamParser.java @@ -0,0 +1,247 @@ +package org.bc.asn1; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; + +public class ASN1StreamParser +{ + private final InputStream _in; + private final int _limit; + private final byte[][] tmpBuffers; + + public ASN1StreamParser( + InputStream in) + { + this(in, StreamUtil.findLimit(in)); + } + + public ASN1StreamParser( + InputStream in, + int limit) + { + this._in = in; + this._limit = limit; + + this.tmpBuffers = new byte[11][]; + } + + public ASN1StreamParser( + byte[] encoding) + { + this(new ByteArrayInputStream(encoding), encoding.length); + } + + ASN1Encodable readIndef(int tagValue) throws IOException + { + // Note: INDEF => CONSTRUCTED + + // TODO There are other tags that may be constructed (e.g. BIT_STRING) + switch (tagValue) + { + case BERTags.EXTERNAL: + return new DERExternalParser(this); + case BERTags.OCTET_STRING: + return new BEROctetStringParser(this); + case BERTags.SEQUENCE: + return new BERSequenceParser(this); + case BERTags.SET: + return new BERSetParser(this); + default: + throw new ASN1Exception("unknown BER object encountered: 0x" + Integer.toHexString(tagValue)); + } + } + + ASN1Encodable readImplicit(boolean constructed, int tag) throws IOException + { + if (_in instanceof IndefiniteLengthInputStream) + { + if (!constructed) + { + throw new IOException("indefinite length primitive encoding encountered"); + } + + return readIndef(tag); + } + + if (constructed) + { + switch (tag) + { + case BERTags.SET: + return new DERSetParser(this); + case BERTags.SEQUENCE: + return new DERSequenceParser(this); + case BERTags.OCTET_STRING: + return new BEROctetStringParser(this); + } + } + else + { + switch (tag) + { + case BERTags.SET: + throw new ASN1Exception("sequences must use constructed encoding (see X.690 8.9.1/8.10.1)"); + case BERTags.SEQUENCE: + throw new ASN1Exception("sets must use constructed encoding (see X.690 8.11.1/8.12.1)"); + case BERTags.OCTET_STRING: + return new DEROctetStringParser((DefiniteLengthInputStream)_in); + } + } + + // TODO ASN1Exception + throw new RuntimeException("implicit tagging not implemented"); + } + + ASN1Primitive readTaggedObject(boolean constructed, int tag) throws IOException + { + if (!constructed) + { + // Note: !CONSTRUCTED => IMPLICIT + DefiniteLengthInputStream defIn = (DefiniteLengthInputStream)_in; + return new DERTaggedObject(false, tag, new DEROctetString(defIn.toByteArray())); + } + + ASN1EncodableVector v = readVector(); + + if (_in instanceof IndefiniteLengthInputStream) + { + return v.size() == 1 + ? new BERTaggedObject(true, tag, v.get(0)) + : new BERTaggedObject(false, tag, BERFactory.createSequence(v)); + } + + return v.size() == 1 + ? new DERTaggedObject(true, tag, v.get(0)) + : new DERTaggedObject(false, tag, DERFactory.createSequence(v)); + } + + public ASN1Encodable readObject() + throws IOException + { + int tag = _in.read(); + if (tag == -1) + { + return null; + } + + // + // turn of looking for "00" while we resolve the tag + // + set00Check(false); + + // + // calculate tag number + // + int tagNo = ASN1InputStream.readTagNumber(_in, tag); + + boolean isConstructed = (tag & BERTags.CONSTRUCTED) != 0; + + // + // calculate length + // + int length = ASN1InputStream.readLength(_in, _limit); + + if (length < 0) // indefinite length method + { + if (!isConstructed) + { + throw new IOException("indefinite length primitive encoding encountered"); + } + + IndefiniteLengthInputStream indIn = new IndefiniteLengthInputStream(_in, _limit); + ASN1StreamParser sp = new ASN1StreamParser(indIn, _limit); + + if ((tag & BERTags.APPLICATION) != 0) + { + return new BERApplicationSpecificParser(tagNo, sp); + } + + if ((tag & BERTags.TAGGED) != 0) + { + return new BERTaggedObjectParser(true, tagNo, sp); + } + + return sp.readIndef(tagNo); + } + else + { + DefiniteLengthInputStream defIn = new DefiniteLengthInputStream(_in, length); + + if ((tag & BERTags.APPLICATION) != 0) + { + return new DERApplicationSpecific(isConstructed, tagNo, defIn.toByteArray()); + } + + if ((tag & BERTags.TAGGED) != 0) + { + return new BERTaggedObjectParser(isConstructed, tagNo, new ASN1StreamParser(defIn)); + } + + if (isConstructed) + { + // TODO There are other tags that may be constructed (e.g. BIT_STRING) + switch (tagNo) + { + case BERTags.OCTET_STRING: + // + // yes, people actually do this... + // + return new BEROctetStringParser(new ASN1StreamParser(defIn)); + case BERTags.SEQUENCE: + return new DERSequenceParser(new ASN1StreamParser(defIn)); + case BERTags.SET: + return new DERSetParser(new ASN1StreamParser(defIn)); + case BERTags.EXTERNAL: + return new DERExternalParser(new ASN1StreamParser(defIn)); + default: + throw new IOException("unknown tag " + tagNo + " encountered"); + } + } + + // Some primitive encodings can be handled by parsers too... + switch (tagNo) + { + case BERTags.OCTET_STRING: + return new DEROctetStringParser(defIn); + } + + try + { + return ASN1InputStream.createPrimitiveDERObject(tagNo, defIn, tmpBuffers); + } + catch (IllegalArgumentException e) + { + throw new ASN1Exception("corrupted stream detected", e); + } + } + } + + private void set00Check(boolean enabled) + { + if (_in instanceof IndefiniteLengthInputStream) + { + ((IndefiniteLengthInputStream)_in).setEofOn00(enabled); + } + } + + ASN1EncodableVector readVector() throws IOException + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + ASN1Encodable obj; + while ((obj = readObject()) != null) + { + if (obj instanceof InMemoryRepresentable) + { + v.add(((InMemoryRepresentable)obj).getLoadedObject()); + } + else + { + v.add(obj.toASN1Primitive()); + } + } + + return v; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ASN1String.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ASN1String.java new file mode 100644 index 0000000..187f364 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ASN1String.java @@ -0,0 +1,6 @@ +package org.bc.asn1; + +public interface ASN1String +{ + public String getString(); +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ASN1TaggedObject.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ASN1TaggedObject.java new file mode 100644 index 0000000..5fcff1c --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ASN1TaggedObject.java @@ -0,0 +1,236 @@ +package org.bc.asn1; + +import java.io.IOException; + +/** + * ASN.1 TaggedObject - in ASN.1 notation this is any object preceded by + * a [n] where n is some number - these are assumed to follow the construction + * rules (as with sequences). + */ +public abstract class ASN1TaggedObject + extends ASN1Primitive + implements ASN1TaggedObjectParser +{ + int tagNo; + boolean empty = false; + boolean explicit = true; + ASN1Encodable obj = null; + + static public ASN1TaggedObject getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + if (explicit) + { + return (ASN1TaggedObject)obj.getObject(); + } + + throw new IllegalArgumentException("implicitly tagged tagged object"); + } + + static public ASN1TaggedObject getInstance( + Object obj) + { + if (obj == null || obj instanceof ASN1TaggedObject) + { + return (ASN1TaggedObject)obj; + } + else if (obj instanceof byte[]) + { + try + { + return ASN1TaggedObject.getInstance(fromByteArray((byte[])obj)); + } + catch (IOException e) + { + throw new IllegalArgumentException("failed to construct tagged object from byte[]: " + e.getMessage()); + } + } + + throw new IllegalArgumentException("unknown object in getInstance: " + obj.getClass().getName()); + } + + /** + * Create a tagged object with the style given by the value of explicit. + *
+ * If the object implements ASN1Choice the tag style will always be changed + * to explicit in accordance with the ASN.1 encoding rules. + *
+ * @param explicit true if the object is explicitly tagged. + * @param tagNo the tag number for this object. + * @param obj the tagged object. + */ + public ASN1TaggedObject( + boolean explicit, + int tagNo, + ASN1Encodable obj) + { + if (obj instanceof ASN1Choice) + { + this.explicit = true; + } + else + { + this.explicit = explicit; + } + + this.tagNo = tagNo; + + if (this.explicit) + { + this.obj = obj; + } + else + { + ASN1Primitive prim = obj.toASN1Primitive(); + + if (prim instanceof ASN1Set) + { + ASN1Set s = null; + } + + this.obj = obj; + } + } + + boolean asn1Equals( + ASN1Primitive o) + { + if (!(o instanceof ASN1TaggedObject)) + { + return false; + } + + ASN1TaggedObject other = (ASN1TaggedObject)o; + + if (tagNo != other.tagNo || empty != other.empty || explicit != other.explicit) + { + return false; + } + + if(obj == null) + { + if (other.obj != null) + { + return false; + } + } + else + { + if (!(obj.toASN1Primitive().equals(other.obj.toASN1Primitive()))) + { + return false; + } + } + + return true; + } + + public int hashCode() + { + int code = tagNo; + + // TODO: actually this is wrong - the problem is that a re-encoded + // object may end up with a different hashCode due to implicit + // tagging. As implicit tagging is ambiguous if a sequence is involved + // it seems the only correct method for both equals and hashCode is to + // compare the encodings... + if (obj != null) + { + code ^= obj.hashCode(); + } + + return code; + } + + public int getTagNo() + { + return tagNo; + } + + /** + * return whether or not the object may be explicitly tagged. + *+ * Note: if the object has been read from an input stream, the only + * time you can be sure if isExplicit is returning the true state of + * affairs is if it returns false. An implicitly tagged object may appear + * to be explicitly tagged, so you need to understand the context under + * which the reading was done as well, see getObject below. + */ + public boolean isExplicit() + { + return explicit; + } + + public boolean isEmpty() + { + return empty; + } + + /** + * return whatever was following the tag. + *
+ * Note: tagged objects are generally context dependent if you're
+ * trying to extract a tagged object you should be going via the
+ * appropriate getInstance method.
+ */
+ public ASN1Primitive getObject()
+ {
+ if (obj != null)
+ {
+ return obj.toASN1Primitive();
+ }
+
+ return null;
+ }
+
+ /**
+ * Return the object held in this tagged object as a parser assuming it has
+ * the type of the passed in tag. If the object doesn't have a parser
+ * associated with it, the base object is returned.
+ */
+ public ASN1Encodable getObjectParser(
+ int tag,
+ boolean isExplicit)
+ {
+ switch (tag)
+ {
+ case BERTags.SET:
+ return ASN1Set.getInstance(this, isExplicit).parser();
+ case BERTags.SEQUENCE:
+ return ASN1Sequence.getInstance(this, isExplicit).parser();
+ case BERTags.OCTET_STRING:
+ return ASN1OctetString.getInstance(this, isExplicit).parser();
+ }
+
+ if (isExplicit)
+ {
+ return getObject();
+ }
+
+ throw new RuntimeException("implicit tagging not implemented for tag: " + tag);
+ }
+
+ public ASN1Primitive getLoadedObject()
+ {
+ return this.toASN1Primitive();
+ }
+
+ ASN1Primitive toDERObject()
+ {
+ return new DERTaggedObject(explicit, tagNo, obj);
+ }
+
+ ASN1Primitive toDLObject()
+ {
+ return new DLTaggedObject(explicit, tagNo, obj);
+ }
+
+ abstract void encode(ASN1OutputStream out)
+ throws IOException;
+
+ public String toString()
+ {
+ return "[" + tagNo + "]" + obj;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ASN1TaggedObjectParser.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ASN1TaggedObjectParser.java
new file mode 100644
index 0000000..93d5378
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ASN1TaggedObjectParser.java
@@ -0,0 +1,12 @@
+package org.bc.asn1;
+
+import java.io.IOException;
+
+public interface ASN1TaggedObjectParser
+ extends ASN1Encodable, InMemoryRepresentable
+{
+ public int getTagNo();
+
+ public ASN1Encodable getObjectParser(int tag, boolean isExplicit)
+ throws IOException;
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ASN1UTCTime.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ASN1UTCTime.java
new file mode 100644
index 0000000..c6eff82
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ASN1UTCTime.java
@@ -0,0 +1,22 @@
+package org.bc.asn1;
+
+import java.util.Date;
+
+public class ASN1UTCTime
+ extends DERUTCTime
+{
+ ASN1UTCTime(byte[] bytes)
+ {
+ super(bytes);
+ }
+
+ public ASN1UTCTime(Date time)
+ {
+ super(time);
+ }
+
+ public ASN1UTCTime(String time)
+ {
+ super(time);
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/BERApplicationSpecific.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/BERApplicationSpecific.java
new file mode 100644
index 0000000..5510f2e
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/BERApplicationSpecific.java
@@ -0,0 +1,10 @@
+package org.bc.asn1;
+
+public class BERApplicationSpecific
+ extends DERApplicationSpecific
+{
+ public BERApplicationSpecific(int tagNo, ASN1EncodableVector vec)
+ {
+ super(tagNo, vec);
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/BERApplicationSpecificParser.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/BERApplicationSpecificParser.java
new file mode 100644
index 0000000..293edf1
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/BERApplicationSpecificParser.java
@@ -0,0 +1,41 @@
+package org.bc.asn1;
+
+import java.io.IOException;
+
+public class BERApplicationSpecificParser
+ implements ASN1ApplicationSpecificParser
+{
+ private final int tag;
+ private final ASN1StreamParser parser;
+
+ BERApplicationSpecificParser(int tag, ASN1StreamParser parser)
+ {
+ this.tag = tag;
+ this.parser = parser;
+ }
+
+ public ASN1Encodable readObject()
+ throws IOException
+ {
+ return parser.readObject();
+ }
+
+ public ASN1Primitive getLoadedObject()
+ throws IOException
+ {
+ return new BERApplicationSpecific(tag, parser.readVector());
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+ try
+ {
+ return getLoadedObject();
+ }
+ catch (IOException e)
+ {
+ throw new ASN1ParsingException(e.getMessage(), e);
+ }
+ }
+
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/BERConstructedOctetString.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/BERConstructedOctetString.java
new file mode 100644
index 0000000..d0ad7ed
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/BERConstructedOctetString.java
@@ -0,0 +1,144 @@
+package org.bc.asn1;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.Vector;
+
+/**
+ * @deprecated use BEROctetString
+ */
+public class BERConstructedOctetString
+ extends BEROctetString
+{
+ private static final int MAX_LENGTH = 1000;
+
+ /**
+ * convert a vector of octet strings into a single byte string
+ */
+ static private byte[] toBytes(
+ Vector octs)
+ {
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ for (int i = 0; i != octs.size(); i++)
+ {
+ try
+ {
+ DEROctetString o = (DEROctetString)octs.elementAt(i);
+
+ bOut.write(o.getOctets());
+ }
+ catch (ClassCastException e)
+ {
+ throw new IllegalArgumentException(octs.elementAt(i).getClass().getName() + " found in input should only contain DEROctetString");
+ }
+ catch (IOException e)
+ {
+ throw new IllegalArgumentException("exception converting octets " + e.toString());
+ }
+ }
+
+ return bOut.toByteArray();
+ }
+
+ private Vector octs;
+
+ /**
+ * @param string the octets making up the octet string.
+ */
+ public BERConstructedOctetString(
+ byte[] string)
+ {
+ super(string);
+ }
+
+ public BERConstructedOctetString(
+ Vector octs)
+ {
+ super(toBytes(octs));
+
+ this.octs = octs;
+ }
+
+ public BERConstructedOctetString(
+ ASN1Primitive obj)
+ {
+ super(toByteArray(obj));
+ }
+
+ private static byte[] toByteArray(ASN1Primitive obj)
+ {
+ try
+ {
+ return obj.getEncoded();
+ }
+ catch (IOException e)
+ {
+ throw new IllegalArgumentException("Unable to encode object");
+ }
+ }
+
+ public BERConstructedOctetString(
+ ASN1Encodable obj)
+ {
+ this(obj.toASN1Primitive());
+ }
+
+ public byte[] getOctets()
+ {
+ return string;
+ }
+
+ /**
+ * return the DER octets that make up this string.
+ */
+ public Enumeration getObjects()
+ {
+ if (octs == null)
+ {
+ return generateOcts().elements();
+ }
+
+ return octs.elements();
+ }
+
+ private Vector generateOcts()
+ {
+ Vector vec = new Vector();
+ for (int i = 0; i < string.length; i += MAX_LENGTH)
+ {
+ int end;
+
+ if (i + MAX_LENGTH > string.length)
+ {
+ end = string.length;
+ }
+ else
+ {
+ end = i + MAX_LENGTH;
+ }
+
+ byte[] nStr = new byte[end - i];
+
+ System.arraycopy(string, i, nStr, 0, nStr.length);
+
+ vec.addElement(new DEROctetString(nStr));
+ }
+
+ return vec;
+ }
+
+ public static BEROctetString fromSequence(ASN1Sequence seq)
+ {
+ Vector v = new Vector();
+ Enumeration e = seq.getObjects();
+
+ while (e.hasMoreElements())
+ {
+ v.addElement(e.nextElement());
+ }
+
+ return new BERConstructedOctetString(v);
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/BERFactory.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/BERFactory.java
new file mode 100644
index 0000000..41d4d51
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/BERFactory.java
@@ -0,0 +1,17 @@
+package org.bc.asn1;
+
+class BERFactory
+{
+ static final BERSequence EMPTY_SEQUENCE = new BERSequence();
+ static final BERSet EMPTY_SET = new BERSet();
+
+ static BERSequence createSequence(ASN1EncodableVector v)
+ {
+ return v.size() < 1 ? EMPTY_SEQUENCE : new BERSequence(v);
+ }
+
+ static BERSet createSet(ASN1EncodableVector v)
+ {
+ return v.size() < 1 ? EMPTY_SET : new BERSet(v);
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/BERGenerator.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/BERGenerator.java
new file mode 100644
index 0000000..d143647
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/BERGenerator.java
@@ -0,0 +1,100 @@
+package org.bc.asn1;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+public class BERGenerator
+ extends ASN1Generator
+{
+ private boolean _tagged = false;
+ private boolean _isExplicit;
+ private int _tagNo;
+
+ protected BERGenerator(
+ OutputStream out)
+ {
+ super(out);
+ }
+
+ public BERGenerator(
+ OutputStream out,
+ int tagNo,
+ boolean isExplicit)
+ {
+ super(out);
+
+ _tagged = true;
+ _isExplicit = isExplicit;
+ _tagNo = tagNo;
+ }
+
+ public OutputStream getRawOutputStream()
+ {
+ return _out;
+ }
+
+ private void writeHdr(
+ int tag)
+ throws IOException
+ {
+ _out.write(tag);
+ _out.write(0x80);
+ }
+
+ protected void writeBERHeader(
+ int tag)
+ throws IOException
+ {
+ if (_tagged)
+ {
+ int tagNum = _tagNo | BERTags.TAGGED;
+
+ if (_isExplicit)
+ {
+ writeHdr(tagNum | BERTags.CONSTRUCTED);
+ writeHdr(tag);
+ }
+ else
+ {
+ if ((tag & BERTags.CONSTRUCTED) != 0)
+ {
+ writeHdr(tagNum | BERTags.CONSTRUCTED);
+ }
+ else
+ {
+ writeHdr(tagNum);
+ }
+ }
+ }
+ else
+ {
+ writeHdr(tag);
+ }
+ }
+
+ protected void writeBERBody(
+ InputStream contentStream)
+ throws IOException
+ {
+ int ch;
+
+ while ((ch = contentStream.read()) >= 0)
+ {
+ _out.write(ch);
+ }
+ }
+
+ protected void writeBEREnd()
+ throws IOException
+ {
+ _out.write(0x00);
+ _out.write(0x00);
+
+ if (_tagged && _isExplicit) // write extra end for tag header
+ {
+ _out.write(0x00);
+ _out.write(0x00);
+ }
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/BEROctetString.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/BEROctetString.java
new file mode 100644
index 0000000..49f71fe
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/BEROctetString.java
@@ -0,0 +1,168 @@
+package org.bc.asn1;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.Vector;
+
+public class BEROctetString
+ extends ASN1OctetString
+{
+ private static final int MAX_LENGTH = 1000;
+
+ private ASN1OctetString[] octs;
+
+ /**
+ * convert a vector of octet strings into a single byte string
+ */
+ static private byte[] toBytes(
+ ASN1OctetString[] octs)
+ {
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ for (int i = 0; i != octs.length; i++)
+ {
+ try
+ {
+ DEROctetString o = (DEROctetString)octs[i];
+
+ bOut.write(o.getOctets());
+ }
+ catch (ClassCastException e)
+ {
+ throw new IllegalArgumentException(octs[i].getClass().getName() + " found in input should only contain DEROctetString");
+ }
+ catch (IOException e)
+ {
+ throw new IllegalArgumentException("exception converting octets " + e.toString());
+ }
+ }
+
+ return bOut.toByteArray();
+ }
+
+ /**
+ * @param string the octets making up the octet string.
+ */
+ public BEROctetString(
+ byte[] string)
+ {
+ super(string);
+ }
+
+ public BEROctetString(
+ ASN1OctetString[] octs)
+ {
+ super(toBytes(octs));
+
+ this.octs = octs;
+ }
+
+ public byte[] getOctets()
+ {
+ return string;
+ }
+
+ /**
+ * return the DER octets that make up this string.
+ */
+ public Enumeration getObjects()
+ {
+ if (octs == null)
+ {
+ return generateOcts().elements();
+ }
+
+ return new Enumeration()
+ {
+ int counter = 0;
+
+ public boolean hasMoreElements()
+ {
+ return counter < octs.length;
+ }
+
+ public Object nextElement()
+ {
+ return octs[counter++];
+ }
+ };
+ }
+
+ private Vector generateOcts()
+ {
+ Vector vec = new Vector();
+ for (int i = 0; i < string.length; i += MAX_LENGTH)
+ {
+ int end;
+
+ if (i + MAX_LENGTH > string.length)
+ {
+ end = string.length;
+ }
+ else
+ {
+ end = i + MAX_LENGTH;
+ }
+
+ byte[] nStr = new byte[end - i];
+
+ System.arraycopy(string, i, nStr, 0, nStr.length);
+
+ vec.addElement(new DEROctetString(nStr));
+ }
+
+ return vec;
+ }
+
+ boolean isConstructed()
+ {
+ return true;
+ }
+
+ int encodedLength()
+ throws IOException
+ {
+ int length = 0;
+ for (Enumeration e = getObjects(); e.hasMoreElements();)
+ {
+ length += ((ASN1Encodable)e.nextElement()).toASN1Primitive().encodedLength();
+ }
+
+ return 2 + length + 2;
+ }
+
+ public void encode(
+ ASN1OutputStream out)
+ throws IOException
+ {
+ out.write(BERTags.CONSTRUCTED | BERTags.OCTET_STRING);
+
+ out.write(0x80);
+
+ //
+ // write out the octet array
+ //
+ for (Enumeration e = getObjects(); e.hasMoreElements();)
+ {
+ out.writeObject((ASN1Encodable)e.nextElement());
+ }
+
+ out.write(0x00);
+ out.write(0x00);
+ }
+
+ static BEROctetString fromSequence(ASN1Sequence seq)
+ {
+ ASN1OctetString[] v = new ASN1OctetString[seq.size()];
+ Enumeration e = seq.getObjects();
+ int index = 0;
+
+ while (e.hasMoreElements())
+ {
+ v[index++] = (ASN1OctetString)e.nextElement();
+ }
+
+ return new BEROctetString(v);
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/BEROctetStringGenerator.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/BEROctetStringGenerator.java
new file mode 100644
index 0000000..2c16db5
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/BEROctetStringGenerator.java
@@ -0,0 +1,102 @@
+package org.bc.asn1;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+public class BEROctetStringGenerator
+ extends BERGenerator
+{
+ public BEROctetStringGenerator(OutputStream out)
+ throws IOException
+ {
+ super(out);
+
+ writeBERHeader(BERTags.CONSTRUCTED | BERTags.OCTET_STRING);
+ }
+
+ public BEROctetStringGenerator(
+ OutputStream out,
+ int tagNo,
+ boolean isExplicit)
+ throws IOException
+ {
+ super(out, tagNo, isExplicit);
+
+ writeBERHeader(BERTags.CONSTRUCTED | BERTags.OCTET_STRING);
+ }
+
+ public OutputStream getOctetOutputStream()
+ {
+ return getOctetOutputStream(new byte[1000]); // limit for CER encoding.
+ }
+
+ public OutputStream getOctetOutputStream(
+ byte[] buf)
+ {
+ return new BufferedBEROctetStream(buf);
+ }
+
+ private class BufferedBEROctetStream
+ extends OutputStream
+ {
+ private byte[] _buf;
+ private int _off;
+ private DEROutputStream _derOut;
+
+ BufferedBEROctetStream(
+ byte[] buf)
+ {
+ _buf = buf;
+ _off = 0;
+ _derOut = new DEROutputStream(_out);
+ }
+
+ public void write(
+ int b)
+ throws IOException
+ {
+ _buf[_off++] = (byte)b;
+
+ if (_off == _buf.length)
+ {
+ DEROctetString.encode(_derOut, _buf);
+ _off = 0;
+ }
+ }
+
+ public void write(byte[] b, int off, int len) throws IOException
+ {
+ while (len > 0)
+ {
+ int numToCopy = Math.min(len, _buf.length - _off);
+ System.arraycopy(b, off, _buf, _off, numToCopy);
+
+ _off += numToCopy;
+ if (_off < _buf.length)
+ {
+ break;
+ }
+
+ DEROctetString.encode(_derOut, _buf);
+ _off = 0;
+
+ off += numToCopy;
+ len -= numToCopy;
+ }
+ }
+
+ public void close()
+ throws IOException
+ {
+ if (_off != 0)
+ {
+ byte[] bytes = new byte[_off];
+ System.arraycopy(_buf, 0, bytes, 0, _off);
+
+ DEROctetString.encode(_derOut, bytes);
+ }
+
+ writeBEREnd();
+ }
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/BEROctetStringParser.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/BEROctetStringParser.java
new file mode 100644
index 0000000..3dde143
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/BEROctetStringParser.java
@@ -0,0 +1,41 @@
+package org.bc.asn1;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.bc.util.io.Streams;
+
+public class BEROctetStringParser
+ implements ASN1OctetStringParser
+{
+ private ASN1StreamParser _parser;
+
+ BEROctetStringParser(
+ ASN1StreamParser parser)
+ {
+ _parser = parser;
+ }
+
+ public InputStream getOctetStream()
+ {
+ return new ConstructedOctetStream(_parser);
+ }
+
+ public ASN1Primitive getLoadedObject()
+ throws IOException
+ {
+ return new BEROctetString(Streams.readAll(getOctetStream()));
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+ try
+ {
+ return getLoadedObject();
+ }
+ catch (IOException e)
+ {
+ throw new ASN1ParsingException("IOException converting stream to byte array: " + e.getMessage(), e);
+ }
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/BEROutputStream.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/BEROutputStream.java
new file mode 100644
index 0000000..787f1bd
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/BEROutputStream.java
@@ -0,0 +1,36 @@
+package org.bc.asn1;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+public class BEROutputStream
+ extends DEROutputStream
+{
+ public BEROutputStream(
+ OutputStream os)
+ {
+ super(os);
+ }
+
+ public void writeObject(
+ Object obj)
+ throws IOException
+ {
+ if (obj == null)
+ {
+ writeNull();
+ }
+ else if (obj instanceof ASN1Primitive)
+ {
+ ((ASN1Primitive)obj).encode(this);
+ }
+ else if (obj instanceof ASN1Encodable)
+ {
+ ((ASN1Encodable)obj).toASN1Primitive().encode(this);
+ }
+ else
+ {
+ throw new IOException("object not BEREncodable");
+ }
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/BERSequence.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/BERSequence.java
new file mode 100644
index 0000000..cdfb4e7
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/BERSequence.java
@@ -0,0 +1,73 @@
+package org.bc.asn1;
+
+import java.io.IOException;
+import java.util.Enumeration;
+
+public class BERSequence
+ extends ASN1Sequence
+{
+ /**
+ * create an empty sequence
+ */
+ public BERSequence()
+ {
+ }
+
+ /**
+ * create a sequence containing one object
+ */
+ public BERSequence(
+ ASN1Encodable obj)
+ {
+ super(obj);
+ }
+
+ /**
+ * create a sequence containing a vector of objects.
+ */
+ public BERSequence(
+ ASN1EncodableVector v)
+ {
+ super(v);
+ }
+
+ /**
+ * create a sequence containing an array of objects.
+ */
+ public BERSequence(
+ ASN1Encodable[] array)
+ {
+ super(array);
+ }
+
+ int encodedLength()
+ throws IOException
+ {
+ int length = 0;
+ for (Enumeration e = getObjects(); e.hasMoreElements();)
+ {
+ length += ((ASN1Encodable)e.nextElement()).toASN1Primitive().encodedLength();
+ }
+
+ return 2 + length + 2;
+ }
+
+ /*
+ */
+ void encode(
+ ASN1OutputStream out)
+ throws IOException
+ {
+ out.write(BERTags.SEQUENCE | BERTags.CONSTRUCTED);
+ out.write(0x80);
+
+ Enumeration e = getObjects();
+ while (e.hasMoreElements())
+ {
+ out.writeObject((ASN1Encodable)e.nextElement());
+ }
+
+ out.write(0x00);
+ out.write(0x00);
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/BERSequenceGenerator.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/BERSequenceGenerator.java
new file mode 100644
index 0000000..29cedcf
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/BERSequenceGenerator.java
@@ -0,0 +1,41 @@
+package org.bc.asn1;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+public class BERSequenceGenerator
+ extends BERGenerator
+{
+ public BERSequenceGenerator(
+ OutputStream out)
+ throws IOException
+ {
+ super(out);
+
+ writeBERHeader(BERTags.CONSTRUCTED | BERTags.SEQUENCE);
+ }
+
+ public BERSequenceGenerator(
+ OutputStream out,
+ int tagNo,
+ boolean isExplicit)
+ throws IOException
+ {
+ super(out, tagNo, isExplicit);
+
+ writeBERHeader(BERTags.CONSTRUCTED | BERTags.SEQUENCE);
+ }
+
+ public void addObject(
+ ASN1Encodable object)
+ throws IOException
+ {
+ object.toASN1Primitive().encode(new BEROutputStream(_out));
+ }
+
+ public void close()
+ throws IOException
+ {
+ writeBEREnd();
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/BERSequenceParser.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/BERSequenceParser.java
new file mode 100644
index 0000000..37ba30a
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/BERSequenceParser.java
@@ -0,0 +1,38 @@
+package org.bc.asn1;
+
+import java.io.IOException;
+
+public class BERSequenceParser
+ implements ASN1SequenceParser
+{
+ private ASN1StreamParser _parser;
+
+ BERSequenceParser(ASN1StreamParser parser)
+ {
+ this._parser = parser;
+ }
+
+ public ASN1Encodable readObject()
+ throws IOException
+ {
+ return _parser.readObject();
+ }
+
+ public ASN1Primitive getLoadedObject()
+ throws IOException
+ {
+ return new BERSequence(_parser.readVector());
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+ try
+ {
+ return getLoadedObject();
+ }
+ catch (IOException e)
+ {
+ throw new IllegalStateException(e.getMessage());
+ }
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/BERSet.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/BERSet.java
new file mode 100644
index 0000000..a161d60
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/BERSet.java
@@ -0,0 +1,73 @@
+package org.bc.asn1;
+
+import java.io.IOException;
+import java.util.Enumeration;
+
+public class BERSet
+ extends ASN1Set
+{
+ /**
+ * create an empty sequence
+ */
+ public BERSet()
+ {
+ }
+
+ /**
+ * @param obj - a single object that makes up the set.
+ */
+ public BERSet(
+ ASN1Encodable obj)
+ {
+ super(obj);
+ }
+
+ /**
+ * @param v - a vector of objects making up the set.
+ */
+ public BERSet(
+ ASN1EncodableVector v)
+ {
+ super(v, false);
+ }
+
+ /**
+ * create a set from an array of objects.
+ */
+ public BERSet(
+ ASN1Encodable[] a)
+ {
+ super(a, false);
+ }
+
+ int encodedLength()
+ throws IOException
+ {
+ int length = 0;
+ for (Enumeration e = getObjects(); e.hasMoreElements();)
+ {
+ length += ((ASN1Encodable)e.nextElement()).toASN1Primitive().encodedLength();
+ }
+
+ return 2 + length + 2;
+ }
+
+ /*
+ */
+ void encode(
+ ASN1OutputStream out)
+ throws IOException
+ {
+ out.write(BERTags.SET | BERTags.CONSTRUCTED);
+ out.write(0x80);
+
+ Enumeration e = getObjects();
+ while (e.hasMoreElements())
+ {
+ out.writeObject((ASN1Encodable)e.nextElement());
+ }
+
+ out.write(0x00);
+ out.write(0x00);
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/BERSetParser.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/BERSetParser.java
new file mode 100644
index 0000000..49d6638
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/BERSetParser.java
@@ -0,0 +1,38 @@
+package org.bc.asn1;
+
+import java.io.IOException;
+
+public class BERSetParser
+ implements ASN1SetParser
+{
+ private ASN1StreamParser _parser;
+
+ BERSetParser(ASN1StreamParser parser)
+ {
+ this._parser = parser;
+ }
+
+ public ASN1Encodable readObject()
+ throws IOException
+ {
+ return _parser.readObject();
+ }
+
+ public ASN1Primitive getLoadedObject()
+ throws IOException
+ {
+ return new BERSet(_parser.readVector());
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+ try
+ {
+ return getLoadedObject();
+ }
+ catch (IOException e)
+ {
+ throw new ASN1ParsingException(e.getMessage(), e);
+ }
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/BERTaggedObject.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/BERTaggedObject.java
new file mode 100644
index 0000000..24a8882
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/BERTaggedObject.java
@@ -0,0 +1,147 @@
+package org.bc.asn1;
+
+import java.io.IOException;
+import java.util.Enumeration;
+
+/**
+ * BER TaggedObject - in ASN.1 notation this is any object preceded by
+ * a [n] where n is some number - these are assumed to follow the construction
+ * rules (as with sequences).
+ */
+public class BERTaggedObject
+ extends ASN1TaggedObject
+{
+ /**
+ * @param tagNo the tag number for this object.
+ * @param obj the tagged object.
+ */
+ public BERTaggedObject(
+ int tagNo,
+ ASN1Encodable obj)
+ {
+ super(true, tagNo, obj);
+ }
+
+ /**
+ * @param explicit true if an explicitly tagged object.
+ * @param tagNo the tag number for this object.
+ * @param obj the tagged object.
+ */
+ public BERTaggedObject(
+ boolean explicit,
+ int tagNo,
+ ASN1Encodable obj)
+ {
+ super(explicit, tagNo, obj);
+ }
+
+ /**
+ * create an implicitly tagged object that contains a zero
+ * length sequence.
+ */
+ public BERTaggedObject(
+ int tagNo)
+ {
+ super(false, tagNo, new BERSequence());
+ }
+
+ boolean isConstructed()
+ {
+ if (!empty)
+ {
+ if (explicit)
+ {
+ return true;
+ }
+ else
+ {
+ ASN1Primitive primitive = obj.toASN1Primitive().toDERObject();
+
+ return primitive.isConstructed();
+ }
+ }
+ else
+ {
+ return true;
+ }
+ }
+
+ int encodedLength()
+ throws IOException
+ {
+ if (!empty)
+ {
+ ASN1Primitive primitive = obj.toASN1Primitive();
+ int length = primitive.encodedLength();
+
+ if (explicit)
+ {
+ return StreamUtil.calculateTagLength(tagNo) + StreamUtil.calculateBodyLength(length) + length;
+ }
+ else
+ {
+ // header length already in calculation
+ length = length - 1;
+
+ return StreamUtil.calculateTagLength(tagNo) + length;
+ }
+ }
+ else
+ {
+ return StreamUtil.calculateTagLength(tagNo) + 1;
+ }
+ }
+
+ void encode(
+ ASN1OutputStream out)
+ throws IOException
+ {
+ out.writeTag(BERTags.CONSTRUCTED | BERTags.TAGGED, tagNo);
+ out.write(0x80);
+
+ if (!empty)
+ {
+ if (!explicit)
+ {
+ Enumeration e;
+ if (obj instanceof ASN1OctetString)
+ {
+ if (obj instanceof BEROctetString)
+ {
+ e = ((BEROctetString)obj).getObjects();
+ }
+ else
+ {
+ ASN1OctetString octs = (ASN1OctetString)obj;
+ BEROctetString berO = new BEROctetString(octs.getOctets());
+ e = berO.getObjects();
+ }
+ }
+ else if (obj instanceof ASN1Sequence)
+ {
+ e = ((ASN1Sequence)obj).getObjects();
+ }
+ else if (obj instanceof ASN1Set)
+ {
+ e = ((ASN1Set)obj).getObjects();
+ }
+ else
+ {
+ throw new RuntimeException("not implemented: " + obj.getClass().getName());
+ }
+
+ while (e.hasMoreElements())
+ {
+ out.writeObject((ASN1Encodable)e.nextElement());
+ }
+ }
+ else
+ {
+ out.writeObject(obj);
+ }
+ }
+
+ out.write(0x00);
+ out.write(0x00);
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/BERTaggedObjectParser.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/BERTaggedObjectParser.java
new file mode 100644
index 0000000..c2b8ae0
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/BERTaggedObjectParser.java
@@ -0,0 +1,66 @@
+package org.bc.asn1;
+
+import java.io.IOException;
+
+public class BERTaggedObjectParser
+ implements ASN1TaggedObjectParser
+{
+ private boolean _constructed;
+ private int _tagNumber;
+ private ASN1StreamParser _parser;
+
+ BERTaggedObjectParser(
+ boolean constructed,
+ int tagNumber,
+ ASN1StreamParser parser)
+ {
+ _constructed = constructed;
+ _tagNumber = tagNumber;
+ _parser = parser;
+ }
+
+ public boolean isConstructed()
+ {
+ return _constructed;
+ }
+
+ public int getTagNo()
+ {
+ return _tagNumber;
+ }
+
+ public ASN1Encodable getObjectParser(
+ int tag,
+ boolean isExplicit)
+ throws IOException
+ {
+ if (isExplicit)
+ {
+ if (!_constructed)
+ {
+ throw new IOException("Explicit tags must be constructed (see X.690 8.14.2)");
+ }
+ return _parser.readObject();
+ }
+
+ return _parser.readImplicit(_constructed, tag);
+ }
+
+ public ASN1Primitive getLoadedObject()
+ throws IOException
+ {
+ return _parser.readTaggedObject(_constructed, _tagNumber);
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+ try
+ {
+ return this.getLoadedObject();
+ }
+ catch (IOException e)
+ {
+ throw new ASN1ParsingException(e.getMessage());
+ }
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/BERTags.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/BERTags.java
new file mode 100644
index 0000000..9a7e969
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/BERTags.java
@@ -0,0 +1,36 @@
+package org.bc.asn1;
+
+public interface BERTags
+{
+ public static final int BOOLEAN = 0x01;
+ public static final int INTEGER = 0x02;
+ public static final int BIT_STRING = 0x03;
+ public static final int OCTET_STRING = 0x04;
+ public static final int NULL = 0x05;
+ public static final int OBJECT_IDENTIFIER = 0x06;
+ public static final int EXTERNAL = 0x08;
+ public static final int ENUMERATED = 0x0a;
+ public static final int SEQUENCE = 0x10;
+ public static final int SEQUENCE_OF = 0x10; // for completeness
+ public static final int SET = 0x11;
+ public static final int SET_OF = 0x11; // for completeness
+
+
+ public static final int NUMERIC_STRING = 0x12;
+ public static final int PRINTABLE_STRING = 0x13;
+ public static final int T61_STRING = 0x14;
+ public static final int VIDEOTEX_STRING = 0x15;
+ public static final int IA5_STRING = 0x16;
+ public static final int UTC_TIME = 0x17;
+ public static final int GENERALIZED_TIME = 0x18;
+ public static final int GRAPHIC_STRING = 0x19;
+ public static final int VISIBLE_STRING = 0x1a;
+ public static final int GENERAL_STRING = 0x1b;
+ public static final int UNIVERSAL_STRING = 0x1c;
+ public static final int BMP_STRING = 0x1e;
+ public static final int UTF8_STRING = 0x0c;
+
+ public static final int CONSTRUCTED = 0x20;
+ public static final int APPLICATION = 0x40;
+ public static final int TAGGED = 0x80;
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ConstructedOctetStream.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ConstructedOctetStream.java
new file mode 100644
index 0000000..b690e69
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ConstructedOctetStream.java
@@ -0,0 +1,111 @@
+package org.bc.asn1;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+class ConstructedOctetStream
+ extends InputStream
+{
+ private final ASN1StreamParser _parser;
+
+ private boolean _first = true;
+ private InputStream _currentStream;
+
+ ConstructedOctetStream(
+ ASN1StreamParser parser)
+ {
+ _parser = parser;
+ }
+
+ public int read(byte[] b, int off, int len) throws IOException
+ {
+ if (_currentStream == null)
+ {
+ if (!_first)
+ {
+ return -1;
+ }
+
+ ASN1OctetStringParser s = (ASN1OctetStringParser)_parser.readObject();
+
+ if (s == null)
+ {
+ return -1;
+ }
+
+ _first = false;
+ _currentStream = s.getOctetStream();
+ }
+
+ int totalRead = 0;
+
+ for (;;)
+ {
+ int numRead = _currentStream.read(b, off + totalRead, len - totalRead);
+
+ if (numRead >= 0)
+ {
+ totalRead += numRead;
+
+ if (totalRead == len)
+ {
+ return totalRead;
+ }
+ }
+ else
+ {
+ ASN1OctetStringParser aos = (ASN1OctetStringParser)_parser.readObject();
+
+ if (aos == null)
+ {
+ _currentStream = null;
+ return totalRead < 1 ? -1 : totalRead;
+ }
+
+ _currentStream = aos.getOctetStream();
+ }
+ }
+ }
+
+ public int read()
+ throws IOException
+ {
+ if (_currentStream == null)
+ {
+ if (!_first)
+ {
+ return -1;
+ }
+
+ ASN1OctetStringParser s = (ASN1OctetStringParser)_parser.readObject();
+
+ if (s == null)
+ {
+ return -1;
+ }
+
+ _first = false;
+ _currentStream = s.getOctetStream();
+ }
+
+ for (;;)
+ {
+ int b = _currentStream.read();
+
+ if (b >= 0)
+ {
+ return b;
+ }
+
+ ASN1OctetStringParser s = (ASN1OctetStringParser)_parser.readObject();
+
+ if (s == null)
+ {
+ _currentStream = null;
+ return -1;
+ }
+
+ _currentStream = s.getOctetStream();
+ }
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DERApplicationSpecific.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DERApplicationSpecific.java
new file mode 100644
index 0000000..1788ce4
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DERApplicationSpecific.java
@@ -0,0 +1,276 @@
+package org.bc.asn1;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+import org.bc.util.Arrays;
+
+/**
+ * Base class for an application specific object
+ */
+public class DERApplicationSpecific
+ extends ASN1Primitive
+{
+ private final boolean isConstructed;
+ private final int tag;
+ private final byte[] octets;
+
+ DERApplicationSpecific(
+ boolean isConstructed,
+ int tag,
+ byte[] octets)
+ {
+ this.isConstructed = isConstructed;
+ this.tag = tag;
+ this.octets = octets;
+ }
+
+ public DERApplicationSpecific(
+ int tag,
+ byte[] octets)
+ {
+ this(false, tag, octets);
+ }
+
+ public DERApplicationSpecific(
+ int tag,
+ ASN1Encodable object)
+ throws IOException
+ {
+ this(true, tag, object);
+ }
+
+ public DERApplicationSpecific(
+ boolean explicit,
+ int tag,
+ ASN1Encodable object)
+ throws IOException
+ {
+ ASN1Primitive primitive = object.toASN1Primitive();
+
+ byte[] data = primitive.getEncoded(ASN1Encoding.DER);
+
+ this.isConstructed = explicit || (primitive instanceof ASN1Set || primitive instanceof ASN1Sequence);
+ this.tag = tag;
+
+ if (explicit)
+ {
+ this.octets = data;
+ }
+ else
+ {
+ int lenBytes = getLengthOfHeader(data);
+ byte[] tmp = new byte[data.length - lenBytes];
+ System.arraycopy(data, lenBytes, tmp, 0, tmp.length);
+ this.octets = tmp;
+ }
+ }
+
+ public DERApplicationSpecific(int tagNo, ASN1EncodableVector vec)
+ {
+ this.tag = tagNo;
+ this.isConstructed = true;
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ for (int i = 0; i != vec.size(); i++)
+ {
+ try
+ {
+ bOut.write(((ASN1Object)vec.get(i)).getEncoded(ASN1Encoding.DER));
+ }
+ catch (IOException e)
+ {
+ throw new ASN1ParsingException("malformed object: " + e, e);
+ }
+ }
+ this.octets = bOut.toByteArray();
+ }
+
+ public static DERApplicationSpecific getInstance(Object obj)
+ {
+ if (obj == null || obj instanceof DERApplicationSpecific)
+ {
+ return (DERApplicationSpecific)obj;
+ }
+ else if (obj instanceof byte[])
+ {
+ try
+ {
+ return DERApplicationSpecific.getInstance(ASN1Primitive.fromByteArray((byte[])obj));
+ }
+ catch (IOException e)
+ {
+ throw new IllegalArgumentException("failed to construct object from byte[]: " + e.getMessage());
+ }
+ }
+ else if (obj instanceof ASN1Encodable)
+ {
+ ASN1Primitive primitive = ((ASN1Encodable)obj).toASN1Primitive();
+
+ if (primitive instanceof ASN1Sequence)
+ {
+ return (DERApplicationSpecific)primitive;
+ }
+ }
+
+ throw new IllegalArgumentException("unknown object in getInstance: " + obj.getClass().getName());
+ }
+
+ private int getLengthOfHeader(byte[] data)
+ {
+ int length = data[1] & 0xff; // TODO: assumes 1 byte tag
+
+ if (length == 0x80)
+ {
+ return 2; // indefinite-length encoding
+ }
+
+ if (length > 127)
+ {
+ int size = length & 0x7f;
+
+ // Note: The invalid long form "0xff" (see X.690 8.1.3.5c) will be caught here
+ if (size > 4)
+ {
+ throw new IllegalStateException("DER length more than 4 bytes: " + size);
+ }
+
+ return size + 2;
+ }
+
+ return 2;
+ }
+
+ public boolean isConstructed()
+ {
+ return isConstructed;
+ }
+
+ public byte[] getContents()
+ {
+ return octets;
+ }
+
+ public int getApplicationTag()
+ {
+ return tag;
+ }
+
+ /**
+ * Return the enclosed object assuming explicit tagging.
+ *
+ * @return the resulting object
+ * @throws IOException if reconstruction fails.
+ */
+ public ASN1Primitive getObject()
+ throws IOException
+ {
+ return new ASN1InputStream(getContents()).readObject();
+ }
+
+ /**
+ * Return the enclosed object assuming implicit tagging.
+ *
+ * @param derTagNo the type tag that should be applied to the object's contents.
+ * @return the resulting object
+ * @throws IOException if reconstruction fails.
+ */
+ public ASN1Primitive getObject(int derTagNo)
+ throws IOException
+ {
+ if (derTagNo >= 0x1f)
+ {
+ throw new IOException("unsupported tag number");
+ }
+
+ byte[] orig = this.getEncoded();
+ byte[] tmp = replaceTagNumber(derTagNo, orig);
+
+ if ((orig[0] & BERTags.CONSTRUCTED) != 0)
+ {
+ tmp[0] |= BERTags.CONSTRUCTED;
+ }
+
+ return new ASN1InputStream(tmp).readObject();
+ }
+
+ int encodedLength()
+ throws IOException
+ {
+ return StreamUtil.calculateTagLength(tag) + StreamUtil.calculateBodyLength(octets.length) + octets.length;
+ }
+
+ /* (non-Javadoc)
+ * @see org.bouncycastle.asn1.ASN1Primitive#encode(org.bouncycastle.asn1.DEROutputStream)
+ */
+ void encode(ASN1OutputStream out) throws IOException
+ {
+ int classBits = BERTags.APPLICATION;
+ if (isConstructed)
+ {
+ classBits |= BERTags.CONSTRUCTED;
+ }
+
+ out.writeEncoded(classBits, tag, octets);
+ }
+
+ boolean asn1Equals(
+ ASN1Primitive o)
+ {
+ if (!(o instanceof DERApplicationSpecific))
+ {
+ return false;
+ }
+
+ DERApplicationSpecific other = (DERApplicationSpecific)o;
+
+ return isConstructed == other.isConstructed
+ && tag == other.tag
+ && Arrays.areEqual(octets, other.octets);
+ }
+
+ public int hashCode()
+ {
+ return (isConstructed ? 1 : 0) ^ tag ^ Arrays.hashCode(octets);
+ }
+
+ private byte[] replaceTagNumber(int newTag, byte[] input)
+ throws IOException
+ {
+ int tagNo = input[0] & 0x1f;
+ int index = 1;
+ //
+ // with tagged object tag number is bottom 5 bits, or stored at the start of the content
+ //
+ if (tagNo == 0x1f)
+ {
+ tagNo = 0;
+
+ int b = input[index++] & 0xff;
+
+ // X.690-0207 8.1.2.4.2
+ // "c) bits 7 to 1 of the first subsequent octet shall not all be zero."
+ if ((b & 0x7f) == 0) // Note: -1 will pass
+ {
+ throw new ASN1ParsingException("corrupted stream - invalid high tag number found");
+ }
+
+ while ((b >= 0) && ((b & 0x80) != 0))
+ {
+ tagNo |= (b & 0x7f);
+ tagNo <<= 7;
+ b = input[index++] & 0xff;
+ }
+
+ tagNo |= (b & 0x7f);
+ }
+
+ byte[] tmp = new byte[input.length - index + 1];
+
+ System.arraycopy(input, index, tmp, 1, tmp.length - 1);
+
+ tmp[0] = (byte)newTag;
+
+ return tmp;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DERBMPString.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DERBMPString.java
new file mode 100644
index 0000000..f172150
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DERBMPString.java
@@ -0,0 +1,153 @@
+package org.bc.asn1;
+
+import java.io.IOException;
+
+import org.bc.util.Arrays;
+
+/**
+ * DER BMPString object.
+ */
+public class DERBMPString
+ extends ASN1Primitive
+ implements ASN1String
+{
+ private char[] string;
+
+ /**
+ * return a BMP String from the given object.
+ *
+ * @param obj the object we want converted.
+ * @exception IllegalArgumentException if the object cannot be converted.
+ */
+ public static DERBMPString getInstance(
+ Object obj)
+ {
+ if (obj == null || obj instanceof DERBMPString)
+ {
+ return (DERBMPString)obj;
+ }
+
+ if (obj instanceof byte[])
+ {
+ try
+ {
+ return (DERBMPString)fromByteArray((byte[])obj);
+ }
+ catch (Exception e)
+ {
+ throw new IllegalArgumentException("encoding error in getInstance: " + e.toString());
+ }
+ }
+
+ throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
+ }
+
+ /**
+ * return a BMP String from a tagged object.
+ *
+ * @param obj the tagged object holding the object we want
+ * @param explicit true if the object is meant to be explicitly
+ * tagged false otherwise.
+ * @exception IllegalArgumentException if the tagged object cannot
+ * be converted.
+ */
+ public static DERBMPString getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit)
+ {
+ ASN1Primitive o = obj.getObject();
+
+ if (explicit || o instanceof DERBMPString)
+ {
+ return getInstance(o);
+ }
+ else
+ {
+ return new DERBMPString(ASN1OctetString.getInstance(o).getOctets());
+ }
+ }
+
+ /**
+ * basic constructor - byte encoded string.
+ */
+ DERBMPString(
+ byte[] string)
+ {
+ char[] cs = new char[string.length / 2];
+
+ for (int i = 0; i != cs.length; i++)
+ {
+ cs[i] = (char)((string[2 * i] << 8) | (string[2 * i + 1] & 0xff));
+ }
+
+ this.string = cs;
+ }
+
+ DERBMPString(char[] string)
+ {
+ this.string = string;
+ }
+
+ /**
+ * basic constructor
+ */
+ public DERBMPString(
+ String string)
+ {
+ this.string = string.toCharArray();
+ }
+
+ public String getString()
+ {
+ return new String(string);
+ }
+
+ public String toString()
+ {
+ return getString();
+ }
+
+ public int hashCode()
+ {
+ return Arrays.hashCode(string);
+ }
+
+ protected boolean asn1Equals(
+ ASN1Primitive o)
+ {
+ if (!(o instanceof DERBMPString))
+ {
+ return false;
+ }
+
+ DERBMPString s = (DERBMPString)o;
+
+ return Arrays.areEqual(string, s.string);
+ }
+
+ boolean isConstructed()
+ {
+ return false;
+ }
+
+ int encodedLength()
+ {
+ return 1 + StreamUtil.calculateBodyLength(string.length * 2) + (string.length * 2);
+ }
+
+ void encode(
+ ASN1OutputStream out)
+ throws IOException
+ {
+ out.write(BERTags.BMP_STRING);
+ out.writeLength(string.length * 2);
+
+ for (int i = 0; i != string.length; i++)
+ {
+ char c = string[i];
+
+ out.write((byte)(c >> 8));
+ out.write((byte)c);
+ }
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DERBitString.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DERBitString.java
new file mode 100644
index 0000000..a4d431a
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DERBitString.java
@@ -0,0 +1,313 @@
+package org.bc.asn1;
+
+import java.io.ByteArrayOutputStream;
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.bc.util.Arrays;
+import org.bc.util.io.Streams;
+
+public class DERBitString
+ extends ASN1Primitive
+ implements ASN1String
+{
+ private static final char[] table = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
+
+ protected byte[] data;
+ protected int padBits;
+
+ /**
+ * return the correct number of pad bits for a bit string defined in
+ * a 32 bit constant
+ */
+ static protected int getPadBits(
+ int bitString)
+ {
+ int val = 0;
+ for (int i = 3; i >= 0; i--)
+ {
+ //
+ // this may look a little odd, but if it isn't done like this pre jdk1.2
+ // JVM's break!
+ //
+ if (i != 0)
+ {
+ if ((bitString >> (i * 8)) != 0)
+ {
+ val = (bitString >> (i * 8)) & 0xFF;
+ break;
+ }
+ }
+ else
+ {
+ if (bitString != 0)
+ {
+ val = bitString & 0xFF;
+ break;
+ }
+ }
+ }
+
+ if (val == 0)
+ {
+ return 7;
+ }
+
+
+ int bits = 1;
+
+ while (((val <<= 1) & 0xFF) != 0)
+ {
+ bits++;
+ }
+
+ return 8 - bits;
+ }
+
+ /**
+ * return the correct number of bytes for a bit string defined in
+ * a 32 bit constant
+ */
+ static protected byte[] getBytes(int bitString)
+ {
+ int bytes = 4;
+ for (int i = 3; i >= 1; i--)
+ {
+ if ((bitString & (0xFF << (i * 8))) != 0)
+ {
+ break;
+ }
+ bytes--;
+ }
+
+ byte[] result = new byte[bytes];
+ for (int i = 0; i < bytes; i++)
+ {
+ result[i] = (byte) ((bitString >> (i * 8)) & 0xFF);
+ }
+
+ return result;
+ }
+
+ /**
+ * return a Bit String from the passed in object
+ *
+ * @exception IllegalArgumentException if the object cannot be converted.
+ */
+ public static DERBitString getInstance(
+ Object obj)
+ {
+ if (obj == null || obj instanceof DERBitString)
+ {
+ return (DERBitString)obj;
+ }
+
+ throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
+ }
+
+ /**
+ * return a Bit String from a tagged object.
+ *
+ * @param obj the tagged object holding the object we want
+ * @param explicit true if the object is meant to be explicitly
+ * tagged false otherwise.
+ * @exception IllegalArgumentException if the tagged object cannot
+ * be converted.
+ */
+ public static DERBitString getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit)
+ {
+ ASN1Primitive o = obj.getObject();
+
+ if (explicit || o instanceof DERBitString)
+ {
+ return getInstance(o);
+ }
+ else
+ {
+ return fromOctetString(((ASN1OctetString)o).getOctets());
+ }
+ }
+
+ protected DERBitString(
+ byte data,
+ int padBits)
+ {
+ this.data = new byte[1];
+ this.data[0] = data;
+ this.padBits = padBits;
+ }
+
+ /**
+ * @param data the octets making up the bit string.
+ * @param padBits the number of extra bits at the end of the string.
+ */
+ public DERBitString(
+ byte[] data,
+ int padBits)
+ {
+ this.data = data;
+ this.padBits = padBits;
+ }
+
+ public DERBitString(
+ byte[] data)
+ {
+ this(data, 0);
+ }
+
+ public DERBitString(
+ int value)
+ {
+ this.data = getBytes(value);
+ this.padBits = getPadBits(value);
+ }
+
+ public DERBitString(
+ ASN1Encodable obj)
+ throws IOException
+ {
+ this.data = obj.toASN1Primitive().getEncoded(ASN1Encoding.DER);
+ this.padBits = 0;
+ }
+
+ public byte[] getBytes()
+ {
+ return data;
+ }
+
+ public int getPadBits()
+ {
+ return padBits;
+ }
+
+
+ /**
+ * @return the value of the bit string as an int (truncating if necessary)
+ */
+ public int intValue()
+ {
+ int value = 0;
+
+ for (int i = 0; i != data.length && i != 4; i++)
+ {
+ value |= (data[i] & 0xff) << (8 * i);
+ }
+
+ return value;
+ }
+
+ boolean isConstructed()
+ {
+ return false;
+ }
+
+ int encodedLength()
+ {
+ return 1 + StreamUtil.calculateBodyLength(data.length + 1) + data.length + 1;
+ }
+
+ void encode(
+ ASN1OutputStream out)
+ throws IOException
+ {
+ byte[] bytes = new byte[getBytes().length + 1];
+
+ bytes[0] = (byte)getPadBits();
+ System.arraycopy(getBytes(), 0, bytes, 1, bytes.length - 1);
+
+ out.writeEncoded(BERTags.BIT_STRING, bytes);
+ }
+
+ public int hashCode()
+ {
+ return padBits ^ Arrays.hashCode(data);
+ }
+
+ protected boolean asn1Equals(
+ ASN1Primitive o)
+ {
+ if (!(o instanceof DERBitString))
+ {
+ return false;
+ }
+
+ DERBitString other = (DERBitString)o;
+
+ return this.padBits == other.padBits
+ && Arrays.areEqual(this.data, other.data);
+ }
+
+ public String getString()
+ {
+ StringBuffer buf = new StringBuffer("#");
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ ASN1OutputStream aOut = new ASN1OutputStream(bOut);
+
+ try
+ {
+ aOut.writeObject(this);
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException("internal error encoding BitString");
+ }
+
+ byte[] string = bOut.toByteArray();
+
+ for (int i = 0; i != string.length; i++)
+ {
+ buf.append(table[(string[i] >>> 4) & 0xf]);
+ buf.append(table[string[i] & 0xf]);
+ }
+
+ return buf.toString();
+ }
+
+ public String toString()
+ {
+ return getString();
+ }
+
+ static DERBitString fromOctetString(byte[] bytes)
+ {
+ if (bytes.length < 1)
+ {
+ throw new IllegalArgumentException("truncated BIT STRING detected");
+ }
+
+ int padBits = bytes[0];
+ byte[] data = new byte[bytes.length - 1];
+
+ if (data.length != 0)
+ {
+ System.arraycopy(bytes, 1, data, 0, bytes.length - 1);
+ }
+
+ return new DERBitString(data, padBits);
+ }
+
+ static DERBitString fromInputStream(int length, InputStream stream)
+ throws IOException
+ {
+ if (length < 1)
+ {
+ throw new IllegalArgumentException("truncated BIT STRING detected");
+ }
+
+ int padBits = stream.read();
+ byte[] data = new byte[length - 1];
+
+ if (data.length != 0)
+ {
+ if (Streams.readFully(stream, data) != data.length)
+ {
+ throw new EOFException("EOF encountered in middle of BIT STRING");
+ }
+ }
+
+ return new DERBitString(data, padBits);
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DERBoolean.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DERBoolean.java
new file mode 100644
index 0000000..ea87b14
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DERBoolean.java
@@ -0,0 +1,179 @@
+package org.bc.asn1;
+
+import java.io.IOException;
+
+import org.bc.util.Arrays;
+
+public class DERBoolean
+ extends ASN1Primitive
+{
+ private static final byte[] TRUE_VALUE = new byte[] { (byte)0xff };
+ private static final byte[] FALSE_VALUE = new byte[] { 0 };
+
+ private byte[] value;
+
+ public static final ASN1Boolean FALSE = new ASN1Boolean(false);
+ public static final ASN1Boolean TRUE = new ASN1Boolean(true);
+
+
+ /**
+ * return a boolean from the passed in object.
+ *
+ * @exception IllegalArgumentException if the object cannot be converted.
+ */
+ public static ASN1Boolean getInstance(
+ Object obj)
+ {
+ if (obj == null || obj instanceof ASN1Boolean)
+ {
+ return (ASN1Boolean)obj;
+ }
+
+ if (obj instanceof DERBoolean)
+ {
+ return ((DERBoolean)obj).isTrue() ? DERBoolean.TRUE : DERBoolean.FALSE;
+ }
+
+ throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
+ }
+
+ /**
+ * return a ASN1Boolean from the passed in boolean.
+ */
+ public static ASN1Boolean getInstance(
+ boolean value)
+ {
+ return (value ? TRUE : FALSE);
+ }
+
+ /**
+ * return a ASN1Boolean from the passed in boolean.
+ */
+ public static ASN1Boolean getInstance(
+ int value)
+ {
+ return (value != 0 ? TRUE : FALSE);
+ }
+
+ /**
+ * return a Boolean from a tagged object.
+ *
+ * @param obj the tagged object holding the object we want
+ * @param explicit true if the object is meant to be explicitly
+ * tagged false otherwise.
+ * @exception IllegalArgumentException if the tagged object cannot
+ * be converted.
+ */
+ public static DERBoolean getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit)
+ {
+ ASN1Primitive o = obj.getObject();
+
+ if (explicit || o instanceof DERBoolean)
+ {
+ return getInstance(o);
+ }
+ else
+ {
+ return ASN1Boolean.fromOctetString(((ASN1OctetString)o).getOctets());
+ }
+ }
+
+ DERBoolean(
+ byte[] value)
+ {
+ if (value.length != 1)
+ {
+ throw new IllegalArgumentException("byte value should have 1 byte in it");
+ }
+
+ if (value[0] == 0)
+ {
+ this.value = FALSE_VALUE;
+ }
+ else if (value[0] == 0xff)
+ {
+ this.value = TRUE_VALUE;
+ }
+ else
+ {
+ this.value = Arrays.clone(value);
+ }
+ }
+
+ /**
+ * @deprecated use getInstance(boolean) method.
+ * @param value
+ */
+ public DERBoolean(
+ boolean value)
+ {
+ this.value = (value) ? TRUE_VALUE : FALSE_VALUE;
+ }
+
+ public boolean isTrue()
+ {
+ return (value[0] != 0);
+ }
+
+ boolean isConstructed()
+ {
+ return false;
+ }
+
+ int encodedLength()
+ {
+ return 3;
+ }
+
+ void encode(
+ ASN1OutputStream out)
+ throws IOException
+ {
+ out.writeEncoded(BERTags.BOOLEAN, value);
+ }
+
+ protected boolean asn1Equals(
+ ASN1Primitive o)
+ {
+ if ((o == null) || !(o instanceof DERBoolean))
+ {
+ return false;
+ }
+
+ return (value[0] == ((DERBoolean)o).value[0]);
+ }
+
+ public int hashCode()
+ {
+ return value[0];
+ }
+
+
+ public String toString()
+ {
+ return (value[0] != 0) ? "TRUE" : "FALSE";
+ }
+
+ static ASN1Boolean fromOctetString(byte[] value)
+ {
+ if (value.length != 1)
+ {
+ throw new IllegalArgumentException("byte value should have 1 byte in it");
+ }
+
+ if (value[0] == 0)
+ {
+ return FALSE;
+ }
+ else if (value[0] == 0xff)
+ {
+ return TRUE;
+ }
+ else
+ {
+ return new ASN1Boolean(value);
+ }
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DEREncodableVector.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DEREncodableVector.java
new file mode 100644
index 0000000..9d85b8e
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DEREncodableVector.java
@@ -0,0 +1,18 @@
+package org.bc.asn1;
+
+/**
+ * a general class for building up a vector of DER encodable objects -
+ * this will eventually be superceded by ASN1EncodableVector so you should
+ * use that class in preference.
+ */
+public class DEREncodableVector
+ extends ASN1EncodableVector
+{
+ /**
+ * @deprecated use ASN1EncodableVector instead.
+ */
+ public DEREncodableVector()
+ {
+
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DEREnumerated.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DEREnumerated.java
new file mode 100644
index 0000000..b2b87ed
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DEREnumerated.java
@@ -0,0 +1,158 @@
+package org.bc.asn1;
+
+import java.io.IOException;
+import java.math.BigInteger;
+
+import org.bc.util.Arrays;
+
+public class DEREnumerated
+ extends ASN1Primitive
+{
+ byte[] bytes;
+
+ /**
+ * return an integer from the passed in object
+ *
+ * @exception IllegalArgumentException if the object cannot be converted.
+ */
+ public static ASN1Enumerated getInstance(
+ Object obj)
+ {
+ if (obj == null || obj instanceof ASN1Enumerated)
+ {
+ return (ASN1Enumerated)obj;
+ }
+
+ if (obj instanceof DEREnumerated)
+ {
+ return new ASN1Enumerated(((DEREnumerated)obj).getValue());
+ }
+
+ if (obj instanceof byte[])
+ {
+ try
+ {
+ return (ASN1Enumerated)fromByteArray((byte[])obj);
+ }
+ catch (Exception e)
+ {
+ throw new IllegalArgumentException("encoding error in getInstance: " + e.toString());
+ }
+ }
+
+ throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
+ }
+
+ /**
+ * return an Enumerated from a tagged object.
+ *
+ * @param obj the tagged object holding the object we want
+ * @param explicit true if the object is meant to be explicitly
+ * tagged false otherwise.
+ * @exception IllegalArgumentException if the tagged object cannot
+ * be converted.
+ */
+ public static DEREnumerated getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit)
+ {
+ ASN1Primitive o = obj.getObject();
+
+ if (explicit || o instanceof DEREnumerated)
+ {
+ return getInstance(o);
+ }
+ else
+ {
+ return fromOctetString(((ASN1OctetString)o).getOctets());
+ }
+ }
+
+ public DEREnumerated(
+ int value)
+ {
+ bytes = BigInteger.valueOf(value).toByteArray();
+ }
+
+ public DEREnumerated(
+ BigInteger value)
+ {
+ bytes = value.toByteArray();
+ }
+
+ public DEREnumerated(
+ byte[] bytes)
+ {
+ this.bytes = bytes;
+ }
+
+ public BigInteger getValue()
+ {
+ return new BigInteger(bytes);
+ }
+
+ boolean isConstructed()
+ {
+ return false;
+ }
+
+ int encodedLength()
+ {
+ return 1 + StreamUtil.calculateBodyLength(bytes.length) + bytes.length;
+ }
+
+ void encode(
+ ASN1OutputStream out)
+ throws IOException
+ {
+ out.writeEncoded(BERTags.ENUMERATED, bytes);
+ }
+
+ boolean asn1Equals(
+ ASN1Primitive o)
+ {
+ if (!(o instanceof DEREnumerated))
+ {
+ return false;
+ }
+
+ DEREnumerated other = (DEREnumerated)o;
+
+ return Arrays.areEqual(this.bytes, other.bytes);
+ }
+
+ public int hashCode()
+ {
+ return Arrays.hashCode(bytes);
+ }
+
+ private static ASN1Enumerated[] cache = new ASN1Enumerated[12];
+
+ static ASN1Enumerated fromOctetString(byte[] enc)
+ {
+ if (enc.length > 1)
+ {
+ return new ASN1Enumerated(Arrays.clone(enc));
+ }
+
+ if (enc.length == 0)
+ {
+ throw new IllegalArgumentException("ENUMERATED has zero length");
+ }
+ int value = enc[0] & 0xff;
+
+ if (value >= cache.length)
+ {
+ return new ASN1Enumerated(Arrays.clone(enc));
+ }
+
+ ASN1Enumerated possibleMatch = cache[value];
+
+ if (possibleMatch == null)
+ {
+ possibleMatch = cache[value] = new ASN1Enumerated(Arrays.clone(enc));
+ }
+
+ return possibleMatch;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DERExternal.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DERExternal.java
new file mode 100644
index 0000000..b392ed1
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DERExternal.java
@@ -0,0 +1,294 @@
+package org.bc.asn1;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+/**
+ * Class representing the DER-type External
+ */
+public class DERExternal
+ extends ASN1Primitive
+{
+ private ASN1ObjectIdentifier directReference;
+ private ASN1Integer indirectReference;
+ private ASN1Primitive dataValueDescriptor;
+ private int encoding;
+ private ASN1Primitive externalContent;
+
+ public DERExternal(ASN1EncodableVector vector)
+ {
+ int offset = 0;
+
+ ASN1Primitive enc = getObjFromVector(vector, offset);
+ if (enc instanceof ASN1ObjectIdentifier)
+ {
+ directReference = (ASN1ObjectIdentifier)enc;
+ offset++;
+ enc = getObjFromVector(vector, offset);
+ }
+ if (enc instanceof ASN1Integer)
+ {
+ indirectReference = (ASN1Integer) enc;
+ offset++;
+ enc = getObjFromVector(vector, offset);
+ }
+ if (!(enc instanceof DERTaggedObject))
+ {
+ dataValueDescriptor = (ASN1Primitive) enc;
+ offset++;
+ enc = getObjFromVector(vector, offset);
+ }
+
+ if (vector.size() != offset + 1)
+ {
+ throw new IllegalArgumentException("input vector too large");
+ }
+
+ if (!(enc instanceof DERTaggedObject))
+ {
+ throw new IllegalArgumentException("No tagged object found in vector. Structure doesn't seem to be of type External");
+ }
+ DERTaggedObject obj = (DERTaggedObject)enc;
+ setEncoding(obj.getTagNo());
+ externalContent = obj.getObject();
+ }
+
+ private ASN1Primitive getObjFromVector(ASN1EncodableVector v, int index)
+ {
+ if (v.size() <= index)
+ {
+ throw new IllegalArgumentException("too few objects in input vector");
+ }
+
+ return v.get(index).toASN1Primitive();
+ }
+ /**
+ * Creates a new instance of DERExternal
+ * See X.690 for more informations about the meaning of these parameters
+ * @param directReference The direct reference or null
if not set.
+ * @param indirectReference The indirect reference or null
if not set.
+ * @param dataValueDescriptor The data value descriptor or null
if not set.
+ * @param externalData The external data in its encoded form.
+ */
+ public DERExternal(ASN1ObjectIdentifier directReference, ASN1Integer indirectReference, ASN1Primitive dataValueDescriptor, DERTaggedObject externalData)
+ {
+ this(directReference, indirectReference, dataValueDescriptor, externalData.getTagNo(), externalData.toASN1Primitive());
+ }
+
+ /**
+ * Creates a new instance of DERExternal.
+ * See X.690 for more informations about the meaning of these parameters
+ * @param directReference The direct reference or null
if not set.
+ * @param indirectReference The indirect reference or null
if not set.
+ * @param dataValueDescriptor The data value descriptor or null
if not set.
+ * @param encoding The encoding to be used for the external data
+ * @param externalData The external data
+ */
+ public DERExternal(ASN1ObjectIdentifier directReference, ASN1Integer indirectReference, ASN1Primitive dataValueDescriptor, int encoding, ASN1Primitive externalData)
+ {
+ setDirectReference(directReference);
+ setIndirectReference(indirectReference);
+ setDataValueDescriptor(dataValueDescriptor);
+ setEncoding(encoding);
+ setExternalContent(externalData.toASN1Primitive());
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#hashCode()
+ */
+ public int hashCode()
+ {
+ int ret = 0;
+ if (directReference != null)
+ {
+ ret = directReference.hashCode();
+ }
+ if (indirectReference != null)
+ {
+ ret ^= indirectReference.hashCode();
+ }
+ if (dataValueDescriptor != null)
+ {
+ ret ^= dataValueDescriptor.hashCode();
+ }
+ ret ^= externalContent.hashCode();
+ return ret;
+ }
+
+ boolean isConstructed()
+ {
+ return true;
+ }
+
+ int encodedLength()
+ throws IOException
+ {
+ return this.getEncoded().length;
+ }
+
+ /* (non-Javadoc)
+ * @see org.bouncycastle.asn1.ASN1Primitive#encode(org.bouncycastle.asn1.DEROutputStream)
+ */
+ void encode(ASN1OutputStream out)
+ throws IOException
+ {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ if (directReference != null)
+ {
+ baos.write(directReference.getEncoded(ASN1Encoding.DER));
+ }
+ if (indirectReference != null)
+ {
+ baos.write(indirectReference.getEncoded(ASN1Encoding.DER));
+ }
+ if (dataValueDescriptor != null)
+ {
+ baos.write(dataValueDescriptor.getEncoded(ASN1Encoding.DER));
+ }
+ DERTaggedObject obj = new DERTaggedObject(true, encoding, externalContent);
+ baos.write(obj.getEncoded(ASN1Encoding.DER));
+ out.writeEncoded(BERTags.CONSTRUCTED, BERTags.EXTERNAL, baos.toByteArray());
+ }
+
+ /* (non-Javadoc)
+ * @see org.bouncycastle.asn1.ASN1Primitive#asn1Equals(org.bouncycastle.asn1.ASN1Primitive)
+ */
+ boolean asn1Equals(ASN1Primitive o)
+ {
+ if (!(o instanceof DERExternal))
+ {
+ return false;
+ }
+ if (this == o)
+ {
+ return true;
+ }
+ DERExternal other = (DERExternal)o;
+ if (directReference != null)
+ {
+ if (other.directReference == null || !other.directReference.equals(directReference))
+ {
+ return false;
+ }
+ }
+ if (indirectReference != null)
+ {
+ if (other.indirectReference == null || !other.indirectReference.equals(indirectReference))
+ {
+ return false;
+ }
+ }
+ if (dataValueDescriptor != null)
+ {
+ if (other.dataValueDescriptor == null || !other.dataValueDescriptor.equals(dataValueDescriptor))
+ {
+ return false;
+ }
+ }
+ return externalContent.equals(other.externalContent);
+ }
+
+ /**
+ * Returns the data value descriptor
+ * @return The descriptor
+ */
+ public ASN1Primitive getDataValueDescriptor()
+ {
+ return dataValueDescriptor;
+ }
+
+ /**
+ * Returns the direct reference of the external element
+ * @return The reference
+ */
+ public ASN1ObjectIdentifier getDirectReference()
+ {
+ return directReference;
+ }
+
+ /**
+ * Returns the encoding of the content. Valid values are
+ *
0
single-ASN1-type1
OCTET STRING2
BIT STRING0
single-ASN1-type1
OCTET STRING2
BIT STRING+ * Normally in a certificate we would expect "Z" rather than "GMT", + * however adding the "GMT" means we can just use: + *
+ * dateF = new SimpleDateFormat("yyyyMMddHHmmssz"); + *+ * To read in the time and get a date which is compatible with our local + * time zone. + */ + public String getTime() + { + String stime = Strings.fromByteArray(time); + + // + // standardise the format. + // + if (stime.charAt(stime.length() - 1) == 'Z') + { + return stime.substring(0, stime.length() - 1) + "GMT+00:00"; + } + else + { + int signPos = stime.length() - 5; + char sign = stime.charAt(signPos); + if (sign == '-' || sign == '+') + { + return stime.substring(0, signPos) + + "GMT" + + stime.substring(signPos, signPos + 3) + + ":" + + stime.substring(signPos + 3); + } + else + { + signPos = stime.length() - 3; + sign = stime.charAt(signPos); + if (sign == '-' || sign == '+') + { + return stime.substring(0, signPos) + + "GMT" + + stime.substring(signPos) + + ":00"; + } + } + } + return stime + calculateGMTOffset(); + } + + private String calculateGMTOffset() + { + String sign = "+"; + TimeZone timeZone = TimeZone.getDefault(); + int offset = timeZone.getRawOffset(); + if (offset < 0) + { + sign = "-"; + offset = -offset; + } + int hours = offset / (60 * 60 * 1000); + int minutes = (offset - (hours * 60 * 60 * 1000)) / (60 * 1000); + + try + { + if (timeZone.useDaylightTime() && timeZone.inDaylightTime(this.getDate())) + { + hours += sign.equals("+") ? 1 : -1; + } + } + catch (ParseException e) + { + // we'll do our best and ignore daylight savings + } + + return "GMT" + sign + convert(hours) + ":" + convert(minutes); + } + + private String convert(int time) + { + if (time < 10) + { + return "0" + time; + } + + return Integer.toString(time); + } + + public Date getDate() + throws ParseException + { + SimpleDateFormat dateF; + String stime = Strings.fromByteArray(time); + String d = stime; + + if (stime.endsWith("Z")) + { + if (hasFractionalSeconds()) + { + dateF = new SimpleDateFormat("yyyyMMddHHmmss.SSS'Z'"); + } + else + { + dateF = new SimpleDateFormat("yyyyMMddHHmmss'Z'"); + } + + dateF.setTimeZone(new SimpleTimeZone(0, "Z")); + } + else if (stime.indexOf('-') > 0 || stime.indexOf('+') > 0) + { + d = this.getTime(); + if (hasFractionalSeconds()) + { + dateF = new SimpleDateFormat("yyyyMMddHHmmss.SSSz"); + } + else + { + dateF = new SimpleDateFormat("yyyyMMddHHmmssz"); + } + + dateF.setTimeZone(new SimpleTimeZone(0, "Z")); + } + else + { + if (hasFractionalSeconds()) + { + dateF = new SimpleDateFormat("yyyyMMddHHmmss.SSS"); + } + else + { + dateF = new SimpleDateFormat("yyyyMMddHHmmss"); + } + + dateF.setTimeZone(new SimpleTimeZone(0, TimeZone.getDefault().getID())); + } + + if (hasFractionalSeconds()) + { + // java misinterprets extra digits as being milliseconds... + String frac = d.substring(14); + int index; + for (index = 1; index < frac.length(); index++) + { + char ch = frac.charAt(index); + if (!('0' <= ch && ch <= '9')) + { + break; + } + } + + if (index - 1 > 3) + { + frac = frac.substring(0, 4) + frac.substring(index); + d = d.substring(0, 14) + frac; + } + else if (index - 1 == 1) + { + frac = frac.substring(0, index) + "00" + frac.substring(index); + d = d.substring(0, 14) + frac; + } + else if (index - 1 == 2) + { + frac = frac.substring(0, index) + "0" + frac.substring(index); + d = d.substring(0, 14) + frac; + } + } + + return dateF.parse(d); + } + + private boolean hasFractionalSeconds() + { + for (int i = 0; i != time.length; i++) + { + if (time[i] == '.') + { + if (i == 14) + { + return true; + } + } + } + return false; + } + + boolean isConstructed() + { + return false; + } + + int encodedLength() + { + int length = time.length; + + return 1 + StreamUtil.calculateBodyLength(length) + length; + } + + void encode( + ASN1OutputStream out) + throws IOException + { + out.writeEncoded(BERTags.GENERALIZED_TIME, time); + } + + boolean asn1Equals( + ASN1Primitive o) + { + if (!(o instanceof DERGeneralizedTime)) + { + return false; + } + + return Arrays.areEqual(time, ((DERGeneralizedTime)o).time); + } + + public int hashCode() + { + return Arrays.hashCode(time); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DERGenerator.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DERGenerator.java new file mode 100644 index 0000000..2da9d90 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DERGenerator.java @@ -0,0 +1,119 @@ +package org.bc.asn1; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import org.bc.util.io.Streams; + +public abstract class DERGenerator + extends ASN1Generator +{ + private boolean _tagged = false; + private boolean _isExplicit; + private int _tagNo; + + protected DERGenerator( + OutputStream out) + { + super(out); + } + + public DERGenerator( + OutputStream out, + int tagNo, + boolean isExplicit) + { + super(out); + + _tagged = true; + _isExplicit = isExplicit; + _tagNo = tagNo; + } + + private void writeLength( + OutputStream out, + int length) + throws IOException + { + if (length > 127) + { + int size = 1; + int val = length; + + while ((val >>>= 8) != 0) + { + size++; + } + + out.write((byte)(size | 0x80)); + + for (int i = (size - 1) * 8; i >= 0; i -= 8) + { + out.write((byte)(length >> i)); + } + } + else + { + out.write((byte)length); + } + } + + void writeDEREncoded( + OutputStream out, + int tag, + byte[] bytes) + throws IOException + { + out.write(tag); + writeLength(out, bytes.length); + out.write(bytes); + } + + void writeDEREncoded( + int tag, + byte[] bytes) + throws IOException + { + if (_tagged) + { + int tagNum = _tagNo | BERTags.TAGGED; + + if (_isExplicit) + { + int newTag = _tagNo | BERTags.CONSTRUCTED | BERTags.TAGGED; + + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + writeDEREncoded(bOut, tag, bytes); + + writeDEREncoded(_out, newTag, bOut.toByteArray()); + } + else + { + if ((tag & BERTags.CONSTRUCTED) != 0) + { + writeDEREncoded(_out, tagNum | BERTags.CONSTRUCTED, bytes); + } + else + { + writeDEREncoded(_out, tagNum, bytes); + } + } + } + else + { + writeDEREncoded(_out, tag, bytes); + } + } + + void writeDEREncoded( + OutputStream out, + int tag, + InputStream in) + throws IOException + { + writeDEREncoded(out, tag, Streams.readAll(in)); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DERIA5String.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DERIA5String.java new file mode 100644 index 0000000..4c1ef6d --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DERIA5String.java @@ -0,0 +1,183 @@ +package org.bc.asn1; + +import java.io.IOException; + +import org.bc.util.Arrays; +import org.bc.util.Strings; + +/** + * DER IA5String object - this is an ascii string. + */ +public class DERIA5String + extends ASN1Primitive + implements ASN1String +{ + private byte[] string; + + /** + * return a IA5 string from the passed in object + * + * @exception IllegalArgumentException if the object cannot be converted. + */ + public static DERIA5String getInstance( + Object obj) + { + if (obj == null || obj instanceof DERIA5String) + { + return (DERIA5String)obj; + } + + if (obj instanceof byte[]) + { + try + { + return (DERIA5String)fromByteArray((byte[])obj); + } + catch (Exception e) + { + throw new IllegalArgumentException("encoding error in getInstance: " + e.toString()); + } + } + + throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); + } + + /** + * return an IA5 String from a tagged object. + * + * @param obj the tagged object holding the object we want + * @param explicit true if the object is meant to be explicitly + * tagged false otherwise. + * @exception IllegalArgumentException if the tagged object cannot + * be converted. + */ + public static DERIA5String getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + ASN1Primitive o = obj.getObject(); + + if (explicit || o instanceof DERIA5String) + { + return getInstance(o); + } + else + { + return new DERIA5String(((ASN1OctetString)o).getOctets()); + } + } + + /** + * basic constructor - with bytes. + */ + DERIA5String( + byte[] string) + { + this.string = string; + } + + /** + * basic constructor - without validation. + */ + public DERIA5String( + String string) + { + this(string, false); + } + + /** + * Constructor with optional validation. + * + * @param string the base string to wrap. + * @param validate whether or not to check the string. + * @throws IllegalArgumentException if validate is true and the string + * contains characters that should not be in an IA5String. + */ + public DERIA5String( + String string, + boolean validate) + { + if (string == null) + { + throw new NullPointerException("string cannot be null"); + } + if (validate && !isIA5String(string)) + { + throw new IllegalArgumentException("string contains illegal characters"); + } + + this.string = Strings.toByteArray(string); + } + + public String getString() + { + return Strings.fromByteArray(string); + } + + public String toString() + { + return getString(); + } + + public byte[] getOctets() + { + return Arrays.clone(string); + } + + boolean isConstructed() + { + return false; + } + + int encodedLength() + { + return 1 + StreamUtil.calculateBodyLength(string.length) + string.length; + } + + void encode( + ASN1OutputStream out) + throws IOException + { + out.writeEncoded(BERTags.IA5_STRING, string); + } + + public int hashCode() + { + return Arrays.hashCode(string); + } + + boolean asn1Equals( + ASN1Primitive o) + { + if (!(o instanceof DERIA5String)) + { + return false; + } + + DERIA5String s = (DERIA5String)o; + + return Arrays.areEqual(string, s.string); + } + + /** + * return true if the passed in String can be represented without + * loss as an IA5String, false otherwise. + * + * @return true if in printable set, false otherwise. + */ + public static boolean isIA5String( + String str) + { + for (int i = str.length() - 1; i >= 0; i--) + { + char ch = str.charAt(i); + + if (ch > 0x007f) + { + return false; + } + } + + return true; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DERInteger.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DERInteger.java new file mode 100644 index 0000000..28c00b1 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DERInteger.java @@ -0,0 +1,148 @@ +package org.bc.asn1; + +import java.io.IOException; +import java.math.BigInteger; + +import org.bc.util.Arrays; + +public class DERInteger + extends ASN1Primitive +{ + byte[] bytes; + + /** + * return an integer from the passed in object + * + * @exception IllegalArgumentException if the object cannot be converted. + */ + public static ASN1Integer getInstance( + Object obj) + { + if (obj == null || obj instanceof ASN1Integer) + { + return (ASN1Integer)obj; + } + if (obj instanceof DERInteger) + { + return new ASN1Integer((((DERInteger)obj).getValue())); + } + + if (obj instanceof byte[]) + { + try + { + return (ASN1Integer)fromByteArray((byte[])obj); + } + catch (Exception e) + { + throw new IllegalArgumentException("encoding error in getInstance: " + e.toString()); + } + } + + throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); + } + + /** + * return an Integer from a tagged object. + * + * @param obj the tagged object holding the object we want + * @param explicit true if the object is meant to be explicitly + * tagged false otherwise. + * @exception IllegalArgumentException if the tagged object cannot + * be converted. + */ + public static ASN1Integer getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + ASN1Primitive o = obj.getObject(); + + if (explicit || o instanceof DERInteger) + { + return getInstance(o); + } + else + { + return new ASN1Integer(ASN1OctetString.getInstance(obj.getObject()).getOctets()); + } + } + + public DERInteger( + long value) + { + bytes = BigInteger.valueOf(value).toByteArray(); + } + + public DERInteger( + BigInteger value) + { + bytes = value.toByteArray(); + } + + public DERInteger( + byte[] bytes) + { + this.bytes = bytes; + } + + public BigInteger getValue() + { + return new BigInteger(bytes); + } + + /** + * in some cases positive values get crammed into a space, + * that's not quite big enough... + */ + public BigInteger getPositiveValue() + { + return new BigInteger(1, bytes); + } + + boolean isConstructed() + { + return false; + } + + int encodedLength() + { + return 1 + StreamUtil.calculateBodyLength(bytes.length) + bytes.length; + } + + void encode( + ASN1OutputStream out) + throws IOException + { + out.writeEncoded(BERTags.INTEGER, bytes); + } + + public int hashCode() + { + int value = 0; + + for (int i = 0; i != bytes.length; i++) + { + value ^= (bytes[i] & 0xff) << (i % 4); + } + + return value; + } + + boolean asn1Equals( + ASN1Primitive o) + { + if (!(o instanceof DERInteger)) + { + return false; + } + + DERInteger other = (DERInteger)o; + + return Arrays.areEqual(bytes, other.bytes); + } + + public String toString() + { + return getValue().toString(); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DERNull.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DERNull.java new file mode 100644 index 0000000..c41f3d3 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DERNull.java @@ -0,0 +1,38 @@ +package org.bc.asn1; + +import java.io.IOException; + +/** + * A NULL object. + */ +public class DERNull + extends ASN1Null +{ + public static final DERNull INSTANCE = new DERNull(); + + private static final byte[] zeroBytes = new byte[0]; + + /** + * @deprecated use DERNull.INSTANCE + */ + public DERNull() + { + } + + boolean isConstructed() + { + return false; + } + + int encodedLength() + { + return 2; + } + + void encode( + ASN1OutputStream out) + throws IOException + { + out.writeEncoded(BERTags.NULL, zeroBytes); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DERNumericString.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DERNumericString.java new file mode 100644 index 0000000..7b597ad --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DERNumericString.java @@ -0,0 +1,186 @@ +package org.bc.asn1; + +import java.io.IOException; + +import org.bc.util.Arrays; +import org.bc.util.Strings; + +/** + * DER NumericString object - this is an ascii string of characters {0,1,2,3,4,5,6,7,8,9, }. + */ +public class DERNumericString + extends ASN1Primitive + implements ASN1String +{ + private byte[] string; + + /** + * return a Numeric string from the passed in object + * + * @exception IllegalArgumentException if the object cannot be converted. + */ + public static DERNumericString getInstance( + Object obj) + { + if (obj == null || obj instanceof DERNumericString) + { + return (DERNumericString)obj; + } + + if (obj instanceof byte[]) + { + try + { + return (DERNumericString)fromByteArray((byte[])obj); + } + catch (Exception e) + { + throw new IllegalArgumentException("encoding error in getInstance: " + e.toString()); + } + } + + throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); + } + + /** + * return an Numeric String from a tagged object. + * + * @param obj the tagged object holding the object we want + * @param explicit true if the object is meant to be explicitly + * tagged false otherwise. + * @exception IllegalArgumentException if the tagged object cannot + * be converted. + */ + public static DERNumericString getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + ASN1Primitive o = obj.getObject(); + + if (explicit || o instanceof DERNumericString) + { + return getInstance(o); + } + else + { + return new DERNumericString(ASN1OctetString.getInstance(o).getOctets()); + } + } + + /** + * basic constructor - with bytes. + */ + DERNumericString( + byte[] string) + { + this.string = string; + } + + /** + * basic constructor - without validation.. + */ + public DERNumericString( + String string) + { + this(string, false); + } + + /** + * Constructor with optional validation. + * + * @param string the base string to wrap. + * @param validate whether or not to check the string. + * @throws IllegalArgumentException if validate is true and the string + * contains characters that should not be in a NumericString. + */ + public DERNumericString( + String string, + boolean validate) + { + if (validate && !isNumericString(string)) + { + throw new IllegalArgumentException("string contains illegal characters"); + } + + this.string = Strings.toByteArray(string); + } + + public String getString() + { + return Strings.fromByteArray(string); + } + + public String toString() + { + return getString(); + } + + public byte[] getOctets() + { + return Arrays.clone(string); + } + + boolean isConstructed() + { + return false; + } + + int encodedLength() + { + return 1 + StreamUtil.calculateBodyLength(string.length) + string.length; + } + + void encode( + ASN1OutputStream out) + throws IOException + { + out.writeEncoded(BERTags.NUMERIC_STRING, string); + } + + public int hashCode() + { + return Arrays.hashCode(string); + } + + boolean asn1Equals( + ASN1Primitive o) + { + if (!(o instanceof DERNumericString)) + { + return false; + } + + DERNumericString s = (DERNumericString)o; + + return Arrays.areEqual(string, s.string); + } + + /** + * Return true if the string can be represented as a NumericString ('0'..'9', ' ') + * + * @param str string to validate. + * @return true if numeric, fale otherwise. + */ + public static boolean isNumericString( + String str) + { + for (int i = str.length() - 1; i >= 0; i--) + { + char ch = str.charAt(i); + + if (ch > 0x007f) + { + return false; + } + + if (('0' <= ch && ch <= '9') || ch == ' ') + { + continue; + } + + return false; + } + + return true; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DERObjectIdentifier.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DERObjectIdentifier.java new file mode 100644 index 0000000..91b36fa --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DERObjectIdentifier.java @@ -0,0 +1,404 @@ +package org.bc.asn1; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.math.BigInteger; + +import org.bc.util.Arrays; + +public class DERObjectIdentifier + extends ASN1Primitive +{ + String identifier; + + private byte[] body; + + /** + * return an OID from the passed in object + * + * @exception IllegalArgumentException if the object cannot be converted. + */ + public static ASN1ObjectIdentifier getInstance( + Object obj) + { + if (obj == null || obj instanceof ASN1ObjectIdentifier) + { + return (ASN1ObjectIdentifier)obj; + } + + if (obj instanceof DERObjectIdentifier) + { + return new ASN1ObjectIdentifier(((DERObjectIdentifier)obj).getId()); + } + + if (obj instanceof ASN1Encodable && ((ASN1Encodable)obj).toASN1Primitive() instanceof ASN1ObjectIdentifier) + { + return (ASN1ObjectIdentifier)((ASN1Encodable)obj).toASN1Primitive(); + } + + if (obj instanceof byte[]) + { + return ASN1ObjectIdentifier.fromOctetString((byte[])obj); + } + + throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); + } + + /** + * return an Object Identifier from a tagged object. + * + * @param obj the tagged object holding the object we want + * @param explicit true if the object is meant to be explicitly + * tagged false otherwise. + * @exception IllegalArgumentException if the tagged object cannot + * be converted. + */ + public static ASN1ObjectIdentifier getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + ASN1Primitive o = obj.getObject(); + + if (explicit || o instanceof DERObjectIdentifier) + { + return getInstance(o); + } + else + { + return ASN1ObjectIdentifier.fromOctetString(ASN1OctetString.getInstance(obj.getObject()).getOctets()); + } + } + + private static final long LONG_LIMIT = (Long.MAX_VALUE >> 7) - 0x7f; + + DERObjectIdentifier( + byte[] bytes) + { + StringBuffer objId = new StringBuffer(); + long value = 0; + BigInteger bigValue = null; + boolean first = true; + + for (int i = 0; i != bytes.length; i++) + { + int b = bytes[i] & 0xff; + + if (value <= LONG_LIMIT) + { + value += (b & 0x7f); + if ((b & 0x80) == 0) // end of number reached + { + if (first) + { + if (value < 40) + { + objId.append('0'); + } + else if (value < 80) + { + objId.append('1'); + value -= 40; + } + else + { + objId.append('2'); + value -= 80; + } + first = false; + } + + objId.append('.'); + objId.append(value); + value = 0; + } + else + { + value <<= 7; + } + } + else + { + if (bigValue == null) + { + bigValue = BigInteger.valueOf(value); + } + bigValue = bigValue.or(BigInteger.valueOf(b & 0x7f)); + if ((b & 0x80) == 0) + { + if (first) + { + objId.append('2'); + bigValue = bigValue.subtract(BigInteger.valueOf(80)); + first = false; + } + + objId.append('.'); + objId.append(bigValue); + bigValue = null; + value = 0; + } + else + { + bigValue = bigValue.shiftLeft(7); + } + } + } + + this.identifier = objId.toString(); + this.body = Arrays.clone(bytes); + } + + public DERObjectIdentifier( + String identifier) + { + if (!isValidIdentifier(identifier)) + { + throw new IllegalArgumentException("string " + identifier + " not an OID"); + } + + this.identifier = identifier; + } + + public String getId() + { + return identifier; + } + + private void writeField( + ByteArrayOutputStream out, + long fieldValue) + { + byte[] result = new byte[9]; + int pos = 8; + result[pos] = (byte)((int)fieldValue & 0x7f); + while (fieldValue >= (1L << 7)) + { + fieldValue >>= 7; + result[--pos] = (byte)((int)fieldValue & 0x7f | 0x80); + } + out.write(result, pos, 9 - pos); + } + + private void writeField( + ByteArrayOutputStream out, + BigInteger fieldValue) + { + int byteCount = (fieldValue.bitLength()+6)/7; + if (byteCount == 0) + { + out.write(0); + } + else + { + BigInteger tmpValue = fieldValue; + byte[] tmp = new byte[byteCount]; + for (int i = byteCount-1; i >= 0; i--) + { + tmp[i] = (byte) ((tmpValue.intValue() & 0x7f) | 0x80); + tmpValue = tmpValue.shiftRight(7); + } + tmp[byteCount-1] &= 0x7f; + out.write(tmp, 0, tmp.length); + } + } + + private void doOutput(ByteArrayOutputStream aOut) + { + OIDTokenizer tok = new OIDTokenizer(identifier); + int first = Integer.parseInt(tok.nextToken()) * 40; + + String secondToken = tok.nextToken(); + if (secondToken.length() <= 18) + { + writeField(aOut, first + Long.parseLong(secondToken)); + } + else + { + writeField(aOut, new BigInteger(secondToken).add(BigInteger.valueOf(first))); + } + + while (tok.hasMoreTokens()) + { + String token = tok.nextToken(); + if (token.length() <= 18) + { + writeField(aOut, Long.parseLong(token)); + } + else + { + writeField(aOut, new BigInteger(token)); + } + } + } + + protected synchronized byte[] getBody() + { + if (body == null) + { + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + doOutput(bOut); + + body = bOut.toByteArray(); + } + + return body; + } + + boolean isConstructed() + { + return false; + } + + int encodedLength() + throws IOException + { + int length = getBody().length; + + return 1 + StreamUtil.calculateBodyLength(length) + length; + } + + void encode( + ASN1OutputStream out) + throws IOException + { + byte[] enc = getBody(); + + out.write(BERTags.OBJECT_IDENTIFIER); + out.writeLength(enc.length); + out.write(enc); + } + + public int hashCode() + { + return identifier.hashCode(); + } + + boolean asn1Equals( + ASN1Primitive o) + { + if (!(o instanceof DERObjectIdentifier)) + { + return false; + } + + return identifier.equals(((DERObjectIdentifier)o).identifier); + } + + public String toString() + { + return getId(); + } + + private static boolean isValidIdentifier( + String identifier) + { + if (identifier.length() < 3 + || identifier.charAt(1) != '.') + { + return false; + } + + char first = identifier.charAt(0); + if (first < '0' || first > '2') + { + return false; + } + + boolean periodAllowed = false; + for (int i = identifier.length() - 1; i >= 2; i--) + { + char ch = identifier.charAt(i); + + // TODO Leading zeroes? + if ('0' <= ch && ch <= '9') + { + periodAllowed = true; + continue; + } + + if (ch == '.') + { + if (!periodAllowed) + { + return false; + } + + periodAllowed = false; + continue; + } + + return false; + } + + return periodAllowed; + } + + private static ASN1ObjectIdentifier[][] cache = new ASN1ObjectIdentifier[256][]; + + static ASN1ObjectIdentifier fromOctetString(byte[] enc) + { + if (enc.length < 3) + { + return new ASN1ObjectIdentifier(enc); + } + + int idx1 = enc[enc.length - 2] & 0xff; + // in this case top bit is always zero + int idx2 = enc[enc.length - 1] & 0x7f; + + ASN1ObjectIdentifier possibleMatch; + + synchronized (cache) + { + ASN1ObjectIdentifier[] first = cache[idx1]; + if (first == null) + { + first = cache[idx1] = new ASN1ObjectIdentifier[128]; + } + + possibleMatch = first[idx2]; + if (possibleMatch == null) + { + return first[idx2] = new ASN1ObjectIdentifier(enc); + } + + if (Arrays.areEqual(enc, possibleMatch.getBody())) + { + return possibleMatch; + } + + idx1 = (idx1 + 1) & 0xff; + first = cache[idx1]; + if (first == null) + { + first = cache[idx1] = new ASN1ObjectIdentifier[128]; + } + + possibleMatch = first[idx2]; + if (possibleMatch == null) + { + return first[idx2] = new ASN1ObjectIdentifier(enc); + } + + if (Arrays.areEqual(enc, possibleMatch.getBody())) + { + return possibleMatch; + } + + idx2 = (idx2 + 1) & 0x7f; + possibleMatch = first[idx2]; + if (possibleMatch == null) + { + return first[idx2] = new ASN1ObjectIdentifier(enc); + } + } + + if (Arrays.areEqual(enc, possibleMatch.getBody())) + { + return possibleMatch; + } + + return new ASN1ObjectIdentifier(enc); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DEROctetString.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DEROctetString.java new file mode 100644 index 0000000..61ab68c --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DEROctetString.java @@ -0,0 +1,48 @@ +package org.bc.asn1; + +import java.io.IOException; + +public class DEROctetString + extends ASN1OctetString +{ + /** + * @param string the octets making up the octet string. + */ + public DEROctetString( + byte[] string) + { + super(string); + } + + public DEROctetString( + ASN1Encodable obj) + throws IOException + { + super(obj.toASN1Primitive().getEncoded(ASN1Encoding.DER)); + } + + boolean isConstructed() + { + return false; + } + + int encodedLength() + { + return 1 + StreamUtil.calculateBodyLength(string.length) + string.length; + } + + void encode( + ASN1OutputStream out) + throws IOException + { + out.writeEncoded(BERTags.OCTET_STRING, string); + } + + static void encode( + DEROutputStream derOut, + byte[] bytes) + throws IOException + { + derOut.writeEncoded(BERTags.OCTET_STRING, bytes); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DEROctetStringParser.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DEROctetStringParser.java new file mode 100644 index 0000000..6fd6036 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DEROctetStringParser.java @@ -0,0 +1,39 @@ +package org.bc.asn1; + +import java.io.IOException; +import java.io.InputStream; + +public class DEROctetStringParser + implements ASN1OctetStringParser +{ + private DefiniteLengthInputStream stream; + + DEROctetStringParser( + DefiniteLengthInputStream stream) + { + this.stream = stream; + } + + public InputStream getOctetStream() + { + return stream; + } + + public ASN1Primitive getLoadedObject() + throws IOException + { + return new DEROctetString(stream.toByteArray()); + } + + public ASN1Primitive toASN1Primitive() + { + try + { + return getLoadedObject(); + } + catch (IOException e) + { + throw new ASN1ParsingException("IOException converting stream to byte array: " + e.getMessage(), e); + } + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DEROutputStream.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DEROutputStream.java new file mode 100644 index 0000000..81ac19e --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DEROutputStream.java @@ -0,0 +1,41 @@ +package org.bc.asn1; + +import java.io.IOException; +import java.io.OutputStream; + +/** + * Stream that outputs encoding based on distinguished encoding rules. + */ +public class DEROutputStream + extends ASN1OutputStream +{ + public DEROutputStream( + OutputStream os) + { + super(os); + } + + public void writeObject( + ASN1Encodable obj) + throws IOException + { + if (obj != null) + { + obj.toASN1Primitive().toDERObject().encode(this); + } + else + { + throw new IOException("null object detected"); + } + } + + ASN1OutputStream getDERSubStream() + { + return this; + } + + ASN1OutputStream getDLSubStream() + { + return this; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DERPrintableString.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DERPrintableString.java new file mode 100644 index 0000000..7d9c14b --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DERPrintableString.java @@ -0,0 +1,213 @@ +package org.bc.asn1; + +import java.io.IOException; + +import org.bc.util.Arrays; +import org.bc.util.Strings; + +/** + * DER PrintableString object. + */ +public class DERPrintableString + extends ASN1Primitive + implements ASN1String +{ + private byte[] string; + + /** + * return a printable string from the passed in object. + * + * @exception IllegalArgumentException if the object cannot be converted. + */ + public static DERPrintableString getInstance( + Object obj) + { + if (obj == null || obj instanceof DERPrintableString) + { + return (DERPrintableString)obj; + } + + if (obj instanceof byte[]) + { + try + { + return (DERPrintableString)fromByteArray((byte[])obj); + } + catch (Exception e) + { + throw new IllegalArgumentException("encoding error in getInstance: " + e.toString()); + } + } + + throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); + } + + /** + * return a Printable String from a tagged object. + * + * @param obj the tagged object holding the object we want + * @param explicit true if the object is meant to be explicitly + * tagged false otherwise. + * @exception IllegalArgumentException if the tagged object cannot + * be converted. + */ + public static DERPrintableString getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + ASN1Primitive o = obj.getObject(); + + if (explicit || o instanceof DERPrintableString) + { + return getInstance(o); + } + else + { + return new DERPrintableString(ASN1OctetString.getInstance(o).getOctets()); + } + } + + /** + * basic constructor - byte encoded string. + */ + DERPrintableString( + byte[] string) + { + this.string = string; + } + + /** + * basic constructor - this does not validate the string + */ + public DERPrintableString( + String string) + { + this(string, false); + } + + /** + * Constructor with optional validation. + * + * @param string the base string to wrap. + * @param validate whether or not to check the string. + * @throws IllegalArgumentException if validate is true and the string + * contains characters that should not be in a PrintableString. + */ + public DERPrintableString( + String string, + boolean validate) + { + if (validate && !isPrintableString(string)) + { + throw new IllegalArgumentException("string contains illegal characters"); + } + + this.string = Strings.toByteArray(string); + } + + public String getString() + { + return Strings.fromByteArray(string); + } + + public byte[] getOctets() + { + return Arrays.clone(string); + } + + boolean isConstructed() + { + return false; + } + + int encodedLength() + { + return 1 + StreamUtil.calculateBodyLength(string.length) + string.length; + } + + void encode( + ASN1OutputStream out) + throws IOException + { + out.writeEncoded(BERTags.PRINTABLE_STRING, string); + } + + public int hashCode() + { + return Arrays.hashCode(string); + } + + boolean asn1Equals( + ASN1Primitive o) + { + if (!(o instanceof DERPrintableString)) + { + return false; + } + + DERPrintableString s = (DERPrintableString)o; + + return Arrays.areEqual(string, s.string); + } + + public String toString() + { + return getString(); + } + + /** + * return true if the passed in String can be represented without + * loss as a PrintableString, false otherwise. + * + * @return true if in printable set, false otherwise. + */ + public static boolean isPrintableString( + String str) + { + for (int i = str.length() - 1; i >= 0; i--) + { + char ch = str.charAt(i); + + if (ch > 0x007f) + { + return false; + } + + if ('a' <= ch && ch <= 'z') + { + continue; + } + + if ('A' <= ch && ch <= 'Z') + { + continue; + } + + if ('0' <= ch && ch <= '9') + { + continue; + } + + switch (ch) + { + case ' ': + case '\'': + case '(': + case ')': + case '+': + case '-': + case '.': + case ':': + case '=': + case '?': + case '/': + case ',': + continue; + } + + return false; + } + + return true; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DERSequence.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DERSequence.java new file mode 100644 index 0000000..0d7ff45 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DERSequence.java @@ -0,0 +1,98 @@ +package org.bc.asn1; + +import java.io.IOException; +import java.util.Enumeration; + +public class DERSequence + extends ASN1Sequence +{ + private int bodyLength = -1; + + /** + * create an empty sequence + */ + public DERSequence() + { + } + + /** + * create a sequence containing one object + */ + public DERSequence( + ASN1Encodable obj) + { + super(obj); + } + + /** + * create a sequence containing a vector of objects. + */ + public DERSequence( + ASN1EncodableVector v) + { + super(v); + } + + /** + * create a sequence containing an array of objects. + */ + public DERSequence( + ASN1Encodable[] array) + { + super(array); + } + + private int getBodyLength() + throws IOException + { + if (bodyLength < 0) + { + int length = 0; + + for (Enumeration e = this.getObjects(); e.hasMoreElements();) + { + Object obj = e.nextElement(); + + length += ((ASN1Encodable)obj).toASN1Primitive().toDERObject().encodedLength(); + } + + bodyLength = length; + } + + return bodyLength; + } + + int encodedLength() + throws IOException + { + int length = getBodyLength(); + + return 1 + StreamUtil.calculateBodyLength(length) + length; + } + + /* + * A note on the implementation: + *
+ * As DER requires the constructed, definite-length model to + * be used for structured types, this varies slightly from the + * ASN.1 descriptions given. Rather than just outputting SEQUENCE, + * we also have to specify CONSTRUCTED, and the objects length. + */ + void encode( + ASN1OutputStream out) + throws IOException + { + ASN1OutputStream dOut = out.getDERSubStream(); + int length = getBodyLength(); + + out.write(BERTags.SEQUENCE | BERTags.CONSTRUCTED); + out.writeLength(length); + + for (Enumeration e = this.getObjects(); e.hasMoreElements();) + { + Object obj = e.nextElement(); + + dOut.writeObject((ASN1Encodable)obj); + } + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DERSequenceGenerator.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DERSequenceGenerator.java new file mode 100644 index 0000000..0a79fcf --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DERSequenceGenerator.java @@ -0,0 +1,45 @@ +package org.bc.asn1; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +public class DERSequenceGenerator + extends DERGenerator +{ + private final ByteArrayOutputStream _bOut = new ByteArrayOutputStream(); + + public DERSequenceGenerator( + OutputStream out) + throws IOException + { + super(out); + } + + public DERSequenceGenerator( + OutputStream out, + int tagNo, + boolean isExplicit) + throws IOException + { + super(out, tagNo, isExplicit); + } + + public void addObject( + ASN1Encodable object) + throws IOException + { + object.toASN1Primitive().encode(new DEROutputStream(_bOut)); + } + + public OutputStream getRawOutputStream() + { + return _bOut; + } + + public void close() + throws IOException + { + writeDEREncoded(BERTags.CONSTRUCTED | BERTags.SEQUENCE, _bOut.toByteArray()); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DERSequenceParser.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DERSequenceParser.java new file mode 100644 index 0000000..1337c96 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DERSequenceParser.java @@ -0,0 +1,38 @@ +package org.bc.asn1; + +import java.io.IOException; + +public class DERSequenceParser + implements ASN1SequenceParser +{ + private ASN1StreamParser _parser; + + DERSequenceParser(ASN1StreamParser parser) + { + this._parser = parser; + } + + public ASN1Encodable readObject() + throws IOException + { + return _parser.readObject(); + } + + public ASN1Primitive getLoadedObject() + throws IOException + { + return new DERSequence(_parser.readVector()); + } + + public ASN1Primitive toASN1Primitive() + { + try + { + return getLoadedObject(); + } + catch (IOException e) + { + throw new IllegalStateException(e.getMessage()); + } + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DERSet.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DERSet.java new file mode 100644 index 0000000..cfc7fb2 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DERSet.java @@ -0,0 +1,108 @@ +package org.bc.asn1; + +import java.io.IOException; +import java.util.Enumeration; + +/** + * A DER encoded set object + */ +public class DERSet + extends ASN1Set +{ + private int bodyLength = -1; + + /** + * create an empty set + */ + public DERSet() + { + } + + /** + * @param obj - a single object that makes up the set. + */ + public DERSet( + ASN1Encodable obj) + { + super(obj); + } + + /** + * @param v - a vector of objects making up the set. + */ + public DERSet( + ASN1EncodableVector v) + { + super(v, true); + } + + /** + * create a set from an array of objects. + */ + public DERSet( + ASN1Encodable[] a) + { + super(a, true); + } + + DERSet( + ASN1EncodableVector v, + boolean doSort) + { + super(v, doSort); + } + + private int getBodyLength() + throws IOException + { + if (bodyLength < 0) + { + int length = 0; + + for (Enumeration e = this.getObjects(); e.hasMoreElements();) + { + Object obj = e.nextElement(); + + length += ((ASN1Encodable)obj).toASN1Primitive().toDERObject().encodedLength(); + } + + bodyLength = length; + } + + return bodyLength; + } + + int encodedLength() + throws IOException + { + int length = getBodyLength(); + + return 1 + StreamUtil.calculateBodyLength(length) + length; + } + + /* + * A note on the implementation: + *
+ * As DER requires the constructed, definite-length model to + * be used for structured types, this varies slightly from the + * ASN.1 descriptions given. Rather than just outputting SET, + * we also have to specify CONSTRUCTED, and the objects length. + */ + void encode( + ASN1OutputStream out) + throws IOException + { + ASN1OutputStream dOut = out.getDERSubStream(); + int length = getBodyLength(); + + out.write(BERTags.SET | BERTags.CONSTRUCTED); + out.writeLength(length); + + for (Enumeration e = this.getObjects(); e.hasMoreElements();) + { + Object obj = e.nextElement(); + + dOut.writeObject((ASN1Encodable)obj); + } + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DERSetParser.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DERSetParser.java new file mode 100644 index 0000000..44c7fd2 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DERSetParser.java @@ -0,0 +1,38 @@ +package org.bc.asn1; + +import java.io.IOException; + +public class DERSetParser + implements ASN1SetParser +{ + private ASN1StreamParser _parser; + + DERSetParser(ASN1StreamParser parser) + { + this._parser = parser; + } + + public ASN1Encodable readObject() + throws IOException + { + return _parser.readObject(); + } + + public ASN1Primitive getLoadedObject() + throws IOException + { + return new DERSet(_parser.readVector(), false); + } + + public ASN1Primitive toASN1Primitive() + { + try + { + return getLoadedObject(); + } + catch (IOException e) + { + throw new ASN1ParsingException(e.getMessage(), e); + } + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DERT61String.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DERT61String.java new file mode 100644 index 0000000..47e5465 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DERT61String.java @@ -0,0 +1,135 @@ +package org.bc.asn1; + +import java.io.IOException; + +import org.bc.util.Arrays; +import org.bc.util.Strings; + +/** + * DER T61String (also the teletex string) + */ +public class DERT61String + extends ASN1Primitive + implements ASN1String +{ + private byte[] string; + + /** + * return a T61 string from the passed in object. + * + * @exception IllegalArgumentException if the object cannot be converted. + */ + public static DERT61String getInstance( + Object obj) + { + if (obj == null || obj instanceof DERT61String) + { + return (DERT61String)obj; + } + + if (obj instanceof byte[]) + { + try + { + return (DERT61String)fromByteArray((byte[])obj); + } + catch (Exception e) + { + throw new IllegalArgumentException("encoding error in getInstance: " + e.toString()); + } + } + + throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); + } + + /** + * return an T61 String from a tagged object. + * + * @param obj the tagged object holding the object we want + * @param explicit true if the object is meant to be explicitly + * tagged false otherwise. + * @exception IllegalArgumentException if the tagged object cannot + * be converted. + */ + public static DERT61String getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + ASN1Primitive o = obj.getObject(); + + if (explicit || o instanceof DERT61String) + { + return getInstance(o); + } + else + { + return new DERT61String(ASN1OctetString.getInstance(o).getOctets()); + } + } + + /** + * basic constructor - with bytes. + */ + DERT61String( + byte[] string) + { + this.string = string; + } + + /** + * basic constructor - with string. + */ + public DERT61String( + String string) + { + this.string = Strings.toUTF8ByteArray(string); + } + + public String getString() + { + return Strings.fromUTF8ByteArray(string); + } + + public String toString() + { + return getString(); + } + + boolean isConstructed() + { + return false; + } + + int encodedLength() + { + return 1 + StreamUtil.calculateBodyLength(string.length) + string.length; + } + + void encode( + ASN1OutputStream out) + throws IOException + { + out.writeEncoded(BERTags.T61_STRING, string); + } + + public byte[] getOctets() + { + return Arrays.clone(string); + } + + boolean asn1Equals( + ASN1Primitive o) + { + if (!(o instanceof DERT61String)) + { + return false; + } + + return Arrays.areEqual(string, ((DERT61String)o).string); + } + + public int hashCode() + { + return Arrays.hashCode(string); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DERTaggedObject.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DERTaggedObject.java new file mode 100644 index 0000000..9d31bdb --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DERTaggedObject.java @@ -0,0 +1,118 @@ +package org.bc.asn1; + +import java.io.IOException; + +/** + * DER TaggedObject - in ASN.1 notation this is any object preceded by + * a [n] where n is some number - these are assumed to follow the construction + * rules (as with sequences). + */ +public class DERTaggedObject + extends ASN1TaggedObject +{ + private static final byte[] ZERO_BYTES = new byte[0]; + + /** + * @param explicit true if an explicitly tagged object. + * @param tagNo the tag number for this object. + * @param obj the tagged object. + */ + public DERTaggedObject( + boolean explicit, + int tagNo, + ASN1Encodable obj) + { + super(explicit, tagNo, obj); + } + + public DERTaggedObject(int tagNo, ASN1Encodable encodable) + { + super(true, tagNo, encodable); + } + + boolean isConstructed() + { + if (!empty) + { + if (explicit) + { + return true; + } + else + { + ASN1Primitive primitive = obj.toASN1Primitive().toDERObject(); + + return primitive.isConstructed(); + } + } + else + { + return true; + } + } + + int encodedLength() + throws IOException + { + if (!empty) + { + ASN1Primitive primitive = obj.toASN1Primitive().toDERObject(); + int length = primitive.encodedLength(); + + if (explicit) + { + return StreamUtil.calculateTagLength(tagNo) + StreamUtil.calculateBodyLength(length) + length; + } + else + { + // header length already in calculation + length = length - 1; + + return StreamUtil.calculateTagLength(tagNo) + length; + } + } + else + { + return StreamUtil.calculateTagLength(tagNo) + 1; + } + } + + void encode( + ASN1OutputStream out) + throws IOException + { + if (!empty) + { + ASN1Primitive primitive = obj.toASN1Primitive().toDERObject(); + + if (explicit) + { + out.writeTag(BERTags.CONSTRUCTED | BERTags.TAGGED, tagNo); + out.writeLength(primitive.encodedLength()); + out.writeObject(primitive); + } + else + { + // + // need to mark constructed types... + // + int flags; + if (primitive.isConstructed()) + { + flags = BERTags.CONSTRUCTED | BERTags.TAGGED; + } + else + { + flags = BERTags.TAGGED; + } + + out.writeTag(flags, tagNo); + out.writeImplicitObject(primitive); + } + } + else + { + out.writeEncoded(BERTags.CONSTRUCTED | BERTags.TAGGED, tagNo, ZERO_BYTES); + } + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DERTags.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DERTags.java new file mode 100644 index 0000000..1ecfa54 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DERTags.java @@ -0,0 +1,9 @@ +package org.bc.asn1; + +/** + * @deprecated use BERTags + */ +public interface DERTags + extends BERTags +{ +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DERUTCTime.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DERUTCTime.java new file mode 100644 index 0000000..1cbff48 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DERUTCTime.java @@ -0,0 +1,278 @@ +package org.bc.asn1; + +import java.io.IOException; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.SimpleTimeZone; + +import org.bc.util.Arrays; +import org.bc.util.Strings; + +/** + * UTC time object. + */ +public class DERUTCTime + extends ASN1Primitive +{ + private byte[] time; + + /** + * return an UTC Time from the passed in object. + * + * @exception IllegalArgumentException if the object cannot be converted. + */ + public static ASN1UTCTime getInstance( + Object obj) + { + if (obj == null || obj instanceof ASN1UTCTime) + { + return (ASN1UTCTime)obj; + } + + if (obj instanceof DERUTCTime) + { + return new ASN1UTCTime(((DERUTCTime)obj).time); + } + + if (obj instanceof byte[]) + { + try + { + return (ASN1UTCTime)fromByteArray((byte[])obj); + } + catch (Exception e) + { + throw new IllegalArgumentException("encoding error in getInstance: " + e.toString()); + } + } + + throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); + } + + /** + * return an UTC Time from a tagged object. + * + * @param obj the tagged object holding the object we want + * @param explicit true if the object is meant to be explicitly + * tagged false otherwise. + * @exception IllegalArgumentException if the tagged object cannot + * be converted. + */ + public static ASN1UTCTime getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + ASN1Object o = obj.getObject(); + + if (explicit || o instanceof ASN1UTCTime) + { + return getInstance(o); + } + else + { + return new ASN1UTCTime(((ASN1OctetString)o).getOctets()); + } + } + + /** + * The correct format for this is YYMMDDHHMMSSZ (it used to be that seconds were + * never encoded. When you're creating one of these objects from scratch, that's + * what you want to use, otherwise we'll try to deal with whatever gets read from + * the input stream... (this is why the input format is different from the getTime() + * method output). + *
+ * + * @param time the time string. + */ + public DERUTCTime( + String time) + { + this.time = Strings.toByteArray(time); + try + { + this.getDate(); + } + catch (ParseException e) + { + throw new IllegalArgumentException("invalid date string: " + e.getMessage()); + } + } + + /** + * base constructer from a java.util.date object + */ + public DERUTCTime( + Date time) + { + SimpleDateFormat dateF = new SimpleDateFormat("yyMMddHHmmss'Z'"); + + dateF.setTimeZone(new SimpleTimeZone(0,"Z")); + + this.time = Strings.toByteArray(dateF.format(time)); + } + + DERUTCTime( + byte[] time) + { + this.time = time; + } + + /** + * return the time as a date based on whatever a 2 digit year will return. For + * standardised processing use getAdjustedDate(). + * + * @return the resulting date + * @exception ParseException if the date string cannot be parsed. + */ + public Date getDate() + throws ParseException + { + SimpleDateFormat dateF = new SimpleDateFormat("yyMMddHHmmssz"); + + return dateF.parse(getTime()); + } + + /** + * return the time as an adjusted date + * in the range of 1950 - 2049. + * + * @return a date in the range of 1950 to 2049. + * @exception ParseException if the date string cannot be parsed. + */ + public Date getAdjustedDate() + throws ParseException + { + SimpleDateFormat dateF = new SimpleDateFormat("yyyyMMddHHmmssz"); + + dateF.setTimeZone(new SimpleTimeZone(0, "Z")); + + return dateF.parse(getAdjustedTime()); + } + + /** + * return the time - always in the form of + * YYMMDDhhmmssGMT(+hh:mm|-hh:mm). + *
+ * Normally in a certificate we would expect "Z" rather than "GMT", + * however adding the "GMT" means we can just use: + *
+ * dateF = new SimpleDateFormat("yyMMddHHmmssz"); + *+ * To read in the time and get a date which is compatible with our local + * time zone. + *
+ * Note: In some cases, due to the local date processing, this + * may lead to unexpected results. If you want to stick the normal + * convention of 1950 to 2049 use the getAdjustedTime() method. + */ + public String getTime() + { + String stime = Strings.fromByteArray(time); + + // + // standardise the format. + // + if (stime.indexOf('-') < 0 && stime.indexOf('+') < 0) + { + if (stime.length() == 11) + { + return stime.substring(0, 10) + "00GMT+00:00"; + } + else + { + return stime.substring(0, 12) + "GMT+00:00"; + } + } + else + { + int index = stime.indexOf('-'); + if (index < 0) + { + index = stime.indexOf('+'); + } + String d = stime; + + if (index == stime.length() - 3) + { + d += "00"; + } + + if (index == 10) + { + return d.substring(0, 10) + "00GMT" + d.substring(10, 13) + ":" + d.substring(13, 15); + } + else + { + return d.substring(0, 12) + "GMT" + d.substring(12, 15) + ":" + d.substring(15, 17); + } + } + } + + /** + * return a time string as an adjusted date with a 4 digit year. This goes + * in the range of 1950 - 2049. + */ + public String getAdjustedTime() + { + String d = this.getTime(); + + if (d.charAt(0) < '5') + { + return "20" + d; + } + else + { + return "19" + d; + } + } + + boolean isConstructed() + { + return false; + } + + int encodedLength() + { + int length = time.length; + + return 1 + StreamUtil.calculateBodyLength(length) + length; + } + + void encode( + ASN1OutputStream out) + throws IOException + { + out.write(BERTags.UTC_TIME); + + int length = time.length; + + out.writeLength(length); + + for (int i = 0; i != length; i++) + { + out.write((byte)time[i]); + } + } + + boolean asn1Equals( + ASN1Primitive o) + { + if (!(o instanceof DERUTCTime)) + { + return false; + } + + return Arrays.areEqual(time, ((DERUTCTime)o).time); + } + + public int hashCode() + { + return Arrays.hashCode(time); + } + + public String toString() + { + return Strings.fromByteArray(time); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DERUTF8String.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DERUTF8String.java new file mode 100644 index 0000000..e3a7aa9 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DERUTF8String.java @@ -0,0 +1,132 @@ +package org.bc.asn1; + +import java.io.IOException; + +import org.bc.util.Arrays; +import org.bc.util.Strings; + +/** + * DER UTF8String object. + */ +public class DERUTF8String + extends ASN1Primitive + implements ASN1String +{ + private byte[] string; + + /** + * return an UTF8 string from the passed in object. + * + * @exception IllegalArgumentException + * if the object cannot be converted. + */ + public static DERUTF8String getInstance(Object obj) + { + if (obj == null || obj instanceof DERUTF8String) + { + return (DERUTF8String)obj; + } + + if (obj instanceof byte[]) + { + try + { + return (DERUTF8String)fromByteArray((byte[])obj); + } + catch (Exception e) + { + throw new IllegalArgumentException("encoding error in getInstance: " + e.toString()); + } + } + + throw new IllegalArgumentException("illegal object in getInstance: " + + obj.getClass().getName()); + } + + /** + * return an UTF8 String from a tagged object. + * + * @param obj + * the tagged object holding the object we want + * @param explicit + * true if the object is meant to be explicitly tagged false + * otherwise. + * @exception IllegalArgumentException + * if the tagged object cannot be converted. + */ + public static DERUTF8String getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + ASN1Primitive o = obj.getObject(); + + if (explicit || o instanceof DERUTF8String) + { + return getInstance(o); + } + else + { + return new DERUTF8String(ASN1OctetString.getInstance(o).getOctets()); + } + } + + /** + * basic constructor - byte encoded string. + */ + DERUTF8String(byte[] string) + { + this.string = string; + } + + /** + * basic constructor + */ + public DERUTF8String(String string) + { + this.string = Strings.toUTF8ByteArray(string); + } + + public String getString() + { + return Strings.fromUTF8ByteArray(string); + } + + public String toString() + { + return getString(); + } + + public int hashCode() + { + return Arrays.hashCode(string); + } + + boolean asn1Equals(ASN1Primitive o) + { + if (!(o instanceof DERUTF8String)) + { + return false; + } + + DERUTF8String s = (DERUTF8String)o; + + return Arrays.areEqual(string, s.string); + } + + boolean isConstructed() + { + return false; + } + + int encodedLength() + throws IOException + { + return 1 + StreamUtil.calculateBodyLength(string.length) + string.length; + } + + void encode(ASN1OutputStream out) + throws IOException + { + out.writeEncoded(BERTags.UTF8_STRING, string); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DERUniversalString.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DERUniversalString.java new file mode 100644 index 0000000..2e571be --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DERUniversalString.java @@ -0,0 +1,148 @@ +package org.bc.asn1; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +import org.bc.util.Arrays; + +/** + * DER UniversalString object. + */ +public class DERUniversalString + extends ASN1Primitive + implements ASN1String +{ + private static final char[] table = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; + private byte[] string; + + /** + * return a Universal String from the passed in object. + * + * @exception IllegalArgumentException if the object cannot be converted. + */ + public static DERUniversalString getInstance( + Object obj) + { + if (obj == null || obj instanceof DERUniversalString) + { + return (DERUniversalString)obj; + } + + if (obj instanceof byte[]) + { + try + { + return (DERUniversalString)fromByteArray((byte[])obj); + } + catch (Exception e) + { + throw new IllegalArgumentException("encoding error getInstance: " + e.toString()); + } + } + + throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); + } + + /** + * return a Universal String from a tagged object. + * + * @param obj the tagged object holding the object we want + * @param explicit true if the object is meant to be explicitly + * tagged false otherwise. + * @exception IllegalArgumentException if the tagged object cannot + * be converted. + */ + public static DERUniversalString getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + ASN1Primitive o = obj.getObject(); + + if (explicit || o instanceof DERUniversalString) + { + return getInstance(o); + } + else + { + return new DERUniversalString(((ASN1OctetString)o).getOctets()); + } + } + + /** + * basic constructor - byte encoded string. + */ + public DERUniversalString( + byte[] string) + { + this.string = string; + } + + public String getString() + { + StringBuffer buf = new StringBuffer("#"); + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + ASN1OutputStream aOut = new ASN1OutputStream(bOut); + + try + { + aOut.writeObject(this); + } + catch (IOException e) + { + throw new RuntimeException("internal error encoding BitString"); + } + + byte[] string = bOut.toByteArray(); + + for (int i = 0; i != string.length; i++) + { + buf.append(table[(string[i] >>> 4) & 0xf]); + buf.append(table[string[i] & 0xf]); + } + + return buf.toString(); + } + + public String toString() + { + return getString(); + } + + public byte[] getOctets() + { + return string; + } + + boolean isConstructed() + { + return false; + } + + int encodedLength() + { + return 1 + StreamUtil.calculateBodyLength(string.length) + string.length; + } + + void encode( + ASN1OutputStream out) + throws IOException + { + out.writeEncoded(BERTags.UNIVERSAL_STRING, this.getOctets()); + } + + boolean asn1Equals( + ASN1Primitive o) + { + if (!(o instanceof DERUniversalString)) + { + return false; + } + + return Arrays.areEqual(string, ((DERUniversalString)o).string); + } + + public int hashCode() + { + return Arrays.hashCode(string); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DERVisibleString.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DERVisibleString.java new file mode 100644 index 0000000..54674cd --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DERVisibleString.java @@ -0,0 +1,135 @@ +package org.bc.asn1; + +import java.io.IOException; + +import org.bc.util.Arrays; +import org.bc.util.Strings; + +/** + * DER VisibleString object. + */ +public class DERVisibleString + extends ASN1Primitive + implements ASN1String +{ + private byte[] string; + + /** + * return a Visible String from the passed in object. + * + * @exception IllegalArgumentException if the object cannot be converted. + */ + public static DERVisibleString getInstance( + Object obj) + { + if (obj == null || obj instanceof DERVisibleString) + { + return (DERVisibleString)obj; + } + + if (obj instanceof byte[]) + { + try + { + return (DERVisibleString)fromByteArray((byte[])obj); + } + catch (Exception e) + { + throw new IllegalArgumentException("encoding error in getInstance: " + e.toString()); + } + } + + throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); + } + + /** + * return a Visible String from a tagged object. + * + * @param obj the tagged object holding the object we want + * @param explicit true if the object is meant to be explicitly + * tagged false otherwise. + * @exception IllegalArgumentException if the tagged object cannot + * be converted. + */ + public static DERVisibleString getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + ASN1Primitive o = obj.getObject(); + + if (explicit || o instanceof DERVisibleString) + { + return getInstance(o); + } + else + { + return new DERVisibleString(ASN1OctetString.getInstance(o).getOctets()); + } + } + + /** + * basic constructor - byte encoded string. + */ + DERVisibleString( + byte[] string) + { + this.string = string; + } + + /** + * basic constructor + */ + public DERVisibleString( + String string) + { + this.string = Strings.toByteArray(string); + } + + public String getString() + { + return Strings.fromByteArray(string); + } + + public String toString() + { + return getString(); + } + + public byte[] getOctets() + { + return Arrays.clone(string); + } + + boolean isConstructed() + { + return false; + } + + int encodedLength() + { + return 1 + StreamUtil.calculateBodyLength(string.length) + string.length; + } + + void encode( + ASN1OutputStream out) + throws IOException + { + out.writeEncoded(BERTags.VISIBLE_STRING, this.string); + } + + boolean asn1Equals( + ASN1Primitive o) + { + if (!(o instanceof DERVisibleString)) + { + return false; + } + + return Arrays.areEqual(string, ((DERVisibleString)o).string); + } + + public int hashCode() + { + return Arrays.hashCode(string); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DLOutputStream.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DLOutputStream.java new file mode 100644 index 0000000..930dd3d --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DLOutputStream.java @@ -0,0 +1,31 @@ +package org.bc.asn1; + +import java.io.IOException; +import java.io.OutputStream; + +/** + * Stream that outputs encoding based on definite length. + */ +public class DLOutputStream + extends ASN1OutputStream +{ + public DLOutputStream( + OutputStream os) + { + super(os); + } + + public void writeObject( + ASN1Encodable obj) + throws IOException + { + if (obj != null) + { + obj.toASN1Primitive().toDLObject().encode(this); + } + else + { + throw new IOException("null object detected"); + } + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DLSequence.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DLSequence.java new file mode 100644 index 0000000..e911829 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DLSequence.java @@ -0,0 +1,98 @@ +package org.bc.asn1; + +import java.io.IOException; +import java.util.Enumeration; + +public class DLSequence + extends ASN1Sequence +{ + private int bodyLength = -1; + + /** + * create an empty sequence + */ + public DLSequence() + { + } + + /** + * create a sequence containing one object + */ + public DLSequence( + ASN1Encodable obj) + { + super(obj); + } + + /** + * create a sequence containing a vector of objects. + */ + public DLSequence( + ASN1EncodableVector v) + { + super(v); + } + + /** + * create a sequence containing an array of objects. + */ + public DLSequence( + ASN1Encodable[] array) + { + super(array); + } + + private int getBodyLength() + throws IOException + { + if (bodyLength < 0) + { + int length = 0; + + for (Enumeration e = this.getObjects(); e.hasMoreElements();) + { + Object obj = e.nextElement(); + + length += ((ASN1Encodable)obj).toASN1Primitive().toDLObject().encodedLength(); + } + + bodyLength = length; + } + + return bodyLength; + } + + int encodedLength() + throws IOException + { + int length = getBodyLength(); + + return 1 + StreamUtil.calculateBodyLength(length) + length; + } + + /* + * A note on the implementation: + *
+ * As DL requires the constructed, definite-length model to + * be used for structured types, this varies slightly from the + * ASN.1 descriptions given. Rather than just outputting SEQUENCE, + * we also have to specify CONSTRUCTED, and the objects length. + */ + void encode( + ASN1OutputStream out) + throws IOException + { + ASN1OutputStream dOut = out.getDLSubStream(); + int length = getBodyLength(); + + out.write(BERTags.SEQUENCE | BERTags.CONSTRUCTED); + out.writeLength(length); + + for (Enumeration e = this.getObjects(); e.hasMoreElements();) + { + Object obj = e.nextElement(); + + dOut.writeObject((ASN1Encodable)obj); + } + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DLSet.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DLSet.java new file mode 100644 index 0000000..ec64ed2 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DLSet.java @@ -0,0 +1,101 @@ +package org.bc.asn1; + +import java.io.IOException; +import java.util.Enumeration; + +/** + * A DER encoded set object + */ +public class DLSet + extends ASN1Set +{ + private int bodyLength = -1; + + /** + * create an empty set + */ + public DLSet() + { + } + + /** + * @param obj - a single object that makes up the set. + */ + public DLSet( + ASN1Encodable obj) + { + super(obj); + } + + /** + * @param v - a vector of objects making up the set. + */ + public DLSet( + ASN1EncodableVector v) + { + super(v, false); + } + + /** + * create a set from an array of objects. + */ + public DLSet( + ASN1Encodable[] a) + { + super(a, false); + } + + private int getBodyLength() + throws IOException + { + if (bodyLength < 0) + { + int length = 0; + + for (Enumeration e = this.getObjects(); e.hasMoreElements();) + { + Object obj = e.nextElement(); + + length += ((ASN1Encodable)obj).toASN1Primitive().toDLObject().encodedLength(); + } + + bodyLength = length; + } + + return bodyLength; + } + + int encodedLength() + throws IOException + { + int length = getBodyLength(); + + return 1 + StreamUtil.calculateBodyLength(length) + length; + } + + /* + * A note on the implementation: + *
+ * As DL requires the constructed, definite-length model to + * be used for structured types, this varies slightly from the + * ASN.1 descriptions given. Rather than just outputting SET, + * we also have to specify CONSTRUCTED, and the objects length. + */ + void encode( + ASN1OutputStream out) + throws IOException + { + ASN1OutputStream dOut = out.getDLSubStream(); + int length = getBodyLength(); + + out.write(BERTags.SET | BERTags.CONSTRUCTED); + out.writeLength(length); + + for (Enumeration e = this.getObjects(); e.hasMoreElements();) + { + Object obj = e.nextElement(); + + dOut.writeObject((ASN1Encodable)obj); + } + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DLTaggedObject.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DLTaggedObject.java new file mode 100644 index 0000000..ee3caff --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DLTaggedObject.java @@ -0,0 +1,112 @@ +package org.bc.asn1; + +import java.io.IOException; + +/** + * Definite Length TaggedObject - in ASN.1 notation this is any object preceded by + * a [n] where n is some number - these are assumed to follow the construction + * rules (as with sequences). + */ +public class DLTaggedObject + extends ASN1TaggedObject +{ + private static final byte[] ZERO_BYTES = new byte[0]; + + /** + * @param explicit true if an explicitly tagged object. + * @param tagNo the tag number for this object. + * @param obj the tagged object. + */ + public DLTaggedObject( + boolean explicit, + int tagNo, + ASN1Encodable obj) + { + super(explicit, tagNo, obj); + } + + boolean isConstructed() + { + if (!empty) + { + if (explicit) + { + return true; + } + else + { + ASN1Primitive primitive = obj.toASN1Primitive().toDLObject(); + + return primitive.isConstructed(); + } + } + else + { + return true; + } + } + + int encodedLength() + throws IOException + { + if (!empty) + { + int length = obj.toASN1Primitive().toDLObject().encodedLength(); + + if (explicit) + { + return StreamUtil.calculateTagLength(tagNo) + StreamUtil.calculateBodyLength(length) + length; + } + else + { + // header length already in calculation + length = length - 1; + + return StreamUtil.calculateTagLength(tagNo) + length; + } + } + else + { + return StreamUtil.calculateTagLength(tagNo) + 1; + } + } + + void encode( + ASN1OutputStream out) + throws IOException + { + if (!empty) + { + ASN1Primitive primitive = obj.toASN1Primitive().toDLObject(); + + if (explicit) + { + out.writeTag(BERTags.CONSTRUCTED | BERTags.TAGGED, tagNo); + out.writeLength(primitive.encodedLength()); + out.writeObject(primitive); + } + else + { + // + // need to mark constructed types... + // + int flags; + if (primitive.isConstructed()) + { + flags = BERTags.CONSTRUCTED | BERTags.TAGGED; + } + else + { + flags = BERTags.TAGGED; + } + + out.writeTag(flags, tagNo); + out.writeImplicitObject(primitive); + } + } + else + { + out.writeEncoded(BERTags.CONSTRUCTED | BERTags.TAGGED, tagNo, ZERO_BYTES); + } + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DefiniteLengthInputStream.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DefiniteLengthInputStream.java new file mode 100644 index 0000000..8872b12 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/DefiniteLengthInputStream.java @@ -0,0 +1,105 @@ +package org.bc.asn1; + +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStream; + +import org.bc.util.io.Streams; + +class DefiniteLengthInputStream + extends LimitedInputStream +{ + private static final byte[] EMPTY_BYTES = new byte[0]; + + private final int _originalLength; + private int _remaining; + + DefiniteLengthInputStream( + InputStream in, + int length) + { + super(in, length); + + if (length < 0) + { + throw new IllegalArgumentException("negative lengths not allowed"); + } + + this._originalLength = length; + this._remaining = length; + + if (length == 0) + { + setParentEofDetect(true); + } + } + + int getRemaining() + { + return _remaining; + } + + public int read() + throws IOException + { + if (_remaining == 0) + { + return -1; + } + + int b = _in.read(); + + if (b < 0) + { + throw new EOFException("DEF length " + _originalLength + " object truncated by " + _remaining); + } + + if (--_remaining == 0) + { + setParentEofDetect(true); + } + + return b; + } + + public int read(byte[] buf, int off, int len) + throws IOException + { + if (_remaining == 0) + { + return -1; + } + + int toRead = Math.min(len, _remaining); + int numRead = _in.read(buf, off, toRead); + + if (numRead < 0) + { + throw new EOFException("DEF length " + _originalLength + " object truncated by " + _remaining); + } + + if ((_remaining -= numRead) == 0) + { + setParentEofDetect(true); + } + + return numRead; + } + + byte[] toByteArray() + throws IOException + { + if (_remaining == 0) + { + return EMPTY_BYTES; + } + + byte[] bytes = new byte[_remaining]; + if ((_remaining -= Streams.readFully(_in, bytes)) != 0) + { + throw new EOFException("DEF length " + _originalLength + " object truncated by " + _remaining); + } + setParentEofDetect(true); + return bytes; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/InMemoryRepresentable.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/InMemoryRepresentable.java new file mode 100644 index 0000000..8bc8521 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/InMemoryRepresentable.java @@ -0,0 +1,9 @@ +package org.bc.asn1; + +import java.io.IOException; + +public interface InMemoryRepresentable +{ + ASN1Primitive getLoadedObject() + throws IOException; +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/IndefiniteLengthInputStream.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/IndefiniteLengthInputStream.java new file mode 100644 index 0000000..ed189c4 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/IndefiniteLengthInputStream.java @@ -0,0 +1,111 @@ +package org.bc.asn1; + +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStream; + +class IndefiniteLengthInputStream + extends LimitedInputStream +{ + private int _b1; + private int _b2; + private boolean _eofReached = false; + private boolean _eofOn00 = true; + + IndefiniteLengthInputStream( + InputStream in, + int limit) + throws IOException + { + super(in, limit); + + _b1 = in.read(); + _b2 = in.read(); + + if (_b2 < 0) + { + // Corrupted stream + throw new EOFException(); + } + + checkForEof(); + } + + void setEofOn00( + boolean eofOn00) + { + _eofOn00 = eofOn00; + checkForEof(); + } + + private boolean checkForEof() + { + if (!_eofReached && _eofOn00 && (_b1 == 0x00 && _b2 == 0x00)) + { + _eofReached = true; + setParentEofDetect(true); + } + return _eofReached; + } + + public int read(byte[] b, int off, int len) + throws IOException + { + // Only use this optimisation if we aren't checking for 00 + if (_eofOn00 || len < 3) + { + return super.read(b, off, len); + } + + if (_eofReached) + { + return -1; + } + + int numRead = _in.read(b, off + 2, len - 2); + + if (numRead < 0) + { + // Corrupted stream + throw new EOFException(); + } + + b[off] = (byte)_b1; + b[off + 1] = (byte)_b2; + + _b1 = _in.read(); + _b2 = _in.read(); + + if (_b2 < 0) + { + // Corrupted stream + throw new EOFException(); + } + + return numRead + 2; + } + + public int read() + throws IOException + { + if (checkForEof()) + { + return -1; + } + + int b = _in.read(); + + if (b < 0) + { + // Corrupted stream + throw new EOFException(); + } + + int v = _b1; + + _b1 = _b2; + _b2 = b; + + return v; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/LazyConstructionEnumeration.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/LazyConstructionEnumeration.java new file mode 100644 index 0000000..53dc8d3 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/LazyConstructionEnumeration.java @@ -0,0 +1,43 @@ +package org.bc.asn1; + +import java.io.IOException; +import java.util.Enumeration; + +class LazyConstructionEnumeration + implements Enumeration +{ + private ASN1InputStream aIn; + private Object nextObj; + + public LazyConstructionEnumeration(byte[] encoded) + { + aIn = new ASN1InputStream(encoded, true); + nextObj = readObject(); + } + + public boolean hasMoreElements() + { + return nextObj != null; + } + + public Object nextElement() + { + Object o = nextObj; + + nextObj = readObject(); + + return o; + } + + private Object readObject() + { + try + { + return aIn.readObject(); + } + catch (IOException e) + { + throw new ASN1ParsingException("malformed DER construction: " + e, e); + } + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/LazyEncodedSequence.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/LazyEncodedSequence.java new file mode 100644 index 0000000..dfb96be --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/LazyEncodedSequence.java @@ -0,0 +1,109 @@ +package org.bc.asn1; + +import java.io.IOException; +import java.util.Enumeration; + +/** + * Note: this class is for processing DER/DL encoded sequences only. + */ +class LazyEncodedSequence + extends ASN1Sequence +{ + private byte[] encoded; + + LazyEncodedSequence( + byte[] encoded) + throws IOException + { + this.encoded = encoded; + } + + private void parse() + { + Enumeration en = new LazyConstructionEnumeration(encoded); + + while (en.hasMoreElements()) + { + seq.addElement(en.nextElement()); + } + + encoded = null; + } + + public synchronized ASN1Encodable getObjectAt(int index) + { + if (encoded != null) + { + parse(); + } + + return super.getObjectAt(index); + } + + public synchronized Enumeration getObjects() + { + if (encoded == null) + { + return super.getObjects(); + } + + return new LazyConstructionEnumeration(encoded); + } + + public synchronized int size() + { + if (encoded != null) + { + parse(); + } + + return super.size(); + } + + ASN1Primitive toDERObject() + { + if (encoded != null) + { + parse(); + } + + return super.toDERObject(); + } + + ASN1Primitive toDLObject() + { + if (encoded != null) + { + parse(); + } + + return super.toDLObject(); + } + + int encodedLength() + throws IOException + { + if (encoded != null) + { + return 1 + StreamUtil.calculateBodyLength(encoded.length) + encoded.length; + } + else + { + return super.toDLObject().encodedLength(); + } + } + + void encode( + ASN1OutputStream out) + throws IOException + { + if (encoded != null) + { + out.writeEncoded(BERTags.SEQUENCE | BERTags.CONSTRUCTED, encoded); + } + else + { + super.toDLObject().encode(out); + } + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/LimitedInputStream.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/LimitedInputStream.java new file mode 100644 index 0000000..deb8c9d --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/LimitedInputStream.java @@ -0,0 +1,32 @@ +package org.bc.asn1; + +import java.io.InputStream; + +abstract class LimitedInputStream + extends InputStream +{ + protected final InputStream _in; + private int _limit; + + LimitedInputStream( + InputStream in, + int limit) + { + this._in = in; + this._limit = limit; + } + + int getRemaining() + { + // TODO: maybe one day this can become more accurate + return _limit; + } + + protected void setParentEofDetect(boolean on) + { + if (_in instanceof IndefiniteLengthInputStream) + { + ((IndefiniteLengthInputStream)_in).setEofOn00(on); + } + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/OIDTokenizer.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/OIDTokenizer.java new file mode 100644 index 0000000..a5c3d48 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/OIDTokenizer.java @@ -0,0 +1,48 @@ +package org.bc.asn1; + +/** + * class for breaking up an OID into it's component tokens, ala + * java.util.StringTokenizer. We need this class as some of the + * lightweight Java environment don't support classes like + * StringTokenizer. + */ +public class OIDTokenizer +{ + private String oid; + private int index; + + public OIDTokenizer( + String oid) + { + this.oid = oid; + this.index = 0; + } + + public boolean hasMoreTokens() + { + return (index != -1); + } + + public String nextToken() + { + if (index == -1) + { + return null; + } + + String token; + int end = oid.indexOf('.', index); + + if (end == -1) + { + token = oid.substring(index); + index = -1; + return token; + } + + token = oid.substring(index, end); + + index = end + 1; + return token; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/StreamUtil.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/StreamUtil.java new file mode 100644 index 0000000..d429439 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/StreamUtil.java @@ -0,0 +1,112 @@ +package org.bc.asn1; + +import java.io.ByteArrayInputStream; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; + +class StreamUtil +{ + private static final long MAX_MEMORY = Runtime.getRuntime().maxMemory(); + + /** + * Find out possible longest length... + * + * @param in input stream of interest + * @return length calculation or MAX_VALUE. + */ + static int findLimit(InputStream in) + { + if (in instanceof LimitedInputStream) + { + return ((LimitedInputStream)in).getRemaining(); + } + else if (in instanceof ASN1InputStream) + { + return ((ASN1InputStream)in).getLimit(); + } + else if (in instanceof ByteArrayInputStream) + { + return ((ByteArrayInputStream)in).available(); + } + else if (in instanceof FileInputStream) + { + try + { + long size = ((FileInputStream)in).getChannel().size(); + + if (size < Integer.MAX_VALUE) + { + return (int)size; + } + } + catch (IOException e) + { + // ignore - they'll find out soon enough! + } + } + + if (MAX_MEMORY > Integer.MAX_VALUE) + { + return Integer.MAX_VALUE; + } + + return (int)MAX_MEMORY; + } + + static int calculateBodyLength( + int length) + { + int count = 1; + + if (length > 127) + { + int size = 1; + int val = length; + + while ((val >>>= 8) != 0) + { + size++; + } + + for (int i = (size - 1) * 8; i >= 0; i -= 8) + { + count++; + } + } + + return count; + } + + static int calculateTagLength(int tagNo) + throws IOException + { + int length = 1; + + if (tagNo >= 31) + { + if (tagNo < 128) + { + length++; + } + else + { + byte[] stack = new byte[5]; + int pos = stack.length; + + stack[--pos] = (byte)(tagNo & 0x7F); + + do + { + tagNo >>= 7; + stack[--pos] = (byte)(tagNo & 0x7F | 0x80); + } + while (tagNo > 127); + + length += stack.length - pos; + } + } + + return length; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/bc/BCObjectIdentifiers.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/bc/BCObjectIdentifiers.java new file mode 100644 index 0000000..c0c7681 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/bc/BCObjectIdentifiers.java @@ -0,0 +1,51 @@ +package org.bc.asn1.bc; + +import org.bc.asn1.ASN1ObjectIdentifier; + +public interface BCObjectIdentifiers +{ + /** + * iso.org.dod.internet.private.enterprise.legion-of-the-bouncy-castle + * + * 1.3.6.1.4.1.22554 + */ + public static final ASN1ObjectIdentifier bc = new ASN1ObjectIdentifier("1.3.6.1.4.1.22554"); + + /** + * pbe(1) algorithms + */ + public static final ASN1ObjectIdentifier bc_pbe = new ASN1ObjectIdentifier(bc.getId() + ".1"); + + /** + * SHA-1(1) + */ + public static final ASN1ObjectIdentifier bc_pbe_sha1 = new ASN1ObjectIdentifier(bc_pbe.getId() + ".1"); + + /** + * SHA-2(2) . (SHA-256(1)|SHA-384(2)|SHA-512(3)|SHA-224(4)) + */ + public static final ASN1ObjectIdentifier bc_pbe_sha256 = new ASN1ObjectIdentifier(bc_pbe.getId() + ".2.1"); + public static final ASN1ObjectIdentifier bc_pbe_sha384 = new ASN1ObjectIdentifier(bc_pbe.getId() + ".2.2"); + public static final ASN1ObjectIdentifier bc_pbe_sha512 = new ASN1ObjectIdentifier(bc_pbe.getId() + ".2.3"); + public static final ASN1ObjectIdentifier bc_pbe_sha224 = new ASN1ObjectIdentifier(bc_pbe.getId() + ".2.4"); + + /** + * PKCS-5(1)|PKCS-12(2) + */ + public static final ASN1ObjectIdentifier bc_pbe_sha1_pkcs5 = new ASN1ObjectIdentifier(bc_pbe_sha1.getId() + ".1"); + public static final ASN1ObjectIdentifier bc_pbe_sha1_pkcs12 = new ASN1ObjectIdentifier(bc_pbe_sha1.getId() + ".2"); + + public static final ASN1ObjectIdentifier bc_pbe_sha256_pkcs5 = new ASN1ObjectIdentifier(bc_pbe_sha256.getId() + ".1"); + public static final ASN1ObjectIdentifier bc_pbe_sha256_pkcs12 = new ASN1ObjectIdentifier(bc_pbe_sha256.getId() + ".2"); + + /** + * AES(1) . (CBC-128(2)|CBC-192(22)|CBC-256(42)) + */ + public static final ASN1ObjectIdentifier bc_pbe_sha1_pkcs12_aes128_cbc = new ASN1ObjectIdentifier(bc_pbe_sha1_pkcs12.getId() + ".1.2"); + public static final ASN1ObjectIdentifier bc_pbe_sha1_pkcs12_aes192_cbc = new ASN1ObjectIdentifier(bc_pbe_sha1_pkcs12.getId() + ".1.22"); + public static final ASN1ObjectIdentifier bc_pbe_sha1_pkcs12_aes256_cbc = new ASN1ObjectIdentifier(bc_pbe_sha1_pkcs12.getId() + ".1.42"); + + public static final ASN1ObjectIdentifier bc_pbe_sha256_pkcs12_aes128_cbc = new ASN1ObjectIdentifier(bc_pbe_sha256_pkcs12.getId() + ".1.2"); + public static final ASN1ObjectIdentifier bc_pbe_sha256_pkcs12_aes192_cbc = new ASN1ObjectIdentifier(bc_pbe_sha256_pkcs12.getId() + ".1.22"); + public static final ASN1ObjectIdentifier bc_pbe_sha256_pkcs12_aes256_cbc = new ASN1ObjectIdentifier(bc_pbe_sha256_pkcs12.getId() + ".1.42"); +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/CAKeyUpdAnnContent.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/CAKeyUpdAnnContent.java new file mode 100644 index 0000000..800eed2 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/CAKeyUpdAnnContent.java @@ -0,0 +1,80 @@ +package org.bc.asn1.cmp; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DERSequence; + +public class CAKeyUpdAnnContent + extends ASN1Object +{ + private CMPCertificate oldWithNew; + private CMPCertificate newWithOld; + private CMPCertificate newWithNew; + + private CAKeyUpdAnnContent(ASN1Sequence seq) + { + oldWithNew = CMPCertificate.getInstance(seq.getObjectAt(0)); + newWithOld = CMPCertificate.getInstance(seq.getObjectAt(1)); + newWithNew = CMPCertificate.getInstance(seq.getObjectAt(2)); + } + + public static CAKeyUpdAnnContent getInstance(Object o) + { + if (o instanceof CAKeyUpdAnnContent) + { + return (CAKeyUpdAnnContent)o; + } + + if (o != null) + { + return new CAKeyUpdAnnContent(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public CAKeyUpdAnnContent(CMPCertificate oldWithNew, CMPCertificate newWithOld, CMPCertificate newWithNew) + { + this.oldWithNew = oldWithNew; + this.newWithOld = newWithOld; + this.newWithNew = newWithNew; + } + + public CMPCertificate getOldWithNew() + { + return oldWithNew; + } + + public CMPCertificate getNewWithOld() + { + return newWithOld; + } + + public CMPCertificate getNewWithNew() + { + return newWithNew; + } + + /** + *
+ * CAKeyUpdAnnContent ::= SEQUENCE { + * oldWithNew CMPCertificate, -- old pub signed with new priv + * newWithOld CMPCertificate, -- new pub signed with old priv + * newWithNew CMPCertificate -- new pub signed with new priv + * } + *+ * @return a basic ASN.1 object representation. + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(oldWithNew); + v.add(newWithOld); + v.add(newWithNew); + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/CMPCertificate.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/CMPCertificate.java new file mode 100644 index 0000000..d1c9f53 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/CMPCertificate.java @@ -0,0 +1,92 @@ +package org.bc.asn1.cmp; + +import org.bc.asn1.ASN1Choice; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERTaggedObject; +import org.bc.asn1.x509.AttributeCertificate; +import org.bc.asn1.x509.Certificate; + +public class CMPCertificate + extends ASN1Object + implements ASN1Choice +{ + private Certificate x509v3PKCert; + private AttributeCertificate x509v2AttrCert; + + /** + * Note: the addition of attribute certificates is a BC extension. + */ + public CMPCertificate(AttributeCertificate x509v2AttrCert) + { + this.x509v2AttrCert = x509v2AttrCert; + } + + public CMPCertificate(Certificate x509v3PKCert) + { + if (x509v3PKCert.getVersionNumber() != 3) + { + throw new IllegalArgumentException("only version 3 certificates allowed"); + } + + this.x509v3PKCert = x509v3PKCert; + } + + public static CMPCertificate getInstance(Object o) + { + if (o == null || o instanceof CMPCertificate) + { + return (CMPCertificate)o; + } + + if (o instanceof ASN1Sequence || o instanceof byte[]) + { + return new CMPCertificate(Certificate.getInstance(o)); + } + + if (o instanceof ASN1TaggedObject) + { + return new CMPCertificate(AttributeCertificate.getInstance(((ASN1TaggedObject)o).getObject())); + } + + throw new IllegalArgumentException("Invalid object: " + o.getClass().getName()); + } + + public boolean isX509v3PKCert() + { + return x509v3PKCert != null; + } + + public Certificate getX509v3PKCert() + { + return x509v3PKCert; + } + + public AttributeCertificate getX509v2AttrCert() + { + return x509v2AttrCert; + } + + /** + *
+ * CMPCertificate ::= CHOICE { + * x509v3PKCert Certificate + * x509v2AttrCert [1] AttributeCertificate + * } + *+ * Note: the addition of attribute certificates is a BC extension. + * + * @return a basic ASN.1 object representation. + */ + public ASN1Primitive toASN1Primitive() + { + if (x509v2AttrCert != null) + { // explicit following CMP conventions + return new DERTaggedObject(true, 1, x509v2AttrCert); + } + + return x509v3PKCert.toASN1Primitive(); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/CMPObjectIdentifiers.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/CMPObjectIdentifiers.java new file mode 100644 index 0000000..7d026d3 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/CMPObjectIdentifiers.java @@ -0,0 +1,106 @@ +package org.bc.asn1.cmp; + +import org.bc.asn1.ASN1ObjectIdentifier; + +public interface CMPObjectIdentifiers +{ + // RFC 4210 + + // id-PasswordBasedMac OBJECT IDENTIFIER ::= {1 2 840 113533 7 66 13} + static final ASN1ObjectIdentifier passwordBasedMac = new ASN1ObjectIdentifier("1.2.840.113533.7.66.13"); + + // id-DHBasedMac OBJECT IDENTIFIER ::= {1 2 840 113533 7 66 30} + static final ASN1ObjectIdentifier dhBasedMac = new ASN1ObjectIdentifier("1.2.840.113533.7.66.30"); + + // Example InfoTypeAndValue contents include, but are not limited + // to, the following (un-comment in this ASN.1 module and use as + // appropriate for a given environment): + // + // id-it-caProtEncCert OBJECT IDENTIFIER ::= {id-it 1} + // CAProtEncCertValue ::= CMPCertificate + // id-it-signKeyPairTypes OBJECT IDENTIFIER ::= {id-it 2} + // SignKeyPairTypesValue ::= SEQUENCE OF AlgorithmIdentifier + // id-it-encKeyPairTypes OBJECT IDENTIFIER ::= {id-it 3} + // EncKeyPairTypesValue ::= SEQUENCE OF AlgorithmIdentifier + // id-it-preferredSymmAlg OBJECT IDENTIFIER ::= {id-it 4} + // PreferredSymmAlgValue ::= AlgorithmIdentifier + // id-it-caKeyUpdateInfo OBJECT IDENTIFIER ::= {id-it 5} + // CAKeyUpdateInfoValue ::= CAKeyUpdAnnContent + // id-it-currentCRL OBJECT IDENTIFIER ::= {id-it 6} + // CurrentCRLValue ::= CertificateList + // id-it-unsupportedOIDs OBJECT IDENTIFIER ::= {id-it 7} + // UnsupportedOIDsValue ::= SEQUENCE OF OBJECT IDENTIFIER + // id-it-keyPairParamReq OBJECT IDENTIFIER ::= {id-it 10} + // KeyPairParamReqValue ::= OBJECT IDENTIFIER + // id-it-keyPairParamRep OBJECT IDENTIFIER ::= {id-it 11} + // KeyPairParamRepValue ::= AlgorithmIdentifer + // id-it-revPassphrase OBJECT IDENTIFIER ::= {id-it 12} + // RevPassphraseValue ::= EncryptedValue + // id-it-implicitConfirm OBJECT IDENTIFIER ::= {id-it 13} + // ImplicitConfirmValue ::= NULL + // id-it-confirmWaitTime OBJECT IDENTIFIER ::= {id-it 14} + // ConfirmWaitTimeValue ::= GeneralizedTime + // id-it-origPKIMessage OBJECT IDENTIFIER ::= {id-it 15} + // OrigPKIMessageValue ::= PKIMessages + // id-it-suppLangTags OBJECT IDENTIFIER ::= {id-it 16} + // SuppLangTagsValue ::= SEQUENCE OF UTF8String + // + // where + // + // id-pkix OBJECT IDENTIFIER ::= { + // iso(1) identified-organization(3) + // dod(6) internet(1) security(5) mechanisms(5) pkix(7)} + // and + // id-it OBJECT IDENTIFIER ::= {id-pkix 4} + static final ASN1ObjectIdentifier it_caProtEncCert = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.4.1"); + static final ASN1ObjectIdentifier it_signKeyPairTypes = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.4.2"); + static final ASN1ObjectIdentifier it_encKeyPairTypes = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.4.3"); + static final ASN1ObjectIdentifier it_preferredSymAlg = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.4.4"); + static final ASN1ObjectIdentifier it_caKeyUpdateInfo = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.4.5"); + static final ASN1ObjectIdentifier it_currentCRL = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.4.6"); + static final ASN1ObjectIdentifier it_unsupportedOIDs = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.4.7"); + static final ASN1ObjectIdentifier it_keyPairParamReq = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.4.10"); + static final ASN1ObjectIdentifier it_keyPairParamRep = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.4.11"); + static final ASN1ObjectIdentifier it_revPassphrase = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.4.12"); + static final ASN1ObjectIdentifier it_implicitConfirm = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.4.13"); + static final ASN1ObjectIdentifier it_confirmWaitTime = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.4.14"); + static final ASN1ObjectIdentifier it_origPKIMessage = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.4.15"); + static final ASN1ObjectIdentifier it_suppLangTags = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.4.16"); + + // RFC 4211 + + // id-pkix OBJECT IDENTIFIER ::= { iso(1) identified-organization(3) + // dod(6) internet(1) security(5) mechanisms(5) pkix(7) } + // + // arc for Internet X.509 PKI protocols and their components + // id-pkip OBJECT IDENTIFIER :: { id-pkix pkip(5) } + // + // arc for Registration Controls in CRMF + // id-regCtrl OBJECT IDENTIFIER ::= { id-pkip regCtrl(1) } + // + // arc for Registration Info in CRMF + // id-regInfo OBJECT IDENTIFIER ::= { id-pkip id-regInfo(2) } + + static final ASN1ObjectIdentifier regCtrl_regToken = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.5.1.1"); + static final ASN1ObjectIdentifier regCtrl_authenticator = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.5.1.2"); + static final ASN1ObjectIdentifier regCtrl_pkiPublicationInfo = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.5.1.3"); + static final ASN1ObjectIdentifier regCtrl_pkiArchiveOptions = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.5.1.4"); + static final ASN1ObjectIdentifier regCtrl_oldCertID = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.5.1.5"); + static final ASN1ObjectIdentifier regCtrl_protocolEncrKey = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.5.1.6"); + + // From RFC4210: + // id-regCtrl-altCertTemplate OBJECT IDENTIFIER ::= {id-regCtrl 7} + static final ASN1ObjectIdentifier regCtrl_altCertTemplate = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.5.1.7"); + + static final ASN1ObjectIdentifier regInfo_utf8Pairs = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.5.2.1"); + static final ASN1ObjectIdentifier regInfo_certReq = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.5.2.2"); + + // id-smime OBJECT IDENTIFIER ::= { iso(1) member-body(2) + // us(840) rsadsi(113549) pkcs(1) pkcs9(9) 16 } + // + // id-ct OBJECT IDENTIFIER ::= { id-smime 1 } -- content types + // + // id-ct-encKeyWithID OBJECT IDENTIFIER ::= {id-ct 21} + static final ASN1ObjectIdentifier ct_encKeyWithID = new ASN1ObjectIdentifier("1.2.840.113549.1.9.16.1.21"); + +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/CRLAnnContent.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/CRLAnnContent.java new file mode 100644 index 0000000..7834f3b --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/CRLAnnContent.java @@ -0,0 +1,61 @@ +package org.bc.asn1.cmp; + +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DERSequence; +import org.bc.asn1.x509.CertificateList; + +public class CRLAnnContent + extends ASN1Object +{ + private ASN1Sequence content; + + private CRLAnnContent(ASN1Sequence seq) + { + content = seq; + } + + public static CRLAnnContent getInstance(Object o) + { + if (o instanceof CRLAnnContent) + { + return (CRLAnnContent)o; + } + + if (o != null) + { + return new CRLAnnContent(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public CRLAnnContent(CertificateList crl) + { + this.content = new DERSequence(crl); + } + + public CertificateList[] getCertificateLists() + { + CertificateList[] result = new CertificateList[content.size()]; + + for (int i = 0; i != result.length; i++) + { + result[i] = CertificateList.getInstance(content.getObjectAt(i)); + } + + return result; + } + + /** + *
+ * CRLAnnContent ::= SEQUENCE OF CertificateList + *+ * @return a basic ASN.1 object representation. + */ + public ASN1Primitive toASN1Primitive() + { + return content; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/CertConfirmContent.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/CertConfirmContent.java new file mode 100644 index 0000000..71dd6d4 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/CertConfirmContent.java @@ -0,0 +1,54 @@ +package org.bc.asn1.cmp; + +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; + +public class CertConfirmContent + extends ASN1Object +{ + private ASN1Sequence content; + + private CertConfirmContent(ASN1Sequence seq) + { + content = seq; + } + + public static CertConfirmContent getInstance(Object o) + { + if (o instanceof CertConfirmContent) + { + return (CertConfirmContent)o; + } + + if (o != null) + { + return new CertConfirmContent(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public CertStatus[] toCertStatusArray() + { + CertStatus[] result = new CertStatus[content.size()]; + + for (int i = 0; i != result.length; i++) + { + result[i] = CertStatus.getInstance(content.getObjectAt(i)); + } + + return result; + } + + /** + *
+ * CertConfirmContent ::= SEQUENCE OF CertStatus + *+ * @return a basic ASN.1 object representation. + */ + public ASN1Primitive toASN1Primitive() + { + return content; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/CertOrEncCert.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/CertOrEncCert.java new file mode 100644 index 0000000..32b0ee3 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/CertOrEncCert.java @@ -0,0 +1,96 @@ +package org.bc.asn1.cmp; + +import org.bc.asn1.ASN1Choice; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERTaggedObject; +import org.bc.asn1.crmf.EncryptedValue; + +public class CertOrEncCert + extends ASN1Object + implements ASN1Choice +{ + private CMPCertificate certificate; + private EncryptedValue encryptedCert; + + private CertOrEncCert(ASN1TaggedObject tagged) + { + if (tagged.getTagNo() == 0) + { + certificate = CMPCertificate.getInstance(tagged.getObject()); + } + else if (tagged.getTagNo() == 1) + { + encryptedCert = EncryptedValue.getInstance(tagged.getObject()); + } + else + { + throw new IllegalArgumentException("unknown tag: " + tagged.getTagNo()); + } + } + + public static CertOrEncCert getInstance(Object o) + { + if (o instanceof CertOrEncCert) + { + return (CertOrEncCert)o; + } + + if (o instanceof ASN1TaggedObject) + { + return new CertOrEncCert((ASN1TaggedObject)o); + } + + return null; + } + + public CertOrEncCert(CMPCertificate certificate) + { + if (certificate == null) + { + throw new IllegalArgumentException("'certificate' cannot be null"); + } + + this.certificate = certificate; + } + + public CertOrEncCert(EncryptedValue encryptedCert) + { + if (encryptedCert == null) + { + throw new IllegalArgumentException("'encryptedCert' cannot be null"); + } + + this.encryptedCert = encryptedCert; + } + + public CMPCertificate getCertificate() + { + return certificate; + } + + public EncryptedValue getEncryptedCert() + { + return encryptedCert; + } + + /** + *
+ * CertOrEncCert ::= CHOICE { + * certificate [0] CMPCertificate, + * encryptedCert [1] EncryptedValue + * } + *+ * @return a basic ASN.1 object representation. + */ + public ASN1Primitive toASN1Primitive() + { + if (certificate != null) + { + return new DERTaggedObject(true, 0, certificate); + } + + return new DERTaggedObject(true, 1, encryptedCert); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/CertRepMessage.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/CertRepMessage.java new file mode 100644 index 0000000..b02107c --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/CertRepMessage.java @@ -0,0 +1,123 @@ +package org.bc.asn1.cmp; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERSequence; +import org.bc.asn1.DERTaggedObject; + +public class CertRepMessage + extends ASN1Object +{ + private ASN1Sequence caPubs; + private ASN1Sequence response; + + private CertRepMessage(ASN1Sequence seq) + { + int index = 0; + + if (seq.size() > 1) + { + caPubs = ASN1Sequence.getInstance((ASN1TaggedObject)seq.getObjectAt(index++), true); + } + + response = ASN1Sequence.getInstance(seq.getObjectAt(index)); + } + + public static CertRepMessage getInstance(Object o) + { + if (o instanceof CertRepMessage) + { + return (CertRepMessage)o; + } + + if (o != null) + { + return new CertRepMessage(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public CertRepMessage(CMPCertificate[] caPubs, CertResponse[] response) + { + if (response == null) + { + throw new IllegalArgumentException("'response' cannot be null"); + } + + if (caPubs != null) + { + ASN1EncodableVector v = new ASN1EncodableVector(); + for (int i = 0; i < caPubs.length; i++) + { + v.add(caPubs[i]); + } + this.caPubs = new DERSequence(v); + } + + { + ASN1EncodableVector v = new ASN1EncodableVector(); + for (int i = 0; i < response.length; i++) + { + v.add(response[i]); + } + this.response = new DERSequence(v); + } + } + + public CMPCertificate[] getCaPubs() + { + if (caPubs == null) + { + return null; + } + + CMPCertificate[] results = new CMPCertificate[caPubs.size()]; + + for (int i = 0; i != results.length; i++) + { + results[i] = CMPCertificate.getInstance(caPubs.getObjectAt(i)); + } + + return results; + } + + public CertResponse[] getResponse() + { + CertResponse[] results = new CertResponse[response.size()]; + + for (int i = 0; i != results.length; i++) + { + results[i] = CertResponse.getInstance(response.getObjectAt(i)); + } + + return results; + } + + /** + *
+ * CertRepMessage ::= SEQUENCE { + * caPubs [1] SEQUENCE SIZE (1..MAX) OF CMPCertificate + * OPTIONAL, + * response SEQUENCE OF CertResponse + * } + *+ * @return a basic ASN.1 object representation. + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + if (caPubs != null) + { + v.add(new DERTaggedObject(true, 1, caPubs)); + } + + v.add(response); + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/CertResponse.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/CertResponse.java new file mode 100644 index 0000000..48f7df8 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/CertResponse.java @@ -0,0 +1,139 @@ +package org.bc.asn1.cmp; + +import org.bc.asn1.ASN1Encodable; +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1OctetString; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DERSequence; + +public class CertResponse + extends ASN1Object +{ + private ASN1Integer certReqId; + private PKIStatusInfo status; + private CertifiedKeyPair certifiedKeyPair; + private ASN1OctetString rspInfo; + + private CertResponse(ASN1Sequence seq) + { + certReqId = ASN1Integer.getInstance(seq.getObjectAt(0)); + status = PKIStatusInfo.getInstance(seq.getObjectAt(1)); + + if (seq.size() >= 3) + { + if (seq.size() == 3) + { + ASN1Encodable o = seq.getObjectAt(2); + if (o instanceof ASN1OctetString) + { + rspInfo = ASN1OctetString.getInstance(o); + } + else + { + certifiedKeyPair = CertifiedKeyPair.getInstance(o); + } + } + else + { + certifiedKeyPair = CertifiedKeyPair.getInstance(seq.getObjectAt(2)); + rspInfo = ASN1OctetString.getInstance(seq.getObjectAt(3)); + } + } + } + + public static CertResponse getInstance(Object o) + { + if (o instanceof CertResponse) + { + return (CertResponse)o; + } + + if (o != null) + { + return new CertResponse(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public CertResponse( + ASN1Integer certReqId, + PKIStatusInfo status) + { + this(certReqId, status, null, null); + } + + public CertResponse( + ASN1Integer certReqId, + PKIStatusInfo status, + CertifiedKeyPair certifiedKeyPair, + ASN1OctetString rspInfo) + { + if (certReqId == null) + { + throw new IllegalArgumentException("'certReqId' cannot be null"); + } + if (status == null) + { + throw new IllegalArgumentException("'status' cannot be null"); + } + this.certReqId = certReqId; + this.status = status; + this.certifiedKeyPair = certifiedKeyPair; + this.rspInfo = rspInfo; + } + + public ASN1Integer getCertReqId() + { + return certReqId; + } + + public PKIStatusInfo getStatus() + { + return status; + } + + public CertifiedKeyPair getCertifiedKeyPair() + { + return certifiedKeyPair; + } + + /** + *
+ * CertResponse ::= SEQUENCE { + * certReqId INTEGER, + * -- to match this response with corresponding request (a value + * -- of -1 is to be used if certReqId is not specified in the + * -- corresponding request) + * status PKIStatusInfo, + * certifiedKeyPair CertifiedKeyPair OPTIONAL, + * rspInfo OCTET STRING OPTIONAL + * -- analogous to the id-regInfo-utf8Pairs string defined + * -- for regInfo in CertReqMsg [CRMF] + * } + *+ * @return a basic ASN.1 object representation. + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(certReqId); + v.add(status); + + if (certifiedKeyPair != null) + { + v.add(certifiedKeyPair); + } + + if (rspInfo != null) + { + v.add(rspInfo); + } + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/CertStatus.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/CertStatus.java new file mode 100644 index 0000000..6c380bf --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/CertStatus.java @@ -0,0 +1,102 @@ +package org.bc.asn1.cmp; + +import java.math.BigInteger; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1OctetString; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DEROctetString; +import org.bc.asn1.DERSequence; + +public class CertStatus + extends ASN1Object +{ + private ASN1OctetString certHash; + private ASN1Integer certReqId; + private PKIStatusInfo statusInfo; + + private CertStatus(ASN1Sequence seq) + { + certHash = ASN1OctetString.getInstance(seq.getObjectAt(0)); + certReqId = ASN1Integer.getInstance(seq.getObjectAt(1)); + + if (seq.size() > 2) + { + statusInfo = PKIStatusInfo.getInstance(seq.getObjectAt(2)); + } + } + + public CertStatus(byte[] certHash, BigInteger certReqId) + { + this.certHash = new DEROctetString(certHash); + this.certReqId = new ASN1Integer(certReqId); + } + + public CertStatus(byte[] certHash, BigInteger certReqId, PKIStatusInfo statusInfo) + { + this.certHash = new DEROctetString(certHash); + this.certReqId = new ASN1Integer(certReqId); + this.statusInfo = statusInfo; + } + + public static CertStatus getInstance(Object o) + { + if (o instanceof CertStatus) + { + return (CertStatus)o; + } + + if (o != null) + { + return new CertStatus(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public ASN1OctetString getCertHash() + { + return certHash; + } + + public ASN1Integer getCertReqId() + { + return certReqId; + } + + public PKIStatusInfo getStatusInfo() + { + return statusInfo; + } + + /** + *
+ * CertStatus ::= SEQUENCE { + * certHash OCTET STRING, + * -- the hash of the certificate, using the same hash algorithm + * -- as is used to create and verify the certificate signature + * certReqId INTEGER, + * -- to match this confirmation with the corresponding req/rep + * statusInfo PKIStatusInfo OPTIONAL + * } + *+ * @return a basic ASN.1 object representation. + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(certHash); + v.add(certReqId); + + if (statusInfo != null) + { + v.add(statusInfo); + } + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/CertifiedKeyPair.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/CertifiedKeyPair.java new file mode 100644 index 0000000..b59cd42 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/CertifiedKeyPair.java @@ -0,0 +1,127 @@ +package org.bc.asn1.cmp; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERSequence; +import org.bc.asn1.DERTaggedObject; +import org.bc.asn1.crmf.EncryptedValue; +import org.bc.asn1.crmf.PKIPublicationInfo; + +public class CertifiedKeyPair + extends ASN1Object +{ + private CertOrEncCert certOrEncCert; + private EncryptedValue privateKey; + private PKIPublicationInfo publicationInfo; + + private CertifiedKeyPair(ASN1Sequence seq) + { + certOrEncCert = CertOrEncCert.getInstance(seq.getObjectAt(0)); + + if (seq.size() >= 2) + { + if (seq.size() == 2) + { + ASN1TaggedObject tagged = ASN1TaggedObject.getInstance(seq.getObjectAt(1)); + if (tagged.getTagNo() == 0) + { + privateKey = EncryptedValue.getInstance(tagged.getObject()); + } + else + { + publicationInfo = PKIPublicationInfo.getInstance(tagged.getObject()); + } + } + else + { + privateKey = EncryptedValue.getInstance(ASN1TaggedObject.getInstance(seq.getObjectAt(1))); + publicationInfo = PKIPublicationInfo.getInstance(ASN1TaggedObject.getInstance(seq.getObjectAt(2))); + } + } + } + + public static CertifiedKeyPair getInstance(Object o) + { + if (o instanceof CertifiedKeyPair) + { + return (CertifiedKeyPair)o; + } + + if (o != null) + { + return new CertifiedKeyPair(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public CertifiedKeyPair( + CertOrEncCert certOrEncCert) + { + this(certOrEncCert, null, null); + } + + public CertifiedKeyPair( + CertOrEncCert certOrEncCert, + EncryptedValue privateKey, + PKIPublicationInfo publicationInfo + ) + { + if (certOrEncCert == null) + { + throw new IllegalArgumentException("'certOrEncCert' cannot be null"); + } + + this.certOrEncCert = certOrEncCert; + this.privateKey = privateKey; + this.publicationInfo = publicationInfo; + } + + public CertOrEncCert getCertOrEncCert() + { + return certOrEncCert; + } + + public EncryptedValue getPrivateKey() + { + return privateKey; + } + + public PKIPublicationInfo getPublicationInfo() + { + return publicationInfo; + } + + /** + *
+ * CertifiedKeyPair ::= SEQUENCE { + * certOrEncCert CertOrEncCert, + * privateKey [0] EncryptedValue OPTIONAL, + * -- see [CRMF] for comment on encoding + * publicationInfo [1] PKIPublicationInfo OPTIONAL + * } + *+ * @return a basic ASN.1 object representation. + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(certOrEncCert); + + if (privateKey != null) + { + v.add(new DERTaggedObject(true, 0, privateKey)); + } + + if (publicationInfo != null) + { + v.add(new DERTaggedObject(true, 1, publicationInfo)); + } + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/Challenge.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/Challenge.java new file mode 100644 index 0000000..f20b3ab --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/Challenge.java @@ -0,0 +1,120 @@ +package org.bc.asn1.cmp; + +import org.bc.asn1.ASN1Encodable; +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1OctetString; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DEROctetString; +import org.bc.asn1.DERSequence; +import org.bc.asn1.x509.AlgorithmIdentifier; + +public class Challenge + extends ASN1Object +{ + private AlgorithmIdentifier owf; + private ASN1OctetString witness; + private ASN1OctetString challenge; + + private Challenge(ASN1Sequence seq) + { + int index = 0; + + if (seq.size() == 3) + { + owf = AlgorithmIdentifier.getInstance(seq.getObjectAt(index++)); + } + + witness = ASN1OctetString.getInstance(seq.getObjectAt(index++)); + challenge = ASN1OctetString.getInstance(seq.getObjectAt(index)); + } + + public static Challenge getInstance(Object o) + { + if (o instanceof Challenge) + { + return (Challenge)o; + } + + if (o != null) + { + return new Challenge(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public Challenge(byte[] witness, byte[] challenge) + { + this(null, witness, challenge); + } + + public Challenge(AlgorithmIdentifier owf, byte[] witness, byte[] challenge) + { + this.owf = owf; + this.witness = new DEROctetString(witness); + this.challenge = new DEROctetString(challenge); + } + + public AlgorithmIdentifier getOwf() + { + return owf; + } + + public byte[] getWitness() + { + return witness.getOctets(); + } + + public byte[] getChallenge() + { + return challenge.getOctets(); + } + + /** + *
+ * Challenge ::= SEQUENCE { + * owf AlgorithmIdentifier OPTIONAL, + * + * -- MUST be present in the first Challenge; MAY be omitted in + * -- any subsequent Challenge in POPODecKeyChallContent (if + * -- omitted, then the owf used in the immediately preceding + * -- Challenge is to be used). + * + * witness OCTET STRING, + * -- the result of applying the one-way function (owf) to a + * -- randomly-generated INTEGER, A. [Note that a different + * -- INTEGER MUST be used for each Challenge.] + * challenge OCTET STRING + * -- the encryption (under the public key for which the cert. + * -- request is being made) of Rand, where Rand is specified as + * -- Rand ::= SEQUENCE { + * -- int INTEGER, + * -- - the randomly-generated INTEGER A (above) + * -- sender GeneralName + * -- - the sender's name (as included in PKIHeader) + * -- } + * } + *+ * @return a basic ASN.1 object representation. + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + addOptional(v, owf); + v.add(witness); + v.add(challenge); + + return new DERSequence(v); + } + + private void addOptional(ASN1EncodableVector v, ASN1Encodable obj) + { + if (obj != null) + { + v.add(obj); + } + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/ErrorMsgContent.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/ErrorMsgContent.java new file mode 100644 index 0000000..de659ce --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/ErrorMsgContent.java @@ -0,0 +1,121 @@ +package org.bc.asn1.cmp; + +import java.util.Enumeration; + +import org.bc.asn1.ASN1Encodable; +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DERSequence; + +public class ErrorMsgContent + extends ASN1Object +{ + private PKIStatusInfo pkiStatusInfo; + private ASN1Integer errorCode; + private PKIFreeText errorDetails; + + private ErrorMsgContent(ASN1Sequence seq) + { + Enumeration en = seq.getObjects(); + + pkiStatusInfo = PKIStatusInfo.getInstance(en.nextElement()); + + while (en.hasMoreElements()) + { + Object o = en.nextElement(); + + if (o instanceof ASN1Integer) + { + errorCode = ASN1Integer.getInstance(o); + } + else + { + errorDetails = PKIFreeText.getInstance(o); + } + } + } + + public static ErrorMsgContent getInstance(Object o) + { + if (o instanceof ErrorMsgContent) + { + return (ErrorMsgContent)o; + } + + if (o != null) + { + return new ErrorMsgContent(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public ErrorMsgContent(PKIStatusInfo pkiStatusInfo) + { + this(pkiStatusInfo, null, null); + } + + public ErrorMsgContent( + PKIStatusInfo pkiStatusInfo, + ASN1Integer errorCode, + PKIFreeText errorDetails) + { + if (pkiStatusInfo == null) + { + throw new IllegalArgumentException("'pkiStatusInfo' cannot be null"); + } + + this.pkiStatusInfo = pkiStatusInfo; + this.errorCode = errorCode; + this.errorDetails = errorDetails; + } + + public PKIStatusInfo getPKIStatusInfo() + { + return pkiStatusInfo; + } + + public ASN1Integer getErrorCode() + { + return errorCode; + } + + public PKIFreeText getErrorDetails() + { + return errorDetails; + } + + /** + *
+ * ErrorMsgContent ::= SEQUENCE { + * pKIStatusInfo PKIStatusInfo, + * errorCode INTEGER OPTIONAL, + * -- implementation-specific error codes + * errorDetails PKIFreeText OPTIONAL + * -- implementation-specific error details + * } + *+ * @return a basic ASN.1 object representation. + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(pkiStatusInfo); + addOptional(v, errorCode); + addOptional(v, errorDetails); + + return new DERSequence(v); + } + + private void addOptional(ASN1EncodableVector v, ASN1Encodable obj) + { + if (obj != null) + { + v.add(obj); + } + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/GenMsgContent.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/GenMsgContent.java new file mode 100644 index 0000000..405138c --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/GenMsgContent.java @@ -0,0 +1,71 @@ +package org.bc.asn1.cmp; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DERSequence; + +public class GenMsgContent + extends ASN1Object +{ + private ASN1Sequence content; + + private GenMsgContent(ASN1Sequence seq) + { + content = seq; + } + + public static GenMsgContent getInstance(Object o) + { + if (o instanceof GenMsgContent) + { + return (GenMsgContent)o; + } + + if (o != null) + { + return new GenMsgContent(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public GenMsgContent(InfoTypeAndValue itv) + { + content = new DERSequence(itv); + } + + public GenMsgContent(InfoTypeAndValue[] itv) + { + ASN1EncodableVector v = new ASN1EncodableVector(); + for (int i = 0; i < itv.length; i++) + { + v.add(itv[i]); + } + content = new DERSequence(v); + } + + public InfoTypeAndValue[] toInfoTypeAndValueArray() + { + InfoTypeAndValue[] result = new InfoTypeAndValue[content.size()]; + + for (int i = 0; i != result.length; i++) + { + result[i] = InfoTypeAndValue.getInstance(content.getObjectAt(i)); + } + + return result; + } + + /** + *
+ * GenMsgContent ::= SEQUENCE OF InfoTypeAndValue + *+ * @return a basic ASN.1 object representation. + */ + public ASN1Primitive toASN1Primitive() + { + return content; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/GenRepContent.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/GenRepContent.java new file mode 100644 index 0000000..9597a9f --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/GenRepContent.java @@ -0,0 +1,71 @@ +package org.bc.asn1.cmp; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DERSequence; + +public class GenRepContent + extends ASN1Object +{ + private ASN1Sequence content; + + private GenRepContent(ASN1Sequence seq) + { + content = seq; + } + + public static GenRepContent getInstance(Object o) + { + if (o instanceof GenRepContent) + { + return (GenRepContent)o; + } + + if (o != null) + { + return new GenRepContent(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public GenRepContent(InfoTypeAndValue itv) + { + content = new DERSequence(itv); + } + + public GenRepContent(InfoTypeAndValue[] itv) + { + ASN1EncodableVector v = new ASN1EncodableVector(); + for (int i = 0; i < itv.length; i++) + { + v.add(itv[i]); + } + content = new DERSequence(v); + } + + public InfoTypeAndValue[] toInfoTypeAndValueArray() + { + InfoTypeAndValue[] result = new InfoTypeAndValue[content.size()]; + + for (int i = 0; i != result.length; i++) + { + result[i] = InfoTypeAndValue.getInstance(content.getObjectAt(i)); + } + + return result; + } + + /** + *
+ * GenRepContent ::= SEQUENCE OF InfoTypeAndValue + *+ * @return a basic ASN.1 object representation. + */ + public ASN1Primitive toASN1Primitive() + { + return content; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/InfoTypeAndValue.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/InfoTypeAndValue.java new file mode 100644 index 0000000..167e6f4 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/InfoTypeAndValue.java @@ -0,0 +1,132 @@ +package org.bc.asn1.cmp; + +import org.bc.asn1.ASN1Encodable; +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1ObjectIdentifier; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DERSequence; + +/** + * Example InfoTypeAndValue contents include, but are not limited + * to, the following (un-comment in this ASN.1 module and use as + * appropriate for a given environment): + *
+ * id-it-caProtEncCert OBJECT IDENTIFIER ::= {id-it 1} + * CAProtEncCertValue ::= CMPCertificate + * id-it-signKeyPairTypes OBJECT IDENTIFIER ::= {id-it 2} + * SignKeyPairTypesValue ::= SEQUENCE OF AlgorithmIdentifier + * id-it-encKeyPairTypes OBJECT IDENTIFIER ::= {id-it 3} + * EncKeyPairTypesValue ::= SEQUENCE OF AlgorithmIdentifier + * id-it-preferredSymmAlg OBJECT IDENTIFIER ::= {id-it 4} + * PreferredSymmAlgValue ::= AlgorithmIdentifier + * id-it-caKeyUpdateInfo OBJECT IDENTIFIER ::= {id-it 5} + * CAKeyUpdateInfoValue ::= CAKeyUpdAnnContent + * id-it-currentCRL OBJECT IDENTIFIER ::= {id-it 6} + * CurrentCRLValue ::= CertificateList + * id-it-unsupportedOIDs OBJECT IDENTIFIER ::= {id-it 7} + * UnsupportedOIDsValue ::= SEQUENCE OF OBJECT IDENTIFIER + * id-it-keyPairParamReq OBJECT IDENTIFIER ::= {id-it 10} + * KeyPairParamReqValue ::= OBJECT IDENTIFIER + * id-it-keyPairParamRep OBJECT IDENTIFIER ::= {id-it 11} + * KeyPairParamRepValue ::= AlgorithmIdentifer + * id-it-revPassphrase OBJECT IDENTIFIER ::= {id-it 12} + * RevPassphraseValue ::= EncryptedValue + * id-it-implicitConfirm OBJECT IDENTIFIER ::= {id-it 13} + * ImplicitConfirmValue ::= NULL + * id-it-confirmWaitTime OBJECT IDENTIFIER ::= {id-it 14} + * ConfirmWaitTimeValue ::= GeneralizedTime + * id-it-origPKIMessage OBJECT IDENTIFIER ::= {id-it 15} + * OrigPKIMessageValue ::= PKIMessages + * id-it-suppLangTags OBJECT IDENTIFIER ::= {id-it 16} + * SuppLangTagsValue ::= SEQUENCE OF UTF8String + * + * where + * + * id-pkix OBJECT IDENTIFIER ::= { + * iso(1) identified-organization(3) + * dod(6) internet(1) security(5) mechanisms(5) pkix(7)} + * and + * id-it OBJECT IDENTIFIER ::= {id-pkix 4} + *+ */ +public class InfoTypeAndValue + extends ASN1Object +{ + private ASN1ObjectIdentifier infoType; + private ASN1Encodable infoValue; + + private InfoTypeAndValue(ASN1Sequence seq) + { + infoType = ASN1ObjectIdentifier.getInstance(seq.getObjectAt(0)); + + if (seq.size() > 1) + { + infoValue = (ASN1Encodable)seq.getObjectAt(1); + } + } + + public static InfoTypeAndValue getInstance(Object o) + { + if (o instanceof InfoTypeAndValue) + { + return (InfoTypeAndValue)o; + } + + if (o != null) + { + return new InfoTypeAndValue(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public InfoTypeAndValue( + ASN1ObjectIdentifier infoType) + { + this.infoType = infoType; + this.infoValue = null; + } + + public InfoTypeAndValue( + ASN1ObjectIdentifier infoType, + ASN1Encodable optionalValue) + { + this.infoType = infoType; + this.infoValue = optionalValue; + } + + public ASN1ObjectIdentifier getInfoType() + { + return infoType; + } + + public ASN1Encodable getInfoValue() + { + return infoValue; + } + + /** + *
+ * InfoTypeAndValue ::= SEQUENCE { + * infoType OBJECT IDENTIFIER, + * infoValue ANY DEFINED BY infoType OPTIONAL + * } + *+ * @return a basic ASN.1 object representation. + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(infoType); + + if (infoValue != null) + { + v.add(infoValue); + } + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/KeyRecRepContent.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/KeyRecRepContent.java new file mode 100644 index 0000000..bf96e4c --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/KeyRecRepContent.java @@ -0,0 +1,142 @@ +package org.bc.asn1.cmp; + +import java.util.Enumeration; + +import org.bc.asn1.ASN1Encodable; +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERSequence; +import org.bc.asn1.DERTaggedObject; + +public class KeyRecRepContent + extends ASN1Object +{ + private PKIStatusInfo status; + private CMPCertificate newSigCert; + private ASN1Sequence caCerts; + private ASN1Sequence keyPairHist; + + private KeyRecRepContent(ASN1Sequence seq) + { + Enumeration en = seq.getObjects(); + + status = PKIStatusInfo.getInstance(en.nextElement()); + + while (en.hasMoreElements()) + { + ASN1TaggedObject tObj = ASN1TaggedObject.getInstance(en.nextElement()); + + switch (tObj.getTagNo()) + { + case 0: + newSigCert = CMPCertificate.getInstance(tObj.getObject()); + break; + case 1: + caCerts = ASN1Sequence.getInstance(tObj.getObject()); + break; + case 2: + keyPairHist = ASN1Sequence.getInstance(tObj.getObject()); + break; + default: + throw new IllegalArgumentException("unknown tag number: " + tObj.getTagNo()); + } + } + } + + public static KeyRecRepContent getInstance(Object o) + { + if (o instanceof KeyRecRepContent) + { + return (KeyRecRepContent)o; + } + + if (o != null) + { + return new KeyRecRepContent(ASN1Sequence.getInstance(o)); + } + + return null; + } + + + public PKIStatusInfo getStatus() + { + return status; + } + + public CMPCertificate getNewSigCert() + { + return newSigCert; + } + + public CMPCertificate[] getCaCerts() + { + if (caCerts == null) + { + return null; + } + + CMPCertificate[] results = new CMPCertificate[caCerts.size()]; + + for (int i = 0; i != results.length; i++) + { + results[i] = CMPCertificate.getInstance(caCerts.getObjectAt(i)); + } + + return results; + } + + public CertifiedKeyPair[] getKeyPairHist() + { + if (keyPairHist == null) + { + return null; + } + + CertifiedKeyPair[] results = new CertifiedKeyPair[keyPairHist.size()]; + + for (int i = 0; i != results.length; i++) + { + results[i] = CertifiedKeyPair.getInstance(keyPairHist.getObjectAt(i)); + } + + return results; + } + + /** + *
+ * KeyRecRepContent ::= SEQUENCE { + * status PKIStatusInfo, + * newSigCert [0] CMPCertificate OPTIONAL, + * caCerts [1] SEQUENCE SIZE (1..MAX) OF + * CMPCertificate OPTIONAL, + * keyPairHist [2] SEQUENCE SIZE (1..MAX) OF + * CertifiedKeyPair OPTIONAL + * } + *+ * @return a basic ASN.1 object representation. + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(status); + + addOptional(v, 0, newSigCert); + addOptional(v, 1, caCerts); + addOptional(v, 2, keyPairHist); + + return new DERSequence(v); + } + + private void addOptional(ASN1EncodableVector v, int tagNo, ASN1Encodable obj) + { + if (obj != null) + { + v.add(new DERTaggedObject(true, tagNo, obj)); + } + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/OOBCertHash.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/OOBCertHash.java new file mode 100644 index 0000000..25ee23f --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/OOBCertHash.java @@ -0,0 +1,117 @@ +package org.bc.asn1.cmp; + +import org.bc.asn1.ASN1Encodable; +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERBitString; +import org.bc.asn1.DERSequence; +import org.bc.asn1.DERTaggedObject; +import org.bc.asn1.crmf.CertId; +import org.bc.asn1.x509.AlgorithmIdentifier; + +public class OOBCertHash + extends ASN1Object +{ + private AlgorithmIdentifier hashAlg; + private CertId certId; + private DERBitString hashVal; + + private OOBCertHash(ASN1Sequence seq) + { + int index = seq.size() - 1; + + hashVal = DERBitString.getInstance(seq.getObjectAt(index--)); + + for (int i = index; i >= 0; i--) + { + ASN1TaggedObject tObj = (ASN1TaggedObject)seq.getObjectAt(i); + + if (tObj.getTagNo() == 0) + { + hashAlg = AlgorithmIdentifier.getInstance(tObj, true); + } + else + { + certId = CertId.getInstance(tObj, true); + } + } + + } + + public static OOBCertHash getInstance(Object o) + { + if (o instanceof OOBCertHash) + { + return (OOBCertHash)o; + } + + if (o != null) + { + return new OOBCertHash(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public OOBCertHash(AlgorithmIdentifier hashAlg, CertId certId, byte[] hashVal) + { + this(hashAlg, certId, new DERBitString(hashVal)); + } + + public OOBCertHash(AlgorithmIdentifier hashAlg, CertId certId, DERBitString hashVal) + { + this.hashAlg = hashAlg; + this.certId = certId; + this.hashVal = hashVal; + } + + public AlgorithmIdentifier getHashAlg() + { + return hashAlg; + } + + public CertId getCertId() + { + return certId; + } + + public DERBitString getHashVal() + { + return hashVal; + } + + /** + *
+ * OOBCertHash ::= SEQUENCE { + * hashAlg [0] AlgorithmIdentifier OPTIONAL, + * certId [1] CertId OPTIONAL, + * hashVal BIT STRING + * -- hashVal is calculated over the DER encoding of the + * -- self-signed certificate with the identifier certID. + * } + *+ * @return a basic ASN.1 object representation. + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + addOptional(v, 0, hashAlg); + addOptional(v, 1, certId); + + v.add(hashVal); + + return new DERSequence(v); + } + + private void addOptional(ASN1EncodableVector v, int tagNo, ASN1Encodable obj) + { + if (obj != null) + { + v.add(new DERTaggedObject(true, tagNo, obj)); + } + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/PBMParameter.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/PBMParameter.java new file mode 100644 index 0000000..d37681f --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/PBMParameter.java @@ -0,0 +1,117 @@ +package org.bc.asn1.cmp; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1OctetString; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DEROctetString; +import org.bc.asn1.DERSequence; +import org.bc.asn1.x509.AlgorithmIdentifier; + +public class PBMParameter + extends ASN1Object +{ + private ASN1OctetString salt; + private AlgorithmIdentifier owf; + private ASN1Integer iterationCount; + private AlgorithmIdentifier mac; + + private PBMParameter(ASN1Sequence seq) + { + salt = ASN1OctetString.getInstance(seq.getObjectAt(0)); + owf = AlgorithmIdentifier.getInstance(seq.getObjectAt(1)); + iterationCount = ASN1Integer.getInstance(seq.getObjectAt(2)); + mac = AlgorithmIdentifier.getInstance(seq.getObjectAt(3)); + } + + public static PBMParameter getInstance(Object o) + { + if (o instanceof PBMParameter) + { + return (PBMParameter)o; + } + + if (o != null) + { + return new PBMParameter(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public PBMParameter( + byte[] salt, + AlgorithmIdentifier owf, + int iterationCount, + AlgorithmIdentifier mac) + { + this(new DEROctetString(salt), owf, + new ASN1Integer(iterationCount), mac); + } + + public PBMParameter( + ASN1OctetString salt, + AlgorithmIdentifier owf, + ASN1Integer iterationCount, + AlgorithmIdentifier mac) + { + this.salt = salt; + this.owf = owf; + this.iterationCount = iterationCount; + this.mac = mac; + } + + public ASN1OctetString getSalt() + { + return salt; + } + + public AlgorithmIdentifier getOwf() + { + return owf; + } + + public ASN1Integer getIterationCount() + { + return iterationCount; + } + + public AlgorithmIdentifier getMac() + { + return mac; + } + + /** + *
+ * PBMParameter ::= SEQUENCE { + * salt OCTET STRING, + * -- note: implementations MAY wish to limit acceptable sizes + * -- of this string to values appropriate for their environment + * -- in order to reduce the risk of denial-of-service attacks + * owf AlgorithmIdentifier, + * -- AlgId for a One-Way Function (SHA-1 recommended) + * iterationCount INTEGER, + * -- number of times the OWF is applied + * -- note: implementations MAY wish to limit acceptable sizes + * -- of this integer to values appropriate for their environment + * -- in order to reduce the risk of denial-of-service attacks + * mac AlgorithmIdentifier + * -- the MAC AlgId (e.g., DES-MAC, Triple-DES-MAC [PKCS11], + * } -- or HMAC [RFC2104, RFC2202]) + *+ * @return a basic ASN.1 object representation. + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(salt); + v.add(owf); + v.add(iterationCount); + v.add(mac); + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/PKIBody.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/PKIBody.java new file mode 100644 index 0000000..d0e53b6 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/PKIBody.java @@ -0,0 +1,194 @@ +package org.bc.asn1.cmp; + +import org.bc.asn1.ASN1Choice; +import org.bc.asn1.ASN1Encodable; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERTaggedObject; +import org.bc.asn1.crmf.CertReqMessages; +import org.bc.asn1.pkcs.CertificationRequest; + +public class PKIBody + extends ASN1Object + implements ASN1Choice +{ + public static final int TYPE_INIT_REQ = 0; + public static final int TYPE_INIT_REP = 1; + public static final int TYPE_CERT_REQ = 2; + public static final int TYPE_CERT_REP = 3; + public static final int TYPE_P10_CERT_REQ = 4; + public static final int TYPE_POPO_CHALL = 5; + public static final int TYPE_POPO_REP = 6; + public static final int TYPE_KEY_UPDATE_REQ = 7; + public static final int TYPE_KEY_UPDATE_REP = 8; + public static final int TYPE_KEY_RECOVERY_REQ = 9; + public static final int TYPE_KEY_RECOVERY_REP = 10; + public static final int TYPE_REVOCATION_REQ = 11; + public static final int TYPE_REVOCATION_REP = 12; + public static final int TYPE_CROSS_CERT_REQ = 13; + public static final int TYPE_CROSS_CERT_REP = 14; + public static final int TYPE_CA_KEY_UPDATE_ANN = 15; + public static final int TYPE_CERT_ANN = 16; + public static final int TYPE_REVOCATION_ANN = 17; + public static final int TYPE_CRL_ANN = 18; + public static final int TYPE_CONFIRM = 19; + public static final int TYPE_NESTED = 20; + public static final int TYPE_GEN_MSG = 21; + public static final int TYPE_GEN_REP = 22; + public static final int TYPE_ERROR = 23; + public static final int TYPE_CERT_CONFIRM = 24; + public static final int TYPE_POLL_REQ = 25; + public static final int TYPE_POLL_REP = 26; + + private int tagNo; + private ASN1Encodable body; + + public static PKIBody getInstance(Object o) + { + if (o == null || o instanceof PKIBody) + { + return (PKIBody)o; + } + + if (o instanceof ASN1TaggedObject) + { + return new PKIBody((ASN1TaggedObject)o); + } + + throw new IllegalArgumentException("Invalid object: " + o.getClass().getName()); + } + + private PKIBody(ASN1TaggedObject tagged) + { + tagNo = tagged.getTagNo(); + body = getBodyForType(tagNo, tagged.getObject()); + } + + /** + * Creates a new PKIBody. + * @param type one of the TYPE_* constants + * @param content message content + */ + public PKIBody( + int type, + ASN1Encodable content) + { + tagNo = type; + body = getBodyForType(type, content); + } + + private static ASN1Encodable getBodyForType( + int type, + ASN1Encodable o) + { + switch (type) + { + case TYPE_INIT_REQ: + return CertReqMessages.getInstance(o); + case TYPE_INIT_REP: + return CertRepMessage.getInstance(o); + case TYPE_CERT_REQ: + return CertReqMessages.getInstance(o); + case TYPE_CERT_REP: + return CertRepMessage.getInstance(o); + case TYPE_P10_CERT_REQ: + return CertificationRequest.getInstance(o); + case TYPE_POPO_CHALL: + return POPODecKeyChallContent.getInstance(o); + case TYPE_POPO_REP: + return POPODecKeyRespContent.getInstance(o); + case TYPE_KEY_UPDATE_REQ: + return CertReqMessages.getInstance(o); + case TYPE_KEY_UPDATE_REP: + return CertRepMessage.getInstance(o); + case TYPE_KEY_RECOVERY_REQ: + return CertReqMessages.getInstance(o); + case TYPE_KEY_RECOVERY_REP: + return KeyRecRepContent.getInstance(o); + case TYPE_REVOCATION_REQ: + return RevReqContent.getInstance(o); + case TYPE_REVOCATION_REP: + return RevRepContent.getInstance(o); + case TYPE_CROSS_CERT_REQ: + return CertReqMessages.getInstance(o); + case TYPE_CROSS_CERT_REP: + return CertRepMessage.getInstance(o); + case TYPE_CA_KEY_UPDATE_ANN: + return CAKeyUpdAnnContent.getInstance(o); + case TYPE_CERT_ANN: + return CMPCertificate.getInstance(o); + case TYPE_REVOCATION_ANN: + return RevAnnContent.getInstance(o); + case TYPE_CRL_ANN: + return CRLAnnContent.getInstance(o); + case TYPE_CONFIRM: + return PKIConfirmContent.getInstance(o); + case TYPE_NESTED: + return PKIMessages.getInstance(o); + case TYPE_GEN_MSG: + return GenMsgContent.getInstance(o); + case TYPE_GEN_REP: + return GenRepContent.getInstance(o); + case TYPE_ERROR: + return ErrorMsgContent.getInstance(o); + case TYPE_CERT_CONFIRM: + return CertConfirmContent.getInstance(o); + case TYPE_POLL_REQ: + return PollReqContent.getInstance(o); + case TYPE_POLL_REP: + return PollRepContent.getInstance(o); + default: + throw new IllegalArgumentException("unknown tag number: " + type); + } + } + + public int getType() + { + return tagNo; + } + + public ASN1Encodable getContent() + { + return body; + } + + /** + *
+ * PKIBody ::= CHOICE { -- message-specific body elements + * ir [0] CertReqMessages, --Initialization Request + * ip [1] CertRepMessage, --Initialization Response + * cr [2] CertReqMessages, --Certification Request + * cp [3] CertRepMessage, --Certification Response + * p10cr [4] CertificationRequest, --imported from [PKCS10] + * popdecc [5] POPODecKeyChallContent, --pop Challenge + * popdecr [6] POPODecKeyRespContent, --pop Response + * kur [7] CertReqMessages, --Key Update Request + * kup [8] CertRepMessage, --Key Update Response + * krr [9] CertReqMessages, --Key Recovery Request + * krp [10] KeyRecRepContent, --Key Recovery Response + * rr [11] RevReqContent, --Revocation Request + * rp [12] RevRepContent, --Revocation Response + * ccr [13] CertReqMessages, --Cross-Cert. Request + * ccp [14] CertRepMessage, --Cross-Cert. Response + * ckuann [15] CAKeyUpdAnnContent, --CA Key Update Ann. + * cann [16] CertAnnContent, --Certificate Ann. + * rann [17] RevAnnContent, --Revocation Ann. + * crlann [18] CRLAnnContent, --CRL Announcement + * pkiconf [19] PKIConfirmContent, --Confirmation + * nested [20] NestedMessageContent, --Nested Message + * genm [21] GenMsgContent, --General Message + * genp [22] GenRepContent, --General Response + * error [23] ErrorMsgContent, --Error Message + * certConf [24] CertConfirmContent, --Certificate confirm + * pollReq [25] PollReqContent, --Polling request + * pollRep [26] PollRepContent --Polling response + * } + *+ * @return a basic ASN.1 object representation. + */ + public ASN1Primitive toASN1Primitive() + { + return new DERTaggedObject(true, tagNo, body); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/PKIConfirmContent.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/PKIConfirmContent.java new file mode 100644 index 0000000..498cc93 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/PKIConfirmContent.java @@ -0,0 +1,48 @@ +package org.bc.asn1.cmp; + +import org.bc.asn1.ASN1Null; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.DERNull; + +public class PKIConfirmContent + extends ASN1Object +{ + private ASN1Null val; + + private PKIConfirmContent(ASN1Null val) + { + this.val = val; + } + + public static PKIConfirmContent getInstance(Object o) + { + if (o == null || o instanceof PKIConfirmContent) + { + return (PKIConfirmContent)o; + } + + if (o instanceof ASN1Null) + { + return new PKIConfirmContent((ASN1Null)o); + } + + throw new IllegalArgumentException("Invalid object: " + o.getClass().getName()); + } + + public PKIConfirmContent() + { + val = DERNull.INSTANCE; + } + + /** + *
+ * PKIConfirmContent ::= NULL + *+ * @return a basic ASN.1 object representation. + */ + public ASN1Primitive toASN1Primitive() + { + return val; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/PKIFailureInfo.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/PKIFailureInfo.java new file mode 100644 index 0000000..16fc2a4 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/PKIFailureInfo.java @@ -0,0 +1,126 @@ +package org.bc.asn1.cmp; + +import org.bc.asn1.DERBitString; + +/** + *
+ * PKIFailureInfo ::= BIT STRING { + * badAlg (0), + * -- unrecognized or unsupported Algorithm Identifier + * badMessageCheck (1), -- integrity check failed (e.g., signature did not verify) + * badRequest (2), + * -- transaction not permitted or supported + * badTime (3), -- messageTime was not sufficiently close to the system time, as defined by local policy + * badCertId (4), -- no certificate could be found matching the provided criteria + * badDataFormat (5), + * -- the data submitted has the wrong format + * wrongAuthority (6), -- the authority indicated in the request is different from the one creating the response token + * incorrectData (7), -- the requester's data is incorrect (for notary services) + * missingTimeStamp (8), -- when the timestamp is missing but should be there (by policy) + * badPOP (9) -- the proof-of-possession failed + * certRevoked (10), + * certConfirmed (11), + * wrongIntegrity (12), + * badRecipientNonce (13), + * timeNotAvailable (14), + * -- the TSA's time source is not available + * unacceptedPolicy (15), + * -- the requested TSA policy is not supported by the TSA + * unacceptedExtension (16), + * -- the requested extension is not supported by the TSA + * addInfoNotAvailable (17) + * -- the additional information requested could not be understood + * -- or is not available + * badSenderNonce (18), + * badCertTemplate (19), + * signerNotTrusted (20), + * transactionIdInUse (21), + * unsupportedVersion (22), + * notAuthorized (23), + * systemUnavail (24), + * systemFailure (25), + * -- the request cannot be handled due to system failure + * duplicateCertReq (26) + *+ */ +public class PKIFailureInfo + extends DERBitString +{ + public static final int badAlg = (1 << 7); // unrecognized or unsupported Algorithm Identifier + public static final int badMessageCheck = (1 << 6); // integrity check failed (e.g., signature did not verify) + public static final int badRequest = (1 << 5); + public static final int badTime = (1 << 4); // -- messageTime was not sufficiently close to the system time, as defined by local policy + public static final int badCertId = (1 << 3); // no certificate could be found matching the provided criteria + public static final int badDataFormat = (1 << 2); + public static final int wrongAuthority = (1 << 1); // the authority indicated in the request is different from the one creating the response token + public static final int incorrectData = 1; // the requester's data is incorrect (for notary services) + public static final int missingTimeStamp = (1 << 15); // when the timestamp is missing but should be there (by policy) + public static final int badPOP = (1 << 14); // the proof-of-possession failed + public static final int certRevoked = (1 << 13); + public static final int certConfirmed = (1 << 12); + public static final int wrongIntegrity = (1 << 11); + public static final int badRecipientNonce = (1 << 10); + public static final int timeNotAvailable = (1 << 9); // the TSA's time source is not available + public static final int unacceptedPolicy = (1 << 8); // the requested TSA policy is not supported by the TSA + public static final int unacceptedExtension = (1 << 23); //the requested extension is not supported by the TSA + public static final int addInfoNotAvailable = (1 << 22); //the additional information requested could not be understood or is not available + public static final int badSenderNonce = (1 << 21); + public static final int badCertTemplate = (1 << 20); + public static final int signerNotTrusted = (1 << 19); + public static final int transactionIdInUse = (1 << 18); + public static final int unsupportedVersion = (1 << 17); + public static final int notAuthorized = (1 << 16); + public static final int systemUnavail = (1 << 31); + public static final int systemFailure = (1 << 30); //the request cannot be handled due to system failure + public static final int duplicateCertReq = (1 << 29); + + /** @deprecated use lower case version */ + public static final int BAD_ALG = badAlg; // unrecognized or unsupported Algorithm Identifier + /** @deprecated use lower case version */ + public static final int BAD_MESSAGE_CHECK = badMessageCheck; + /** @deprecated use lower case version */ + public static final int BAD_REQUEST = badRequest; // transaction not permitted or supported + /** @deprecated use lower case version */ + public static final int BAD_TIME = badTime; + /** @deprecated use lower case version */ + public static final int BAD_CERT_ID = badCertId; + /** @deprecated use lower case version */ + public static final int BAD_DATA_FORMAT = badDataFormat; // the data submitted has the wrong format + /** @deprecated use lower case version */ + public static final int WRONG_AUTHORITY = wrongAuthority; + /** @deprecated use lower case version */ + public static final int INCORRECT_DATA = incorrectData; + /** @deprecated use lower case version */ + public static final int MISSING_TIME_STAMP = missingTimeStamp; + /** @deprecated use lower case version */ + public static final int BAD_POP = badPOP; + /** @deprecated use lower case version */ + public static final int TIME_NOT_AVAILABLE = timeNotAvailable; + /** @deprecated use lower case version */ + public static final int UNACCEPTED_POLICY = unacceptedPolicy; + /** @deprecated use lower case version */ + public static final int UNACCEPTED_EXTENSION = unacceptedExtension; + /** @deprecated use lower case version */ + public static final int ADD_INFO_NOT_AVAILABLE = addInfoNotAvailable; + /** @deprecated use lower case version */ + public static final int SYSTEM_FAILURE = systemFailure; + /** + * Basic constructor. + */ + public PKIFailureInfo( + int info) + { + super(getBytes(info), getPadBits(info)); + } + + public PKIFailureInfo( + DERBitString info) + { + super(info.getBytes(), info.getPadBits()); + } + + public String toString() + { + return "PKIFailureInfo: 0x" + Integer.toHexString(this.intValue()); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/PKIFreeText.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/PKIFreeText.java new file mode 100644 index 0000000..c6c5ab5 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/PKIFreeText.java @@ -0,0 +1,114 @@ +package org.bc.asn1.cmp; + +import java.util.Enumeration; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERSequence; +import org.bc.asn1.DERUTF8String; + +public class PKIFreeText + extends ASN1Object +{ + ASN1Sequence strings; + + public static PKIFreeText getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static PKIFreeText getInstance( + Object obj) + { + if (obj instanceof PKIFreeText) + { + return (PKIFreeText)obj; + } + else if (obj != null) + { + return new PKIFreeText(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + private PKIFreeText( + ASN1Sequence seq) + { + Enumeration e = seq.getObjects(); + while (e.hasMoreElements()) + { + if (!(e.nextElement() instanceof DERUTF8String)) + { + throw new IllegalArgumentException("attempt to insert non UTF8 STRING into PKIFreeText"); + } + } + + strings = seq; + } + + public PKIFreeText( + DERUTF8String p) + { + strings = new DERSequence(p); + } + + public PKIFreeText( + String p) + { + this(new DERUTF8String(p)); + } + + public PKIFreeText( + DERUTF8String[] strs) + { + strings = new DERSequence(strs); + } + + public PKIFreeText( + String[] strs) + { + ASN1EncodableVector v = new ASN1EncodableVector(); + for (int i = 0; i < strs.length; i++) { + v.add(new DERUTF8String(strs[i])); + } + strings = new DERSequence(v); + } + + /** + * Return the number of string elements present. + * + * @return number of elements present. + */ + public int size() + { + return strings.size(); + } + + /** + * Return the UTF8STRING at index i. + * + * @param i index of the string of interest + * @return the string at index i. + */ + public DERUTF8String getStringAt( + int i) + { + return (DERUTF8String)strings.getObjectAt(i); + } + + /** + *
+ * PKIFreeText ::= SEQUENCE SIZE (1..MAX) OF UTF8String + *+ */ + public ASN1Primitive toASN1Primitive() + { + return strings; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/PKIHeader.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/PKIHeader.java new file mode 100644 index 0000000..e5286dc --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/PKIHeader.java @@ -0,0 +1,257 @@ +package org.bc.asn1.cmp; + +import java.util.Enumeration; + +import org.bc.asn1.ASN1Encodable; +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1OctetString; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERGeneralizedTime; +import org.bc.asn1.DERSequence; +import org.bc.asn1.DERTaggedObject; +import org.bc.asn1.x500.X500Name; +import org.bc.asn1.x509.AlgorithmIdentifier; +import org.bc.asn1.x509.GeneralName; + +public class PKIHeader + extends ASN1Object +{ + /** + * Value for a "null" recipient or sender. + */ + public static final GeneralName NULL_NAME = new GeneralName(X500Name.getInstance(new DERSequence())); + + public static final int CMP_1999 = 1; + public static final int CMP_2000 = 2; + + private ASN1Integer pvno; + private GeneralName sender; + private GeneralName recipient; + private DERGeneralizedTime messageTime; + private AlgorithmIdentifier protectionAlg; + private ASN1OctetString senderKID; // KeyIdentifier + private ASN1OctetString recipKID; // KeyIdentifier + private ASN1OctetString transactionID; + private ASN1OctetString senderNonce; + private ASN1OctetString recipNonce; + private PKIFreeText freeText; + private ASN1Sequence generalInfo; + + private PKIHeader(ASN1Sequence seq) + { + Enumeration en = seq.getObjects(); + + pvno = ASN1Integer.getInstance(en.nextElement()); + sender = GeneralName.getInstance(en.nextElement()); + recipient = GeneralName.getInstance(en.nextElement()); + + while (en.hasMoreElements()) + { + ASN1TaggedObject tObj = (ASN1TaggedObject)en.nextElement(); + + switch (tObj.getTagNo()) + { + case 0: + messageTime = DERGeneralizedTime.getInstance(tObj, true); + break; + case 1: + protectionAlg = AlgorithmIdentifier.getInstance(tObj, true); + break; + case 2: + senderKID = ASN1OctetString.getInstance(tObj, true); + break; + case 3: + recipKID = ASN1OctetString.getInstance(tObj, true); + break; + case 4: + transactionID = ASN1OctetString.getInstance(tObj, true); + break; + case 5: + senderNonce = ASN1OctetString.getInstance(tObj, true); + break; + case 6: + recipNonce = ASN1OctetString.getInstance(tObj, true); + break; + case 7: + freeText = PKIFreeText.getInstance(tObj, true); + break; + case 8: + generalInfo = ASN1Sequence.getInstance(tObj, true); + break; + default: + throw new IllegalArgumentException("unknown tag number: " + tObj.getTagNo()); + } + } + } + + public static PKIHeader getInstance(Object o) + { + if (o instanceof PKIHeader) + { + return (PKIHeader)o; + } + + if (o != null) + { + return new PKIHeader(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public PKIHeader( + int pvno, + GeneralName sender, + GeneralName recipient) + { + this(new ASN1Integer(pvno), sender, recipient); + } + + private PKIHeader( + ASN1Integer pvno, + GeneralName sender, + GeneralName recipient) + { + this.pvno = pvno; + this.sender = sender; + this.recipient = recipient; + } + + public ASN1Integer getPvno() + { + return pvno; + } + + public GeneralName getSender() + { + return sender; + } + + public GeneralName getRecipient() + { + return recipient; + } + + public DERGeneralizedTime getMessageTime() + { + return messageTime; + } + + public AlgorithmIdentifier getProtectionAlg() + { + return protectionAlg; + } + + public ASN1OctetString getSenderKID() + { + return senderKID; + } + + public ASN1OctetString getRecipKID() + { + return recipKID; + } + + public ASN1OctetString getTransactionID() + { + return transactionID; + } + + public ASN1OctetString getSenderNonce() + { + return senderNonce; + } + + public ASN1OctetString getRecipNonce() + { + return recipNonce; + } + + public PKIFreeText getFreeText() + { + return freeText; + } + + public InfoTypeAndValue[] getGeneralInfo() + { + if (generalInfo == null) { + return null; + } + InfoTypeAndValue[] results = new InfoTypeAndValue[generalInfo.size()]; + for (int i = 0; i < results.length; i++) { + results[i] + = InfoTypeAndValue.getInstance(generalInfo.getObjectAt(i)); + } + return results; + } + + /** + *
+ * PKIHeader ::= SEQUENCE { + * pvno INTEGER { cmp1999(1), cmp2000(2) }, + * sender GeneralName, + * -- identifies the sender + * recipient GeneralName, + * -- identifies the intended recipient + * messageTime [0] GeneralizedTime OPTIONAL, + * -- time of production of this message (used when sender + * -- believes that the transport will be "suitable"; i.e., + * -- that the time will still be meaningful upon receipt) + * protectionAlg [1] AlgorithmIdentifier OPTIONAL, + * -- algorithm used for calculation of protection bits + * senderKID [2] KeyIdentifier OPTIONAL, + * recipKID [3] KeyIdentifier OPTIONAL, + * -- to identify specific keys used for protection + * transactionID [4] OCTET STRING OPTIONAL, + * -- identifies the transaction; i.e., this will be the same in + * -- corresponding request, response, certConf, and PKIConf + * -- messages + * senderNonce [5] OCTET STRING OPTIONAL, + * recipNonce [6] OCTET STRING OPTIONAL, + * -- nonces used to provide replay protection, senderNonce + * -- is inserted by the creator of this message; recipNonce + * -- is a nonce previously inserted in a related message by + * -- the intended recipient of this message + * freeText [7] PKIFreeText OPTIONAL, + * -- this may be used to indicate context-specific instructions + * -- (this field is intended for human consumption) + * generalInfo [8] SEQUENCE SIZE (1..MAX) OF + * InfoTypeAndValue OPTIONAL + * -- this may be used to convey context-specific information + * -- (this field not primarily intended for human consumption) + * } + *+ * @return a basic ASN.1 object representation. + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(pvno); + v.add(sender); + v.add(recipient); + addOptional(v, 0, messageTime); + addOptional(v, 1, protectionAlg); + addOptional(v, 2, senderKID); + addOptional(v, 3, recipKID); + addOptional(v, 4, transactionID); + addOptional(v, 5, senderNonce); + addOptional(v, 6, recipNonce); + addOptional(v, 7, freeText); + addOptional(v, 8, generalInfo); + + return new DERSequence(v); + } + + private void addOptional(ASN1EncodableVector v, int tagNo, ASN1Encodable obj) + { + if (obj != null) + { + v.add(new DERTaggedObject(true, tagNo, obj)); + } + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/PKIHeaderBuilder.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/PKIHeaderBuilder.java new file mode 100644 index 0000000..bfdb5e5 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/PKIHeaderBuilder.java @@ -0,0 +1,254 @@ +package org.bc.asn1.cmp; + +import org.bc.asn1.ASN1Encodable; +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1GeneralizedTime; +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1OctetString; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DERGeneralizedTime; +import org.bc.asn1.DEROctetString; +import org.bc.asn1.DERSequence; +import org.bc.asn1.DERTaggedObject; +import org.bc.asn1.x509.AlgorithmIdentifier; +import org.bc.asn1.x509.GeneralName; + +public class PKIHeaderBuilder +{ + private ASN1Integer pvno; + private GeneralName sender; + private GeneralName recipient; + private ASN1GeneralizedTime messageTime; + private AlgorithmIdentifier protectionAlg; + private ASN1OctetString senderKID; // KeyIdentifier + private ASN1OctetString recipKID; // KeyIdentifier + private ASN1OctetString transactionID; + private ASN1OctetString senderNonce; + private ASN1OctetString recipNonce; + private PKIFreeText freeText; + private ASN1Sequence generalInfo; + + public PKIHeaderBuilder( + int pvno, + GeneralName sender, + GeneralName recipient) + { + this(new ASN1Integer(pvno), sender, recipient); + } + + private PKIHeaderBuilder( + ASN1Integer pvno, + GeneralName sender, + GeneralName recipient) + { + this.pvno = pvno; + this.sender = sender; + this.recipient = recipient; + } + + /** + * @deprecated use ASN1GeneralizedTime + */ + public PKIHeaderBuilder setMessageTime(DERGeneralizedTime time) + { + messageTime = ASN1GeneralizedTime.getInstance(time); + + return this; + } + + public PKIHeaderBuilder setMessageTime(ASN1GeneralizedTime time) + { + messageTime = time; + + return this; + } + + public PKIHeaderBuilder setProtectionAlg(AlgorithmIdentifier aid) + { + protectionAlg = aid; + + return this; + } + + public PKIHeaderBuilder setSenderKID(byte[] kid) + { + return setSenderKID(kid == null ? null : new DEROctetString(kid)); + } + + public PKIHeaderBuilder setSenderKID(ASN1OctetString kid) + { + senderKID = kid; + + return this; + } + + public PKIHeaderBuilder setRecipKID(byte[] kid) + { + return setRecipKID(kid == null ? null : new DEROctetString(kid)); + } + + public PKIHeaderBuilder setRecipKID(DEROctetString kid) + { + recipKID = kid; + + return this; + } + + public PKIHeaderBuilder setTransactionID(byte[] tid) + { + return setTransactionID(tid == null ? null : new DEROctetString(tid)); + } + + public PKIHeaderBuilder setTransactionID(ASN1OctetString tid) + { + transactionID = tid; + + return this; + } + + public PKIHeaderBuilder setSenderNonce(byte[] nonce) + { + return setSenderNonce(nonce == null ? null : new DEROctetString(nonce)); + } + + public PKIHeaderBuilder setSenderNonce(ASN1OctetString nonce) + { + senderNonce = nonce; + + return this; + } + + public PKIHeaderBuilder setRecipNonce(byte[] nonce) + { + return setRecipNonce(nonce == null ? null : new DEROctetString(nonce)); + } + + public PKIHeaderBuilder setRecipNonce(ASN1OctetString nonce) + { + recipNonce = nonce; + + return this; + } + + public PKIHeaderBuilder setFreeText(PKIFreeText text) + { + freeText = text; + + return this; + } + + public PKIHeaderBuilder setGeneralInfo(InfoTypeAndValue genInfo) + { + return setGeneralInfo(makeGeneralInfoSeq(genInfo)); + } + + public PKIHeaderBuilder setGeneralInfo(InfoTypeAndValue[] genInfos) + { + return setGeneralInfo(makeGeneralInfoSeq(genInfos)); + } + + public PKIHeaderBuilder setGeneralInfo(ASN1Sequence seqOfInfoTypeAndValue) + { + generalInfo = seqOfInfoTypeAndValue; + + return this; + } + + private static ASN1Sequence makeGeneralInfoSeq( + InfoTypeAndValue generalInfo) + { + return new DERSequence(generalInfo); + } + + private static ASN1Sequence makeGeneralInfoSeq( + InfoTypeAndValue[] generalInfos) + { + ASN1Sequence genInfoSeq = null; + if (generalInfos != null) + { + ASN1EncodableVector v = new ASN1EncodableVector(); + for (int i = 0; i < generalInfos.length; i++) + { + v.add(generalInfos[i]); + } + genInfoSeq = new DERSequence(v); + } + return genInfoSeq; + } + + /** + *
+ * PKIHeader ::= SEQUENCE { + * pvno INTEGER { cmp1999(1), cmp2000(2) }, + * sender GeneralName, + * -- identifies the sender + * recipient GeneralName, + * -- identifies the intended recipient + * messageTime [0] GeneralizedTime OPTIONAL, + * -- time of production of this message (used when sender + * -- believes that the transport will be "suitable"; i.e., + * -- that the time will still be meaningful upon receipt) + * protectionAlg [1] AlgorithmIdentifier OPTIONAL, + * -- algorithm used for calculation of protection bits + * senderKID [2] KeyIdentifier OPTIONAL, + * recipKID [3] KeyIdentifier OPTIONAL, + * -- to identify specific keys used for protection + * transactionID [4] OCTET STRING OPTIONAL, + * -- identifies the transaction; i.e., this will be the same in + * -- corresponding request, response, certConf, and PKIConf + * -- messages + * senderNonce [5] OCTET STRING OPTIONAL, + * recipNonce [6] OCTET STRING OPTIONAL, + * -- nonces used to provide replay protection, senderNonce + * -- is inserted by the creator of this message; recipNonce + * -- is a nonce previously inserted in a related message by + * -- the intended recipient of this message + * freeText [7] PKIFreeText OPTIONAL, + * -- this may be used to indicate context-specific instructions + * -- (this field is intended for human consumption) + * generalInfo [8] SEQUENCE SIZE (1..MAX) OF + * InfoTypeAndValue OPTIONAL + * -- this may be used to convey context-specific information + * -- (this field not primarily intended for human consumption) + * } + *+ * @return a basic ASN.1 object representation. + */ + public PKIHeader build() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(pvno); + v.add(sender); + v.add(recipient); + addOptional(v, 0, messageTime); + addOptional(v, 1, protectionAlg); + addOptional(v, 2, senderKID); + addOptional(v, 3, recipKID); + addOptional(v, 4, transactionID); + addOptional(v, 5, senderNonce); + addOptional(v, 6, recipNonce); + addOptional(v, 7, freeText); + addOptional(v, 8, generalInfo); + + messageTime = null; + protectionAlg = null; + senderKID = null; + recipKID = null; + transactionID = null; + senderNonce = null; + recipNonce = null; + freeText = null; + generalInfo = null; + + return PKIHeader.getInstance(new DERSequence(v)); + } + + private void addOptional(ASN1EncodableVector v, int tagNo, ASN1Encodable obj) + { + if (obj != null) + { + v.add(new DERTaggedObject(true, tagNo, obj)); + } + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/PKIMessage.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/PKIMessage.java new file mode 100644 index 0000000..061bcca --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/PKIMessage.java @@ -0,0 +1,163 @@ +package org.bc.asn1.cmp; + +import java.util.Enumeration; + +import org.bc.asn1.ASN1Encodable; +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERBitString; +import org.bc.asn1.DERSequence; +import org.bc.asn1.DERTaggedObject; + +public class PKIMessage + extends ASN1Object +{ + private PKIHeader header; + private PKIBody body; + private DERBitString protection; + private ASN1Sequence extraCerts; + + private PKIMessage(ASN1Sequence seq) + { + Enumeration en = seq.getObjects(); + + header = PKIHeader.getInstance(en.nextElement()); + body = PKIBody.getInstance(en.nextElement()); + + while (en.hasMoreElements()) + { + ASN1TaggedObject tObj = (ASN1TaggedObject)en.nextElement(); + + if (tObj.getTagNo() == 0) + { + protection = DERBitString.getInstance(tObj, true); + } + else + { + extraCerts = ASN1Sequence.getInstance(tObj, true); + } + } + } + + public static PKIMessage getInstance(Object o) + { + if (o instanceof PKIMessage) + { + return (PKIMessage)o; + } + else if (o != null) + { + return new PKIMessage(ASN1Sequence.getInstance(o)); + } + + return null; + } + + /** + * Creates a new PKIMessage. + * + * @param header message header + * @param body message body + * @param protection message protection (may be null) + * @param extraCerts extra certificates (may be null) + */ + public PKIMessage( + PKIHeader header, + PKIBody body, + DERBitString protection, + CMPCertificate[] extraCerts) + { + this.header = header; + this.body = body; + this.protection = protection; + if (extraCerts != null) { + ASN1EncodableVector v = new ASN1EncodableVector(); + for (int i = 0; i < extraCerts.length; i++) { + v.add(extraCerts[i]); + } + this.extraCerts = new DERSequence(v); + } + } + + public PKIMessage( + PKIHeader header, + PKIBody body, + DERBitString protection) + { + this(header, body, protection, null); + } + + public PKIMessage( + PKIHeader header, + PKIBody body) + { + this(header, body, null, null); + } + + public PKIHeader getHeader() + { + return header; + } + + public PKIBody getBody() + { + return body; + } + + public DERBitString getProtection() + { + return protection; + } + + public CMPCertificate[] getExtraCerts() + { + if (extraCerts == null) + { + return null; + } + + CMPCertificate[] results = new CMPCertificate[extraCerts.size()]; + + for (int i = 0; i < results.length; i++) + { + results[i] = CMPCertificate.getInstance(extraCerts.getObjectAt(i)); + } + return results; + } + + /** + *
+ * PKIMessage ::= SEQUENCE { + * header PKIHeader, + * body PKIBody, + * protection [0] PKIProtection OPTIONAL, + * extraCerts [1] SEQUENCE SIZE (1..MAX) OF CMPCertificate + * OPTIONAL + * } + *+ * @return a basic ASN.1 object representation. + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(header); + v.add(body); + + addOptional(v, 0, protection); + addOptional(v, 1, extraCerts); + + return new DERSequence(v); + } + + private void addOptional(ASN1EncodableVector v, int tagNo, ASN1Encodable obj) + { + if (obj != null) + { + v.add(new DERTaggedObject(true, tagNo, obj)); + } + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/PKIMessages.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/PKIMessages.java new file mode 100644 index 0000000..2734911 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/PKIMessages.java @@ -0,0 +1,71 @@ +package org.bc.asn1.cmp; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DERSequence; + +public class PKIMessages + extends ASN1Object +{ + private ASN1Sequence content; + + private PKIMessages(ASN1Sequence seq) + { + content = seq; + } + + public static PKIMessages getInstance(Object o) + { + if (o instanceof PKIMessages) + { + return (PKIMessages)o; + } + + if (o != null) + { + return new PKIMessages(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public PKIMessages(PKIMessage msg) + { + content = new DERSequence(msg); + } + + public PKIMessages(PKIMessage[] msgs) + { + ASN1EncodableVector v = new ASN1EncodableVector(); + for (int i = 0; i < msgs.length; i++) + { + v.add(msgs[i]); + } + content = new DERSequence(v); + } + + public PKIMessage[] toPKIMessageArray() + { + PKIMessage[] result = new PKIMessage[content.size()]; + + for (int i = 0; i != result.length; i++) + { + result[i] = PKIMessage.getInstance(content.getObjectAt(i)); + } + + return result; + } + + /** + *
+ * PKIMessages ::= SEQUENCE SIZE (1..MAX) OF PKIMessage + *+ * @return a basic ASN.1 object representation. + */ + public ASN1Primitive toASN1Primitive() + { + return content; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/PKIStatus.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/PKIStatus.java new file mode 100644 index 0000000..5ebdaa8 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/PKIStatus.java @@ -0,0 +1,64 @@ +package org.bc.asn1.cmp; + +import java.math.BigInteger; + +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; + +public class PKIStatus + extends ASN1Object +{ + public static final int GRANTED = 0; + public static final int GRANTED_WITH_MODS = 1; + public static final int REJECTION = 2; + public static final int WAITING = 3; + public static final int REVOCATION_WARNING = 4; + public static final int REVOCATION_NOTIFICATION = 5; + public static final int KEY_UPDATE_WARNING = 6; + + public static final PKIStatus granted = new PKIStatus(GRANTED); + public static final PKIStatus grantedWithMods = new PKIStatus(GRANTED_WITH_MODS); + public static final PKIStatus rejection = new PKIStatus(REJECTION); + public static final PKIStatus waiting = new PKIStatus(WAITING); + public static final PKIStatus revocationWarning = new PKIStatus(REVOCATION_WARNING); + public static final PKIStatus revocationNotification = new PKIStatus(REVOCATION_NOTIFICATION); + public static final PKIStatus keyUpdateWaiting = new PKIStatus(KEY_UPDATE_WARNING); + + private ASN1Integer value; + + private PKIStatus(int value) + { + this(new ASN1Integer(value)); + } + + private PKIStatus(ASN1Integer value) + { + this.value = value; + } + + public static PKIStatus getInstance(Object o) + { + if (o instanceof PKIStatus) + { + return (PKIStatus)o; + } + + if (o != null) + { + return new PKIStatus(ASN1Integer.getInstance(o)); + } + + return null; + } + + public BigInteger getValue() + { + return value.getValue(); + } + + public ASN1Primitive toASN1Primitive() + { + return value; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/PKIStatusInfo.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/PKIStatusInfo.java new file mode 100644 index 0000000..1d0c0cb --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/PKIStatusInfo.java @@ -0,0 +1,165 @@ +package org.bc.asn1.cmp; + +import java.math.BigInteger; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERBitString; +import org.bc.asn1.DERSequence; + +public class PKIStatusInfo + extends ASN1Object +{ + ASN1Integer status; + PKIFreeText statusString; + DERBitString failInfo; + + public static PKIStatusInfo getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static PKIStatusInfo getInstance( + Object obj) + { + if (obj instanceof PKIStatusInfo) + { + return (PKIStatusInfo)obj; + } + else if (obj != null) + { + return new PKIStatusInfo(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + private PKIStatusInfo( + ASN1Sequence seq) + { + this.status = ASN1Integer.getInstance(seq.getObjectAt(0)); + + this.statusString = null; + this.failInfo = null; + + if (seq.size() > 2) + { + this.statusString = PKIFreeText.getInstance(seq.getObjectAt(1)); + this.failInfo = DERBitString.getInstance(seq.getObjectAt(2)); + } + else if (seq.size() > 1) + { + Object obj = seq.getObjectAt(1); + if (obj instanceof DERBitString) + { + this.failInfo = DERBitString.getInstance(obj); + } + else + { + this.statusString = PKIFreeText.getInstance(obj); + } + } + } + + /** + * @param status + */ + public PKIStatusInfo(PKIStatus status) + { + this.status = ASN1Integer.getInstance(status.toASN1Primitive()); + } + + /** + * + * @param status + * @param statusString + */ + public PKIStatusInfo( + PKIStatus status, + PKIFreeText statusString) + { + this.status = ASN1Integer.getInstance(status.toASN1Primitive()); + this.statusString = statusString; + } + + public PKIStatusInfo( + PKIStatus status, + PKIFreeText statusString, + PKIFailureInfo failInfo) + { + this.status = ASN1Integer.getInstance(status.toASN1Primitive());; + this.statusString = statusString; + this.failInfo = failInfo; + } + + public BigInteger getStatus() + { + return status.getValue(); + } + + public PKIFreeText getStatusString() + { + return statusString; + } + + public DERBitString getFailInfo() + { + return failInfo; + } + + /** + *
+ * PKIStatusInfo ::= SEQUENCE { + * status PKIStatus, (INTEGER) + * statusString PKIFreeText OPTIONAL, + * failInfo PKIFailureInfo OPTIONAL (BIT STRING) + * } + * + * PKIStatus: + * granted (0), -- you got exactly what you asked for + * grantedWithMods (1), -- you got something like what you asked for + * rejection (2), -- you don't get it, more information elsewhere in the message + * waiting (3), -- the request body part has not yet been processed, expect to hear more later + * revocationWarning (4), -- this message contains a warning that a revocation is imminent + * revocationNotification (5), -- notification that a revocation has occurred + * keyUpdateWarning (6) -- update already done for the oldCertId specified in CertReqMsg + * + * PKIFailureInfo: + * badAlg (0), -- unrecognized or unsupported Algorithm Identifier + * badMessageCheck (1), -- integrity check failed (e.g., signature did not verify) + * badRequest (2), -- transaction not permitted or supported + * badTime (3), -- messageTime was not sufficiently close to the system time, as defined by local policy + * badCertId (4), -- no certificate could be found matching the provided criteria + * badDataFormat (5), -- the data submitted has the wrong format + * wrongAuthority (6), -- the authority indicated in the request is different from the one creating the response token + * incorrectData (7), -- the requester's data is incorrect (for notary services) + * missingTimeStamp (8), -- when the timestamp is missing but should be there (by policy) + * badPOP (9) -- the proof-of-possession failed + * + *+ */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(status); + + if (statusString != null) + { + v.add(statusString); + } + + if (failInfo!= null) + { + v.add(failInfo); + } + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/POPODecKeyChallContent.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/POPODecKeyChallContent.java new file mode 100644 index 0000000..c3bd57b --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/POPODecKeyChallContent.java @@ -0,0 +1,54 @@ +package org.bc.asn1.cmp; + +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; + +public class POPODecKeyChallContent + extends ASN1Object +{ + private ASN1Sequence content; + + private POPODecKeyChallContent(ASN1Sequence seq) + { + content = seq; + } + + public static POPODecKeyChallContent getInstance(Object o) + { + if (o instanceof POPODecKeyChallContent) + { + return (POPODecKeyChallContent)o; + } + + if (o != null) + { + return new POPODecKeyChallContent(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public Challenge[] toChallengeArray() + { + Challenge[] result = new Challenge[content.size()]; + + for (int i = 0; i != result.length; i++) + { + result[i] = Challenge.getInstance(content.getObjectAt(i)); + } + + return result; + } + + /** + *
+ * POPODecKeyChallContent ::= SEQUENCE OF Challenge + *+ * @return a basic ASN.1 object representation. + */ + public ASN1Primitive toASN1Primitive() + { + return content; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/POPODecKeyRespContent.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/POPODecKeyRespContent.java new file mode 100644 index 0000000..37a5ec7 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/POPODecKeyRespContent.java @@ -0,0 +1,55 @@ +package org.bc.asn1.cmp; + +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; + +public class POPODecKeyRespContent + extends ASN1Object +{ + private ASN1Sequence content; + + private POPODecKeyRespContent(ASN1Sequence seq) + { + content = seq; + } + + public static POPODecKeyRespContent getInstance(Object o) + { + if (o instanceof POPODecKeyRespContent) + { + return (POPODecKeyRespContent)o; + } + + if (o != null) + { + return new POPODecKeyRespContent(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public ASN1Integer[] toASN1IntegerArray() + { + ASN1Integer[] result = new ASN1Integer[content.size()]; + + for (int i = 0; i != result.length; i++) + { + result[i] = ASN1Integer.getInstance(content.getObjectAt(i)); + } + + return result; + } + + /** + *
+ * POPODecKeyRespContent ::= SEQUENCE OF INTEGER + *+ * @return a basic ASN.1 object representation. + */ + public ASN1Primitive toASN1Primitive() + { + return content; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/PollRepContent.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/PollRepContent.java new file mode 100644 index 0000000..a6bf435 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/PollRepContent.java @@ -0,0 +1,119 @@ +package org.bc.asn1.cmp; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DERSequence; + +public class PollRepContent + extends ASN1Object +{ + private ASN1Integer[] certReqId; + private ASN1Integer[] checkAfter; + private PKIFreeText[] reason; + + private PollRepContent(ASN1Sequence seq) + { + certReqId = new ASN1Integer[seq.size()]; + checkAfter = new ASN1Integer[seq.size()]; + reason = new PKIFreeText[seq.size()]; + + for (int i = 0; i != seq.size(); i++) + { + ASN1Sequence s = ASN1Sequence.getInstance(seq.getObjectAt(i)); + + certReqId[i] = ASN1Integer.getInstance(s.getObjectAt(0)); + checkAfter[i] = ASN1Integer.getInstance(s.getObjectAt(1)); + + if (s.size() > 2) + { + reason[i] = PKIFreeText.getInstance(s.getObjectAt(2)); + } + } + } + + public static PollRepContent getInstance(Object o) + { + if (o instanceof PollRepContent) + { + return (PollRepContent)o; + } + + if (o != null) + { + return new PollRepContent(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public PollRepContent(ASN1Integer certReqId, ASN1Integer checkAfter) + { + this(certReqId, checkAfter, null); + } + + public PollRepContent(ASN1Integer certReqId, ASN1Integer checkAfter, PKIFreeText reason) + { + this.certReqId = new ASN1Integer[1]; + this.checkAfter = new ASN1Integer[1]; + this.reason = new PKIFreeText[1]; + + this.certReqId[0] = certReqId; + this.checkAfter[0] = checkAfter; + this.reason[0] = reason; + } + + public int size() + { + return certReqId.length; + } + + public ASN1Integer getCertReqId(int index) + { + return certReqId[index]; + } + + public ASN1Integer getCheckAfter(int index) + { + return checkAfter[index]; + } + + public PKIFreeText getReason(int index) + { + return reason[index]; + } + + /** + *
+ * PollRepContent ::= SEQUENCE OF SEQUENCE { + * certReqId INTEGER, + * checkAfter INTEGER, -- time in seconds + * reason PKIFreeText OPTIONAL + * } + *+ * @return a basic ASN.1 object representation. + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector outer = new ASN1EncodableVector(); + + for (int i = 0; i != certReqId.length; i++) + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(certReqId[i]); + v.add(checkAfter[i]); + + if (reason[i] != null) + { + v.add(reason[i]); + } + + outer.add(new DERSequence(v)); + } + + return new DERSequence(outer); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/PollReqContent.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/PollReqContent.java new file mode 100644 index 0000000..baa1575 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/PollReqContent.java @@ -0,0 +1,80 @@ +package org.bc.asn1.cmp; + +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DERSequence; + +public class PollReqContent + extends ASN1Object +{ + private ASN1Sequence content; + + private PollReqContent(ASN1Sequence seq) + { + content = seq; + } + + public static PollReqContent getInstance(Object o) + { + if (o instanceof PollReqContent) + { + return (PollReqContent)o; + } + + if (o != null) + { + return new PollReqContent(ASN1Sequence.getInstance(o)); + } + + return null; + } + + /** + * Create a pollReqContent for a single certReqId. + * + * @param certReqId the certificate request ID. + */ + public PollReqContent(ASN1Integer certReqId) + { + this(new DERSequence(new DERSequence(certReqId))); + } + + public ASN1Integer[][] getCertReqIds() + { + ASN1Integer[][] result = new ASN1Integer[content.size()][]; + + for (int i = 0; i != result.length; i++) + { + result[i] = sequenceToASN1IntegerArray((ASN1Sequence)content.getObjectAt(i)); + } + + return result; + } + + private static ASN1Integer[] sequenceToASN1IntegerArray(ASN1Sequence seq) + { + ASN1Integer[] result = new ASN1Integer[seq.size()]; + + for (int i = 0; i != result.length; i++) + { + result[i] = ASN1Integer.getInstance(seq.getObjectAt(i)); + } + + return result; + } + + /** + *
+ * PollReqContent ::= SEQUENCE OF SEQUENCE { + * certReqId INTEGER + * } + *+ * @return a basic ASN.1 object representation. + */ + public ASN1Primitive toASN1Primitive() + { + return content; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/ProtectedPart.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/ProtectedPart.java new file mode 100644 index 0000000..8ac5a0b --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/ProtectedPart.java @@ -0,0 +1,70 @@ +package org.bc.asn1.cmp; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DERSequence; + +public class ProtectedPart + extends ASN1Object +{ + private PKIHeader header; + private PKIBody body; + + private ProtectedPart(ASN1Sequence seq) + { + header = PKIHeader.getInstance(seq.getObjectAt(0)); + body = PKIBody.getInstance(seq.getObjectAt(1)); + } + + public static ProtectedPart getInstance(Object o) + { + if (o instanceof ProtectedPart) + { + return (ProtectedPart)o; + } + + if (o != null) + { + return new ProtectedPart(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public ProtectedPart(PKIHeader header, PKIBody body) + { + this.header = header; + this.body = body; + } + + public PKIHeader getHeader() + { + return header; + } + + public PKIBody getBody() + { + return body; + } + + /** + *
+ * ProtectedPart ::= SEQUENCE { + * header PKIHeader, + * body PKIBody + * } + *+ * @return a basic ASN.1 object representation. + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(header); + v.add(body); + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/RevAnnContent.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/RevAnnContent.java new file mode 100644 index 0000000..becc2b0 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/RevAnnContent.java @@ -0,0 +1,103 @@ +package org.bc.asn1.cmp; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1GeneralizedTime; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DERSequence; +import org.bc.asn1.crmf.CertId; +import org.bc.asn1.x509.Extensions; + +public class RevAnnContent + extends ASN1Object +{ + private PKIStatus status; + private CertId certId; + private ASN1GeneralizedTime willBeRevokedAt; + private ASN1GeneralizedTime badSinceDate; + private Extensions crlDetails; + + private RevAnnContent(ASN1Sequence seq) + { + status = PKIStatus.getInstance(seq.getObjectAt(0)); + certId = CertId.getInstance(seq.getObjectAt(1)); + willBeRevokedAt = ASN1GeneralizedTime.getInstance(seq.getObjectAt(2)); + badSinceDate = ASN1GeneralizedTime.getInstance(seq.getObjectAt(3)); + + if (seq.size() > 4) + { + crlDetails = Extensions.getInstance(seq.getObjectAt(4)); + } + } + + public static RevAnnContent getInstance(Object o) + { + if (o instanceof RevAnnContent) + { + return (RevAnnContent)o; + } + + if (o != null) + { + return new RevAnnContent(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public PKIStatus getStatus() + { + return status; + } + + public CertId getCertId() + { + return certId; + } + + public ASN1GeneralizedTime getWillBeRevokedAt() + { + return willBeRevokedAt; + } + + public ASN1GeneralizedTime getBadSinceDate() + { + return badSinceDate; + } + + public Extensions getCrlDetails() + { + return crlDetails; + } + + /** + *
+ * RevAnnContent ::= SEQUENCE { + * status PKIStatus, + * certId CertId, + * willBeRevokedAt GeneralizedTime, + * badSinceDate GeneralizedTime, + * crlDetails Extensions OPTIONAL + * -- extra CRL details (e.g., crl number, reason, location, etc.) + * } + *+ * @return a basic ASN.1 object representation. + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(status); + v.add(certId); + v.add(willBeRevokedAt); + v.add(badSinceDate); + + if (crlDetails != null) + { + v.add(crlDetails); + } + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/RevDetails.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/RevDetails.java new file mode 100644 index 0000000..88b597f --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/RevDetails.java @@ -0,0 +1,100 @@ +package org.bc.asn1.cmp; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DERSequence; +import org.bc.asn1.crmf.CertTemplate; +import org.bc.asn1.x509.Extensions; +import org.bc.asn1.x509.X509Extensions; + +public class RevDetails + extends ASN1Object +{ + private CertTemplate certDetails; + private Extensions crlEntryDetails; + + private RevDetails(ASN1Sequence seq) + { + certDetails = CertTemplate.getInstance(seq.getObjectAt(0)); + if (seq.size() > 1) + { + crlEntryDetails = Extensions.getInstance(seq.getObjectAt(1)); + } + } + + public static RevDetails getInstance(Object o) + { + if (o instanceof RevDetails) + { + return (RevDetails)o; + } + + if (o != null) + { + return new RevDetails(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public RevDetails(CertTemplate certDetails) + { + this.certDetails = certDetails; + } + + /** + * @deprecated use method taking Extensions + * @param certDetails + * @param crlEntryDetails + */ + public RevDetails(CertTemplate certDetails, X509Extensions crlEntryDetails) + { + this.certDetails = certDetails; + this.crlEntryDetails = Extensions.getInstance(crlEntryDetails.toASN1Primitive()); + } + + public RevDetails(CertTemplate certDetails, Extensions crlEntryDetails) + { + this.certDetails = certDetails; + this.crlEntryDetails = crlEntryDetails; + } + + public CertTemplate getCertDetails() + { + return certDetails; + } + + public Extensions getCrlEntryDetails() + { + return crlEntryDetails; + } + + /** + *
+ * RevDetails ::= SEQUENCE { + * certDetails CertTemplate, + * -- allows requester to specify as much as they can about + * -- the cert. for which revocation is requested + * -- (e.g., for cases in which serialNumber is not available) + * crlEntryDetails Extensions OPTIONAL + * -- requested crlEntryExtensions + * } + *+ * @return a basic ASN.1 object representation. + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(certDetails); + + if (crlEntryDetails != null) + { + v.add(crlEntryDetails); + } + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/RevRepContent.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/RevRepContent.java new file mode 100644 index 0000000..47a41d9 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/RevRepContent.java @@ -0,0 +1,137 @@ +package org.bc.asn1.cmp; + +import java.util.Enumeration; + +import org.bc.asn1.ASN1Encodable; +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERSequence; +import org.bc.asn1.DERTaggedObject; +import org.bc.asn1.crmf.CertId; +import org.bc.asn1.x509.CertificateList; + +public class RevRepContent + extends ASN1Object +{ + private ASN1Sequence status; + private ASN1Sequence revCerts; + private ASN1Sequence crls; + + private RevRepContent(ASN1Sequence seq) + { + Enumeration en = seq.getObjects(); + + status = ASN1Sequence.getInstance(en.nextElement()); + while (en.hasMoreElements()) + { + ASN1TaggedObject tObj = ASN1TaggedObject.getInstance(en.nextElement()); + + if (tObj.getTagNo() == 0) + { + revCerts = ASN1Sequence.getInstance(tObj, true); + } + else + { + crls = ASN1Sequence.getInstance(tObj, true); + } + } + } + + public static RevRepContent getInstance(Object o) + { + if (o instanceof RevRepContent) + { + return (RevRepContent)o; + } + + if (o != null) + { + return new RevRepContent(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public PKIStatusInfo[] getStatus() + { + PKIStatusInfo[] results = new PKIStatusInfo[status.size()]; + + for (int i = 0; i != results.length; i++) + { + results[i] = PKIStatusInfo.getInstance(status.getObjectAt(i)); + } + + return results; + } + + public CertId[] getRevCerts() + { + if (revCerts == null) + { + return null; + } + + CertId[] results = new CertId[revCerts.size()]; + + for (int i = 0; i != results.length; i++) + { + results[i] = CertId.getInstance(revCerts.getObjectAt(i)); + } + + return results; + } + + public CertificateList[] getCrls() + { + if (crls == null) + { + return null; + } + + CertificateList[] results = new CertificateList[crls.size()]; + + for (int i = 0; i != results.length; i++) + { + results[i] = CertificateList.getInstance(crls.getObjectAt(i)); + } + + return results; + } + + /** + *
+ * RevRepContent ::= SEQUENCE { + * status SEQUENCE SIZE (1..MAX) OF PKIStatusInfo, + * -- in same order as was sent in RevReqContent + * revCerts [0] SEQUENCE SIZE (1..MAX) OF CertId OPTIONAL, + * -- IDs for which revocation was requested + * -- (same order as status) + * crls [1] SEQUENCE SIZE (1..MAX) OF CertificateList OPTIONAL + * -- the resulting CRLs (there may be more than one) + * } + *+ * @return a basic ASN.1 object representation. + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(status); + + addOptional(v, 0, revCerts); + addOptional(v, 1, crls); + + return new DERSequence(v); + } + + private void addOptional(ASN1EncodableVector v, int tagNo, ASN1Encodable obj) + { + if (obj != null) + { + v.add(new DERTaggedObject(true, tagNo, obj)); + } + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/RevRepContentBuilder.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/RevRepContentBuilder.java new file mode 100644 index 0000000..70f1dca --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/RevRepContentBuilder.java @@ -0,0 +1,59 @@ +package org.bc.asn1.cmp; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.DERSequence; +import org.bc.asn1.DERTaggedObject; +import org.bc.asn1.crmf.CertId; +import org.bc.asn1.x509.CertificateList; + +public class RevRepContentBuilder +{ + private ASN1EncodableVector status = new ASN1EncodableVector(); + private ASN1EncodableVector revCerts = new ASN1EncodableVector(); + private ASN1EncodableVector crls = new ASN1EncodableVector(); + + public RevRepContentBuilder add(PKIStatusInfo status) + { + this.status.add(status); + + return this; + } + + public RevRepContentBuilder add(PKIStatusInfo status, CertId certId) + { + if (this.status.size() != this.revCerts.size()) + { + throw new IllegalStateException("status and revCerts sequence must be in common order"); + } + this.status.add(status); + this.revCerts.add(certId); + + return this; + } + + public RevRepContentBuilder addCrl(CertificateList crl) + { + this.crls.add(crl); + + return this; + } + + public RevRepContent build() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(new DERSequence(status)); + + if (revCerts.size() != 0) + { + v.add(new DERTaggedObject(true, 0, new DERSequence(revCerts))); + } + + if (crls.size() != 0) + { + v.add(new DERTaggedObject(true, 1, new DERSequence(crls))); + } + + return RevRepContent.getInstance(new DERSequence(v)); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/RevReqContent.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/RevReqContent.java new file mode 100644 index 0000000..141089e --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cmp/RevReqContent.java @@ -0,0 +1,73 @@ +package org.bc.asn1.cmp; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DERSequence; + +public class RevReqContent + extends ASN1Object +{ + private ASN1Sequence content; + + private RevReqContent(ASN1Sequence seq) + { + content = seq; + } + + public static RevReqContent getInstance(Object o) + { + if (o instanceof RevReqContent) + { + return (RevReqContent)o; + } + + if (o != null) + { + return new RevReqContent(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public RevReqContent(RevDetails revDetails) + { + this.content = new DERSequence(revDetails); + } + + public RevReqContent(RevDetails[] revDetailsArray) + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + for (int i = 0; i != revDetailsArray.length; i++) + { + v.add(revDetailsArray[i]); + } + + this.content = new DERSequence(v); + } + + public RevDetails[] toRevDetailsArray() + { + RevDetails[] result = new RevDetails[content.size()]; + + for (int i = 0; i != result.length; i++) + { + result[i] = RevDetails.getInstance(content.getObjectAt(i)); + } + + return result; + } + + /** + *
+ * RevReqContent ::= SEQUENCE OF RevDetails + *+ * @return a basic ASN.1 object representation. + */ + public ASN1Primitive toASN1Primitive() + { + return content; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/Attribute.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/Attribute.java new file mode 100644 index 0000000..f167a19 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/Attribute.java @@ -0,0 +1,100 @@ +package org.bc.asn1.cms; + +import org.bc.asn1.ASN1Encodable; +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1ObjectIdentifier; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1Set; +import org.bc.asn1.DERObjectIdentifier; +import org.bc.asn1.DERSequence; + +public class Attribute + extends ASN1Object +{ + private ASN1ObjectIdentifier attrType; + private ASN1Set attrValues; + + /** + * return an Attribute object from the given object. + * + * @param o the object we want converted. + * @exception IllegalArgumentException if the object cannot be converted. + */ + public static Attribute getInstance( + Object o) + { + if (o instanceof Attribute) + { + return (Attribute)o; + } + + if (o != null) + { + return new Attribute(ASN1Sequence.getInstance(o)); + } + + return null; + } + + private Attribute( + ASN1Sequence seq) + { + attrType = (ASN1ObjectIdentifier)seq.getObjectAt(0); + attrValues = (ASN1Set)seq.getObjectAt(1); + } + + /** + * @deprecated use ASN1ObjectIdentifier + */ + public Attribute( + DERObjectIdentifier attrType, + ASN1Set attrValues) + { + this.attrType = new ASN1ObjectIdentifier(attrType.getId()); + this.attrValues = attrValues; + } + + public Attribute( + ASN1ObjectIdentifier attrType, + ASN1Set attrValues) + { + this.attrType = attrType; + this.attrValues = attrValues; + } + + public ASN1ObjectIdentifier getAttrType() + { + return attrType; + } + + public ASN1Set getAttrValues() + { + return attrValues; + } + + public ASN1Encodable[] getAttributeValues() + { + return attrValues.toArray(); + } + + /** + * Produce an object suitable for an ASN1OutputStream. + *
+ * Attribute ::= SEQUENCE { + * attrType OBJECT IDENTIFIER, + * attrValues SET OF AttributeValue + * } + *+ */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(attrType); + v.add(attrValues); + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/AttributeTable.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/AttributeTable.java new file mode 100644 index 0000000..0dc89bf --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/AttributeTable.java @@ -0,0 +1,254 @@ +package org.bc.asn1.cms; + +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Vector; + +import org.bc.asn1.ASN1Encodable; +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1ObjectIdentifier; +import org.bc.asn1.ASN1Set; +import org.bc.asn1.DERObjectIdentifier; +import org.bc.asn1.DERSet; + +public class AttributeTable +{ + private Hashtable attributes = new Hashtable(); + + public AttributeTable( + Hashtable attrs) + { + attributes = copyTable(attrs); + } + + public AttributeTable( + ASN1EncodableVector v) + { + for (int i = 0; i != v.size(); i++) + { + Attribute a = Attribute.getInstance(v.get(i)); + + addAttribute(a.getAttrType(), a); + } + } + + public AttributeTable( + ASN1Set s) + { + for (int i = 0; i != s.size(); i++) + { + Attribute a = Attribute.getInstance(s.getObjectAt(i)); + + addAttribute(a.getAttrType(), a); + } + } + + public AttributeTable( + Attribute attr) + { + addAttribute(attr.getAttrType(), attr); + } + + public AttributeTable( + Attributes attrs) + { + this(ASN1Set.getInstance(attrs.toASN1Primitive())); + } + + private void addAttribute( + ASN1ObjectIdentifier oid, + Attribute a) + { + Object value = attributes.get(oid); + + if (value == null) + { + attributes.put(oid, a); + } + else + { + Vector v; + + if (value instanceof Attribute) + { + v = new Vector(); + + v.addElement(value); + v.addElement(a); + } + else + { + v = (Vector)value; + + v.addElement(a); + } + + attributes.put(oid, v); + } + } + + /** + * @deprecated use ASN1ObjectIdentifier + */ + public Attribute get(DERObjectIdentifier oid) + { + return get(new ASN1ObjectIdentifier(oid.getId())); + } + + /** + * Return the first attribute matching the OBJECT IDENTIFIER oid. + * + * @param oid type of attribute required. + * @return first attribute found of type oid. + */ + public Attribute get( + ASN1ObjectIdentifier oid) + { + Object value = attributes.get(oid); + + if (value instanceof Vector) + { + return (Attribute)((Vector)value).elementAt(0); + } + + return (Attribute)value; + } + + /** + * @deprecated use ASN1ObjectIdentifier + */ + public ASN1EncodableVector getAll(DERObjectIdentifier oid) + { + return getAll(new ASN1ObjectIdentifier(oid.getId())); + } + + /** + * Return all the attributes matching the OBJECT IDENTIFIER oid. The vector will be + * empty if there are no attributes of the required type present. + * + * @param oid type of attribute required. + * @return a vector of all the attributes found of type oid. + */ + public ASN1EncodableVector getAll( + ASN1ObjectIdentifier oid) + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + Object value = attributes.get(oid); + + if (value instanceof Vector) + { + Enumeration e = ((Vector)value).elements(); + + while (e.hasMoreElements()) + { + v.add((Attribute)e.nextElement()); + } + } + else if (value != null) + { + v.add((Attribute)value); + } + + return v; + } + + public int size() + { + int size = 0; + + for (Enumeration en = attributes.elements(); en.hasMoreElements();) + { + Object o = en.nextElement(); + + if (o instanceof Vector) + { + size += ((Vector)o).size(); + } + else + { + size++; + } + } + + return size; + } + + public Hashtable toHashtable() + { + return copyTable(attributes); + } + + public ASN1EncodableVector toASN1EncodableVector() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + Enumeration e = attributes.elements(); + + while (e.hasMoreElements()) + { + Object value = e.nextElement(); + + if (value instanceof Vector) + { + Enumeration en = ((Vector)value).elements(); + + while (en.hasMoreElements()) + { + v.add(Attribute.getInstance(en.nextElement())); + } + } + else + { + v.add(Attribute.getInstance(value)); + } + } + + return v; + } + + public Attributes toASN1Structure() + { + return new Attributes(this.toASN1EncodableVector()); + } + + private Hashtable copyTable( + Hashtable in) + { + Hashtable out = new Hashtable(); + Enumeration e = in.keys(); + + while (e.hasMoreElements()) + { + Object key = e.nextElement(); + + out.put(key, in.get(key)); + } + + return out; + } + + /** + * Return a new table with the passed in attribute added. + * + * @param attrType + * @param attrValue + * @return + */ + public AttributeTable add(ASN1ObjectIdentifier attrType, ASN1Encodable attrValue) + { + AttributeTable newTable = new AttributeTable(attributes); + + newTable.addAttribute(attrType, new Attribute(attrType, new DERSet(attrValue))); + + return newTable; + } + + public AttributeTable remove(ASN1ObjectIdentifier attrType) + { + AttributeTable newTable = new AttributeTable(attributes); + + newTable.attributes.remove(attrType); + + return newTable; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/Attributes.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/Attributes.java new file mode 100644 index 0000000..ea11765 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/Attributes.java @@ -0,0 +1,49 @@ +package org.bc.asn1.cms; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Set; +import org.bc.asn1.BERSet; + +public class Attributes + extends ASN1Object +{ + private ASN1Set attributes; + + private Attributes(ASN1Set set) + { + attributes = set; + } + + public Attributes(ASN1EncodableVector v) + { + attributes = new BERSet(v); + } + + public static Attributes getInstance(Object obj) + { + if (obj instanceof Attributes) + { + return (Attributes)obj; + } + else if (obj != null) + { + return new Attributes(ASN1Set.getInstance(obj)); + } + + return null; + } + + /** + *
+ * Attributes ::= + * SET SIZE(1..MAX) OF Attribute -- according to RFC 5652 + *+ * @return + */ + public ASN1Primitive toASN1Primitive() + { + return attributes; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/AuthEnvelopedData.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/AuthEnvelopedData.java new file mode 100644 index 0000000..bb5f012 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/AuthEnvelopedData.java @@ -0,0 +1,218 @@ +package org.bc.asn1.cms; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1OctetString; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1Set; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.BERSequence; +import org.bc.asn1.DERTaggedObject; + +public class AuthEnvelopedData + extends ASN1Object +{ + private ASN1Integer version; + private OriginatorInfo originatorInfo; + private ASN1Set recipientInfos; + private EncryptedContentInfo authEncryptedContentInfo; + private ASN1Set authAttrs; + private ASN1OctetString mac; + private ASN1Set unauthAttrs; + + public AuthEnvelopedData( + OriginatorInfo originatorInfo, + ASN1Set recipientInfos, + EncryptedContentInfo authEncryptedContentInfo, + ASN1Set authAttrs, + ASN1OctetString mac, + ASN1Set unauthAttrs) + { + // "It MUST be set to 0." + this.version = new ASN1Integer(0); + + this.originatorInfo = originatorInfo; + + // TODO + // "There MUST be at least one element in the collection." + this.recipientInfos = recipientInfos; + + this.authEncryptedContentInfo = authEncryptedContentInfo; + + // TODO + // "The authAttrs MUST be present if the content type carried in + // EncryptedContentInfo is not id-data." + this.authAttrs = authAttrs; + + this.mac = mac; + + this.unauthAttrs = unauthAttrs; + } + + public AuthEnvelopedData( + ASN1Sequence seq) + { + int index = 0; + + // TODO + // "It MUST be set to 0." + ASN1Primitive tmp = seq.getObjectAt(index++).toASN1Primitive(); + version = (ASN1Integer)tmp; + + tmp = seq.getObjectAt(index++).toASN1Primitive(); + if (tmp instanceof ASN1TaggedObject) + { + originatorInfo = OriginatorInfo.getInstance((ASN1TaggedObject)tmp, false); + tmp = seq.getObjectAt(index++).toASN1Primitive(); + } + + // TODO + // "There MUST be at least one element in the collection." + recipientInfos = ASN1Set.getInstance(tmp); + + tmp = seq.getObjectAt(index++).toASN1Primitive(); + authEncryptedContentInfo = EncryptedContentInfo.getInstance(tmp); + + tmp = seq.getObjectAt(index++).toASN1Primitive(); + if (tmp instanceof ASN1TaggedObject) + { + authAttrs = ASN1Set.getInstance((ASN1TaggedObject)tmp, false); + tmp = seq.getObjectAt(index++).toASN1Primitive(); + } + else + { + // TODO + // "The authAttrs MUST be present if the content type carried in + // EncryptedContentInfo is not id-data." + } + + mac = ASN1OctetString.getInstance(tmp); + + if (seq.size() > index) + { + tmp = seq.getObjectAt(index++).toASN1Primitive(); + unauthAttrs = ASN1Set.getInstance((ASN1TaggedObject)tmp, false); + } + } + + /** + * return an AuthEnvelopedData object from a tagged object. + * + * @param obj the tagged object holding the object we want. + * @param explicit true if the object is meant to be explicitly + * tagged false otherwise. + * @throws IllegalArgumentException if the object held by the + * tagged object cannot be converted. + */ + public static AuthEnvelopedData getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + /** + * return an AuthEnvelopedData object from the given object. + * + * @param obj the object we want converted. + * @throws IllegalArgumentException if the object cannot be converted. + */ + public static AuthEnvelopedData getInstance( + Object obj) + { + if (obj == null || obj instanceof AuthEnvelopedData) + { + return (AuthEnvelopedData)obj; + } + + if (obj instanceof ASN1Sequence) + { + return new AuthEnvelopedData((ASN1Sequence)obj); + } + + throw new IllegalArgumentException("Invalid AuthEnvelopedData: " + obj.getClass().getName()); + } + + public ASN1Integer getVersion() + { + return version; + } + + public OriginatorInfo getOriginatorInfo() + { + return originatorInfo; + } + + public ASN1Set getRecipientInfos() + { + return recipientInfos; + } + + public EncryptedContentInfo getAuthEncryptedContentInfo() + { + return authEncryptedContentInfo; + } + + public ASN1Set getAuthAttrs() + { + return authAttrs; + } + + public ASN1OctetString getMac() + { + return mac; + } + + public ASN1Set getUnauthAttrs() + { + return unauthAttrs; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + *
+ * AuthEnvelopedData ::= SEQUENCE { + * version CMSVersion, + * originatorInfo [0] IMPLICIT OriginatorInfo OPTIONAL, + * recipientInfos RecipientInfos, + * authEncryptedContentInfo EncryptedContentInfo, + * authAttrs [1] IMPLICIT AuthAttributes OPTIONAL, + * mac MessageAuthenticationCode, + * unauthAttrs [2] IMPLICIT UnauthAttributes OPTIONAL } + *+ */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(version); + + if (originatorInfo != null) + { + v.add(new DERTaggedObject(false, 0, originatorInfo)); + } + + v.add(recipientInfos); + v.add(authEncryptedContentInfo); + + // "authAttrs optionally contains the authenticated attributes." + if (authAttrs != null) + { + // "AuthAttributes MUST be DER encoded, even if the rest of the + // AuthEnvelopedData structure is BER encoded." + v.add(new DERTaggedObject(false, 1, authAttrs)); + } + + v.add(mac); + + // "unauthAttrs optionally contains the unauthenticated attributes." + if (unauthAttrs != null) + { + v.add(new DERTaggedObject(false, 2, unauthAttrs)); + } + + return new BERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/AuthEnvelopedDataParser.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/AuthEnvelopedDataParser.java new file mode 100644 index 0000000..5d4a723 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/AuthEnvelopedDataParser.java @@ -0,0 +1,157 @@ +package org.bc.asn1.cms; + +import java.io.IOException; + +import org.bc.asn1.ASN1Encodable; +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1OctetString; +import org.bc.asn1.ASN1SequenceParser; +import org.bc.asn1.ASN1SetParser; +import org.bc.asn1.ASN1TaggedObjectParser; +import org.bc.asn1.BERTags; + +/** + * Produce an object suitable for an ASN1OutputStream. + * + *
+ * AuthEnvelopedData ::= SEQUENCE { + * version CMSVersion, + * originatorInfo [0] IMPLICIT OriginatorInfo OPTIONAL, + * recipientInfos RecipientInfos, + * authEncryptedContentInfo EncryptedContentInfo, + * authAttrs [1] IMPLICIT AuthAttributes OPTIONAL, + * mac MessageAuthenticationCode, + * unauthAttrs [2] IMPLICIT UnauthAttributes OPTIONAL } + *+ */ +public class AuthEnvelopedDataParser +{ + private ASN1SequenceParser seq; + private ASN1Integer version; + private ASN1Encodable nextObject; + private boolean originatorInfoCalled; + + public AuthEnvelopedDataParser(ASN1SequenceParser seq) throws IOException + { + this.seq = seq; + + // TODO + // "It MUST be set to 0." + this.version = ASN1Integer.getInstance(seq.readObject()); + } + + public ASN1Integer getVersion() + { + return version; + } + + public OriginatorInfo getOriginatorInfo() + throws IOException + { + originatorInfoCalled = true; + + if (nextObject == null) + { + nextObject = seq.readObject(); + } + + if (nextObject instanceof ASN1TaggedObjectParser && ((ASN1TaggedObjectParser)nextObject).getTagNo() == 0) + { + ASN1SequenceParser originatorInfo = (ASN1SequenceParser) ((ASN1TaggedObjectParser)nextObject).getObjectParser(BERTags.SEQUENCE, false); + nextObject = null; + return OriginatorInfo.getInstance(originatorInfo.toASN1Primitive()); + } + + return null; + } + + public ASN1SetParser getRecipientInfos() + throws IOException + { + if (!originatorInfoCalled) + { + getOriginatorInfo(); + } + + if (nextObject == null) + { + nextObject = seq.readObject(); + } + + ASN1SetParser recipientInfos = (ASN1SetParser)nextObject; + nextObject = null; + return recipientInfos; + } + + public EncryptedContentInfoParser getAuthEncryptedContentInfo() + throws IOException + { + if (nextObject == null) + { + nextObject = seq.readObject(); + } + + if (nextObject != null) + { + ASN1SequenceParser o = (ASN1SequenceParser) nextObject; + nextObject = null; + return new EncryptedContentInfoParser(o); + } + + return null; + } + + public ASN1SetParser getAuthAttrs() + throws IOException + { + if (nextObject == null) + { + nextObject = seq.readObject(); + } + + if (nextObject instanceof ASN1TaggedObjectParser) + { + ASN1Encodable o = nextObject; + nextObject = null; + return (ASN1SetParser)((ASN1TaggedObjectParser)o).getObjectParser(BERTags.SET, false); + } + + // TODO + // "The authAttrs MUST be present if the content type carried in + // EncryptedContentInfo is not id-data." + + return null; + } + + public ASN1OctetString getMac() + throws IOException + { + if (nextObject == null) + { + nextObject = seq.readObject(); + } + + ASN1Encodable o = nextObject; + nextObject = null; + + return ASN1OctetString.getInstance(o.toASN1Primitive()); + } + + public ASN1SetParser getUnauthAttrs() + throws IOException + { + if (nextObject == null) + { + nextObject = seq.readObject(); + } + + if (nextObject != null) + { + ASN1Encodable o = nextObject; + nextObject = null; + return (ASN1SetParser)((ASN1TaggedObjectParser)o).getObjectParser(BERTags.SET, false); + } + + return null; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/AuthenticatedData.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/AuthenticatedData.java new file mode 100644 index 0000000..19b0786 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/AuthenticatedData.java @@ -0,0 +1,296 @@ +package org.bc.asn1.cms; + +import java.util.Enumeration; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1OctetString; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1Set; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.BERSequence; +import org.bc.asn1.DERTaggedObject; +import org.bc.asn1.x509.AlgorithmIdentifier; + +public class AuthenticatedData + extends ASN1Object +{ + private ASN1Integer version; + private OriginatorInfo originatorInfo; + private ASN1Set recipientInfos; + private AlgorithmIdentifier macAlgorithm; + private AlgorithmIdentifier digestAlgorithm; + private ContentInfo encapsulatedContentInfo; + private ASN1Set authAttrs; + private ASN1OctetString mac; + private ASN1Set unauthAttrs; + + public AuthenticatedData( + OriginatorInfo originatorInfo, + ASN1Set recipientInfos, + AlgorithmIdentifier macAlgorithm, + AlgorithmIdentifier digestAlgorithm, + ContentInfo encapsulatedContent, + ASN1Set authAttrs, + ASN1OctetString mac, + ASN1Set unauthAttrs) + { + if (digestAlgorithm != null || authAttrs != null) + { + if (digestAlgorithm == null || authAttrs == null) + { + throw new IllegalArgumentException("digestAlgorithm and authAttrs must be set together"); + } + } + + version = new ASN1Integer(calculateVersion(originatorInfo)); + + this.originatorInfo = originatorInfo; + this.macAlgorithm = macAlgorithm; + this.digestAlgorithm = digestAlgorithm; + this.recipientInfos = recipientInfos; + this.encapsulatedContentInfo = encapsulatedContent; + this.authAttrs = authAttrs; + this.mac = mac; + this.unauthAttrs = unauthAttrs; + } + + public AuthenticatedData( + ASN1Sequence seq) + { + int index = 0; + + version = (ASN1Integer)seq.getObjectAt(index++); + + Object tmp = seq.getObjectAt(index++); + + if (tmp instanceof ASN1TaggedObject) + { + originatorInfo = OriginatorInfo.getInstance((ASN1TaggedObject)tmp, false); + tmp = seq.getObjectAt(index++); + } + + recipientInfos = ASN1Set.getInstance(tmp); + macAlgorithm = AlgorithmIdentifier.getInstance(seq.getObjectAt(index++)); + + tmp = seq.getObjectAt(index++); + + if (tmp instanceof ASN1TaggedObject) + { + digestAlgorithm = AlgorithmIdentifier.getInstance((ASN1TaggedObject)tmp, false); + tmp = seq.getObjectAt(index++); + } + + encapsulatedContentInfo = ContentInfo.getInstance(tmp); + + tmp = seq.getObjectAt(index++); + + if (tmp instanceof ASN1TaggedObject) + { + authAttrs = ASN1Set.getInstance((ASN1TaggedObject)tmp, false); + tmp = seq.getObjectAt(index++); + } + + mac = ASN1OctetString.getInstance(tmp); + + if (seq.size() > index) + { + unauthAttrs = ASN1Set.getInstance((ASN1TaggedObject)seq.getObjectAt(index), false); + } + } + + /** + * return an AuthenticatedData object from a tagged object. + * + * @param obj the tagged object holding the object we want. + * @param explicit true if the object is meant to be explicitly + * tagged false otherwise. + * @throws IllegalArgumentException if the object held by the + * tagged object cannot be converted. + */ + public static AuthenticatedData getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + /** + * return an AuthenticatedData object from the given object. + * + * @param obj the object we want converted. + * @throws IllegalArgumentException if the object cannot be converted. + */ + public static AuthenticatedData getInstance( + Object obj) + { + if (obj == null || obj instanceof AuthenticatedData) + { + return (AuthenticatedData)obj; + } + + if (obj instanceof ASN1Sequence) + { + return new AuthenticatedData((ASN1Sequence)obj); + } + + throw new IllegalArgumentException("Invalid AuthenticatedData: " + obj.getClass().getName()); + } + + public ASN1Integer getVersion() + { + return version; + } + + public OriginatorInfo getOriginatorInfo() + { + return originatorInfo; + } + + public ASN1Set getRecipientInfos() + { + return recipientInfos; + } + + public AlgorithmIdentifier getMacAlgorithm() + { + return macAlgorithm; + } + + public AlgorithmIdentifier getDigestAlgorithm() + { + return digestAlgorithm; + } + + public ContentInfo getEncapsulatedContentInfo() + { + return encapsulatedContentInfo; + } + + public ASN1Set getAuthAttrs() + { + return authAttrs; + } + + public ASN1OctetString getMac() + { + return mac; + } + + public ASN1Set getUnauthAttrs() + { + return unauthAttrs; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + *
+ * AuthenticatedData ::= SEQUENCE { + * version CMSVersion, + * originatorInfo [0] IMPLICIT OriginatorInfo OPTIONAL, + * recipientInfos RecipientInfos, + * macAlgorithm MessageAuthenticationCodeAlgorithm, + * digestAlgorithm [1] DigestAlgorithmIdentifier OPTIONAL, + * encapContentInfo EncapsulatedContentInfo, + * authAttrs [2] IMPLICIT AuthAttributes OPTIONAL, + * mac MessageAuthenticationCode, + * unauthAttrs [3] IMPLICIT UnauthAttributes OPTIONAL } + * + * AuthAttributes ::= SET SIZE (1..MAX) OF Attribute + * + * UnauthAttributes ::= SET SIZE (1..MAX) OF Attribute + * + * MessageAuthenticationCode ::= OCTET STRING + *+ */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(version); + + if (originatorInfo != null) + { + v.add(new DERTaggedObject(false, 0, originatorInfo)); + } + + v.add(recipientInfos); + v.add(macAlgorithm); + + if (digestAlgorithm != null) + { + v.add(new DERTaggedObject(false, 1, digestAlgorithm)); + } + + v.add(encapsulatedContentInfo); + + if (authAttrs != null) + { + v.add(new DERTaggedObject(false, 2, authAttrs)); + } + + v.add(mac); + + if (unauthAttrs != null) + { + v.add(new DERTaggedObject(false, 3, unauthAttrs)); + } + + return new BERSequence(v); + } + + public static int calculateVersion(OriginatorInfo origInfo) + { + if (origInfo == null) + { + return 0; + } + else + { + int ver = 0; + + for (Enumeration e = origInfo.getCertificates().getObjects(); e.hasMoreElements();) + { + Object obj = e.nextElement(); + + if (obj instanceof ASN1TaggedObject) + { + ASN1TaggedObject tag = (ASN1TaggedObject)obj; + + if (tag.getTagNo() == 2) + { + ver = 1; + } + else if (tag.getTagNo() == 3) + { + ver = 3; + break; + } + } + } + + if (origInfo.getCRLs() != null) + { + for (Enumeration e = origInfo.getCRLs().getObjects(); e.hasMoreElements();) + { + Object obj = e.nextElement(); + + if (obj instanceof ASN1TaggedObject) + { + ASN1TaggedObject tag = (ASN1TaggedObject)obj; + + if (tag.getTagNo() == 1) + { + ver = 3; + break; + } + } + } + } + + return ver; + } + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/AuthenticatedDataParser.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/AuthenticatedDataParser.java new file mode 100644 index 0000000..c007104 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/AuthenticatedDataParser.java @@ -0,0 +1,197 @@ +package org.bc.asn1.cms; + +import java.io.IOException; + +import org.bc.asn1.ASN1Encodable; +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1OctetString; +import org.bc.asn1.ASN1SequenceParser; +import org.bc.asn1.ASN1SetParser; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.ASN1TaggedObjectParser; +import org.bc.asn1.BERTags; +import org.bc.asn1.x509.AlgorithmIdentifier; + +/** + * Produce an object suitable for an ASN1OutputStream. + *
+ * AuthenticatedData ::= SEQUENCE { + * version CMSVersion, + * originatorInfo [0] IMPLICIT OriginatorInfo OPTIONAL, + * recipientInfos RecipientInfos, + * macAlgorithm MessageAuthenticationCodeAlgorithm, + * digestAlgorithm [1] DigestAlgorithmIdentifier OPTIONAL, + * encapContentInfo EncapsulatedContentInfo, + * authAttrs [2] IMPLICIT AuthAttributes OPTIONAL, + * mac MessageAuthenticationCode, + * unauthAttrs [3] IMPLICIT UnauthAttributes OPTIONAL } + * + * AuthAttributes ::= SET SIZE (1..MAX) OF Attribute + * + * UnauthAttributes ::= SET SIZE (1..MAX) OF Attribute + * + * MessageAuthenticationCode ::= OCTET STRING + *+ */ +public class AuthenticatedDataParser +{ + private ASN1SequenceParser seq; + private ASN1Integer version; + private ASN1Encodable nextObject; + private boolean originatorInfoCalled; + + public AuthenticatedDataParser( + ASN1SequenceParser seq) + throws IOException + { + this.seq = seq; + this.version = ASN1Integer.getInstance(seq.readObject()); + } + + public ASN1Integer getVersion() + { + return version; + } + + public OriginatorInfo getOriginatorInfo() + throws IOException + { + originatorInfoCalled = true; + + if (nextObject == null) + { + nextObject = seq.readObject(); + } + + if (nextObject instanceof ASN1TaggedObjectParser && ((ASN1TaggedObjectParser)nextObject).getTagNo() == 0) + { + ASN1SequenceParser originatorInfo = (ASN1SequenceParser) ((ASN1TaggedObjectParser)nextObject).getObjectParser(BERTags.SEQUENCE, false); + nextObject = null; + return OriginatorInfo.getInstance(originatorInfo.toASN1Primitive()); + } + + return null; + } + + public ASN1SetParser getRecipientInfos() + throws IOException + { + if (!originatorInfoCalled) + { + getOriginatorInfo(); + } + + if (nextObject == null) + { + nextObject = seq.readObject(); + } + + ASN1SetParser recipientInfos = (ASN1SetParser)nextObject; + nextObject = null; + return recipientInfos; + } + + public AlgorithmIdentifier getMacAlgorithm() + throws IOException + { + if (nextObject == null) + { + nextObject = seq.readObject(); + } + + if (nextObject != null) + { + ASN1SequenceParser o = (ASN1SequenceParser)nextObject; + nextObject = null; + return AlgorithmIdentifier.getInstance(o.toASN1Primitive()); + } + + return null; + } + + public AlgorithmIdentifier getDigestAlgorithm() + throws IOException + { + if (nextObject == null) + { + nextObject = seq.readObject(); + } + + if (nextObject instanceof ASN1TaggedObjectParser) + { + AlgorithmIdentifier obj = AlgorithmIdentifier.getInstance((ASN1TaggedObject)nextObject.toASN1Primitive(), false); + nextObject = null; + return obj; + } + + return null; + } + + public ContentInfoParser getEnapsulatedContentInfo() + throws IOException + { + if (nextObject == null) + { + nextObject = seq.readObject(); + } + + if (nextObject != null) + { + ASN1SequenceParser o = (ASN1SequenceParser)nextObject; + nextObject = null; + return new ContentInfoParser(o); + } + + return null; + } + + public ASN1SetParser getAuthAttrs() + throws IOException + { + if (nextObject == null) + { + nextObject = seq.readObject(); + } + + if (nextObject instanceof ASN1TaggedObjectParser) + { + ASN1Encodable o = nextObject; + nextObject = null; + return (ASN1SetParser)((ASN1TaggedObjectParser)o).getObjectParser(BERTags.SET, false); + } + + return null; + } + + public ASN1OctetString getMac() + throws IOException + { + if (nextObject == null) + { + nextObject = seq.readObject(); + } + + ASN1Encodable o = nextObject; + nextObject = null; + + return ASN1OctetString.getInstance(o.toASN1Primitive()); + } + + public ASN1SetParser getUnauthAttrs() + throws IOException + { + if (nextObject == null) + { + nextObject = seq.readObject(); + } + + if (nextObject != null) + { + ASN1Encodable o = nextObject; + nextObject = null; + return (ASN1SetParser)((ASN1TaggedObjectParser)o).getObjectParser(BERTags.SET, false); + } + + return null; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/CMSAttributes.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/CMSAttributes.java new file mode 100644 index 0000000..ebf769a --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/CMSAttributes.java @@ -0,0 +1,13 @@ +package org.bc.asn1.cms; + +import org.bc.asn1.ASN1ObjectIdentifier; +import org.bc.asn1.pkcs.PKCSObjectIdentifiers; + +public interface CMSAttributes +{ + public static final ASN1ObjectIdentifier contentType = PKCSObjectIdentifiers.pkcs_9_at_contentType; + public static final ASN1ObjectIdentifier messageDigest = PKCSObjectIdentifiers.pkcs_9_at_messageDigest; + public static final ASN1ObjectIdentifier signingTime = PKCSObjectIdentifiers.pkcs_9_at_signingTime; + public static final ASN1ObjectIdentifier counterSignature = PKCSObjectIdentifiers.pkcs_9_at_counterSignature; + public static final ASN1ObjectIdentifier contentHint = PKCSObjectIdentifiers.id_aa_contentHint; +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/CMSObjectIdentifiers.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/CMSObjectIdentifiers.java new file mode 100644 index 0000000..a918366 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/CMSObjectIdentifiers.java @@ -0,0 +1,18 @@ +package org.bc.asn1.cms; + +import org.bc.asn1.ASN1ObjectIdentifier; +import org.bc.asn1.pkcs.PKCSObjectIdentifiers; + +public interface CMSObjectIdentifiers +{ + static final ASN1ObjectIdentifier data = PKCSObjectIdentifiers.data; + static final ASN1ObjectIdentifier signedData = PKCSObjectIdentifiers.signedData; + static final ASN1ObjectIdentifier envelopedData = PKCSObjectIdentifiers.envelopedData; + static final ASN1ObjectIdentifier signedAndEnvelopedData = PKCSObjectIdentifiers.signedAndEnvelopedData; + static final ASN1ObjectIdentifier digestedData = PKCSObjectIdentifiers.digestedData; + static final ASN1ObjectIdentifier encryptedData = PKCSObjectIdentifiers.encryptedData; + static final ASN1ObjectIdentifier authenticatedData = PKCSObjectIdentifiers.id_ct_authData; + static final ASN1ObjectIdentifier compressedData = PKCSObjectIdentifiers.id_ct_compressedData; + static final ASN1ObjectIdentifier authEnvelopedData = PKCSObjectIdentifiers.id_ct_authEnvelopedData; + static final ASN1ObjectIdentifier timestampedData = PKCSObjectIdentifiers.id_ct_timestampedData; +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/CompressedData.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/CompressedData.java new file mode 100644 index 0000000..a5b2962 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/CompressedData.java @@ -0,0 +1,110 @@ +package org.bc.asn1.cms; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.BERSequence; +import org.bc.asn1.x509.AlgorithmIdentifier; + +/** + * RFC 3274 - CMS Compressed Data. + *
+ * CompressedData ::= SEQUENCE { + * version CMSVersion, + * compressionAlgorithm CompressionAlgorithmIdentifier, + * encapContentInfo EncapsulatedContentInfo + * } + *+ */ +public class CompressedData + extends ASN1Object +{ + private ASN1Integer version; + private AlgorithmIdentifier compressionAlgorithm; + private ContentInfo encapContentInfo; + + public CompressedData( + AlgorithmIdentifier compressionAlgorithm, + ContentInfo encapContentInfo) + { + this.version = new ASN1Integer(0); + this.compressionAlgorithm = compressionAlgorithm; + this.encapContentInfo = encapContentInfo; + } + + private CompressedData( + ASN1Sequence seq) + { + this.version = (ASN1Integer)seq.getObjectAt(0); + this.compressionAlgorithm = AlgorithmIdentifier.getInstance(seq.getObjectAt(1)); + this.encapContentInfo = ContentInfo.getInstance(seq.getObjectAt(2)); + + } + + /** + * return a CompressedData object from a tagged object. + * + * @param _ato the tagged object holding the object we want. + * @param _explicit true if the object is meant to be explicitly + * tagged false otherwise. + * @exception IllegalArgumentException if the object held by the + * tagged object cannot be converted. + */ + public static CompressedData getInstance( + ASN1TaggedObject _ato, + boolean _explicit) + { + return getInstance(ASN1Sequence.getInstance(_ato, _explicit)); + } + + /** + * return a CompressedData object from the given object. + * + * @param obj the object we want converted. + * @exception IllegalArgumentException if the object cannot be converted. + */ + public static CompressedData getInstance( + Object obj) + { + if (obj instanceof CompressedData) + { + return (CompressedData)obj; + } + + if (obj != null) + { + return new CompressedData(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public ASN1Integer getVersion() + { + return version; + } + + public AlgorithmIdentifier getCompressionAlgorithmIdentifier() + { + return compressionAlgorithm; + } + + public ContentInfo getEncapContentInfo() + { + return encapContentInfo; + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(version); + v.add(compressionAlgorithm); + v.add(encapContentInfo); + + return new BERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/CompressedDataParser.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/CompressedDataParser.java new file mode 100644 index 0000000..2c805e9 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/CompressedDataParser.java @@ -0,0 +1,48 @@ +package org.bc.asn1.cms; + +import java.io.IOException; + +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1SequenceParser; +import org.bc.asn1.x509.AlgorithmIdentifier; + +/** + * RFC 3274 - CMS Compressed Data. + *
+ * CompressedData ::= SEQUENCE { + * version CMSVersion, + * compressionAlgorithm CompressionAlgorithmIdentifier, + * encapContentInfo EncapsulatedContentInfo + * } + *+ */ +public class CompressedDataParser +{ + private ASN1Integer _version; + private AlgorithmIdentifier _compressionAlgorithm; + private ContentInfoParser _encapContentInfo; + + public CompressedDataParser( + ASN1SequenceParser seq) + throws IOException + { + this._version = (ASN1Integer)seq.readObject(); + this._compressionAlgorithm = AlgorithmIdentifier.getInstance(seq.readObject().toASN1Primitive()); + this._encapContentInfo = new ContentInfoParser((ASN1SequenceParser)seq.readObject()); + } + + public ASN1Integer getVersion() + { + return _version; + } + + public AlgorithmIdentifier getCompressionAlgorithmIdentifier() + { + return _compressionAlgorithm; + } + + public ContentInfoParser getEncapContentInfo() + { + return _encapContentInfo; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/ContentInfo.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/ContentInfo.java new file mode 100644 index 0000000..a443e46 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/ContentInfo.java @@ -0,0 +1,97 @@ +package org.bc.asn1.cms; + +import org.bc.asn1.ASN1Encodable; +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1ObjectIdentifier; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.BERSequence; +import org.bc.asn1.BERTaggedObject; + +public class ContentInfo + extends ASN1Object + implements CMSObjectIdentifiers +{ + private ASN1ObjectIdentifier contentType; + private ASN1Encodable content; + + public static ContentInfo getInstance( + Object obj) + { + if (obj instanceof ContentInfo) + { + return (ContentInfo)obj; + } + else if (obj != null) + { + return new ContentInfo(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public ContentInfo( + ASN1Sequence seq) + { + if (seq.size() < 1 || seq.size() > 2) + { + throw new IllegalArgumentException("Bad sequence size: " + seq.size()); + } + + contentType = (ASN1ObjectIdentifier)seq.getObjectAt(0); + + if (seq.size() > 1) + { + ASN1TaggedObject tagged = (ASN1TaggedObject)seq.getObjectAt(1); + if (!tagged.isExplicit() || tagged.getTagNo() != 0) + { + throw new IllegalArgumentException("Bad tag for 'content'"); + } + + content = tagged.getObject(); + } + } + + public ContentInfo( + ASN1ObjectIdentifier contentType, + ASN1Encodable content) + { + this.contentType = contentType; + this.content = content; + } + + public ASN1ObjectIdentifier getContentType() + { + return contentType; + } + + public ASN1Encodable getContent() + { + return content; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + *
+ * ContentInfo ::= SEQUENCE { + * contentType ContentType, + * content + * [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL } + *+ */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(contentType); + + if (content != null) + { + v.add(new BERTaggedObject(0, content)); + } + + return new BERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/ContentInfoParser.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/ContentInfoParser.java new file mode 100644 index 0000000..175c08f --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/ContentInfoParser.java @@ -0,0 +1,48 @@ +package org.bc.asn1.cms; + +import java.io.IOException; + +import org.bc.asn1.ASN1Encodable; +import org.bc.asn1.ASN1ObjectIdentifier; +import org.bc.asn1.ASN1SequenceParser; +import org.bc.asn1.ASN1TaggedObjectParser; + +/** + * Produce an object suitable for an ASN1OutputStream. + *
+ * ContentInfo ::= SEQUENCE { + * contentType ContentType, + * content + * [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL } + *+ */ +public class ContentInfoParser +{ + private ASN1ObjectIdentifier contentType; + private ASN1TaggedObjectParser content; + + public ContentInfoParser( + ASN1SequenceParser seq) + throws IOException + { + contentType = (ASN1ObjectIdentifier)seq.readObject(); + content = (ASN1TaggedObjectParser)seq.readObject(); + } + + public ASN1ObjectIdentifier getContentType() + { + return contentType; + } + + public ASN1Encodable getContent( + int tag) + throws IOException + { + if (content != null) + { + return content.getObjectParser(tag, true); + } + + return null; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/DigestedData.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/DigestedData.java new file mode 100644 index 0000000..8d6f821 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/DigestedData.java @@ -0,0 +1,121 @@ +package org.bc.asn1.cms; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1OctetString; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.BERSequence; +import org.bc.asn1.DEROctetString; +import org.bc.asn1.x509.AlgorithmIdentifier; + +/** + * RFC 3274 - CMS Digest Data. + *
+ * DigestedData ::= SEQUENCE { + * version CMSVersion, + * digestAlgorithm DigestAlgorithmIdentifier, + * encapContentInfo EncapsulatedContentInfo, + * digest Digest } + *+ */ +public class DigestedData + extends ASN1Object +{ + private ASN1Integer version; + private AlgorithmIdentifier digestAlgorithm; + private ContentInfo encapContentInfo; + private ASN1OctetString digest; + + public DigestedData( + AlgorithmIdentifier digestAlgorithm, + ContentInfo encapContentInfo, + byte[] digest) + { + this.version = new ASN1Integer(0); + this.digestAlgorithm = digestAlgorithm; + this.encapContentInfo = encapContentInfo; + this.digest = new DEROctetString(digest); + } + + private DigestedData( + ASN1Sequence seq) + { + this.version = (ASN1Integer)seq.getObjectAt(0); + this.digestAlgorithm = AlgorithmIdentifier.getInstance(seq.getObjectAt(1)); + this.encapContentInfo = ContentInfo.getInstance(seq.getObjectAt(2)); + this.digest = ASN1OctetString.getInstance(seq.getObjectAt(3)); + } + + /** + * return a CompressedData object from a tagged object. + * + * @param _ato the tagged object holding the object we want. + * @param _explicit true if the object is meant to be explicitly + * tagged false otherwise. + * @exception IllegalArgumentException if the object held by the + * tagged object cannot be converted. + */ + public static DigestedData getInstance( + ASN1TaggedObject _ato, + boolean _explicit) + { + return getInstance(ASN1Sequence.getInstance(_ato, _explicit)); + } + + /** + * return a CompressedData object from the given object. + * + * @param obj the object we want converted. + * @exception IllegalArgumentException if the object cannot be converted. + */ + public static DigestedData getInstance( + Object obj) + { + if (obj instanceof DigestedData) + { + return (DigestedData)obj; + } + + if (obj != null) + { + return new DigestedData(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public ASN1Integer getVersion() + { + return version; + } + + public AlgorithmIdentifier getDigestAlgorithm() + { + return digestAlgorithm; + } + + public ContentInfo getEncapContentInfo() + { + return encapContentInfo; + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(version); + v.add(digestAlgorithm); + v.add(encapContentInfo); + v.add(digest); + + return new BERSequence(v); + } + + public byte[] getDigest() + { + return digest.getOctets(); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/EncryptedContentInfo.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/EncryptedContentInfo.java new file mode 100644 index 0000000..0da71c3 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/EncryptedContentInfo.java @@ -0,0 +1,109 @@ +package org.bc.asn1.cms; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1ObjectIdentifier; +import org.bc.asn1.ASN1OctetString; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.BERSequence; +import org.bc.asn1.BERTaggedObject; +import org.bc.asn1.x509.AlgorithmIdentifier; + +public class EncryptedContentInfo + extends ASN1Object +{ + private ASN1ObjectIdentifier contentType; + private AlgorithmIdentifier contentEncryptionAlgorithm; + private ASN1OctetString encryptedContent; + + public EncryptedContentInfo( + ASN1ObjectIdentifier contentType, + AlgorithmIdentifier contentEncryptionAlgorithm, + ASN1OctetString encryptedContent) + { + this.contentType = contentType; + this.contentEncryptionAlgorithm = contentEncryptionAlgorithm; + this.encryptedContent = encryptedContent; + } + + private EncryptedContentInfo( + ASN1Sequence seq) + { + if (seq.size() < 2) + { + throw new IllegalArgumentException("Truncated Sequence Found"); + } + + contentType = (ASN1ObjectIdentifier)seq.getObjectAt(0); + contentEncryptionAlgorithm = AlgorithmIdentifier.getInstance( + seq.getObjectAt(1)); + if (seq.size() > 2) + { + encryptedContent = ASN1OctetString.getInstance( + (ASN1TaggedObject)seq.getObjectAt(2), false); + } + } + + /** + * return an EncryptedContentInfo object from the given object. + * + * @param obj the object we want converted. + * @exception IllegalArgumentException if the object cannot be converted. + */ + public static EncryptedContentInfo getInstance( + Object obj) + { + if (obj instanceof EncryptedContentInfo) + { + return (EncryptedContentInfo)obj; + } + if (obj != null) + { + return new EncryptedContentInfo(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public ASN1ObjectIdentifier getContentType() + { + return contentType; + } + + public AlgorithmIdentifier getContentEncryptionAlgorithm() + { + return contentEncryptionAlgorithm; + } + + public ASN1OctetString getEncryptedContent() + { + return encryptedContent; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + *
+ * EncryptedContentInfo ::= SEQUENCE { + * contentType ContentType, + * contentEncryptionAlgorithm ContentEncryptionAlgorithmIdentifier, + * encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL + * } + *+ */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(contentType); + v.add(contentEncryptionAlgorithm); + + if (encryptedContent != null) + { + v.add(new BERTaggedObject(false, 0, encryptedContent)); + } + + return new BERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/EncryptedContentInfoParser.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/EncryptedContentInfoParser.java new file mode 100644 index 0000000..364f1d9 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/EncryptedContentInfoParser.java @@ -0,0 +1,51 @@ +package org.bc.asn1.cms; + +import java.io.IOException; + +import org.bc.asn1.ASN1Encodable; +import org.bc.asn1.ASN1ObjectIdentifier; +import org.bc.asn1.ASN1SequenceParser; +import org.bc.asn1.ASN1TaggedObjectParser; +import org.bc.asn1.x509.AlgorithmIdentifier; + +/** + *
+ * EncryptedContentInfo ::= SEQUENCE { + * contentType ContentType, + * contentEncryptionAlgorithm ContentEncryptionAlgorithmIdentifier, + * encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL + * } + *+ */ +public class EncryptedContentInfoParser +{ + private ASN1ObjectIdentifier _contentType; + private AlgorithmIdentifier _contentEncryptionAlgorithm; + private ASN1TaggedObjectParser _encryptedContent; + + public EncryptedContentInfoParser( + ASN1SequenceParser seq) + throws IOException + { + _contentType = (ASN1ObjectIdentifier)seq.readObject(); + _contentEncryptionAlgorithm = AlgorithmIdentifier.getInstance(seq.readObject().toASN1Primitive()); + _encryptedContent = (ASN1TaggedObjectParser)seq.readObject(); + } + + public ASN1ObjectIdentifier getContentType() + { + return _contentType; + } + + public AlgorithmIdentifier getContentEncryptionAlgorithm() + { + return _contentEncryptionAlgorithm; + } + + public ASN1Encodable getEncryptedContent( + int tag) + throws IOException + { + return _encryptedContent.getObjectParser(tag, false); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/EncryptedData.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/EncryptedData.java new file mode 100644 index 0000000..9b8c617 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/EncryptedData.java @@ -0,0 +1,94 @@ +package org.bc.asn1.cms; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1Set; +import org.bc.asn1.BERSequence; +import org.bc.asn1.BERTaggedObject; + +public class EncryptedData + extends ASN1Object +{ + private ASN1Integer version; + private EncryptedContentInfo encryptedContentInfo; + private ASN1Set unprotectedAttrs; + + public static EncryptedData getInstance(Object o) + { + if (o instanceof EncryptedData) + { + return (EncryptedData)o; + } + + if (o != null) + { + return new EncryptedData(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public EncryptedData(EncryptedContentInfo encInfo) + { + this(encInfo, null); + } + + public EncryptedData(EncryptedContentInfo encInfo, ASN1Set unprotectedAttrs) + { + this.version = new ASN1Integer((unprotectedAttrs == null) ? 0 : 2); + this.encryptedContentInfo = encInfo; + this.unprotectedAttrs = unprotectedAttrs; + } + + private EncryptedData(ASN1Sequence seq) + { + this.version = ASN1Integer.getInstance(seq.getObjectAt(0)); + this.encryptedContentInfo = EncryptedContentInfo.getInstance(seq.getObjectAt(1)); + + if (seq.size() == 3) + { + this.unprotectedAttrs = ASN1Set.getInstance(seq.getObjectAt(2)); + } + } + + public ASN1Integer getVersion() + { + return version; + } + + public EncryptedContentInfo getEncryptedContentInfo() + { + return encryptedContentInfo; + } + + public ASN1Set getUnprotectedAttrs() + { + return unprotectedAttrs; + } + + /** + *
+ * EncryptedData ::= SEQUENCE { + * version CMSVersion, + * encryptedContentInfo EncryptedContentInfo, + * unprotectedAttrs [1] IMPLICIT UnprotectedAttributes OPTIONAL } + *+ * @return a basic ASN.1 object representation. + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(version); + v.add(encryptedContentInfo); + if (unprotectedAttrs != null) + { + v.add(new BERTaggedObject(false, 1, unprotectedAttrs)); + } + + return new BERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/EnvelopedData.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/EnvelopedData.java new file mode 100644 index 0000000..1db3888 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/EnvelopedData.java @@ -0,0 +1,188 @@ +package org.bc.asn1.cms; + +import java.util.Enumeration; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1Set; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.BERSequence; +import org.bc.asn1.DERTaggedObject; + +public class EnvelopedData + extends ASN1Object +{ + private ASN1Integer version; + private OriginatorInfo originatorInfo; + private ASN1Set recipientInfos; + private EncryptedContentInfo encryptedContentInfo; + private ASN1Set unprotectedAttrs; + + public EnvelopedData( + OriginatorInfo originatorInfo, + ASN1Set recipientInfos, + EncryptedContentInfo encryptedContentInfo, + ASN1Set unprotectedAttrs) + { + version = new ASN1Integer(calculateVersion(originatorInfo, recipientInfos, unprotectedAttrs)); + + this.originatorInfo = originatorInfo; + this.recipientInfos = recipientInfos; + this.encryptedContentInfo = encryptedContentInfo; + this.unprotectedAttrs = unprotectedAttrs; + } + + public EnvelopedData( + ASN1Sequence seq) + { + int index = 0; + + version = (ASN1Integer)seq.getObjectAt(index++); + + Object tmp = seq.getObjectAt(index++); + + if (tmp instanceof ASN1TaggedObject) + { + originatorInfo = OriginatorInfo.getInstance((ASN1TaggedObject)tmp, false); + tmp = seq.getObjectAt(index++); + } + + recipientInfos = ASN1Set.getInstance(tmp); + + encryptedContentInfo = EncryptedContentInfo.getInstance(seq.getObjectAt(index++)); + + if(seq.size() > index) + { + unprotectedAttrs = ASN1Set.getInstance((ASN1TaggedObject)seq.getObjectAt(index), false); + } + } + + /** + * return an EnvelopedData object from a tagged object. + * + * @param obj the tagged object holding the object we want. + * @param explicit true if the object is meant to be explicitly + * tagged false otherwise. + * @exception IllegalArgumentException if the object held by the + * tagged object cannot be converted. + */ + public static EnvelopedData getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + /** + * return an EnvelopedData object from the given object. + * + * @param obj the object we want converted. + * @exception IllegalArgumentException if the object cannot be converted. + */ + public static EnvelopedData getInstance( + Object obj) + { + if (obj instanceof EnvelopedData) + { + return (EnvelopedData)obj; + } + + if (obj != null) + { + return new EnvelopedData(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public ASN1Integer getVersion() + { + return version; + } + + public OriginatorInfo getOriginatorInfo() + { + return originatorInfo; + } + + public ASN1Set getRecipientInfos() + { + return recipientInfos; + } + + public EncryptedContentInfo getEncryptedContentInfo() + { + return encryptedContentInfo; + } + + public ASN1Set getUnprotectedAttrs() + { + return unprotectedAttrs; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + *
+ * EnvelopedData ::= SEQUENCE { + * version CMSVersion, + * originatorInfo [0] IMPLICIT OriginatorInfo OPTIONAL, + * recipientInfos RecipientInfos, + * encryptedContentInfo EncryptedContentInfo, + * unprotectedAttrs [1] IMPLICIT UnprotectedAttributes OPTIONAL + * } + *+ */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(version); + + if (originatorInfo != null) + { + v.add(new DERTaggedObject(false, 0, originatorInfo)); + } + + v.add(recipientInfos); + v.add(encryptedContentInfo); + + if (unprotectedAttrs != null) + { + v.add(new DERTaggedObject(false, 1, unprotectedAttrs)); + } + + return new BERSequence(v); + } + + public static int calculateVersion(OriginatorInfo originatorInfo, ASN1Set recipientInfos, ASN1Set unprotectedAttrs) + { + int version; + + if (originatorInfo != null || unprotectedAttrs != null) + { + version = 2; + } + else + { + version = 0; + + Enumeration e = recipientInfos.getObjects(); + + while (e.hasMoreElements()) + { + RecipientInfo ri = RecipientInfo.getInstance(e.nextElement()); + + if (ri.getVersion().getValue().intValue() != version) + { + version = 2; + break; + } + } + } + + return version; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/EnvelopedDataParser.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/EnvelopedDataParser.java new file mode 100644 index 0000000..e03344f --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/EnvelopedDataParser.java @@ -0,0 +1,118 @@ +package org.bc.asn1.cms; + +import java.io.IOException; + +import org.bc.asn1.ASN1Encodable; +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1SequenceParser; +import org.bc.asn1.ASN1SetParser; +import org.bc.asn1.ASN1TaggedObjectParser; +import org.bc.asn1.BERTags; + +/** + *
+ * EnvelopedData ::= SEQUENCE { + * version CMSVersion, + * originatorInfo [0] IMPLICIT OriginatorInfo OPTIONAL, + * recipientInfos RecipientInfos, + * encryptedContentInfo EncryptedContentInfo, + * unprotectedAttrs [1] IMPLICIT UnprotectedAttributes OPTIONAL + * } + *+ */ +public class EnvelopedDataParser +{ + private ASN1SequenceParser _seq; + private ASN1Integer _version; + private ASN1Encodable _nextObject; + private boolean _originatorInfoCalled; + + public EnvelopedDataParser( + ASN1SequenceParser seq) + throws IOException + { + this._seq = seq; + this._version = ASN1Integer.getInstance(seq.readObject()); + } + + public ASN1Integer getVersion() + { + return _version; + } + + public OriginatorInfo getOriginatorInfo() + throws IOException + { + _originatorInfoCalled = true; + + if (_nextObject == null) + { + _nextObject = _seq.readObject(); + } + + if (_nextObject instanceof ASN1TaggedObjectParser && ((ASN1TaggedObjectParser)_nextObject).getTagNo() == 0) + { + ASN1SequenceParser originatorInfo = (ASN1SequenceParser) ((ASN1TaggedObjectParser)_nextObject).getObjectParser(BERTags.SEQUENCE, false); + _nextObject = null; + return OriginatorInfo.getInstance(originatorInfo.toASN1Primitive()); + } + + return null; + } + + public ASN1SetParser getRecipientInfos() + throws IOException + { + if (!_originatorInfoCalled) + { + getOriginatorInfo(); + } + + if (_nextObject == null) + { + _nextObject = _seq.readObject(); + } + + ASN1SetParser recipientInfos = (ASN1SetParser)_nextObject; + _nextObject = null; + return recipientInfos; + } + + public EncryptedContentInfoParser getEncryptedContentInfo() + throws IOException + { + if (_nextObject == null) + { + _nextObject = _seq.readObject(); + } + + + if (_nextObject != null) + { + ASN1SequenceParser o = (ASN1SequenceParser) _nextObject; + _nextObject = null; + return new EncryptedContentInfoParser(o); + } + + return null; + } + + public ASN1SetParser getUnprotectedAttrs() + throws IOException + { + if (_nextObject == null) + { + _nextObject = _seq.readObject(); + } + + + if (_nextObject != null) + { + ASN1Encodable o = _nextObject; + _nextObject = null; + return (ASN1SetParser)((ASN1TaggedObjectParser)o).getObjectParser(BERTags.SET, false); + } + + return null; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/Evidence.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/Evidence.java new file mode 100644 index 0000000..ceb1879 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/Evidence.java @@ -0,0 +1,56 @@ +package org.bc.asn1.cms; + +import org.bc.asn1.ASN1Choice; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERTaggedObject; + +public class Evidence + extends ASN1Object + implements ASN1Choice +{ + private TimeStampTokenEvidence tstEvidence; + + public Evidence(TimeStampTokenEvidence tstEvidence) + { + this.tstEvidence = tstEvidence; + } + + private Evidence(ASN1TaggedObject tagged) + { + if (tagged.getTagNo() == 0) + { + this.tstEvidence = TimeStampTokenEvidence.getInstance(tagged, false); + } + } + + public static Evidence getInstance(Object obj) + { + if (obj == null || obj instanceof Evidence) + { + return (Evidence)obj; + } + else if (obj instanceof ASN1TaggedObject) + { + return new Evidence(ASN1TaggedObject.getInstance(obj)); + } + + throw new IllegalArgumentException("unknown object in getInstance"); + } + + public TimeStampTokenEvidence getTstEvidence() + { + return tstEvidence; + } + + public ASN1Primitive toASN1Primitive() + { + if (tstEvidence != null) + { + return new DERTaggedObject(false, 0, tstEvidence); + } + + return null; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/IssuerAndSerialNumber.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/IssuerAndSerialNumber.java new file mode 100644 index 0000000..1c58fb4 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/IssuerAndSerialNumber.java @@ -0,0 +1,107 @@ +package org.bc.asn1.cms; + +import java.math.BigInteger; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DERSequence; +import org.bc.asn1.x500.X500Name; +import org.bc.asn1.x509.Certificate; +import org.bc.asn1.x509.X509CertificateStructure; +import org.bc.asn1.x509.X509Name; + +public class IssuerAndSerialNumber + extends ASN1Object +{ + private X500Name name; + private ASN1Integer serialNumber; + + public static IssuerAndSerialNumber getInstance( + Object obj) + { + if (obj instanceof IssuerAndSerialNumber) + { + return (IssuerAndSerialNumber)obj; + } + else if (obj != null) + { + return new IssuerAndSerialNumber(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public IssuerAndSerialNumber( + ASN1Sequence seq) + { + this.name = X500Name.getInstance(seq.getObjectAt(0)); + this.serialNumber = (ASN1Integer)seq.getObjectAt(1); + } + + public IssuerAndSerialNumber( + Certificate certificate) + { + this.name = certificate.getIssuer(); + this.serialNumber = certificate.getSerialNumber(); + } + + public IssuerAndSerialNumber( + X509CertificateStructure certificate) + { + this.name = certificate.getIssuer(); + this.serialNumber = certificate.getSerialNumber(); + } + + public IssuerAndSerialNumber( + X500Name name, + BigInteger serialNumber) + { + this.name = name; + this.serialNumber = new ASN1Integer(serialNumber); + } + + /** + * @deprecated use X500Name constructor + */ + public IssuerAndSerialNumber( + X509Name name, + BigInteger serialNumber) + { + this.name = X500Name.getInstance(name); + this.serialNumber = new ASN1Integer(serialNumber); + } + + /** + * @deprecated use X500Name constructor + */ + public IssuerAndSerialNumber( + X509Name name, + ASN1Integer serialNumber) + { + this.name = X500Name.getInstance(name); + this.serialNumber = serialNumber; + } + + public X500Name getName() + { + return name; + } + + public ASN1Integer getSerialNumber() + { + return serialNumber; + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(name); + v.add(serialNumber); + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/KEKIdentifier.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/KEKIdentifier.java new file mode 100644 index 0000000..3d36696 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/KEKIdentifier.java @@ -0,0 +1,139 @@ +package org.bc.asn1.cms; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1GeneralizedTime; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1OctetString; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DEROctetString; +import org.bc.asn1.DERSequence; + +public class KEKIdentifier + extends ASN1Object +{ + private ASN1OctetString keyIdentifier; + private ASN1GeneralizedTime date; + private OtherKeyAttribute other; + + public KEKIdentifier( + byte[] keyIdentifier, + ASN1GeneralizedTime date, + OtherKeyAttribute other) + { + this.keyIdentifier = new DEROctetString(keyIdentifier); + this.date = date; + this.other = other; + } + + private KEKIdentifier( + ASN1Sequence seq) + { + keyIdentifier = (ASN1OctetString)seq.getObjectAt(0); + + switch (seq.size()) + { + case 1: + break; + case 2: + if (seq.getObjectAt(1) instanceof ASN1GeneralizedTime) + { + date = (ASN1GeneralizedTime)seq.getObjectAt(1); + } + else + { + other = OtherKeyAttribute.getInstance(seq.getObjectAt(1)); + } + break; + case 3: + date = (ASN1GeneralizedTime)seq.getObjectAt(1); + other = OtherKeyAttribute.getInstance(seq.getObjectAt(2)); + break; + default: + throw new IllegalArgumentException("Invalid KEKIdentifier"); + } + } + + /** + * return a KEKIdentifier object from a tagged object. + * + * @param obj the tagged object holding the object we want. + * @param explicit true if the object is meant to be explicitly + * tagged false otherwise. + * @exception IllegalArgumentException if the object held by the + * tagged object cannot be converted. + */ + public static KEKIdentifier getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + /** + * return a KEKIdentifier object from the given object. + * + * @param obj the object we want converted. + * @exception IllegalArgumentException if the object cannot be converted. + */ + public static KEKIdentifier getInstance( + Object obj) + { + if (obj == null || obj instanceof KEKIdentifier) + { + return (KEKIdentifier)obj; + } + + if (obj instanceof ASN1Sequence) + { + return new KEKIdentifier((ASN1Sequence)obj); + } + + throw new IllegalArgumentException("Invalid KEKIdentifier: " + obj.getClass().getName()); + } + + public ASN1OctetString getKeyIdentifier() + { + return keyIdentifier; + } + + public ASN1GeneralizedTime getDate() + { + return date; + } + + public OtherKeyAttribute getOther() + { + return other; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + *
+ * KEKIdentifier ::= SEQUENCE { + * keyIdentifier OCTET STRING, + * date GeneralizedTime OPTIONAL, + * other OtherKeyAttribute OPTIONAL + * } + *+ */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(keyIdentifier); + + if (date != null) + { + v.add(date); + } + + if (other != null) + { + v.add(other); + } + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/KEKRecipientInfo.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/KEKRecipientInfo.java new file mode 100644 index 0000000..6112e9f --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/KEKRecipientInfo.java @@ -0,0 +1,121 @@ +package org.bc.asn1.cms; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1OctetString; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERSequence; +import org.bc.asn1.x509.AlgorithmIdentifier; + +public class KEKRecipientInfo + extends ASN1Object +{ + private ASN1Integer version; + private KEKIdentifier kekid; + private AlgorithmIdentifier keyEncryptionAlgorithm; + private ASN1OctetString encryptedKey; + + public KEKRecipientInfo( + KEKIdentifier kekid, + AlgorithmIdentifier keyEncryptionAlgorithm, + ASN1OctetString encryptedKey) + { + this.version = new ASN1Integer(4); + this.kekid = kekid; + this.keyEncryptionAlgorithm = keyEncryptionAlgorithm; + this.encryptedKey = encryptedKey; + } + + public KEKRecipientInfo( + ASN1Sequence seq) + { + version = (ASN1Integer)seq.getObjectAt(0); + kekid = KEKIdentifier.getInstance(seq.getObjectAt(1)); + keyEncryptionAlgorithm = AlgorithmIdentifier.getInstance(seq.getObjectAt(2)); + encryptedKey = (ASN1OctetString)seq.getObjectAt(3); + } + + /** + * return a KEKRecipientInfo object from a tagged object. + * + * @param obj the tagged object holding the object we want. + * @param explicit true if the object is meant to be explicitly + * tagged false otherwise. + * @exception IllegalArgumentException if the object held by the + * tagged object cannot be converted. + */ + public static KEKRecipientInfo getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + /** + * return a KEKRecipientInfo object from the given object. + * + * @param obj the object we want converted. + * @exception IllegalArgumentException if the object cannot be converted. + */ + public static KEKRecipientInfo getInstance( + Object obj) + { + if (obj == null || obj instanceof KEKRecipientInfo) + { + return (KEKRecipientInfo)obj; + } + + if(obj instanceof ASN1Sequence) + { + return new KEKRecipientInfo((ASN1Sequence)obj); + } + + throw new IllegalArgumentException("Invalid KEKRecipientInfo: " + obj.getClass().getName()); + } + + public ASN1Integer getVersion() + { + return version; + } + + public KEKIdentifier getKekid() + { + return kekid; + } + + public AlgorithmIdentifier getKeyEncryptionAlgorithm() + { + return keyEncryptionAlgorithm; + } + + public ASN1OctetString getEncryptedKey() + { + return encryptedKey; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + *
+ * KEKRecipientInfo ::= SEQUENCE { + * version CMSVersion, -- always set to 4 + * kekid KEKIdentifier, + * keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier, + * encryptedKey EncryptedKey + * } + *+ */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(version); + v.add(kekid); + v.add(keyEncryptionAlgorithm); + v.add(encryptedKey); + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/KeyAgreeRecipientIdentifier.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/KeyAgreeRecipientIdentifier.java new file mode 100644 index 0000000..2ad95ae --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/KeyAgreeRecipientIdentifier.java @@ -0,0 +1,103 @@ +package org.bc.asn1.cms; + +import org.bc.asn1.ASN1Choice; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERTaggedObject; + +public class KeyAgreeRecipientIdentifier + extends ASN1Object + implements ASN1Choice +{ + private IssuerAndSerialNumber issuerSerial; + private RecipientKeyIdentifier rKeyID; + + /** + * return an KeyAgreeRecipientIdentifier object from a tagged object. + * + * @param obj the tagged object holding the object we want. + * @param explicit true if the object is meant to be explicitly + * tagged false otherwise. + * @exception IllegalArgumentException if the object held by the + * tagged object cannot be converted. + */ + public static KeyAgreeRecipientIdentifier getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + /** + * return an KeyAgreeRecipientIdentifier object from the given object. + * + * @param obj the object we want converted. + * @exception IllegalArgumentException if the object cannot be converted. + */ + public static KeyAgreeRecipientIdentifier getInstance( + Object obj) + { + if (obj == null || obj instanceof KeyAgreeRecipientIdentifier) + { + return (KeyAgreeRecipientIdentifier)obj; + } + + if (obj instanceof ASN1Sequence) + { + return new KeyAgreeRecipientIdentifier(IssuerAndSerialNumber.getInstance(obj)); + } + + if (obj instanceof ASN1TaggedObject && ((ASN1TaggedObject)obj).getTagNo() == 0) + { + return new KeyAgreeRecipientIdentifier(RecipientKeyIdentifier.getInstance( + (ASN1TaggedObject)obj, false)); + } + + throw new IllegalArgumentException("Invalid KeyAgreeRecipientIdentifier: " + obj.getClass().getName()); + } + + public KeyAgreeRecipientIdentifier( + IssuerAndSerialNumber issuerSerial) + { + this.issuerSerial = issuerSerial; + this.rKeyID = null; + } + + public KeyAgreeRecipientIdentifier( + RecipientKeyIdentifier rKeyID) + { + this.issuerSerial = null; + this.rKeyID = rKeyID; + } + + public IssuerAndSerialNumber getIssuerAndSerialNumber() + { + return issuerSerial; + } + + public RecipientKeyIdentifier getRKeyID() + { + return rKeyID; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + *
+ * KeyAgreeRecipientIdentifier ::= CHOICE { + * issuerAndSerialNumber IssuerAndSerialNumber, + * rKeyId [0] IMPLICIT RecipientKeyIdentifier + * } + *+ */ + public ASN1Primitive toASN1Primitive() + { + if (issuerSerial != null) + { + return issuerSerial.toASN1Primitive(); + } + + return new DERTaggedObject(false, 0, rKeyID); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/KeyAgreeRecipientInfo.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/KeyAgreeRecipientInfo.java new file mode 100644 index 0000000..1724b29 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/KeyAgreeRecipientInfo.java @@ -0,0 +1,153 @@ +package org.bc.asn1.cms; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1OctetString; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERSequence; +import org.bc.asn1.DERTaggedObject; +import org.bc.asn1.x509.AlgorithmIdentifier; + +public class KeyAgreeRecipientInfo + extends ASN1Object +{ + private ASN1Integer version; + private OriginatorIdentifierOrKey originator; + private ASN1OctetString ukm; + private AlgorithmIdentifier keyEncryptionAlgorithm; + private ASN1Sequence recipientEncryptedKeys; + + public KeyAgreeRecipientInfo( + OriginatorIdentifierOrKey originator, + ASN1OctetString ukm, + AlgorithmIdentifier keyEncryptionAlgorithm, + ASN1Sequence recipientEncryptedKeys) + { + this.version = new ASN1Integer(3); + this.originator = originator; + this.ukm = ukm; + this.keyEncryptionAlgorithm = keyEncryptionAlgorithm; + this.recipientEncryptedKeys = recipientEncryptedKeys; + } + + public KeyAgreeRecipientInfo( + ASN1Sequence seq) + { + int index = 0; + + version = (ASN1Integer)seq.getObjectAt(index++); + originator = OriginatorIdentifierOrKey.getInstance( + (ASN1TaggedObject)seq.getObjectAt(index++), true); + + if (seq.getObjectAt(index) instanceof ASN1TaggedObject) + { + ukm = ASN1OctetString.getInstance( + (ASN1TaggedObject)seq.getObjectAt(index++), true); + } + + keyEncryptionAlgorithm = AlgorithmIdentifier.getInstance( + seq.getObjectAt(index++)); + + recipientEncryptedKeys = (ASN1Sequence)seq.getObjectAt(index++); + } + + /** + * return a KeyAgreeRecipientInfo object from a tagged object. + * + * @param obj the tagged object holding the object we want. + * @param explicit true if the object is meant to be explicitly + * tagged false otherwise. + * @exception IllegalArgumentException if the object held by the + * tagged object cannot be converted. + */ + public static KeyAgreeRecipientInfo getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + /** + * return a KeyAgreeRecipientInfo object from the given object. + * + * @param obj the object we want converted. + * @exception IllegalArgumentException if the object cannot be converted. + */ + public static KeyAgreeRecipientInfo getInstance( + Object obj) + { + if (obj == null || obj instanceof KeyAgreeRecipientInfo) + { + return (KeyAgreeRecipientInfo)obj; + } + + if (obj instanceof ASN1Sequence) + { + return new KeyAgreeRecipientInfo((ASN1Sequence)obj); + } + + throw new IllegalArgumentException( + "Illegal object in KeyAgreeRecipientInfo: " + obj.getClass().getName()); + + } + + public ASN1Integer getVersion() + { + return version; + } + + public OriginatorIdentifierOrKey getOriginator() + { + return originator; + } + + public ASN1OctetString getUserKeyingMaterial() + { + return ukm; + } + + public AlgorithmIdentifier getKeyEncryptionAlgorithm() + { + return keyEncryptionAlgorithm; + } + + public ASN1Sequence getRecipientEncryptedKeys() + { + return recipientEncryptedKeys; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + *
+ * KeyAgreeRecipientInfo ::= SEQUENCE { + * version CMSVersion, -- always set to 3 + * originator [0] EXPLICIT OriginatorIdentifierOrKey, + * ukm [1] EXPLICIT UserKeyingMaterial OPTIONAL, + * keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier, + * recipientEncryptedKeys RecipientEncryptedKeys + * } + * + * UserKeyingMaterial ::= OCTET STRING + *+ */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(version); + v.add(new DERTaggedObject(true, 0, originator)); + + if (ukm != null) + { + v.add(new DERTaggedObject(true, 1, ukm)); + } + + v.add(keyEncryptionAlgorithm); + v.add(recipientEncryptedKeys); + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/KeyTransRecipientInfo.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/KeyTransRecipientInfo.java new file mode 100644 index 0000000..717f38f --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/KeyTransRecipientInfo.java @@ -0,0 +1,114 @@ +package org.bc.asn1.cms; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1OctetString; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERSequence; +import org.bc.asn1.x509.AlgorithmIdentifier; + +public class KeyTransRecipientInfo + extends ASN1Object +{ + private ASN1Integer version; + private RecipientIdentifier rid; + private AlgorithmIdentifier keyEncryptionAlgorithm; + private ASN1OctetString encryptedKey; + + public KeyTransRecipientInfo( + RecipientIdentifier rid, + AlgorithmIdentifier keyEncryptionAlgorithm, + ASN1OctetString encryptedKey) + { + if (rid.toASN1Primitive() instanceof ASN1TaggedObject) + { + this.version = new ASN1Integer(2); + } + else + { + this.version = new ASN1Integer(0); + } + + this.rid = rid; + this.keyEncryptionAlgorithm = keyEncryptionAlgorithm; + this.encryptedKey = encryptedKey; + } + + public KeyTransRecipientInfo( + ASN1Sequence seq) + { + this.version = (ASN1Integer)seq.getObjectAt(0); + this.rid = RecipientIdentifier.getInstance(seq.getObjectAt(1)); + this.keyEncryptionAlgorithm = AlgorithmIdentifier.getInstance(seq.getObjectAt(2)); + this.encryptedKey = (ASN1OctetString)seq.getObjectAt(3); + } + + /** + * return a KeyTransRecipientInfo object from the given object. + * + * @param obj the object we want converted. + * @exception IllegalArgumentException if the object cannot be converted. + */ + public static KeyTransRecipientInfo getInstance( + Object obj) + { + if (obj == null || obj instanceof KeyTransRecipientInfo) + { + return (KeyTransRecipientInfo)obj; + } + + if(obj instanceof ASN1Sequence) + { + return new KeyTransRecipientInfo((ASN1Sequence)obj); + } + + throw new IllegalArgumentException( + "Illegal object in KeyTransRecipientInfo: " + obj.getClass().getName()); + } + + public ASN1Integer getVersion() + { + return version; + } + + public RecipientIdentifier getRecipientIdentifier() + { + return rid; + } + + public AlgorithmIdentifier getKeyEncryptionAlgorithm() + { + return keyEncryptionAlgorithm; + } + + public ASN1OctetString getEncryptedKey() + { + return encryptedKey; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + *
+ * KeyTransRecipientInfo ::= SEQUENCE { + * version CMSVersion, -- always set to 0 or 2 + * rid RecipientIdentifier, + * keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier, + * encryptedKey EncryptedKey + * } + *+ */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(version); + v.add(rid); + v.add(keyEncryptionAlgorithm); + v.add(encryptedKey); + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/MetaData.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/MetaData.java new file mode 100644 index 0000000..9620ea2 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/MetaData.java @@ -0,0 +1,120 @@ +package org.bc.asn1.cms; + +import org.bc.asn1.ASN1Boolean; +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DERIA5String; +import org.bc.asn1.DERSequence; +import org.bc.asn1.DERUTF8String; + +public class MetaData + extends ASN1Object +{ + private ASN1Boolean hashProtected; + private DERUTF8String fileName; + private DERIA5String mediaType; + private Attributes otherMetaData; + + public MetaData( + ASN1Boolean hashProtected, + DERUTF8String fileName, + DERIA5String mediaType, + Attributes otherMetaData) + { + this.hashProtected = hashProtected; + this.fileName = fileName; + this.mediaType = mediaType; + this.otherMetaData = otherMetaData; + } + + private MetaData(ASN1Sequence seq) + { + this.hashProtected = ASN1Boolean.getInstance(seq.getObjectAt(0)); + + int index = 1; + + if (index < seq.size() && seq.getObjectAt(index) instanceof DERUTF8String) + { + this.fileName = DERUTF8String.getInstance(seq.getObjectAt(index++)); + } + if (index < seq.size() && seq.getObjectAt(index) instanceof DERIA5String) + { + this.mediaType = DERIA5String.getInstance(seq.getObjectAt(index++)); + } + if (index < seq.size()) + { + this.otherMetaData = Attributes.getInstance(seq.getObjectAt(index++)); + } + } + + public static MetaData getInstance(Object obj) + { + if (obj instanceof MetaData) + { + return (MetaData)obj; + } + else if (obj != null) + { + return new MetaData(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + /** + *
+ * MetaData ::= SEQUENCE { + * hashProtected BOOLEAN, + * fileName UTF8String OPTIONAL, + * mediaType IA5String OPTIONAL, + * otherMetaData Attributes OPTIONAL + * } + *+ * @return + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(hashProtected); + + if (fileName != null) + { + v.add(fileName); + } + + if (mediaType != null) + { + v.add(mediaType); + } + + if (otherMetaData != null) + { + v.add(otherMetaData); + } + + return new DERSequence(v); + } + + public boolean isHashProtected() + { + return hashProtected.isTrue(); + } + + public DERUTF8String getFileName() + { + return this.fileName; + } + + public DERIA5String getMediaType() + { + return this.mediaType; + } + + public Attributes getOtherMetaData() + { + return otherMetaData; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/OriginatorIdentifierOrKey.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/OriginatorIdentifierOrKey.java new file mode 100644 index 0000000..7c8ee42 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/OriginatorIdentifierOrKey.java @@ -0,0 +1,165 @@ +package org.bc.asn1.cms; + +import org.bc.asn1.ASN1Choice; +import org.bc.asn1.ASN1Encodable; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1OctetString; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERTaggedObject; +import org.bc.asn1.x509.SubjectKeyIdentifier; + +public class OriginatorIdentifierOrKey + extends ASN1Object + implements ASN1Choice +{ + private ASN1Encodable id; + + public OriginatorIdentifierOrKey( + IssuerAndSerialNumber id) + { + this.id = id; + } + + /** + * @deprecated use version taking a SubjectKeyIdentifier + */ + public OriginatorIdentifierOrKey( + ASN1OctetString id) + { + this(new SubjectKeyIdentifier(id.getOctets())); + } + + public OriginatorIdentifierOrKey( + SubjectKeyIdentifier id) + { + this.id = new DERTaggedObject(false, 0, id); + } + + public OriginatorIdentifierOrKey( + OriginatorPublicKey id) + { + this.id = new DERTaggedObject(false, 1, id); + } + + /** + * @deprecated use more specific version + */ + public OriginatorIdentifierOrKey( + ASN1Primitive id) + { + this.id = id; + } + + /** + * return an OriginatorIdentifierOrKey object from a tagged object. + * + * @param o the tagged object holding the object we want. + * @param explicit true if the object is meant to be explicitly + * tagged false otherwise. + * @exception IllegalArgumentException if the object held by the + * tagged object cannot be converted. + */ + public static OriginatorIdentifierOrKey getInstance( + ASN1TaggedObject o, + boolean explicit) + { + if (!explicit) + { + throw new IllegalArgumentException( + "Can't implicitly tag OriginatorIdentifierOrKey"); + } + + return getInstance(o.getObject()); + } + + /** + * return an OriginatorIdentifierOrKey object from the given object. + * + * @param o the object we want converted. + * @exception IllegalArgumentException if the object cannot be converted. + */ + public static OriginatorIdentifierOrKey getInstance( + Object o) + { + if (o == null || o instanceof OriginatorIdentifierOrKey) + { + return (OriginatorIdentifierOrKey)o; + } + + if (o instanceof IssuerAndSerialNumber) + { + return new OriginatorIdentifierOrKey((IssuerAndSerialNumber)o); + } + + if (o instanceof SubjectKeyIdentifier) + { + return new OriginatorIdentifierOrKey((SubjectKeyIdentifier)o); + } + + if (o instanceof OriginatorPublicKey) + { + return new OriginatorIdentifierOrKey((OriginatorPublicKey)o); + } + + if (o instanceof ASN1TaggedObject) + { + // TODO Add validation + return new OriginatorIdentifierOrKey((ASN1TaggedObject)o); + } + + throw new IllegalArgumentException("Invalid OriginatorIdentifierOrKey: " + o.getClass().getName()); + } + + public ASN1Encodable getId() + { + return id; + } + + public IssuerAndSerialNumber getIssuerAndSerialNumber() + { + if (id instanceof IssuerAndSerialNumber) + { + return (IssuerAndSerialNumber)id; + } + + return null; + } + + public SubjectKeyIdentifier getSubjectKeyIdentifier() + { + if (id instanceof ASN1TaggedObject && ((ASN1TaggedObject)id).getTagNo() == 0) + { + return SubjectKeyIdentifier.getInstance((ASN1TaggedObject)id, false); + } + + return null; + } + + public OriginatorPublicKey getOriginatorKey() + { + if (id instanceof ASN1TaggedObject && ((ASN1TaggedObject)id).getTagNo() == 1) + { + return OriginatorPublicKey.getInstance((ASN1TaggedObject)id, false); + } + + return null; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + *
+ * OriginatorIdentifierOrKey ::= CHOICE { + * issuerAndSerialNumber IssuerAndSerialNumber, + * subjectKeyIdentifier [0] SubjectKeyIdentifier, + * originatorKey [1] OriginatorPublicKey + * } + * + * SubjectKeyIdentifier ::= OCTET STRING + *+ */ + public ASN1Primitive toASN1Primitive() + { + return id.toASN1Primitive(); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/OriginatorInfo.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/OriginatorInfo.java new file mode 100644 index 0000000..45f05e8 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/OriginatorInfo.java @@ -0,0 +1,128 @@ +package org.bc.asn1.cms; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1Set; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERSequence; +import org.bc.asn1.DERTaggedObject; + +public class OriginatorInfo + extends ASN1Object +{ + private ASN1Set certs; + private ASN1Set crls; + + public OriginatorInfo( + ASN1Set certs, + ASN1Set crls) + { + this.certs = certs; + this.crls = crls; + } + + private OriginatorInfo( + ASN1Sequence seq) + { + switch (seq.size()) + { + case 0: // empty + break; + case 1: + ASN1TaggedObject o = (ASN1TaggedObject)seq.getObjectAt(0); + switch (o.getTagNo()) + { + case 0 : + certs = ASN1Set.getInstance(o, false); + break; + case 1 : + crls = ASN1Set.getInstance(o, false); + break; + default: + throw new IllegalArgumentException("Bad tag in OriginatorInfo: " + o.getTagNo()); + } + break; + case 2: + certs = ASN1Set.getInstance((ASN1TaggedObject)seq.getObjectAt(0), false); + crls = ASN1Set.getInstance((ASN1TaggedObject)seq.getObjectAt(1), false); + break; + default: + throw new IllegalArgumentException("OriginatorInfo too big"); + } + } + + /** + * return an OriginatorInfo object from a tagged object. + * + * @param obj the tagged object holding the object we want. + * @param explicit true if the object is meant to be explicitly + * tagged false otherwise. + * @exception IllegalArgumentException if the object held by the + * tagged object cannot be converted. + */ + public static OriginatorInfo getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + /** + * return an OriginatorInfo object from the given object. + * + * @param obj the object we want converted. + * @exception IllegalArgumentException if the object cannot be converted. + */ + public static OriginatorInfo getInstance( + Object obj) + { + if (obj instanceof OriginatorInfo) + { + return (OriginatorInfo)obj; + } + else if (obj != null) + { + return new OriginatorInfo(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public ASN1Set getCertificates() + { + return certs; + } + + public ASN1Set getCRLs() + { + return crls; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + *
+ * OriginatorInfo ::= SEQUENCE { + * certs [0] IMPLICIT CertificateSet OPTIONAL, + * crls [1] IMPLICIT CertificateRevocationLists OPTIONAL + * } + *+ */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + if (certs != null) + { + v.add(new DERTaggedObject(false, 0, certs)); + } + + if (crls != null) + { + v.add(new DERTaggedObject(false, 1, crls)); + } + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/OriginatorPublicKey.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/OriginatorPublicKey.java new file mode 100644 index 0000000..48b33a0 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/OriginatorPublicKey.java @@ -0,0 +1,100 @@ +package org.bc.asn1.cms; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERBitString; +import org.bc.asn1.DERSequence; +import org.bc.asn1.x509.AlgorithmIdentifier; + + +public class OriginatorPublicKey + extends ASN1Object +{ + private AlgorithmIdentifier algorithm; + private DERBitString publicKey; + + public OriginatorPublicKey( + AlgorithmIdentifier algorithm, + byte[] publicKey) + { + this.algorithm = algorithm; + this.publicKey = new DERBitString(publicKey); + } + + public OriginatorPublicKey( + ASN1Sequence seq) + { + algorithm = AlgorithmIdentifier.getInstance(seq.getObjectAt(0)); + publicKey = (DERBitString)seq.getObjectAt(1); + } + + /** + * return an OriginatorPublicKey object from a tagged object. + * + * @param obj the tagged object holding the object we want. + * @param explicit true if the object is meant to be explicitly + * tagged false otherwise. + * @exception IllegalArgumentException if the object held by the + * tagged object cannot be converted. + */ + public static OriginatorPublicKey getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + /** + * return an OriginatorPublicKey object from the given object. + * + * @param obj the object we want converted. + * @exception IllegalArgumentException if the object cannot be converted. + */ + public static OriginatorPublicKey getInstance( + Object obj) + { + if (obj == null || obj instanceof OriginatorPublicKey) + { + return (OriginatorPublicKey)obj; + } + + if (obj instanceof ASN1Sequence) + { + return new OriginatorPublicKey((ASN1Sequence)obj); + } + + throw new IllegalArgumentException("Invalid OriginatorPublicKey: " + obj.getClass().getName()); + } + + public AlgorithmIdentifier getAlgorithm() + { + return algorithm; + } + + public DERBitString getPublicKey() + { + return publicKey; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + *
+ * OriginatorPublicKey ::= SEQUENCE { + * algorithm AlgorithmIdentifier, + * publicKey BIT STRING + * } + *+ */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(algorithm); + v.add(publicKey); + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/OtherKeyAttribute.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/OtherKeyAttribute.java new file mode 100644 index 0000000..6e64bc6 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/OtherKeyAttribute.java @@ -0,0 +1,82 @@ +package org.bc.asn1.cms; + +import org.bc.asn1.ASN1Encodable; +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1ObjectIdentifier; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DERSequence; + +public class OtherKeyAttribute + extends ASN1Object +{ + private ASN1ObjectIdentifier keyAttrId; + private ASN1Encodable keyAttr; + + /** + * return an OtherKeyAttribute object from the given object. + * + * @param o the object we want converted. + * @exception IllegalArgumentException if the object cannot be converted. + */ + public static OtherKeyAttribute getInstance( + Object o) + { + if (o == null || o instanceof OtherKeyAttribute) + { + return (OtherKeyAttribute)o; + } + + if (o instanceof ASN1Sequence) + { + return new OtherKeyAttribute((ASN1Sequence)o); + } + + throw new IllegalArgumentException("unknown object in factory: " + o.getClass().getName()); + } + + public OtherKeyAttribute( + ASN1Sequence seq) + { + keyAttrId = (ASN1ObjectIdentifier)seq.getObjectAt(0); + keyAttr = seq.getObjectAt(1); + } + + public OtherKeyAttribute( + ASN1ObjectIdentifier keyAttrId, + ASN1Encodable keyAttr) + { + this.keyAttrId = keyAttrId; + this.keyAttr = keyAttr; + } + + public ASN1ObjectIdentifier getKeyAttrId() + { + return keyAttrId; + } + + public ASN1Encodable getKeyAttr() + { + return keyAttr; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + *
+ * OtherKeyAttribute ::= SEQUENCE { + * keyAttrId OBJECT IDENTIFIER, + * keyAttr ANY DEFINED BY keyAttrId OPTIONAL + * } + *+ */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(keyAttrId); + v.add(keyAttr); + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/OtherRecipientInfo.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/OtherRecipientInfo.java new file mode 100644 index 0000000..f253bad --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/OtherRecipientInfo.java @@ -0,0 +1,98 @@ +package org.bc.asn1.cms; + +import org.bc.asn1.ASN1Encodable; +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1ObjectIdentifier; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERSequence; + +public class OtherRecipientInfo + extends ASN1Object +{ + private ASN1ObjectIdentifier oriType; + private ASN1Encodable oriValue; + + public OtherRecipientInfo( + ASN1ObjectIdentifier oriType, + ASN1Encodable oriValue) + { + this.oriType = oriType; + this.oriValue = oriValue; + } + + public OtherRecipientInfo( + ASN1Sequence seq) + { + oriType = ASN1ObjectIdentifier.getInstance(seq.getObjectAt(0)); + oriValue = seq.getObjectAt(1); + } + + /** + * return a OtherRecipientInfo object from a tagged object. + * + * @param obj the tagged object holding the object we want. + * @param explicit true if the object is meant to be explicitly + * tagged false otherwise. + * @exception IllegalArgumentException if the object held by the + * tagged object cannot be converted. + */ + public static OtherRecipientInfo getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + /** + * return a OtherRecipientInfo object from the given object. + * + * @param obj the object we want converted. + * @exception IllegalArgumentException if the object cannot be converted. + */ + public static OtherRecipientInfo getInstance( + Object obj) + { + if (obj == null || obj instanceof OtherRecipientInfo) + { + return (OtherRecipientInfo)obj; + } + + if (obj instanceof ASN1Sequence) + { + return new OtherRecipientInfo((ASN1Sequence)obj); + } + + throw new IllegalArgumentException("Invalid OtherRecipientInfo: " + obj.getClass().getName()); + } + + public ASN1ObjectIdentifier getType() + { + return oriType; + } + + public ASN1Encodable getValue() + { + return oriValue; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + *
+ * OtherRecipientInfo ::= SEQUENCE { + * oriType OBJECT IDENTIFIER, + * oriValue ANY DEFINED BY oriType } + *+ */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(oriType); + v.add(oriValue); + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/PasswordRecipientInfo.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/PasswordRecipientInfo.java new file mode 100644 index 0000000..1bc3da3 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/PasswordRecipientInfo.java @@ -0,0 +1,143 @@ +package org.bc.asn1.cms; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1OctetString; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERSequence; +import org.bc.asn1.DERTaggedObject; +import org.bc.asn1.x509.AlgorithmIdentifier; + +public class PasswordRecipientInfo + extends ASN1Object +{ + private ASN1Integer version; + private AlgorithmIdentifier keyDerivationAlgorithm; + private AlgorithmIdentifier keyEncryptionAlgorithm; + private ASN1OctetString encryptedKey; + + public PasswordRecipientInfo( + AlgorithmIdentifier keyEncryptionAlgorithm, + ASN1OctetString encryptedKey) + { + this.version = new ASN1Integer(0); + this.keyEncryptionAlgorithm = keyEncryptionAlgorithm; + this.encryptedKey = encryptedKey; + } + + public PasswordRecipientInfo( + AlgorithmIdentifier keyDerivationAlgorithm, + AlgorithmIdentifier keyEncryptionAlgorithm, + ASN1OctetString encryptedKey) + { + this.version = new ASN1Integer(0); + this.keyDerivationAlgorithm = keyDerivationAlgorithm; + this.keyEncryptionAlgorithm = keyEncryptionAlgorithm; + this.encryptedKey = encryptedKey; + } + + public PasswordRecipientInfo( + ASN1Sequence seq) + { + version = (ASN1Integer)seq.getObjectAt(0); + if (seq.getObjectAt(1) instanceof ASN1TaggedObject) + { + keyDerivationAlgorithm = AlgorithmIdentifier.getInstance((ASN1TaggedObject)seq.getObjectAt(1), false); + keyEncryptionAlgorithm = AlgorithmIdentifier.getInstance(seq.getObjectAt(2)); + encryptedKey = (ASN1OctetString)seq.getObjectAt(3); + } + else + { + keyEncryptionAlgorithm = AlgorithmIdentifier.getInstance(seq.getObjectAt(1)); + encryptedKey = (ASN1OctetString)seq.getObjectAt(2); + } + } + + /** + * return a PasswordRecipientInfo object from a tagged object. + * + * @param obj the tagged object holding the object we want. + * @param explicit true if the object is meant to be explicitly + * tagged false otherwise. + * @exception IllegalArgumentException if the object held by the + * tagged object cannot be converted. + */ + public static PasswordRecipientInfo getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + /** + * return a PasswordRecipientInfo object from the given object. + * + * @param obj the object we want converted. + * @exception IllegalArgumentException if the object cannot be converted. + */ + public static PasswordRecipientInfo getInstance( + Object obj) + { + if (obj == null || obj instanceof PasswordRecipientInfo) + { + return (PasswordRecipientInfo)obj; + } + + if(obj instanceof ASN1Sequence) + { + return new PasswordRecipientInfo((ASN1Sequence)obj); + } + + throw new IllegalArgumentException("Invalid PasswordRecipientInfo: " + obj.getClass().getName()); + } + + public ASN1Integer getVersion() + { + return version; + } + + public AlgorithmIdentifier getKeyDerivationAlgorithm() + { + return keyDerivationAlgorithm; + } + + public AlgorithmIdentifier getKeyEncryptionAlgorithm() + { + return keyEncryptionAlgorithm; + } + + public ASN1OctetString getEncryptedKey() + { + return encryptedKey; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + *
+ * PasswordRecipientInfo ::= SEQUENCE { + * version CMSVersion, -- Always set to 0 + * keyDerivationAlgorithm [0] KeyDerivationAlgorithmIdentifier + * OPTIONAL, + * keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier, + * encryptedKey EncryptedKey } + *+ */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(version); + + if (keyDerivationAlgorithm != null) + { + v.add(new DERTaggedObject(false, 0, keyDerivationAlgorithm)); + } + v.add(keyEncryptionAlgorithm); + v.add(encryptedKey); + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/RecipientEncryptedKey.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/RecipientEncryptedKey.java new file mode 100644 index 0000000..b888a69 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/RecipientEncryptedKey.java @@ -0,0 +1,99 @@ +package org.bc.asn1.cms; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1OctetString; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERSequence; + + +public class RecipientEncryptedKey + extends ASN1Object +{ + private KeyAgreeRecipientIdentifier identifier; + private ASN1OctetString encryptedKey; + + private RecipientEncryptedKey( + ASN1Sequence seq) + { + identifier = KeyAgreeRecipientIdentifier.getInstance(seq.getObjectAt(0)); + encryptedKey = (ASN1OctetString)seq.getObjectAt(1); + } + + /** + * return an RecipientEncryptedKey object from a tagged object. + * + * @param obj the tagged object holding the object we want. + * @param explicit true if the object is meant to be explicitly + * tagged false otherwise. + * @exception IllegalArgumentException if the object held by the + * tagged object cannot be converted. + */ + public static RecipientEncryptedKey getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + /** + * return a RecipientEncryptedKey object from the given object. + * + * @param obj the object we want converted. + * @exception IllegalArgumentException if the object cannot be converted. + */ + public static RecipientEncryptedKey getInstance( + Object obj) + { + if (obj == null || obj instanceof RecipientEncryptedKey) + { + return (RecipientEncryptedKey)obj; + } + + if (obj instanceof ASN1Sequence) + { + return new RecipientEncryptedKey((ASN1Sequence)obj); + } + + throw new IllegalArgumentException("Invalid RecipientEncryptedKey: " + obj.getClass().getName()); + } + + public RecipientEncryptedKey( + KeyAgreeRecipientIdentifier id, + ASN1OctetString encryptedKey) + { + this.identifier = id; + this.encryptedKey = encryptedKey; + } + + public KeyAgreeRecipientIdentifier getIdentifier() + { + return identifier; + } + + public ASN1OctetString getEncryptedKey() + { + return encryptedKey; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + *
+ * RecipientEncryptedKey ::= SEQUENCE { + * rid KeyAgreeRecipientIdentifier, + * encryptedKey EncryptedKey + * } + *+ */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(identifier); + v.add(encryptedKey); + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/RecipientIdentifier.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/RecipientIdentifier.java new file mode 100644 index 0000000..e2a51ab --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/RecipientIdentifier.java @@ -0,0 +1,98 @@ +package org.bc.asn1.cms; + +import org.bc.asn1.ASN1Choice; +import org.bc.asn1.ASN1Encodable; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1OctetString; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERTaggedObject; + +public class RecipientIdentifier + extends ASN1Object + implements ASN1Choice +{ + private ASN1Encodable id; + + public RecipientIdentifier( + IssuerAndSerialNumber id) + { + this.id = id; + } + + public RecipientIdentifier( + ASN1OctetString id) + { + this.id = new DERTaggedObject(false, 0, id); + } + + public RecipientIdentifier( + ASN1Primitive id) + { + this.id = id; + } + + /** + * return a RecipientIdentifier object from the given object. + * + * @param o the object we want converted. + * @exception IllegalArgumentException if the object cannot be converted. + */ + public static RecipientIdentifier getInstance( + Object o) + { + if (o == null || o instanceof RecipientIdentifier) + { + return (RecipientIdentifier)o; + } + + if (o instanceof IssuerAndSerialNumber) + { + return new RecipientIdentifier((IssuerAndSerialNumber)o); + } + + if (o instanceof ASN1OctetString) + { + return new RecipientIdentifier((ASN1OctetString)o); + } + + if (o instanceof ASN1Primitive) + { + return new RecipientIdentifier((ASN1Primitive)o); + } + + throw new IllegalArgumentException( + "Illegal object in RecipientIdentifier: " + o.getClass().getName()); + } + + public boolean isTagged() + { + return (id instanceof ASN1TaggedObject); + } + + public ASN1Encodable getId() + { + if (id instanceof ASN1TaggedObject) + { + return ASN1OctetString.getInstance((ASN1TaggedObject)id, false); + } + + return IssuerAndSerialNumber.getInstance(id); + } + + /** + * Produce an object suitable for an ASN1OutputStream. + *
+ * RecipientIdentifier ::= CHOICE { + * issuerAndSerialNumber IssuerAndSerialNumber, + * subjectKeyIdentifier [0] SubjectKeyIdentifier + * } + * + * SubjectKeyIdentifier ::= OCTET STRING + *+ */ + public ASN1Primitive toASN1Primitive() + { + return id.toASN1Primitive(); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/RecipientInfo.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/RecipientInfo.java new file mode 100644 index 0000000..11aba6d --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/RecipientInfo.java @@ -0,0 +1,154 @@ +package org.bc.asn1.cms; + +import org.bc.asn1.ASN1Choice; +import org.bc.asn1.ASN1Encodable; +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERTaggedObject; + +public class RecipientInfo + extends ASN1Object + implements ASN1Choice +{ + ASN1Encodable info; + + public RecipientInfo( + KeyTransRecipientInfo info) + { + this.info = info; + } + + public RecipientInfo( + KeyAgreeRecipientInfo info) + { + this.info = new DERTaggedObject(false, 1, info); + } + + public RecipientInfo( + KEKRecipientInfo info) + { + this.info = new DERTaggedObject(false, 2, info); + } + + public RecipientInfo( + PasswordRecipientInfo info) + { + this.info = new DERTaggedObject(false, 3, info); + } + + public RecipientInfo( + OtherRecipientInfo info) + { + this.info = new DERTaggedObject(false, 4, info); + } + + public RecipientInfo( + ASN1Primitive info) + { + this.info = info; + } + + public static RecipientInfo getInstance( + Object o) + { + if (o == null || o instanceof RecipientInfo) + { + return (RecipientInfo)o; + } + else if (o instanceof ASN1Sequence) + { + return new RecipientInfo((ASN1Sequence)o); + } + else if (o instanceof ASN1TaggedObject) + { + return new RecipientInfo((ASN1TaggedObject)o); + } + + throw new IllegalArgumentException("unknown object in factory: " + + o.getClass().getName()); + } + + public ASN1Integer getVersion() + { + if (info instanceof ASN1TaggedObject) + { + ASN1TaggedObject o = (ASN1TaggedObject)info; + + switch (o.getTagNo()) + { + case 1: + return KeyAgreeRecipientInfo.getInstance(o, false).getVersion(); + case 2: + return getKEKInfo(o).getVersion(); + case 3: + return PasswordRecipientInfo.getInstance(o, false).getVersion(); + case 4: + return new ASN1Integer(0); // no syntax version for OtherRecipientInfo + default: + throw new IllegalStateException("unknown tag"); + } + } + + return KeyTransRecipientInfo.getInstance(info).getVersion(); + } + + public boolean isTagged() + { + return (info instanceof ASN1TaggedObject); + } + + public ASN1Encodable getInfo() + { + if (info instanceof ASN1TaggedObject) + { + ASN1TaggedObject o = (ASN1TaggedObject)info; + + switch (o.getTagNo()) + { + case 1: + return KeyAgreeRecipientInfo.getInstance(o, false); + case 2: + return getKEKInfo(o); + case 3: + return PasswordRecipientInfo.getInstance(o, false); + case 4: + return OtherRecipientInfo.getInstance(o, false); + default: + throw new IllegalStateException("unknown tag"); + } + } + + return KeyTransRecipientInfo.getInstance(info); + } + + private KEKRecipientInfo getKEKInfo(ASN1TaggedObject o) + { + if (o.isExplicit()) + { // compatibilty with erroneous version + return KEKRecipientInfo.getInstance(o, true); + } + else + { + return KEKRecipientInfo.getInstance(o, false); + } + } + + /** + * Produce an object suitable for an ASN1OutputStream. + *
+ * RecipientInfo ::= CHOICE { + * ktri KeyTransRecipientInfo, + * kari [1] KeyAgreeRecipientInfo, + * kekri [2] KEKRecipientInfo, + * pwri [3] PasswordRecipientInfo, + * ori [4] OtherRecipientInfo } + *+ */ + public ASN1Primitive toASN1Primitive() + { + return info.toASN1Primitive(); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/RecipientKeyIdentifier.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/RecipientKeyIdentifier.java new file mode 100644 index 0000000..a76c099 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/RecipientKeyIdentifier.java @@ -0,0 +1,156 @@ +package org.bc.asn1.cms; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1OctetString; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERGeneralizedTime; +import org.bc.asn1.DEROctetString; +import org.bc.asn1.DERSequence; + +public class RecipientKeyIdentifier + extends ASN1Object +{ + private ASN1OctetString subjectKeyIdentifier; + private DERGeneralizedTime date; + private OtherKeyAttribute other; + + public RecipientKeyIdentifier( + ASN1OctetString subjectKeyIdentifier, + DERGeneralizedTime date, + OtherKeyAttribute other) + { + this.subjectKeyIdentifier = subjectKeyIdentifier; + this.date = date; + this.other = other; + } + + public RecipientKeyIdentifier( + byte[] subjectKeyIdentifier, + DERGeneralizedTime date, + OtherKeyAttribute other) + { + this.subjectKeyIdentifier = new DEROctetString(subjectKeyIdentifier); + this.date = date; + this.other = other; + } + + public RecipientKeyIdentifier( + byte[] subjectKeyIdentifier) + { + this(subjectKeyIdentifier, null, null); + } + + public RecipientKeyIdentifier( + ASN1Sequence seq) + { + subjectKeyIdentifier = ASN1OctetString.getInstance( + seq.getObjectAt(0)); + + switch(seq.size()) + { + case 1: + break; + case 2: + if (seq.getObjectAt(1) instanceof DERGeneralizedTime) + { + date = (DERGeneralizedTime)seq.getObjectAt(1); + } + else + { + other = OtherKeyAttribute.getInstance(seq.getObjectAt(2)); + } + break; + case 3: + date = (DERGeneralizedTime)seq.getObjectAt(1); + other = OtherKeyAttribute.getInstance(seq.getObjectAt(2)); + break; + default: + throw new IllegalArgumentException("Invalid RecipientKeyIdentifier"); + } + } + + /** + * return a RecipientKeyIdentifier object from a tagged object. + * + * @param _ato the tagged object holding the object we want. + * @param _explicit true if the object is meant to be explicitly + * tagged false otherwise. + * @exception IllegalArgumentException if the object held by the + * tagged object cannot be converted. + */ + public static RecipientKeyIdentifier getInstance(ASN1TaggedObject _ato, boolean _explicit) + { + return getInstance(ASN1Sequence.getInstance(_ato, _explicit)); + } + + /** + * return a RecipientKeyIdentifier object from the given object. + * + * @param _obj the object we want converted. + * @exception IllegalArgumentException if the object cannot be converted. + */ + public static RecipientKeyIdentifier getInstance(Object _obj) + { + if(_obj == null || _obj instanceof RecipientKeyIdentifier) + { + return (RecipientKeyIdentifier)_obj; + } + + if(_obj instanceof ASN1Sequence) + { + return new RecipientKeyIdentifier((ASN1Sequence)_obj); + } + + throw new IllegalArgumentException("Invalid RecipientKeyIdentifier: " + _obj.getClass().getName()); + } + + public ASN1OctetString getSubjectKeyIdentifier() + { + return subjectKeyIdentifier; + } + + public DERGeneralizedTime getDate() + { + return date; + } + + public OtherKeyAttribute getOtherKeyAttribute() + { + return other; + } + + + /** + * Produce an object suitable for an ASN1OutputStream. + *
+ * RecipientKeyIdentifier ::= SEQUENCE { + * subjectKeyIdentifier SubjectKeyIdentifier, + * date GeneralizedTime OPTIONAL, + * other OtherKeyAttribute OPTIONAL + * } + * + * SubjectKeyIdentifier ::= OCTET STRING + *+ */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(subjectKeyIdentifier); + + if (date != null) + { + v.add(date); + } + + if (other != null) + { + v.add(other); + } + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/SignedData.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/SignedData.java new file mode 100644 index 0000000..beec6b3 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/SignedData.java @@ -0,0 +1,302 @@ +package org.bc.asn1.cms; + +import java.util.Enumeration; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1ObjectIdentifier; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1Set; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.BERSequence; +import org.bc.asn1.BERSet; +import org.bc.asn1.BERTaggedObject; +import org.bc.asn1.DERTaggedObject; + +/** + * a signed data object. + */ +public class SignedData + extends ASN1Object +{ + private ASN1Integer version; + private ASN1Set digestAlgorithms; + private ContentInfo contentInfo; + private ASN1Set certificates; + private ASN1Set crls; + private ASN1Set signerInfos; + private boolean certsBer; + private boolean crlsBer; + + public static SignedData getInstance( + Object o) + { + if (o instanceof SignedData) + { + return (SignedData)o; + } + else if (o != null) + { + return new SignedData(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public SignedData( + ASN1Set digestAlgorithms, + ContentInfo contentInfo, + ASN1Set certificates, + ASN1Set crls, + ASN1Set signerInfos) + { + this.version = calculateVersion(contentInfo.getContentType(), certificates, crls, signerInfos); + this.digestAlgorithms = digestAlgorithms; + this.contentInfo = contentInfo; + this.certificates = certificates; + this.crls = crls; + this.signerInfos = signerInfos; + this.crlsBer = crls instanceof BERSet; + this.certsBer = certificates instanceof BERSet; + } + + + // RFC3852, section 5.1: + // IF ((certificates is present) AND + // (any certificates with a type of other are present)) OR + // ((crls is present) AND + // (any crls with a type of other are present)) + // THEN version MUST be 5 + // ELSE + // IF (certificates is present) AND + // (any version 2 attribute certificates are present) + // THEN version MUST be 4 + // ELSE + // IF ((certificates is present) AND + // (any version 1 attribute certificates are present)) OR + // (any SignerInfo structures are version 3) OR + // (encapContentInfo eContentType is other than id-data) + // THEN version MUST be 3 + // ELSE version MUST be 1 + // + private ASN1Integer calculateVersion( + ASN1ObjectIdentifier contentOid, + ASN1Set certs, + ASN1Set crls, + ASN1Set signerInfs) + { + boolean otherCert = false; + boolean otherCrl = false; + boolean attrCertV1Found = false; + boolean attrCertV2Found = false; + + if (certs != null) + { + for (Enumeration en = certs.getObjects(); en.hasMoreElements();) + { + Object obj = en.nextElement(); + if (obj instanceof ASN1TaggedObject) + { + ASN1TaggedObject tagged = ASN1TaggedObject.getInstance(obj); + + if (tagged.getTagNo() == 1) + { + attrCertV1Found = true; + } + else if (tagged.getTagNo() == 2) + { + attrCertV2Found = true; + } + else if (tagged.getTagNo() == 3) + { + otherCert = true; + } + } + } + } + + if (otherCert) + { + return new ASN1Integer(5); + } + + if (crls != null) // no need to check if otherCert is true + { + for (Enumeration en = crls.getObjects(); en.hasMoreElements();) + { + Object obj = en.nextElement(); + if (obj instanceof ASN1TaggedObject) + { + otherCrl = true; + } + } + } + + if (otherCrl) + { + return new ASN1Integer(5); + } + + if (attrCertV2Found) + { + return new ASN1Integer(4); + } + + if (attrCertV1Found) + { + return new ASN1Integer(3); + } + + if (checkForVersion3(signerInfs)) + { + return new ASN1Integer(3); + } + + if (!CMSObjectIdentifiers.data.equals(contentOid)) + { + return new ASN1Integer(3); + } + + return new ASN1Integer(1); + } + + private boolean checkForVersion3(ASN1Set signerInfs) + { + for (Enumeration e = signerInfs.getObjects(); e.hasMoreElements();) + { + SignerInfo s = SignerInfo.getInstance(e.nextElement()); + + if (s.getVersion().getValue().intValue() == 3) + { + return true; + } + } + + return false; + } + + private SignedData( + ASN1Sequence seq) + { + Enumeration e = seq.getObjects(); + + version = ASN1Integer.getInstance(e.nextElement()); + digestAlgorithms = ((ASN1Set)e.nextElement()); + contentInfo = ContentInfo.getInstance(e.nextElement()); + + while (e.hasMoreElements()) + { + ASN1Primitive o = (ASN1Primitive)e.nextElement(); + + // + // an interesting feature of SignedData is that there appear + // to be varying implementations... + // for the moment we ignore anything which doesn't fit. + // + if (o instanceof ASN1TaggedObject) + { + ASN1TaggedObject tagged = (ASN1TaggedObject)o; + + switch (tagged.getTagNo()) + { + case 0: + certsBer = tagged instanceof BERTaggedObject; + certificates = ASN1Set.getInstance(tagged, false); + break; + case 1: + crlsBer = tagged instanceof BERTaggedObject; + crls = ASN1Set.getInstance(tagged, false); + break; + default: + throw new IllegalArgumentException("unknown tag value " + tagged.getTagNo()); + } + } + else + { + signerInfos = (ASN1Set)o; + } + } + } + + public ASN1Integer getVersion() + { + return version; + } + + public ASN1Set getDigestAlgorithms() + { + return digestAlgorithms; + } + + public ContentInfo getEncapContentInfo() + { + return contentInfo; + } + + public ASN1Set getCertificates() + { + return certificates; + } + + public ASN1Set getCRLs() + { + return crls; + } + + public ASN1Set getSignerInfos() + { + return signerInfos; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + *
+ * SignedData ::= SEQUENCE { + * version CMSVersion, + * digestAlgorithms DigestAlgorithmIdentifiers, + * encapContentInfo EncapsulatedContentInfo, + * certificates [0] IMPLICIT CertificateSet OPTIONAL, + * crls [1] IMPLICIT CertificateRevocationLists OPTIONAL, + * signerInfos SignerInfos + * } + *+ */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(version); + v.add(digestAlgorithms); + v.add(contentInfo); + + if (certificates != null) + { + if (certsBer) + { + v.add(new BERTaggedObject(false, 0, certificates)); + } + else + { + v.add(new DERTaggedObject(false, 0, certificates)); + } + } + + if (crls != null) + { + if (crlsBer) + { + v.add(new BERTaggedObject(false, 1, crls)); + } + else + { + v.add(new DERTaggedObject(false, 1, crls)); + } + } + + v.add(signerInfos); + + return new BERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/SignedDataParser.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/SignedDataParser.java new file mode 100644 index 0000000..426a6d0 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/SignedDataParser.java @@ -0,0 +1,139 @@ +package org.bc.asn1.cms; + +import java.io.IOException; + +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1SequenceParser; +import org.bc.asn1.ASN1Set; +import org.bc.asn1.ASN1SetParser; +import org.bc.asn1.ASN1TaggedObjectParser; +import org.bc.asn1.BERTags; + +/** + *
+ * SignedData ::= SEQUENCE { + * version CMSVersion, + * digestAlgorithms DigestAlgorithmIdentifiers, + * encapContentInfo EncapsulatedContentInfo, + * certificates [0] IMPLICIT CertificateSet OPTIONAL, + * crls [1] IMPLICIT CertificateRevocationLists OPTIONAL, + * signerInfos SignerInfos + * } + *+ */ +public class SignedDataParser +{ + private ASN1SequenceParser _seq; + private ASN1Integer _version; + private Object _nextObject; + private boolean _certsCalled; + private boolean _crlsCalled; + + public static SignedDataParser getInstance( + Object o) + throws IOException + { + if (o instanceof ASN1Sequence) + { + return new SignedDataParser(((ASN1Sequence)o).parser()); + } + if (o instanceof ASN1SequenceParser) + { + return new SignedDataParser((ASN1SequenceParser)o); + } + + throw new IOException("unknown object encountered: " + o.getClass().getName()); + } + + private SignedDataParser( + ASN1SequenceParser seq) + throws IOException + { + this._seq = seq; + this._version = (ASN1Integer)seq.readObject(); + } + + public ASN1Integer getVersion() + { + return _version; + } + + public ASN1SetParser getDigestAlgorithms() + throws IOException + { + Object o = _seq.readObject(); + + if (o instanceof ASN1Set) + { + return ((ASN1Set)o).parser(); + } + + return (ASN1SetParser)o; + } + + public ContentInfoParser getEncapContentInfo() + throws IOException + { + return new ContentInfoParser((ASN1SequenceParser)_seq.readObject()); + } + + public ASN1SetParser getCertificates() + throws IOException + { + _certsCalled = true; + _nextObject = _seq.readObject(); + + if (_nextObject instanceof ASN1TaggedObjectParser && ((ASN1TaggedObjectParser)_nextObject).getTagNo() == 0) + { + ASN1SetParser certs = (ASN1SetParser)((ASN1TaggedObjectParser)_nextObject).getObjectParser(BERTags.SET, false); + _nextObject = null; + + return certs; + } + + return null; + } + + public ASN1SetParser getCrls() + throws IOException + { + if (!_certsCalled) + { + throw new IOException("getCerts() has not been called."); + } + + _crlsCalled = true; + + if (_nextObject == null) + { + _nextObject = _seq.readObject(); + } + + if (_nextObject instanceof ASN1TaggedObjectParser && ((ASN1TaggedObjectParser)_nextObject).getTagNo() == 1) + { + ASN1SetParser crls = (ASN1SetParser)((ASN1TaggedObjectParser)_nextObject).getObjectParser(BERTags.SET, false); + _nextObject = null; + + return crls; + } + + return null; + } + + public ASN1SetParser getSignerInfos() + throws IOException + { + if (!_certsCalled || !_crlsCalled) + { + throw new IOException("getCerts() and/or getCrls() has not been called."); + } + + if (_nextObject == null) + { + _nextObject = _seq.readObject(); + } + + return (ASN1SetParser)_nextObject; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/SignerIdentifier.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/SignerIdentifier.java new file mode 100644 index 0000000..6ef574d --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/SignerIdentifier.java @@ -0,0 +1,98 @@ +package org.bc.asn1.cms; + +import org.bc.asn1.ASN1Choice; +import org.bc.asn1.ASN1Encodable; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1OctetString; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERTaggedObject; + +public class SignerIdentifier + extends ASN1Object + implements ASN1Choice +{ + private ASN1Encodable id; + + public SignerIdentifier( + IssuerAndSerialNumber id) + { + this.id = id; + } + + public SignerIdentifier( + ASN1OctetString id) + { + this.id = new DERTaggedObject(false, 0, id); + } + + public SignerIdentifier( + ASN1Primitive id) + { + this.id = id; + } + + /** + * return a SignerIdentifier object from the given object. + * + * @param o the object we want converted. + * @exception IllegalArgumentException if the object cannot be converted. + */ + public static SignerIdentifier getInstance( + Object o) + { + if (o == null || o instanceof SignerIdentifier) + { + return (SignerIdentifier)o; + } + + if (o instanceof IssuerAndSerialNumber) + { + return new SignerIdentifier((IssuerAndSerialNumber)o); + } + + if (o instanceof ASN1OctetString) + { + return new SignerIdentifier((ASN1OctetString)o); + } + + if (o instanceof ASN1Primitive) + { + return new SignerIdentifier((ASN1Primitive)o); + } + + throw new IllegalArgumentException( + "Illegal object in SignerIdentifier: " + o.getClass().getName()); + } + + public boolean isTagged() + { + return (id instanceof ASN1TaggedObject); + } + + public ASN1Encodable getId() + { + if (id instanceof ASN1TaggedObject) + { + return ASN1OctetString.getInstance((ASN1TaggedObject)id, false); + } + + return id; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + *
+ * SignerIdentifier ::= CHOICE { + * issuerAndSerialNumber IssuerAndSerialNumber, + * subjectKeyIdentifier [0] SubjectKeyIdentifier + * } + * + * SubjectKeyIdentifier ::= OCTET STRING + *+ */ + public ASN1Primitive toASN1Primitive() + { + return id.toASN1Primitive(); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/SignerInfo.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/SignerInfo.java new file mode 100644 index 0000000..5a874a8 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/SignerInfo.java @@ -0,0 +1,183 @@ +package org.bc.asn1.cms; + +import java.util.Enumeration; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1OctetString; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1Set; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DEROctetString; +import org.bc.asn1.DERSequence; +import org.bc.asn1.DERTaggedObject; +import org.bc.asn1.x509.AlgorithmIdentifier; + +public class SignerInfo + extends ASN1Object +{ + private ASN1Integer version; + private SignerIdentifier sid; + private AlgorithmIdentifier digAlgorithm; + private ASN1Set authenticatedAttributes; + private AlgorithmIdentifier digEncryptionAlgorithm; + private ASN1OctetString encryptedDigest; + private ASN1Set unauthenticatedAttributes; + + public static SignerInfo getInstance( + Object o) + throws IllegalArgumentException + { + if (o == null || o instanceof SignerInfo) + { + return (SignerInfo)o; + } + else if (o instanceof ASN1Sequence) + { + return new SignerInfo((ASN1Sequence)o); + } + + throw new IllegalArgumentException("unknown object in factory: " + o.getClass().getName()); + } + + public SignerInfo( + SignerIdentifier sid, + AlgorithmIdentifier digAlgorithm, + ASN1Set authenticatedAttributes, + AlgorithmIdentifier digEncryptionAlgorithm, + ASN1OctetString encryptedDigest, + ASN1Set unauthenticatedAttributes) + { + if (sid.isTagged()) + { + this.version = new ASN1Integer(3); + } + else + { + this.version = new ASN1Integer(1); + } + + this.sid = sid; + this.digAlgorithm = digAlgorithm; + this.authenticatedAttributes = authenticatedAttributes; + this.digEncryptionAlgorithm = digEncryptionAlgorithm; + this.encryptedDigest = encryptedDigest; + this.unauthenticatedAttributes = unauthenticatedAttributes; + } + + public SignerInfo( + ASN1Sequence seq) + { + Enumeration e = seq.getObjects(); + + version = (ASN1Integer)e.nextElement(); + sid = SignerIdentifier.getInstance(e.nextElement()); + digAlgorithm = AlgorithmIdentifier.getInstance(e.nextElement()); + + Object obj = e.nextElement(); + + if (obj instanceof ASN1TaggedObject) + { + authenticatedAttributes = ASN1Set.getInstance((ASN1TaggedObject)obj, false); + + digEncryptionAlgorithm = AlgorithmIdentifier.getInstance(e.nextElement()); + } + else + { + authenticatedAttributes = null; + digEncryptionAlgorithm = AlgorithmIdentifier.getInstance(obj); + } + + encryptedDigest = DEROctetString.getInstance(e.nextElement()); + + if (e.hasMoreElements()) + { + unauthenticatedAttributes = ASN1Set.getInstance((ASN1TaggedObject)e.nextElement(), false); + } + else + { + unauthenticatedAttributes = null; + } + } + + public ASN1Integer getVersion() + { + return version; + } + + public SignerIdentifier getSID() + { + return sid; + } + + public ASN1Set getAuthenticatedAttributes() + { + return authenticatedAttributes; + } + + public AlgorithmIdentifier getDigestAlgorithm() + { + return digAlgorithm; + } + + public ASN1OctetString getEncryptedDigest() + { + return encryptedDigest; + } + + public AlgorithmIdentifier getDigestEncryptionAlgorithm() + { + return digEncryptionAlgorithm; + } + + public ASN1Set getUnauthenticatedAttributes() + { + return unauthenticatedAttributes; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + *
+ * SignerInfo ::= SEQUENCE { + * version Version, + * SignerIdentifier sid, + * digestAlgorithm DigestAlgorithmIdentifier, + * authenticatedAttributes [0] IMPLICIT Attributes OPTIONAL, + * digestEncryptionAlgorithm DigestEncryptionAlgorithmIdentifier, + * encryptedDigest EncryptedDigest, + * unauthenticatedAttributes [1] IMPLICIT Attributes OPTIONAL + * } + * + * EncryptedDigest ::= OCTET STRING + * + * DigestAlgorithmIdentifier ::= AlgorithmIdentifier + * + * DigestEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier + *+ */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(version); + v.add(sid); + v.add(digAlgorithm); + + if (authenticatedAttributes != null) + { + v.add(new DERTaggedObject(false, 0, authenticatedAttributes)); + } + + v.add(digEncryptionAlgorithm); + v.add(encryptedDigest); + + if (unauthenticatedAttributes != null) + { + v.add(new DERTaggedObject(false, 1, unauthenticatedAttributes)); + } + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/Time.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/Time.java new file mode 100644 index 0000000..bff2b51 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/Time.java @@ -0,0 +1,128 @@ +package org.bc.asn1.cms; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.SimpleTimeZone; + +import org.bc.asn1.ASN1Choice; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERGeneralizedTime; +import org.bc.asn1.DERUTCTime; + +public class Time + extends ASN1Object + implements ASN1Choice +{ + ASN1Primitive time; + + public static Time getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(obj.getObject()); + } + + public Time( + ASN1Primitive time) + { + if (!(time instanceof DERUTCTime) + && !(time instanceof DERGeneralizedTime)) + { + throw new IllegalArgumentException("unknown object passed to Time"); + } + + this.time = time; + } + + /** + * creates a time object from a given date - if the date is between 1950 + * and 2049 a UTCTime object is generated, otherwise a GeneralizedTime + * is used. + */ + public Time( + Date date) + { + SimpleTimeZone tz = new SimpleTimeZone(0, "Z"); + SimpleDateFormat dateF = new SimpleDateFormat("yyyyMMddHHmmss"); + + dateF.setTimeZone(tz); + + String d = dateF.format(date) + "Z"; + int year = Integer.parseInt(d.substring(0, 4)); + + if (year < 1950 || year > 2049) + { + time = new DERGeneralizedTime(d); + } + else + { + time = new DERUTCTime(d.substring(2)); + } + } + + public static Time getInstance( + Object obj) + { + if (obj == null || obj instanceof Time) + { + return (Time)obj; + } + else if (obj instanceof DERUTCTime) + { + return new Time((DERUTCTime)obj); + } + else if (obj instanceof DERGeneralizedTime) + { + return new Time((DERGeneralizedTime)obj); + } + + throw new IllegalArgumentException("unknown object in factory: " + obj.getClass().getName()); + } + + public String getTime() + { + if (time instanceof DERUTCTime) + { + return ((DERUTCTime)time).getAdjustedTime(); + } + else + { + return ((DERGeneralizedTime)time).getTime(); + } + } + + public Date getDate() + { + try + { + if (time instanceof DERUTCTime) + { + return ((DERUTCTime)time).getAdjustedDate(); + } + else + { + return ((DERGeneralizedTime)time).getDate(); + } + } + catch (ParseException e) + { // this should never happen + throw new IllegalStateException("invalid date string: " + e.getMessage()); + } + } + + /** + * Produce an object suitable for an ASN1OutputStream. + *
+ * Time ::= CHOICE { + * utcTime UTCTime, + * generalTime GeneralizedTime } + *+ */ + public ASN1Primitive toASN1Primitive() + { + return time; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/TimeStampAndCRL.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/TimeStampAndCRL.java new file mode 100644 index 0000000..c4beb63 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/TimeStampAndCRL.java @@ -0,0 +1,82 @@ +package org.bc.asn1.cms; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DERSequence; +import org.bc.asn1.x509.CertificateList; + +public class TimeStampAndCRL + extends ASN1Object +{ + private ContentInfo timeStamp; + private CertificateList crl; + + public TimeStampAndCRL(ContentInfo timeStamp) + { + this.timeStamp = timeStamp; + } + + private TimeStampAndCRL(ASN1Sequence seq) + { + this.timeStamp = ContentInfo.getInstance(seq.getObjectAt(0)); + if (seq.size() == 2) + { + this.crl = CertificateList.getInstance(seq.getObjectAt(1)); + } + } + + public static TimeStampAndCRL getInstance(Object obj) + { + if (obj instanceof TimeStampAndCRL) + { + return (TimeStampAndCRL)obj; + } + else if (obj != null) + { + return new TimeStampAndCRL(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public ContentInfo getTimeStampToken() + { + return this.timeStamp; + } + + /** @deprecated use getCRL() */ + public CertificateList getCertificateList() + { + return this.crl; + } + + public CertificateList getCRL() + { + return this.crl; + } + + /** + *
+ * TimeStampAndCRL ::= SEQUENCE { + * timeStamp TimeStampToken, -- according to RFC 3161 + * crl CertificateList OPTIONAL -- according to RFC 5280 + * } + *+ * @return + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(timeStamp); + + if (crl != null) + { + v.add(crl); + } + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/TimeStampTokenEvidence.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/TimeStampTokenEvidence.java new file mode 100644 index 0000000..9e6eb6b --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/TimeStampTokenEvidence.java @@ -0,0 +1,84 @@ +package org.bc.asn1.cms; + +import java.util.Enumeration; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERSequence; + +public class TimeStampTokenEvidence + extends ASN1Object +{ + private TimeStampAndCRL[] timeStampAndCRLs; + + public TimeStampTokenEvidence(TimeStampAndCRL[] timeStampAndCRLs) + { + this.timeStampAndCRLs = timeStampAndCRLs; + } + + public TimeStampTokenEvidence(TimeStampAndCRL timeStampAndCRL) + { + this.timeStampAndCRLs = new TimeStampAndCRL[1]; + + timeStampAndCRLs[0] = timeStampAndCRL; + } + + private TimeStampTokenEvidence(ASN1Sequence seq) + { + this.timeStampAndCRLs = new TimeStampAndCRL[seq.size()]; + + int count = 0; + + for (Enumeration en = seq.getObjects(); en.hasMoreElements();) + { + timeStampAndCRLs[count++] = TimeStampAndCRL.getInstance(en.nextElement()); + } + } + + public static TimeStampTokenEvidence getInstance(ASN1TaggedObject tagged, boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(tagged, explicit)); + } + + public static TimeStampTokenEvidence getInstance(Object obj) + { + if (obj instanceof TimeStampTokenEvidence) + { + return (TimeStampTokenEvidence)obj; + } + else if (obj != null) + { + return new TimeStampTokenEvidence(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public TimeStampAndCRL[] toTimeStampAndCRLArray() + { + return timeStampAndCRLs; + } + + /** + *
+ * TimeStampTokenEvidence ::= + * SEQUENCE SIZE(1..MAX) OF TimeStampAndCRL + *+ * @return + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + for (int i = 0; i != timeStampAndCRLs.length; i++) + { + v.add(timeStampAndCRLs[i]); + } + + return new DERSequence(v); + } + +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/TimeStampedData.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/TimeStampedData.java new file mode 100644 index 0000000..a2daa1b --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/TimeStampedData.java @@ -0,0 +1,121 @@ +package org.bc.asn1.cms; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1OctetString; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.BERSequence; +import org.bc.asn1.DERIA5String; + +public class TimeStampedData + extends ASN1Object +{ + private ASN1Integer version; + private DERIA5String dataUri; + private MetaData metaData; + private ASN1OctetString content; + private Evidence temporalEvidence; + + public TimeStampedData(DERIA5String dataUri, MetaData metaData, ASN1OctetString content, Evidence temporalEvidence) + { + this.version = new ASN1Integer(1); + this.dataUri = dataUri; + this.metaData = metaData; + this.content = content; + this.temporalEvidence = temporalEvidence; + } + + private TimeStampedData(ASN1Sequence seq) + { + this.version = ASN1Integer.getInstance(seq.getObjectAt(0)); + + int index = 1; + if (seq.getObjectAt(index) instanceof DERIA5String) + { + this.dataUri = DERIA5String.getInstance(seq.getObjectAt(index++)); + } + if (seq.getObjectAt(index) instanceof MetaData || seq.getObjectAt(index) instanceof ASN1Sequence) + { + this.metaData = MetaData.getInstance(seq.getObjectAt(index++)); + } + if (seq.getObjectAt(index) instanceof ASN1OctetString) + { + this.content = ASN1OctetString.getInstance(seq.getObjectAt(index++)); + } + this.temporalEvidence = Evidence.getInstance(seq.getObjectAt(index)); + } + + public static TimeStampedData getInstance(Object obj) + { + if (obj instanceof TimeStampedData) + { + return (TimeStampedData)obj; + } + else if (obj != null) + { + return new TimeStampedData(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public DERIA5String getDataUri() + { + return dataUri; + } + + public MetaData getMetaData() + { + return metaData; + } + + public ASN1OctetString getContent() + { + return content; + } + + public Evidence getTemporalEvidence() + { + return temporalEvidence; + } + + /** + *
+ * TimeStampedData ::= SEQUENCE { + * version INTEGER { v1(1) }, + * dataUri IA5String OPTIONAL, + * metaData MetaData OPTIONAL, + * content OCTET STRING OPTIONAL, + * temporalEvidence Evidence + * } + *+ * @return + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(version); + + if (dataUri != null) + { + v.add(dataUri); + } + + if (metaData != null) + { + v.add(metaData); + } + + if (content != null) + { + v.add(content); + } + + v.add(temporalEvidence); + + return new BERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/TimeStampedDataParser.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/TimeStampedDataParser.java new file mode 100644 index 0000000..dfffc9c --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/TimeStampedDataParser.java @@ -0,0 +1,127 @@ +package org.bc.asn1.cms; + +import java.io.IOException; + +import org.bc.asn1.ASN1Encodable; +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1OctetStringParser; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1SequenceParser; +import org.bc.asn1.BERSequence; +import org.bc.asn1.DERIA5String; + +public class TimeStampedDataParser +{ + private ASN1Integer version; + private DERIA5String dataUri; + private MetaData metaData; + private ASN1OctetStringParser content; + private Evidence temporalEvidence; + private ASN1SequenceParser parser; + + private TimeStampedDataParser(ASN1SequenceParser parser) + throws IOException + { + this.parser = parser; + this.version = ASN1Integer.getInstance(parser.readObject()); + + ASN1Encodable obj = parser.readObject(); + + if (obj instanceof DERIA5String) + { + this.dataUri = DERIA5String.getInstance(obj); + obj = parser.readObject(); + } + if (obj instanceof MetaData || obj instanceof ASN1SequenceParser) + { + this.metaData = MetaData.getInstance(obj.toASN1Primitive()); + obj = parser.readObject(); + } + if (obj instanceof ASN1OctetStringParser) + { + this.content = (ASN1OctetStringParser)obj; + } + } + + public static TimeStampedDataParser getInstance(Object obj) + throws IOException + { + if (obj instanceof ASN1Sequence) + { + return new TimeStampedDataParser(((ASN1Sequence)obj).parser()); + } + if (obj instanceof ASN1SequenceParser) + { + return new TimeStampedDataParser((ASN1SequenceParser)obj); + } + + return null; + } + + public DERIA5String getDataUri() + { + return dataUri; + } + + public MetaData getMetaData() + { + return metaData; + } + + public ASN1OctetStringParser getContent() + { + return content; + } + + public Evidence getTemporalEvidence() + throws IOException + { + if (temporalEvidence == null) + { + temporalEvidence = Evidence.getInstance(parser.readObject().toASN1Primitive()); + } + + return temporalEvidence; + } + + /** + *
+ * TimeStampedData ::= SEQUENCE { + * version INTEGER { v1(1) }, + * dataUri IA5String OPTIONAL, + * metaData MetaData OPTIONAL, + * content OCTET STRING OPTIONAL, + * temporalEvidence Evidence + * } + *+ * @return + * @deprecated will be removed + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(version); + + if (dataUri != null) + { + v.add(dataUri); + } + + if (metaData != null) + { + v.add(metaData); + } + + if (content != null) + { + v.add(content); + } + + v.add(temporalEvidence); + + return new BERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/ecc/MQVuserKeyingMaterial.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/ecc/MQVuserKeyingMaterial.java new file mode 100644 index 0000000..6df4d41 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cms/ecc/MQVuserKeyingMaterial.java @@ -0,0 +1,112 @@ +package org.bc.asn1.cms.ecc; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1OctetString; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERSequence; +import org.bc.asn1.DERTaggedObject; +import org.bc.asn1.cms.OriginatorPublicKey; + +public class MQVuserKeyingMaterial + extends ASN1Object +{ + private OriginatorPublicKey ephemeralPublicKey; + private ASN1OctetString addedukm; + + public MQVuserKeyingMaterial( + OriginatorPublicKey ephemeralPublicKey, + ASN1OctetString addedukm) + { + // TODO Check ephemeralPublicKey not null + + this.ephemeralPublicKey = ephemeralPublicKey; + this.addedukm = addedukm; + } + + private MQVuserKeyingMaterial( + ASN1Sequence seq) + { + // TODO Check seq has either 1 or 2 elements + + this.ephemeralPublicKey = OriginatorPublicKey.getInstance( + seq.getObjectAt(0)); + + if (seq.size() > 1) + { + this.addedukm = ASN1OctetString.getInstance( + (ASN1TaggedObject)seq.getObjectAt(1), true); + } + } + + /** + * return an MQVuserKeyingMaterial object from a tagged object. + * + * @param obj the tagged object holding the object we want. + * @param explicit true if the object is meant to be explicitly + * tagged false otherwise. + * @throws IllegalArgumentException if the object held by the + * tagged object cannot be converted. + */ + public static MQVuserKeyingMaterial getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + /** + * return an MQVuserKeyingMaterial object from the given object. + * + * @param obj the object we want converted. + * @throws IllegalArgumentException if the object cannot be converted. + */ + public static MQVuserKeyingMaterial getInstance( + Object obj) + { + if (obj == null || obj instanceof MQVuserKeyingMaterial) + { + return (MQVuserKeyingMaterial)obj; + } + + if (obj instanceof ASN1Sequence) + { + return new MQVuserKeyingMaterial((ASN1Sequence)obj); + } + + throw new IllegalArgumentException("Invalid MQVuserKeyingMaterial: " + obj.getClass().getName()); + } + + public OriginatorPublicKey getEphemeralPublicKey() + { + return ephemeralPublicKey; + } + + public ASN1OctetString getAddedukm() + { + return addedukm; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + *
+ * MQVuserKeyingMaterial ::= SEQUENCE { + * ephemeralPublicKey OriginatorPublicKey, + * addedukm [0] EXPLICIT UserKeyingMaterial OPTIONAL } + *+ */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + v.add(ephemeralPublicKey); + + if (addedukm != null) + { + v.add(new DERTaggedObject(true, 0, addedukm)); + } + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/crmf/AttributeTypeAndValue.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/crmf/AttributeTypeAndValue.java new file mode 100644 index 0000000..a69e6c4 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/crmf/AttributeTypeAndValue.java @@ -0,0 +1,80 @@ +package org.bc.asn1.crmf; + +import org.bc.asn1.ASN1Encodable; +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1ObjectIdentifier; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DERSequence; + +public class AttributeTypeAndValue + extends ASN1Object +{ + private ASN1ObjectIdentifier type; + private ASN1Encodable value; + + private AttributeTypeAndValue(ASN1Sequence seq) + { + type = (ASN1ObjectIdentifier)seq.getObjectAt(0); + value = (ASN1Encodable)seq.getObjectAt(1); + } + + public static AttributeTypeAndValue getInstance(Object o) + { + if (o instanceof AttributeTypeAndValue) + { + return (AttributeTypeAndValue)o; + } + + if (o != null) + { + return new AttributeTypeAndValue(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public AttributeTypeAndValue( + String oid, + ASN1Encodable value) + { + this(new ASN1ObjectIdentifier(oid), value); + } + + public AttributeTypeAndValue( + ASN1ObjectIdentifier type, + ASN1Encodable value) + { + this.type = type; + this.value = value; + } + + public ASN1ObjectIdentifier getType() + { + return type; + } + + public ASN1Encodable getValue() + { + return value; + } + + /** + *
+ * AttributeTypeAndValue ::= SEQUENCE { + * type OBJECT IDENTIFIER, + * value ANY DEFINED BY type } + *+ * @return a basic ASN.1 object representation. + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(type); + v.add(value); + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/crmf/CRMFObjectIdentifiers.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/crmf/CRMFObjectIdentifiers.java new file mode 100644 index 0000000..38231ea --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/crmf/CRMFObjectIdentifiers.java @@ -0,0 +1,21 @@ +package org.bc.asn1.crmf; + +import org.bc.asn1.ASN1ObjectIdentifier; +import org.bc.asn1.pkcs.PKCSObjectIdentifiers; + +public interface CRMFObjectIdentifiers +{ + static final ASN1ObjectIdentifier id_pkix = new ASN1ObjectIdentifier("1.3.6.1.5.5.7"); + + // arc for Internet X.509 PKI protocols and their components + + static final ASN1ObjectIdentifier id_pkip = id_pkix.branch("5"); + + static final ASN1ObjectIdentifier id_regCtrl = id_pkip.branch("1"); + static final ASN1ObjectIdentifier id_regCtrl_regToken = id_regCtrl.branch("1"); + static final ASN1ObjectIdentifier id_regCtrl_authenticator = id_regCtrl.branch("2"); + static final ASN1ObjectIdentifier id_regCtrl_pkiPublicationInfo = id_regCtrl.branch("3"); + static final ASN1ObjectIdentifier id_regCtrl_pkiArchiveOptions = id_regCtrl.branch("4"); + + static final ASN1ObjectIdentifier id_ct_encKeyWithID = new ASN1ObjectIdentifier(PKCSObjectIdentifiers.id_ct + ".21"); +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/crmf/CertId.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/crmf/CertId.java new file mode 100644 index 0000000..7de065c --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/crmf/CertId.java @@ -0,0 +1,84 @@ +package org.bc.asn1.crmf; + +import java.math.BigInteger; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERSequence; +import org.bc.asn1.x509.GeneralName; + +public class CertId + extends ASN1Object +{ + private GeneralName issuer; + private ASN1Integer serialNumber; + + private CertId(ASN1Sequence seq) + { + issuer = GeneralName.getInstance(seq.getObjectAt(0)); + serialNumber = ASN1Integer.getInstance(seq.getObjectAt(1)); + } + + public static CertId getInstance(Object o) + { + if (o instanceof CertId) + { + return (CertId)o; + } + + if (o != null) + { + return new CertId(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public static CertId getInstance(ASN1TaggedObject obj, boolean isExplicit) + { + return getInstance(ASN1Sequence.getInstance(obj, isExplicit)); + } + + public CertId(GeneralName issuer, BigInteger serialNumber) + { + this(issuer, new ASN1Integer(serialNumber)); + } + + public CertId(GeneralName issuer, ASN1Integer serialNumber) + { + this.issuer = issuer; + this.serialNumber = serialNumber; + } + + public GeneralName getIssuer() + { + return issuer; + } + + public ASN1Integer getSerialNumber() + { + return serialNumber; + } + + /** + *
+ * CertId ::= SEQUENCE { + * issuer GeneralName, + * serialNumber INTEGER } + *+ * @return a basic ASN.1 object representation. + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(issuer); + v.add(serialNumber); + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/crmf/CertReqMessages.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/crmf/CertReqMessages.java new file mode 100644 index 0000000..5bb19c0 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/crmf/CertReqMessages.java @@ -0,0 +1,72 @@ +package org.bc.asn1.crmf; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DERSequence; + +public class CertReqMessages + extends ASN1Object +{ + private ASN1Sequence content; + + private CertReqMessages(ASN1Sequence seq) + { + content = seq; + } + + public static CertReqMessages getInstance(Object o) + { + if (o instanceof CertReqMessages) + { + return (CertReqMessages)o; + } + + if (o != null) + { + return new CertReqMessages(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public CertReqMessages( + CertReqMsg msg) + { + content = new DERSequence(msg); + } + + public CertReqMessages( + CertReqMsg[] msgs) + { + ASN1EncodableVector v = new ASN1EncodableVector(); + for (int i = 0; i < msgs.length; i++) { + v.add(msgs[i]); + } + content = new DERSequence(v); + } + + public CertReqMsg[] toCertReqMsgArray() + { + CertReqMsg[] result = new CertReqMsg[content.size()]; + + for (int i = 0; i != result.length; i++) + { + result[i] = CertReqMsg.getInstance(content.getObjectAt(i)); + } + + return result; + } + + /** + *
+ * CertReqMessages ::= SEQUENCE SIZE (1..MAX) OF CertReqMsg + *+ * @return a basic ASN.1 object representation. + */ + public ASN1Primitive toASN1Primitive() + { + return content; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/crmf/CertReqMsg.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/crmf/CertReqMsg.java new file mode 100644 index 0000000..5a34a76 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/crmf/CertReqMsg.java @@ -0,0 +1,145 @@ +package org.bc.asn1.crmf; + +import java.util.Enumeration; + +import org.bc.asn1.ASN1Encodable; +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERSequence; + +public class CertReqMsg + extends ASN1Object +{ + private CertRequest certReq; + private ProofOfPossession pop; + private ASN1Sequence regInfo; + + private CertReqMsg(ASN1Sequence seq) + { + Enumeration en = seq.getObjects(); + + certReq = CertRequest.getInstance(en.nextElement()); + while (en.hasMoreElements()) + { + Object o = en.nextElement(); + + if (o instanceof ASN1TaggedObject || o instanceof ProofOfPossession) + { + pop = ProofOfPossession.getInstance(o); + } + else + { + regInfo = ASN1Sequence.getInstance(o); + } + } + } + + public static CertReqMsg getInstance(Object o) + { + if (o instanceof CertReqMsg) + { + return (CertReqMsg)o; + } + else if (o != null) + { + return new CertReqMsg(ASN1Sequence.getInstance(o)); + } + + return null; + } + + /** + * Creates a new CertReqMsg. + * @param certReq CertRequest + * @param pop may be null + * @param regInfo may be null + */ + public CertReqMsg( + CertRequest certReq, + ProofOfPossession pop, + AttributeTypeAndValue[] regInfo) + { + if (certReq == null) + { + throw new IllegalArgumentException("'certReq' cannot be null"); + } + + this.certReq = certReq; + this.pop = pop; + + if (regInfo != null) + { + this.regInfo = new DERSequence(regInfo); + } + } + + public CertRequest getCertReq() + { + return certReq; + } + + + /** + * @deprecated use getPopo + */ + public ProofOfPossession getPop() + { + return pop; + } + + + public ProofOfPossession getPopo() + { + return pop; + } + + public AttributeTypeAndValue[] getRegInfo() + { + if (regInfo == null) + { + return null; + } + + AttributeTypeAndValue[] results = new AttributeTypeAndValue[regInfo.size()]; + + for (int i = 0; i != results.length; i++) + { + results[i] = AttributeTypeAndValue.getInstance(regInfo.getObjectAt(i)); + } + + return results; + } + + /** + *
+ * CertReqMsg ::= SEQUENCE { + * certReq CertRequest, + * popo ProofOfPossession OPTIONAL, + * -- content depends upon key type + * regInfo SEQUENCE SIZE(1..MAX) OF AttributeTypeAndValue OPTIONAL } + *+ * @return a basic ASN.1 object representation. + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(certReq); + + addOptional(v, pop); + addOptional(v, regInfo); + + return new DERSequence(v); + } + + private void addOptional(ASN1EncodableVector v, ASN1Encodable obj) + { + if (obj != null) + { + v.add(obj); + } + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/crmf/CertRequest.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/crmf/CertRequest.java new file mode 100644 index 0000000..dfc7087 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/crmf/CertRequest.java @@ -0,0 +1,97 @@ +package org.bc.asn1.crmf; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DERSequence; + +public class CertRequest + extends ASN1Object +{ + private ASN1Integer certReqId; + private CertTemplate certTemplate; + private Controls controls; + + private CertRequest(ASN1Sequence seq) + { + certReqId = new ASN1Integer(ASN1Integer.getInstance(seq.getObjectAt(0)).getValue()); + certTemplate = CertTemplate.getInstance(seq.getObjectAt(1)); + if (seq.size() > 2) + { + controls = Controls.getInstance(seq.getObjectAt(2)); + } + } + + public static CertRequest getInstance(Object o) + { + if (o instanceof CertRequest) + { + return (CertRequest)o; + } + else if (o != null) + { + return new CertRequest(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public CertRequest( + int certReqId, + CertTemplate certTemplate, + Controls controls) + { + this(new ASN1Integer(certReqId), certTemplate, controls); + } + + public CertRequest( + ASN1Integer certReqId, + CertTemplate certTemplate, + Controls controls) + { + this.certReqId = certReqId; + this.certTemplate = certTemplate; + this.controls = controls; + } + + public ASN1Integer getCertReqId() + { + return certReqId; + } + + public CertTemplate getCertTemplate() + { + return certTemplate; + } + + public Controls getControls() + { + return controls; + } + + /** + *
+ * CertRequest ::= SEQUENCE { + * certReqId INTEGER, -- ID for matching request and reply + * certTemplate CertTemplate, -- Selected fields of cert to be issued + * controls Controls OPTIONAL } -- Attributes affecting issuance + *+ * @return a basic ASN.1 object representation. + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(certReqId); + v.add(certTemplate); + + if (controls != null) + { + v.add(controls); + } + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/crmf/CertTemplate.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/crmf/CertTemplate.java new file mode 100644 index 0000000..0341c14 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/crmf/CertTemplate.java @@ -0,0 +1,163 @@ +package org.bc.asn1.crmf; + +import java.util.Enumeration; + +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERBitString; +import org.bc.asn1.x500.X500Name; +import org.bc.asn1.x509.AlgorithmIdentifier; +import org.bc.asn1.x509.Extensions; +import org.bc.asn1.x509.SubjectPublicKeyInfo; + +public class CertTemplate + extends ASN1Object +{ + private ASN1Sequence seq; + + private ASN1Integer version; + private ASN1Integer serialNumber; + private AlgorithmIdentifier signingAlg; + private X500Name issuer; + private OptionalValidity validity; + private X500Name subject; + private SubjectPublicKeyInfo publicKey; + private DERBitString issuerUID; + private DERBitString subjectUID; + private Extensions extensions; + + private CertTemplate(ASN1Sequence seq) + { + this.seq = seq; + + Enumeration en = seq.getObjects(); + while (en.hasMoreElements()) + { + ASN1TaggedObject tObj = (ASN1TaggedObject)en.nextElement(); + + switch (tObj.getTagNo()) + { + case 0: + version = ASN1Integer.getInstance(tObj, false); + break; + case 1: + serialNumber = ASN1Integer.getInstance(tObj, false); + break; + case 2: + signingAlg = AlgorithmIdentifier.getInstance(tObj, false); + break; + case 3: + issuer = X500Name.getInstance(tObj, true); // CHOICE + break; + case 4: + validity = OptionalValidity.getInstance(ASN1Sequence.getInstance(tObj, false)); + break; + case 5: + subject = X500Name.getInstance(tObj, true); // CHOICE + break; + case 6: + publicKey = SubjectPublicKeyInfo.getInstance(tObj, false); + break; + case 7: + issuerUID = DERBitString.getInstance(tObj, false); + break; + case 8: + subjectUID = DERBitString.getInstance(tObj, false); + break; + case 9: + extensions = Extensions.getInstance(tObj, false); + break; + default: + throw new IllegalArgumentException("unknown tag: " + tObj.getTagNo()); + } + } + } + + public static CertTemplate getInstance(Object o) + { + if (o instanceof CertTemplate) + { + return (CertTemplate)o; + } + else if (o != null) + { + return new CertTemplate(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public int getVersion() + { + return version.getValue().intValue(); + } + + public ASN1Integer getSerialNumber() + { + return serialNumber; + } + + public AlgorithmIdentifier getSigningAlg() + { + return signingAlg; + } + + public X500Name getIssuer() + { + return issuer; + } + + public OptionalValidity getValidity() + { + return validity; + } + + public X500Name getSubject() + { + return subject; + } + + public SubjectPublicKeyInfo getPublicKey() + { + return publicKey; + } + + public DERBitString getIssuerUID() + { + return issuerUID; + } + + public DERBitString getSubjectUID() + { + return subjectUID; + } + + public Extensions getExtensions() + { + return extensions; + } + + /** + *
+ * CertTemplate ::= SEQUENCE { + * version [0] Version OPTIONAL, + * serialNumber [1] INTEGER OPTIONAL, + * signingAlg [2] AlgorithmIdentifier OPTIONAL, + * issuer [3] Name OPTIONAL, + * validity [4] OptionalValidity OPTIONAL, + * subject [5] Name OPTIONAL, + * publicKey [6] SubjectPublicKeyInfo OPTIONAL, + * issuerUID [7] UniqueIdentifier OPTIONAL, + * subjectUID [8] UniqueIdentifier OPTIONAL, + * extensions [9] Extensions OPTIONAL } + *+ * @return a basic ASN.1 object representation. + */ + public ASN1Primitive toASN1Primitive() + { + return seq; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/crmf/CertTemplateBuilder.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/crmf/CertTemplateBuilder.java new file mode 100644 index 0000000..cb22e94 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/crmf/CertTemplateBuilder.java @@ -0,0 +1,152 @@ +package org.bc.asn1.crmf; + +import org.bc.asn1.ASN1Encodable; +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.DERBitString; +import org.bc.asn1.DERSequence; +import org.bc.asn1.DERTaggedObject; +import org.bc.asn1.x500.X500Name; +import org.bc.asn1.x509.AlgorithmIdentifier; +import org.bc.asn1.x509.Extensions; +import org.bc.asn1.x509.SubjectPublicKeyInfo; +import org.bc.asn1.x509.X509Extensions; + +public class CertTemplateBuilder +{ + private ASN1Integer version; + private ASN1Integer serialNumber; + private AlgorithmIdentifier signingAlg; + private X500Name issuer; + private OptionalValidity validity; + private X500Name subject; + private SubjectPublicKeyInfo publicKey; + private DERBitString issuerUID; + private DERBitString subjectUID; + private Extensions extensions; + + /** Sets the X.509 version. Note: for X509v3, use 2 here. */ + public CertTemplateBuilder setVersion(int ver) + { + version = new ASN1Integer(ver); + + return this; + } + + public CertTemplateBuilder setSerialNumber(ASN1Integer ser) + { + serialNumber = ser; + + return this; + } + + public CertTemplateBuilder setSigningAlg(AlgorithmIdentifier aid) + { + signingAlg = aid; + + return this; + } + + public CertTemplateBuilder setIssuer(X500Name name) + { + issuer = name; + + return this; + } + + public CertTemplateBuilder setValidity(OptionalValidity v) + { + validity = v; + + return this; + } + + public CertTemplateBuilder setSubject(X500Name name) + { + subject = name; + + return this; + } + + public CertTemplateBuilder setPublicKey(SubjectPublicKeyInfo spki) + { + publicKey = spki; + + return this; + } + + /** Sets the issuer unique ID (deprecated in X.509v3) */ + public CertTemplateBuilder setIssuerUID(DERBitString uid) + { + issuerUID = uid; + + return this; + } + + /** Sets the subject unique ID (deprecated in X.509v3) */ + public CertTemplateBuilder setSubjectUID(DERBitString uid) + { + subjectUID = uid; + + return this; + } + + /** + * @deprecated use method taking Extensions + * @param extens + * @return + */ + public CertTemplateBuilder setExtensions(X509Extensions extens) + { + return setExtensions(Extensions.getInstance(extens)); + } + + public CertTemplateBuilder setExtensions(Extensions extens) + { + extensions = extens; + + return this; + } + + /** + *
+ * CertTemplate ::= SEQUENCE { + * version [0] Version OPTIONAL, + * serialNumber [1] INTEGER OPTIONAL, + * signingAlg [2] AlgorithmIdentifier OPTIONAL, + * issuer [3] Name OPTIONAL, + * validity [4] OptionalValidity OPTIONAL, + * subject [5] Name OPTIONAL, + * publicKey [6] SubjectPublicKeyInfo OPTIONAL, + * issuerUID [7] UniqueIdentifier OPTIONAL, + * subjectUID [8] UniqueIdentifier OPTIONAL, + * extensions [9] Extensions OPTIONAL } + *+ * @return a basic ASN.1 object representation. + */ + public CertTemplate build() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + addOptional(v, 0, false, version); + addOptional(v, 1, false, serialNumber); + addOptional(v, 2, false, signingAlg); + addOptional(v, 3, true, issuer); // CHOICE + addOptional(v, 4, false, validity); + addOptional(v, 5, true, subject); // CHOICE + addOptional(v, 6, false, publicKey); + addOptional(v, 7, false, issuerUID); + addOptional(v, 8, false, subjectUID); + addOptional(v, 9, false, extensions); + + return CertTemplate.getInstance(new DERSequence(v)); + } + + private void addOptional(ASN1EncodableVector v, int tagNo, boolean isExplicit, ASN1Encodable obj) + { + if (obj != null) + { + v.add(new DERTaggedObject(isExplicit, tagNo, obj)); + } + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/crmf/Controls.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/crmf/Controls.java new file mode 100644 index 0000000..f34bc47 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/crmf/Controls.java @@ -0,0 +1,70 @@ +package org.bc.asn1.crmf; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DERSequence; + +public class Controls + extends ASN1Object +{ + private ASN1Sequence content; + + private Controls(ASN1Sequence seq) + { + content = seq; + } + + public static Controls getInstance(Object o) + { + if (o instanceof Controls) + { + return (Controls)o; + } + + if (o != null) + { + return new Controls(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public Controls(AttributeTypeAndValue atv) + { + content = new DERSequence(atv); + } + + public Controls(AttributeTypeAndValue[] atvs) + { + ASN1EncodableVector v = new ASN1EncodableVector(); + for (int i = 0; i < atvs.length; i++) { + v.add(atvs[i]); + } + content = new DERSequence(v); + } + + public AttributeTypeAndValue[] toAttributeTypeAndValueArray() + { + AttributeTypeAndValue[] result = new AttributeTypeAndValue[content.size()]; + + for (int i = 0; i != result.length; i++) + { + result[i] = AttributeTypeAndValue.getInstance(content.getObjectAt(i)); + } + + return result; + } + + /** + *
+ * Controls ::= SEQUENCE SIZE(1..MAX) OF AttributeTypeAndValue + *+ * @return a basic ASN.1 object representation. + */ + public ASN1Primitive toASN1Primitive() + { + return content; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/crmf/EncKeyWithID.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/crmf/EncKeyWithID.java new file mode 100644 index 0000000..5b75dc8 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/crmf/EncKeyWithID.java @@ -0,0 +1,117 @@ +package org.bc.asn1.crmf; + +import org.bc.asn1.ASN1Encodable; +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DERSequence; +import org.bc.asn1.DERUTF8String; +import org.bc.asn1.pkcs.PrivateKeyInfo; +import org.bc.asn1.x509.GeneralName; + +public class EncKeyWithID + extends ASN1Object +{ + private final PrivateKeyInfo privKeyInfo; + private final ASN1Encodable identifier; + + public static EncKeyWithID getInstance(Object o) + { + if (o instanceof EncKeyWithID) + { + return (EncKeyWithID)o; + } + else if (o != null) + { + return new EncKeyWithID(ASN1Sequence.getInstance(o)); + } + + return null; + } + + private EncKeyWithID(ASN1Sequence seq) + { + this.privKeyInfo = PrivateKeyInfo.getInstance(seq.getObjectAt(0)); + + if (seq.size() > 1) + { + if (!(seq.getObjectAt(1) instanceof DERUTF8String)) + { + this.identifier = GeneralName.getInstance(seq.getObjectAt(1)); + } + else + { + this.identifier = (ASN1Encodable)seq.getObjectAt(1); + } + } + else + { + this.identifier = null; + } + } + + public EncKeyWithID(PrivateKeyInfo privKeyInfo) + { + this.privKeyInfo = privKeyInfo; + this.identifier = null; + } + + public EncKeyWithID(PrivateKeyInfo privKeyInfo, DERUTF8String str) + { + this.privKeyInfo = privKeyInfo; + this.identifier = str; + } + + public EncKeyWithID(PrivateKeyInfo privKeyInfo, GeneralName generalName) + { + this.privKeyInfo = privKeyInfo; + this.identifier = generalName; + } + + public PrivateKeyInfo getPrivateKey() + { + return privKeyInfo; + } + + public boolean hasIdentifier() + { + return identifier != null; + } + + public boolean isIdentifierUTF8String() + { + return identifier instanceof DERUTF8String; + } + + public ASN1Encodable getIdentifier() + { + return identifier; + } + + /** + *
+ * EncKeyWithID ::= SEQUENCE { + * privateKey PrivateKeyInfo, + * identifier CHOICE { + * string UTF8String, + * generalName GeneralName + * } OPTIONAL + * } + *+ * @return + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(privKeyInfo); + + if (identifier != null) + { + v.add(identifier); + } + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/crmf/EncryptedKey.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/crmf/EncryptedKey.java new file mode 100644 index 0000000..9bb715b --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/crmf/EncryptedKey.java @@ -0,0 +1,81 @@ +package org.bc.asn1.crmf; + +import org.bc.asn1.ASN1Choice; +import org.bc.asn1.ASN1Encodable; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERTaggedObject; +import org.bc.asn1.cms.EnvelopedData; + +public class EncryptedKey + extends ASN1Object + implements ASN1Choice +{ + private EnvelopedData envelopedData; + private EncryptedValue encryptedValue; + + public static EncryptedKey getInstance(Object o) + { + if (o instanceof EncryptedKey) + { + return (EncryptedKey)o; + } + else if (o instanceof ASN1TaggedObject) + { + return new EncryptedKey(EnvelopedData.getInstance((ASN1TaggedObject)o, false)); + } + else if (o instanceof EncryptedValue) + { + return new EncryptedKey((EncryptedValue)o); + } + else + { + return new EncryptedKey(EncryptedValue.getInstance(o)); + } + } + + public EncryptedKey(EnvelopedData envelopedData) + { + this.envelopedData = envelopedData; + } + + public EncryptedKey(EncryptedValue encryptedValue) + { + this.encryptedValue = encryptedValue; + } + + public boolean isEncryptedValue() + { + return encryptedValue != null; + } + + public ASN1Encodable getValue() + { + if (encryptedValue != null) + { + return encryptedValue; + } + + return envelopedData; + } + + /** + *
+ * EncryptedKey ::= CHOICE { + * encryptedValue EncryptedValue, -- deprecated + * envelopedData [0] EnvelopedData } + * -- The encrypted private key MUST be placed in the envelopedData + * -- encryptedContentInfo encryptedContent OCTET STRING. + *+ */ + public ASN1Primitive toASN1Primitive() + { + if (encryptedValue != null) + { + return encryptedValue.toASN1Primitive(); + } + + return new DERTaggedObject(false, 0, envelopedData); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/crmf/EncryptedValue.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/crmf/EncryptedValue.java new file mode 100644 index 0000000..0aaa198 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/crmf/EncryptedValue.java @@ -0,0 +1,164 @@ +package org.bc.asn1.crmf; + +import org.bc.asn1.ASN1Encodable; +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1OctetString; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERBitString; +import org.bc.asn1.DERSequence; +import org.bc.asn1.DERTaggedObject; +import org.bc.asn1.x509.AlgorithmIdentifier; + +public class EncryptedValue + extends ASN1Object +{ + private AlgorithmIdentifier intendedAlg; + private AlgorithmIdentifier symmAlg; + private DERBitString encSymmKey; + private AlgorithmIdentifier keyAlg; + private ASN1OctetString valueHint; + private DERBitString encValue; + + private EncryptedValue(ASN1Sequence seq) + { + int index = 0; + while (seq.getObjectAt(index) instanceof ASN1TaggedObject) + { + ASN1TaggedObject tObj = (ASN1TaggedObject)seq.getObjectAt(index); + + switch (tObj.getTagNo()) + { + case 0: + intendedAlg = AlgorithmIdentifier.getInstance(tObj, false); + break; + case 1: + symmAlg = AlgorithmIdentifier.getInstance(tObj, false); + break; + case 2: + encSymmKey = DERBitString.getInstance(tObj, false); + break; + case 3: + keyAlg = AlgorithmIdentifier.getInstance(tObj, false); + break; + case 4: + valueHint = ASN1OctetString.getInstance(tObj, false); + break; + } + index++; + } + + encValue = DERBitString.getInstance(seq.getObjectAt(index)); + } + + public static EncryptedValue getInstance(Object o) + { + if (o instanceof EncryptedValue) + { + return (EncryptedValue)o; + } + else if (o != null) + { + return new EncryptedValue(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public EncryptedValue( + AlgorithmIdentifier intendedAlg, + AlgorithmIdentifier symmAlg, + DERBitString encSymmKey, + AlgorithmIdentifier keyAlg, + ASN1OctetString valueHint, + DERBitString encValue) + { + if (encValue == null) + { + throw new IllegalArgumentException("'encValue' cannot be null"); + } + + this.intendedAlg = intendedAlg; + this.symmAlg = symmAlg; + this.encSymmKey = encSymmKey; + this.keyAlg = keyAlg; + this.valueHint = valueHint; + this.encValue = encValue; + } + + public AlgorithmIdentifier getIntendedAlg() + { + return intendedAlg; + } + + public AlgorithmIdentifier getSymmAlg() + { + return symmAlg; + } + + public DERBitString getEncSymmKey() + { + return encSymmKey; + } + + public AlgorithmIdentifier getKeyAlg() + { + return keyAlg; + } + + public ASN1OctetString getValueHint() + { + return valueHint; + } + + public DERBitString getEncValue() + { + return encValue; + } + + /** + *
+ * EncryptedValue ::= SEQUENCE { + * intendedAlg [0] AlgorithmIdentifier OPTIONAL, + * -- the intended algorithm for which the value will be used + * symmAlg [1] AlgorithmIdentifier OPTIONAL, + * -- the symmetric algorithm used to encrypt the value + * encSymmKey [2] BIT STRING OPTIONAL, + * -- the (encrypted) symmetric key used to encrypt the value + * keyAlg [3] AlgorithmIdentifier OPTIONAL, + * -- algorithm used to encrypt the symmetric key + * valueHint [4] OCTET STRING OPTIONAL, + * -- a brief description or identifier of the encValue content + * -- (may be meaningful only to the sending entity, and used only + * -- if EncryptedValue might be re-examined by the sending entity + * -- in the future) + * encValue BIT STRING } + * -- the encrypted value itself + *+ * @return a basic ASN.1 object representation. + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + addOptional(v, 0, intendedAlg); + addOptional(v, 1, symmAlg); + addOptional(v, 2, encSymmKey); + addOptional(v, 3, keyAlg); + addOptional(v, 4, valueHint); + + v.add(encValue); + + return new DERSequence(v); + } + + private void addOptional(ASN1EncodableVector v, int tagNo, ASN1Encodable obj) + { + if (obj != null) + { + v.add(new DERTaggedObject(false, tagNo, obj)); + } + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/crmf/OptionalValidity.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/crmf/OptionalValidity.java new file mode 100644 index 0000000..c8d7b84 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/crmf/OptionalValidity.java @@ -0,0 +1,98 @@ +package org.bc.asn1.crmf; + +import java.util.Enumeration; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERSequence; +import org.bc.asn1.DERTaggedObject; +import org.bc.asn1.x509.Time; + +public class OptionalValidity + extends ASN1Object +{ + private Time notBefore; + private Time notAfter; + + private OptionalValidity(ASN1Sequence seq) + { + Enumeration en = seq.getObjects(); + while (en.hasMoreElements()) + { + ASN1TaggedObject tObj = (ASN1TaggedObject)en.nextElement(); + + if (tObj.getTagNo() == 0) + { + notBefore = Time.getInstance(tObj, true); + } + else + { + notAfter = Time.getInstance(tObj, true); + } + } + } + + public static OptionalValidity getInstance(Object o) + { + if (o instanceof OptionalValidity) + { + return (OptionalValidity)o; + } + + if (o != null) + { + return new OptionalValidity(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public OptionalValidity(Time notBefore, Time notAfter) + { + if (notBefore == null && notAfter == null) + { + throw new IllegalArgumentException("at least one of notBefore/notAfter must not be null."); + } + + this.notBefore = notBefore; + this.notAfter = notAfter; + } + + public Time getNotBefore() + { + return notBefore; + } + + public Time getNotAfter() + { + return notAfter; + } + + /** + *
+ * OptionalValidity ::= SEQUENCE { + * notBefore [0] Time OPTIONAL, + * notAfter [1] Time OPTIONAL } --at least one MUST be present + *+ * @return a basic ASN.1 object representation. + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + if (notBefore != null) + { + v.add(new DERTaggedObject(true, 0, notBefore)); + } + + if (notAfter != null) + { + v.add(new DERTaggedObject(true, 1, notAfter)); + } + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/crmf/PKIArchiveOptions.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/crmf/PKIArchiveOptions.java new file mode 100644 index 0000000..ff06fe9 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/crmf/PKIArchiveOptions.java @@ -0,0 +1,116 @@ +package org.bc.asn1.crmf; + +import org.bc.asn1.ASN1Boolean; +import org.bc.asn1.ASN1Choice; +import org.bc.asn1.ASN1Encodable; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1OctetString; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERTaggedObject; + +public class PKIArchiveOptions + extends ASN1Object + implements ASN1Choice +{ + public static final int encryptedPrivKey = 0; + public static final int keyGenParameters = 1; + public static final int archiveRemGenPrivKey = 2; + + private ASN1Encodable value; + + public static PKIArchiveOptions getInstance(Object o) + { + if (o == null || o instanceof PKIArchiveOptions) + { + return (PKIArchiveOptions)o; + } + else if (o instanceof ASN1TaggedObject) + { + return new PKIArchiveOptions((ASN1TaggedObject)o); + } + + throw new IllegalArgumentException("unknown object: " + o); + } + + private PKIArchiveOptions(ASN1TaggedObject tagged) + { + switch (tagged.getTagNo()) + { + case encryptedPrivKey: + value = EncryptedKey.getInstance(tagged.getObject()); + break; + case keyGenParameters: + value = ASN1OctetString.getInstance(tagged, false); + break; + case archiveRemGenPrivKey: + value = ASN1Boolean.getInstance(tagged, false); + break; + default: + throw new IllegalArgumentException("unknown tag number: " + tagged.getTagNo()); + } + } + + public PKIArchiveOptions(EncryptedKey encKey) + { + this.value = encKey; + } + + public PKIArchiveOptions(ASN1OctetString keyGenParameters) + { + this.value = keyGenParameters; + } + + public PKIArchiveOptions(boolean archiveRemGenPrivKey) + { + this.value = ASN1Boolean.getInstance(archiveRemGenPrivKey); + } + + public int getType() + { + if (value instanceof EncryptedKey) + { + return encryptedPrivKey; + } + + if (value instanceof ASN1OctetString) + { + return keyGenParameters; + } + + return archiveRemGenPrivKey; + } + + public ASN1Encodable getValue() + { + return value; + } + + /** + *
+ * PKIArchiveOptions ::= CHOICE { + * encryptedPrivKey [0] EncryptedKey, + * -- the actual value of the private key + * keyGenParameters [1] KeyGenParameters, + * -- parameters which allow the private key to be re-generated + * archiveRemGenPrivKey [2] BOOLEAN } + * -- set to TRUE if sender wishes receiver to archive the private + * -- key of a key pair that the receiver generates in response to + * -- this request; set to FALSE if no archival is desired. + *+ */ + public ASN1Primitive toASN1Primitive() + { + if (value instanceof EncryptedKey) + { + return new DERTaggedObject(true, encryptedPrivKey, value); // choice + } + + if (value instanceof ASN1OctetString) + { + return new DERTaggedObject(false, keyGenParameters, value); + } + + return new DERTaggedObject(false, archiveRemGenPrivKey, value); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/crmf/PKIPublicationInfo.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/crmf/PKIPublicationInfo.java new file mode 100644 index 0000000..b6901f4 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/crmf/PKIPublicationInfo.java @@ -0,0 +1,81 @@ +package org.bc.asn1.crmf; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DERSequence; + +public class PKIPublicationInfo + extends ASN1Object +{ + private ASN1Integer action; + private ASN1Sequence pubInfos; + + private PKIPublicationInfo(ASN1Sequence seq) + { + action = ASN1Integer.getInstance(seq.getObjectAt(0)); + pubInfos = ASN1Sequence.getInstance(seq.getObjectAt(1)); + } + + public static PKIPublicationInfo getInstance(Object o) + { + if (o instanceof PKIPublicationInfo) + { + return (PKIPublicationInfo)o; + } + + if (o != null) + { + return new PKIPublicationInfo(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public ASN1Integer getAction() + { + return action; + } + + public SinglePubInfo[] getPubInfos() + { + if (pubInfos == null) + { + return null; + } + + SinglePubInfo[] results = new SinglePubInfo[pubInfos.size()]; + + for (int i = 0; i != results.length; i++) + { + results[i] = SinglePubInfo.getInstance(pubInfos.getObjectAt(i)); + } + + return results; + } + + /** + *
+ * PKIPublicationInfo ::= SEQUENCE { + * action INTEGER { + * dontPublish (0), + * pleasePublish (1) }, + * pubInfos SEQUENCE SIZE (1..MAX) OF SinglePubInfo OPTIONAL } + * -- pubInfos MUST NOT be present if action is "dontPublish" + * -- (if action is "pleasePublish" and pubInfos is omitted, + * -- "dontCare" is assumed) + *+ * @return a basic ASN.1 object representation. + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(action); + v.add(pubInfos); + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/crmf/PKMACValue.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/crmf/PKMACValue.java new file mode 100644 index 0000000..90cabc3 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/crmf/PKMACValue.java @@ -0,0 +1,104 @@ +package org.bc.asn1.crmf; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERBitString; +import org.bc.asn1.DERSequence; +import org.bc.asn1.cmp.CMPObjectIdentifiers; +import org.bc.asn1.cmp.PBMParameter; +import org.bc.asn1.x509.AlgorithmIdentifier; + +/** + * Password-based MAC value for use with POPOSigningKeyInput. + */ +public class PKMACValue + extends ASN1Object +{ + private AlgorithmIdentifier algId; + private DERBitString value; + + private PKMACValue(ASN1Sequence seq) + { + algId = AlgorithmIdentifier.getInstance(seq.getObjectAt(0)); + value = DERBitString.getInstance(seq.getObjectAt(1)); + } + + public static PKMACValue getInstance(Object o) + { + if (o instanceof PKMACValue) + { + return (PKMACValue)o; + } + + if (o != null) + { + return new PKMACValue(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public static PKMACValue getInstance(ASN1TaggedObject obj, boolean isExplicit) + { + return getInstance(ASN1Sequence.getInstance(obj, isExplicit)); + } + + /** + * Creates a new PKMACValue. + * @param params parameters for password-based MAC + * @param value MAC of the DER-encoded SubjectPublicKeyInfo + */ + public PKMACValue( + PBMParameter params, + DERBitString value) + { + this(new AlgorithmIdentifier( + CMPObjectIdentifiers.passwordBasedMac, params), value); + } + + /** + * Creates a new PKMACValue. + * @param aid CMPObjectIdentifiers.passwordBasedMAC, with PBMParameter + * @param value MAC of the DER-encoded SubjectPublicKeyInfo + */ + public PKMACValue( + AlgorithmIdentifier aid, + DERBitString value) + { + this.algId = aid; + this.value = value; + } + + public AlgorithmIdentifier getAlgId() + { + return algId; + } + + public DERBitString getValue() + { + return value; + } + + /** + *
+ * PKMACValue ::= SEQUENCE { + * algId AlgorithmIdentifier, + * -- algorithm value shall be PasswordBasedMac 1.2.840.113533.7.66.13 + * -- parameter value is PBMParameter + * value BIT STRING } + *+ * @return a basic ASN.1 object representation. + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(algId); + v.add(value); + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/crmf/POPOPrivKey.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/crmf/POPOPrivKey.java new file mode 100644 index 0000000..2566f0e --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/crmf/POPOPrivKey.java @@ -0,0 +1,104 @@ +package org.bc.asn1.crmf; + +import org.bc.asn1.ASN1Choice; +import org.bc.asn1.ASN1Encodable; +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERBitString; +import org.bc.asn1.DERTaggedObject; +import org.bc.asn1.cms.EnvelopedData; + +public class POPOPrivKey + extends ASN1Object + implements ASN1Choice +{ + public static final int thisMessage = 0; + public static final int subsequentMessage = 1; + public static final int dhMAC = 2; + public static final int agreeMAC = 3; + public static final int encryptedKey = 4; + + private int tagNo; + private ASN1Encodable obj; + + private POPOPrivKey(ASN1TaggedObject obj) + { + this.tagNo = obj.getTagNo(); + + switch (tagNo) + { + case thisMessage: + this.obj = DERBitString.getInstance(obj, false); + break; + case subsequentMessage: + this.obj = SubsequentMessage.valueOf(ASN1Integer.getInstance(obj, false).getValue().intValue()); + break; + case dhMAC: + this.obj = DERBitString.getInstance(obj, false); + break; + case agreeMAC: + this.obj = PKMACValue.getInstance(obj, false); + break; + case encryptedKey: + this.obj = EnvelopedData.getInstance(obj, false); + break; + default: + throw new IllegalArgumentException("unknown tag in POPOPrivKey"); + } + } + + public static POPOPrivKey getInstance(Object obj) + { + if (obj instanceof POPOPrivKey) + { + return (POPOPrivKey)obj; + } + if (obj != null) + { + return new POPOPrivKey(ASN1TaggedObject.getInstance(obj)); + } + + return null; + } + + public static POPOPrivKey getInstance(ASN1TaggedObject obj, boolean explicit) + { + return getInstance(ASN1TaggedObject.getInstance(obj, explicit)); + } + + public POPOPrivKey(SubsequentMessage msg) + { + this.tagNo = subsequentMessage; + this.obj = msg; + } + + public int getType() + { + return tagNo; + } + + public ASN1Encodable getValue() + { + return obj; + } + + /** + *
+ * POPOPrivKey ::= CHOICE { + * thisMessage [0] BIT STRING, -- Deprecated + * -- possession is proven in this message (which contains the private + * -- key itself (encrypted for the CA)) + * subsequentMessage [1] SubsequentMessage, + * -- possession will be proven in a subsequent message + * dhMAC [2] BIT STRING, -- Deprecated + * agreeMAC [3] PKMACValue, + * encryptedKey [4] EnvelopedData } + *+ */ + public ASN1Primitive toASN1Primitive() + { + return new DERTaggedObject(false, tagNo, obj); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/crmf/POPOSigningKey.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/crmf/POPOSigningKey.java new file mode 100644 index 0000000..8a896a4 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/crmf/POPOSigningKey.java @@ -0,0 +1,122 @@ +package org.bc.asn1.crmf; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERBitString; +import org.bc.asn1.DERSequence; +import org.bc.asn1.DERTaggedObject; +import org.bc.asn1.x509.AlgorithmIdentifier; + +public class POPOSigningKey + extends ASN1Object +{ + private POPOSigningKeyInput poposkInput; + private AlgorithmIdentifier algorithmIdentifier; + private DERBitString signature; + + private POPOSigningKey(ASN1Sequence seq) + { + int index = 0; + + if (seq.getObjectAt(index) instanceof ASN1TaggedObject) + { + ASN1TaggedObject tagObj + = (ASN1TaggedObject) seq.getObjectAt(index++); + if (tagObj.getTagNo() != 0) + { + throw new IllegalArgumentException( + "Unknown POPOSigningKeyInput tag: " + tagObj.getTagNo()); + } + poposkInput = POPOSigningKeyInput.getInstance(tagObj.getObject()); + } + algorithmIdentifier = AlgorithmIdentifier.getInstance(seq.getObjectAt(index++)); + signature = DERBitString.getInstance(seq.getObjectAt(index)); + } + + public static POPOSigningKey getInstance(Object o) + { + if (o instanceof POPOSigningKey) + { + return (POPOSigningKey)o; + } + + if (o != null) + { + return new POPOSigningKey(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public static POPOSigningKey getInstance(ASN1TaggedObject obj, boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + /** + * Creates a new Proof of Possession object for a signing key. + * @param poposkIn the POPOSigningKeyInput structure, or null if the + * CertTemplate includes both subject and publicKey values. + * @param aid the AlgorithmIdentifier used to sign the proof of possession. + * @param signature a signature over the DER-encoded value of poposkIn, + * or the DER-encoded value of certReq if poposkIn is null. + */ + public POPOSigningKey( + POPOSigningKeyInput poposkIn, + AlgorithmIdentifier aid, + DERBitString signature) + { + this.poposkInput = poposkIn; + this.algorithmIdentifier = aid; + this.signature = signature; + } + + public POPOSigningKeyInput getPoposkInput() { + return poposkInput; + } + + public AlgorithmIdentifier getAlgorithmIdentifier() { + return algorithmIdentifier; + } + + public DERBitString getSignature() { + return signature; + } + + /** + *
+ * POPOSigningKey ::= SEQUENCE { + * poposkInput [0] POPOSigningKeyInput OPTIONAL, + * algorithmIdentifier AlgorithmIdentifier, + * signature BIT STRING } + * -- The signature (using "algorithmIdentifier") is on the + * -- DER-encoded value of poposkInput. NOTE: If the CertReqMsg + * -- certReq CertTemplate contains the subject and publicKey values, + * -- then poposkInput MUST be omitted and the signature MUST be + * -- computed on the DER-encoded value of CertReqMsg certReq. If + * -- the CertReqMsg certReq CertTemplate does not contain the public + * -- key and subject values, then poposkInput MUST be present and + * -- MUST be signed. This strategy ensures that the public key is + * -- not present in both the poposkInput and CertReqMsg certReq + * -- CertTemplate fields. + *+ * @return a basic ASN.1 object representation. + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + if (poposkInput != null) + { + v.add(new DERTaggedObject(false, 0, poposkInput)); + } + + v.add(algorithmIdentifier); + v.add(signature); + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/crmf/POPOSigningKeyInput.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/crmf/POPOSigningKeyInput.java new file mode 100644 index 0000000..38550d1 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/crmf/POPOSigningKeyInput.java @@ -0,0 +1,134 @@ +package org.bc.asn1.crmf; + +import org.bc.asn1.ASN1Encodable; +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERSequence; +import org.bc.asn1.DERTaggedObject; +import org.bc.asn1.x509.GeneralName; +import org.bc.asn1.x509.SubjectPublicKeyInfo; + +public class POPOSigningKeyInput + extends ASN1Object +{ + private GeneralName sender; + private PKMACValue publicKeyMAC; + private SubjectPublicKeyInfo publicKey; + + private POPOSigningKeyInput(ASN1Sequence seq) + { + ASN1Encodable authInfo = (ASN1Encodable)seq.getObjectAt(0); + + if (authInfo instanceof ASN1TaggedObject) + { + ASN1TaggedObject tagObj = (ASN1TaggedObject)authInfo; + if (tagObj.getTagNo() != 0) + { + throw new IllegalArgumentException( + "Unknown authInfo tag: " + tagObj.getTagNo()); + } + sender = GeneralName.getInstance(tagObj.getObject()); + } + else + { + publicKeyMAC = PKMACValue.getInstance(authInfo); + } + + publicKey = SubjectPublicKeyInfo.getInstance(seq.getObjectAt(1)); + } + + public static POPOSigningKeyInput getInstance(Object o) + { + if (o instanceof POPOSigningKeyInput) + { + return (POPOSigningKeyInput)o; + } + + if (o != null) + { + return new POPOSigningKeyInput(ASN1Sequence.getInstance(o)); + } + + return null; + } + + /** + * Creates a new POPOSigningKeyInput with sender name as authInfo. + */ + public POPOSigningKeyInput( + GeneralName sender, + SubjectPublicKeyInfo spki) + { + this.sender = sender; + this.publicKey = spki; + } + + /** + * Creates a new POPOSigningKeyInput using password-based MAC. + */ + public POPOSigningKeyInput( + PKMACValue pkmac, + SubjectPublicKeyInfo spki) + { + this.publicKeyMAC = pkmac; + this.publicKey = spki; + } + + /** + * Returns the sender field, or null if authInfo is publicKeyMAC + */ + public GeneralName getSender() + { + return sender; + } + + /** + * Returns the publicKeyMAC field, or null if authInfo is sender + */ + public PKMACValue getPublicKeyMAC() + { + return publicKeyMAC; + } + + public SubjectPublicKeyInfo getPublicKey() + { + return publicKey; + } + + /** + *
+ * POPOSigningKeyInput ::= SEQUENCE { + * authInfo CHOICE { + * sender [0] GeneralName, + * -- used only if an authenticated identity has been + * -- established for the sender (e.g., a DN from a + * -- previously-issued and currently-valid certificate + * publicKeyMAC PKMACValue }, + * -- used if no authenticated GeneralName currently exists for + * -- the sender; publicKeyMAC contains a password-based MAC + * -- on the DER-encoded value of publicKey + * publicKey SubjectPublicKeyInfo } -- from CertTemplate + *+ * @return a basic ASN.1 object representation. + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + if (sender != null) + { + v.add(new DERTaggedObject(false, 0, sender)); + } + else + { + v.add(publicKeyMAC); + } + + v.add(publicKey); + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/crmf/ProofOfPossession.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/crmf/ProofOfPossession.java new file mode 100644 index 0000000..0290a2f --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/crmf/ProofOfPossession.java @@ -0,0 +1,108 @@ +package org.bc.asn1.crmf; + +import org.bc.asn1.ASN1Choice; +import org.bc.asn1.ASN1Encodable; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERNull; +import org.bc.asn1.DERTaggedObject; + +public class ProofOfPossession + extends ASN1Object + implements ASN1Choice +{ + public static final int TYPE_RA_VERIFIED = 0; + public static final int TYPE_SIGNING_KEY = 1; + public static final int TYPE_KEY_ENCIPHERMENT = 2; + public static final int TYPE_KEY_AGREEMENT = 3; + + private int tagNo; + private ASN1Encodable obj; + + private ProofOfPossession(ASN1TaggedObject tagged) + { + tagNo = tagged.getTagNo(); + switch (tagNo) + { + case 0: + obj = DERNull.INSTANCE; + break; + case 1: + obj = POPOSigningKey.getInstance(tagged, false); + break; + case 2: + case 3: + obj = POPOPrivKey.getInstance(tagged, true); + break; + default: + throw new IllegalArgumentException("unknown tag: " + tagNo); + } + } + + public static ProofOfPossession getInstance(Object o) + { + if (o == null || o instanceof ProofOfPossession) + { + return (ProofOfPossession)o; + } + + if (o instanceof ASN1TaggedObject) + { + return new ProofOfPossession((ASN1TaggedObject)o); + } + + throw new IllegalArgumentException("Invalid object: " + o.getClass().getName()); + } + + /** Creates a ProofOfPossession with type raVerified. */ + public ProofOfPossession() + { + tagNo = TYPE_RA_VERIFIED; + obj = DERNull.INSTANCE; + } + + /** Creates a ProofOfPossession for a signing key. */ + public ProofOfPossession(POPOSigningKey poposk) + { + tagNo = TYPE_SIGNING_KEY; + obj = poposk; + } + + /** + * Creates a ProofOfPossession for key encipherment or agreement. + * @param type one of TYPE_KEY_ENCIPHERMENT or TYPE_KEY_AGREEMENT + */ + public ProofOfPossession(int type, POPOPrivKey privkey) + { + tagNo = type; + obj = privkey; + } + + public int getType() + { + return tagNo; + } + + public ASN1Encodable getObject() + { + return obj; + } + + /** + *
+ * ProofOfPossession ::= CHOICE { + * raVerified [0] NULL, + * -- used if the RA has already verified that the requester is in + * -- possession of the private key + * signature [1] POPOSigningKey, + * keyEncipherment [2] POPOPrivKey, + * keyAgreement [3] POPOPrivKey } + *+ * @return a basic ASN.1 object representation. + */ + public ASN1Primitive toASN1Primitive() + { + return new DERTaggedObject(false, tagNo, obj); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/crmf/SinglePubInfo.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/crmf/SinglePubInfo.java new file mode 100644 index 0000000..ff398e2 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/crmf/SinglePubInfo.java @@ -0,0 +1,72 @@ +package org.bc.asn1.crmf; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DERSequence; +import org.bc.asn1.x509.GeneralName; + +public class SinglePubInfo + extends ASN1Object +{ + private ASN1Integer pubMethod; + private GeneralName pubLocation; + + private SinglePubInfo(ASN1Sequence seq) + { + pubMethod = ASN1Integer.getInstance(seq.getObjectAt(0)); + + if (seq.size() == 2) + { + pubLocation = GeneralName.getInstance(seq.getObjectAt(1)); + } + } + + public static SinglePubInfo getInstance(Object o) + { + if (o instanceof SinglePubInfo) + { + return (SinglePubInfo)o; + } + + if (o != null) + { + return new SinglePubInfo(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public GeneralName getPubLocation() + { + return pubLocation; + } + + /** + *
+ * SinglePubInfo ::= SEQUENCE { + * pubMethod INTEGER { + * dontCare (0), + * x500 (1), + * web (2), + * ldap (3) }, + * pubLocation GeneralName OPTIONAL } + *+ * @return a basic ASN.1 object representation. + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(pubMethod); + + if (pubLocation != null) + { + v.add(pubLocation); + } + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/crmf/SubsequentMessage.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/crmf/SubsequentMessage.java new file mode 100644 index 0000000..b8baf4f --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/crmf/SubsequentMessage.java @@ -0,0 +1,29 @@ +package org.bc.asn1.crmf; + +import org.bc.asn1.ASN1Integer; + +public class SubsequentMessage + extends ASN1Integer +{ + public static final SubsequentMessage encrCert = new SubsequentMessage(0); + public static final SubsequentMessage challengeResp = new SubsequentMessage(1); + + private SubsequentMessage(int value) + { + super(value); + } + + public static SubsequentMessage valueOf(int value) + { + if (value == 0) + { + return encrCert; + } + if (value == 1) + { + return challengeResp; + } + + throw new IllegalArgumentException("unknown value: " + value); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cryptopro/CryptoProObjectIdentifiers.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cryptopro/CryptoProObjectIdentifiers.java new file mode 100644 index 0000000..6cdde6d --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cryptopro/CryptoProObjectIdentifiers.java @@ -0,0 +1,48 @@ +package org.bc.asn1.cryptopro; + +import org.bc.asn1.ASN1ObjectIdentifier; + +public interface CryptoProObjectIdentifiers +{ + // GOST Algorithms OBJECT IDENTIFIERS : + // { iso(1) member-body(2) ru(643) rans(2) cryptopro(2)} + static final ASN1ObjectIdentifier GOST_id = new ASN1ObjectIdentifier("1.2.643.2.2"); + + static final ASN1ObjectIdentifier gostR3411 = GOST_id.branch("9"); + static final ASN1ObjectIdentifier gostR3411Hmac = GOST_id.branch("10"); + + static final ASN1ObjectIdentifier gostR28147_cbc = new ASN1ObjectIdentifier(GOST_id+".21"); + + static final ASN1ObjectIdentifier id_Gost28147_89_CryptoPro_A_ParamSet = GOST_id.branch("31.1"); + + static final ASN1ObjectIdentifier gostR3410_94 = new ASN1ObjectIdentifier(GOST_id+".20"); + static final ASN1ObjectIdentifier gostR3410_2001 = new ASN1ObjectIdentifier(GOST_id+".19"); + static final ASN1ObjectIdentifier gostR3411_94_with_gostR3410_94 = new ASN1ObjectIdentifier(GOST_id+".4"); + static final ASN1ObjectIdentifier gostR3411_94_with_gostR3410_2001 = new ASN1ObjectIdentifier(GOST_id+".3"); + + // { iso(1) member-body(2) ru(643) rans(2) cryptopro(2) hashes(30) } + static final ASN1ObjectIdentifier gostR3411_94_CryptoProParamSet = new ASN1ObjectIdentifier(GOST_id+".30.1"); + + // { iso(1) member-body(2) ru(643) rans(2) cryptopro(2) signs(32) } + static final ASN1ObjectIdentifier gostR3410_94_CryptoPro_A = new ASN1ObjectIdentifier(GOST_id+".32.2"); + static final ASN1ObjectIdentifier gostR3410_94_CryptoPro_B = new ASN1ObjectIdentifier(GOST_id+".32.3"); + static final ASN1ObjectIdentifier gostR3410_94_CryptoPro_C = new ASN1ObjectIdentifier(GOST_id+".32.4"); + static final ASN1ObjectIdentifier gostR3410_94_CryptoPro_D = new ASN1ObjectIdentifier(GOST_id+".32.5"); + + // { iso(1) member-body(2) ru(643) rans(2) cryptopro(2) exchanges(33) } + static final ASN1ObjectIdentifier gostR3410_94_CryptoPro_XchA = new ASN1ObjectIdentifier(GOST_id+".33.1"); + static final ASN1ObjectIdentifier gostR3410_94_CryptoPro_XchB = new ASN1ObjectIdentifier(GOST_id+".33.2"); + static final ASN1ObjectIdentifier gostR3410_94_CryptoPro_XchC = new ASN1ObjectIdentifier(GOST_id+".33.3"); + + //{ iso(1) member-body(2)ru(643) rans(2) cryptopro(2) ecc-signs(35) } + static final ASN1ObjectIdentifier gostR3410_2001_CryptoPro_A = new ASN1ObjectIdentifier(GOST_id+".35.1"); + static final ASN1ObjectIdentifier gostR3410_2001_CryptoPro_B = new ASN1ObjectIdentifier(GOST_id+".35.2"); + static final ASN1ObjectIdentifier gostR3410_2001_CryptoPro_C = new ASN1ObjectIdentifier(GOST_id+".35.3"); + + // { iso(1) member-body(2) ru(643) rans(2) cryptopro(2) ecc-exchanges(36) } + static final ASN1ObjectIdentifier gostR3410_2001_CryptoPro_XchA = new ASN1ObjectIdentifier(GOST_id+".36.0"); + static final ASN1ObjectIdentifier gostR3410_2001_CryptoPro_XchB = new ASN1ObjectIdentifier(GOST_id+".36.1"); + + static final ASN1ObjectIdentifier gost_ElSgDH3410_default = new ASN1ObjectIdentifier(GOST_id+".36.0"); + static final ASN1ObjectIdentifier gost_ElSgDH3410_1 = new ASN1ObjectIdentifier(GOST_id+".36.1"); +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cryptopro/ECGOST3410NamedCurves.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cryptopro/ECGOST3410NamedCurves.java new file mode 100644 index 0000000..c1f264e --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cryptopro/ECGOST3410NamedCurves.java @@ -0,0 +1,168 @@ +package org.bc.asn1.cryptopro; + +import java.math.BigInteger; +import java.util.Enumeration; +import java.util.Hashtable; + +import org.bc.asn1.ASN1ObjectIdentifier; +import org.bc.crypto.params.ECDomainParameters; +import org.bc.math.ec.ECCurve; +import org.bc.math.ec.ECFieldElement; +import org.bc.math.ec.ECPoint; + +/** + * table of the available named parameters for GOST 3410-2001. + */ +public class ECGOST3410NamedCurves +{ + static final Hashtable objIds = new Hashtable(); + static final Hashtable params = new Hashtable(); + static final Hashtable names = new Hashtable(); + + static + { + BigInteger mod_p = new BigInteger("115792089237316195423570985008687907853269984665640564039457584007913129639319"); + BigInteger mod_q = new BigInteger("115792089237316195423570985008687907853073762908499243225378155805079068850323"); + + ECCurve.Fp curve = new ECCurve.Fp( + mod_p, // p + new BigInteger("115792089237316195423570985008687907853269984665640564039457584007913129639316"), // a + new BigInteger("166")); // b + + ECDomainParameters ecParams = new ECDomainParameters( + curve, + new ECPoint.Fp(curve, + new ECFieldElement.Fp(curve.getQ(),new BigInteger("1")), // x + new ECFieldElement.Fp(curve.getQ(),new BigInteger("64033881142927202683649881450433473985931760268884941288852745803908878638612"))), // y + mod_q); + + params.put(CryptoProObjectIdentifiers.gostR3410_2001_CryptoPro_A, ecParams); + + mod_p = new BigInteger("115792089237316195423570985008687907853269984665640564039457584007913129639319"); + mod_q = new BigInteger("115792089237316195423570985008687907853073762908499243225378155805079068850323"); + + curve = new ECCurve.Fp( + mod_p, // p + new BigInteger("115792089237316195423570985008687907853269984665640564039457584007913129639316"), + new BigInteger("166")); + + ecParams = new ECDomainParameters( + curve, + new ECPoint.Fp(curve, + new ECFieldElement.Fp(curve.getQ(),new BigInteger("1")), // x + new ECFieldElement.Fp(curve.getQ(),new BigInteger("64033881142927202683649881450433473985931760268884941288852745803908878638612"))), // y + mod_q); + + params.put(CryptoProObjectIdentifiers.gostR3410_2001_CryptoPro_XchA, ecParams); + + mod_p = new BigInteger("57896044618658097711785492504343953926634992332820282019728792003956564823193"); //p + mod_q = new BigInteger("57896044618658097711785492504343953927102133160255826820068844496087732066703"); //q + + curve = new ECCurve.Fp( + mod_p, // p + new BigInteger("57896044618658097711785492504343953926634992332820282019728792003956564823190"), // a + new BigInteger("28091019353058090096996979000309560759124368558014865957655842872397301267595")); // b + + ecParams = new ECDomainParameters( + curve, + new ECPoint.Fp(curve, + new ECFieldElement.Fp(mod_p,new BigInteger("1")), // x + new ECFieldElement.Fp(mod_p,new BigInteger("28792665814854611296992347458380284135028636778229113005756334730996303888124"))), // y + mod_q); // q + + params.put(CryptoProObjectIdentifiers.gostR3410_2001_CryptoPro_B, ecParams); + + mod_p = new BigInteger("70390085352083305199547718019018437841079516630045180471284346843705633502619"); + mod_q = new BigInteger("70390085352083305199547718019018437840920882647164081035322601458352298396601"); + + curve = new ECCurve.Fp( + mod_p, // p + new BigInteger("70390085352083305199547718019018437841079516630045180471284346843705633502616"), + new BigInteger("32858")); + + ecParams = new ECDomainParameters( + curve, + new ECPoint.Fp(curve, + new ECFieldElement.Fp(mod_p,new BigInteger("0")), + new ECFieldElement.Fp(mod_p,new BigInteger("29818893917731240733471273240314769927240550812383695689146495261604565990247"))), + mod_q); + + params.put(CryptoProObjectIdentifiers.gostR3410_2001_CryptoPro_XchB, ecParams); + + mod_p = new BigInteger("70390085352083305199547718019018437841079516630045180471284346843705633502619"); //p + mod_q = new BigInteger("70390085352083305199547718019018437840920882647164081035322601458352298396601"); //q + curve = new ECCurve.Fp( + mod_p, // p + new BigInteger("70390085352083305199547718019018437841079516630045180471284346843705633502616"), // a + new BigInteger("32858")); // b + + ecParams = new ECDomainParameters( + curve, + new ECPoint.Fp(curve, + new ECFieldElement.Fp(mod_p,new BigInteger("0")), // x + new ECFieldElement.Fp(mod_p,new BigInteger("29818893917731240733471273240314769927240550812383695689146495261604565990247"))), // y + mod_q); // q + + params.put(CryptoProObjectIdentifiers.gostR3410_2001_CryptoPro_C, ecParams); + + objIds.put("GostR3410-2001-CryptoPro-A", CryptoProObjectIdentifiers.gostR3410_2001_CryptoPro_A); + objIds.put("GostR3410-2001-CryptoPro-B", CryptoProObjectIdentifiers.gostR3410_2001_CryptoPro_B); + objIds.put("GostR3410-2001-CryptoPro-C", CryptoProObjectIdentifiers.gostR3410_2001_CryptoPro_C); + objIds.put("GostR3410-2001-CryptoPro-XchA", CryptoProObjectIdentifiers.gostR3410_2001_CryptoPro_XchA); + objIds.put("GostR3410-2001-CryptoPro-XchB", CryptoProObjectIdentifiers.gostR3410_2001_CryptoPro_XchB); + + names.put(CryptoProObjectIdentifiers.gostR3410_2001_CryptoPro_A, "GostR3410-2001-CryptoPro-A"); + names.put(CryptoProObjectIdentifiers.gostR3410_2001_CryptoPro_B, "GostR3410-2001-CryptoPro-B"); + names.put(CryptoProObjectIdentifiers.gostR3410_2001_CryptoPro_C, "GostR3410-2001-CryptoPro-C"); + names.put(CryptoProObjectIdentifiers.gostR3410_2001_CryptoPro_XchA, "GostR3410-2001-CryptoPro-XchA"); + names.put(CryptoProObjectIdentifiers.gostR3410_2001_CryptoPro_XchB, "GostR3410-2001-CryptoPro-XchB"); + } + + /** + * return the ECDomainParameters object for the given OID, null if it + * isn't present. + * + * @param oid an object identifier representing a named parameters, if present. + */ + public static ECDomainParameters getByOID( + ASN1ObjectIdentifier oid) + { + return (ECDomainParameters)params.get(oid); + } + + /** + * returns an enumeration containing the name strings for parameters + * contained in this structure. + */ + public static Enumeration getNames() + { + return objIds.keys(); + } + + public static ECDomainParameters getByName( + String name) + { + ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)objIds.get(name); + + if (oid != null) + { + return (ECDomainParameters)params.get(oid); + } + + return null; + } + + /** + * return the named curve name represented by the given object identifier. + */ + public static String getName( + ASN1ObjectIdentifier oid) + { + return (String)names.get(oid); + } + + public static ASN1ObjectIdentifier getOID(String name) + { + return (ASN1ObjectIdentifier)objIds.get(name); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cryptopro/ECGOST3410ParamSetParameters.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cryptopro/ECGOST3410ParamSetParameters.java new file mode 100644 index 0000000..f389512 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cryptopro/ECGOST3410ParamSetParameters.java @@ -0,0 +1,99 @@ +package org.bc.asn1.cryptopro; + +import java.math.BigInteger; +import java.util.Enumeration; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERSequence; + +public class ECGOST3410ParamSetParameters + extends ASN1Object +{ + ASN1Integer p, q, a, b, x, y; + + public static ECGOST3410ParamSetParameters getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static ECGOST3410ParamSetParameters getInstance( + Object obj) + { + if(obj == null || obj instanceof ECGOST3410ParamSetParameters) + { + return (ECGOST3410ParamSetParameters)obj; + } + + if(obj instanceof ASN1Sequence) + { + return new ECGOST3410ParamSetParameters((ASN1Sequence)obj); + } + + throw new IllegalArgumentException("Invalid GOST3410Parameter: " + obj.getClass().getName()); + } + + public ECGOST3410ParamSetParameters( + BigInteger a, + BigInteger b, + BigInteger p, + BigInteger q, + int x, + BigInteger y) + { + this.a = new ASN1Integer(a); + this.b = new ASN1Integer(b); + this.p = new ASN1Integer(p); + this.q = new ASN1Integer(q); + this.x = new ASN1Integer(x); + this.y = new ASN1Integer(y); + } + + public ECGOST3410ParamSetParameters( + ASN1Sequence seq) + { + Enumeration e = seq.getObjects(); + + a = (ASN1Integer)e.nextElement(); + b = (ASN1Integer)e.nextElement(); + p = (ASN1Integer)e.nextElement(); + q = (ASN1Integer)e.nextElement(); + x = (ASN1Integer)e.nextElement(); + y = (ASN1Integer)e.nextElement(); + } + + public BigInteger getP() + { + return p.getPositiveValue(); + } + + public BigInteger getQ() + { + return q.getPositiveValue(); + } + + public BigInteger getA() + { + return a.getPositiveValue(); + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(a); + v.add(b); + v.add(p); + v.add(q); + v.add(x); + v.add(y); + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cryptopro/GOST28147Parameters.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cryptopro/GOST28147Parameters.java new file mode 100644 index 0000000..6584ce0 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cryptopro/GOST28147Parameters.java @@ -0,0 +1,72 @@ +package org.bc.asn1.cryptopro; + +import java.util.Enumeration; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1ObjectIdentifier; +import org.bc.asn1.ASN1OctetString; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERSequence; + +public class GOST28147Parameters + extends ASN1Object +{ + ASN1OctetString iv; + ASN1ObjectIdentifier paramSet; + + public static GOST28147Parameters getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static GOST28147Parameters getInstance( + Object obj) + { + if(obj == null || obj instanceof GOST28147Parameters) + { + return (GOST28147Parameters)obj; + } + + if(obj instanceof ASN1Sequence) + { + return new GOST28147Parameters((ASN1Sequence)obj); + } + + throw new IllegalArgumentException("Invalid GOST3410Parameter: " + obj.getClass().getName()); + } + + public GOST28147Parameters( + ASN1Sequence seq) + { + Enumeration e = seq.getObjects(); + + iv = (ASN1OctetString)e.nextElement(); + paramSet = (ASN1ObjectIdentifier)e.nextElement(); + } + + /** + *
+ * Gost28147-89-Parameters ::= + * SEQUENCE { + * iv Gost28147-89-IV, + * encryptionParamSet OBJECT IDENTIFIER + * } + * + * Gost28147-89-IV ::= OCTET STRING (SIZE (8)) + *+ */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(iv); + v.add(paramSet); + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cryptopro/GOST3410NamedParameters.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cryptopro/GOST3410NamedParameters.java new file mode 100644 index 0000000..aa348c8 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cryptopro/GOST3410NamedParameters.java @@ -0,0 +1,116 @@ +package org.bc.asn1.cryptopro; + +import java.math.BigInteger; +import java.util.Enumeration; +import java.util.Hashtable; + +import org.bc.asn1.ASN1ObjectIdentifier; + +/** + * table of the available named parameters for GOST 3410-94. + */ +public class GOST3410NamedParameters +{ + static final Hashtable objIds = new Hashtable(); + static final Hashtable params = new Hashtable(); + static final Hashtable names = new Hashtable(); + + static private GOST3410ParamSetParameters cryptoProA = new GOST3410ParamSetParameters( + 1024, + new BigInteger("127021248288932417465907042777176443525787653508916535812817507265705031260985098497423188333483401180925999995120988934130659205614996724254121049274349357074920312769561451689224110579311248812610229678534638401693520013288995000362260684222750813532307004517341633685004541062586971416883686778842537820383"), + new BigInteger("68363196144955700784444165611827252895102170888761442055095051287550314083023"), + new BigInteger("100997906755055304772081815535925224869841082572053457874823515875577147990529272777244152852699298796483356699682842027972896052747173175480590485607134746852141928680912561502802222185647539190902656116367847270145019066794290930185446216399730872221732889830323194097355403213400972588322876850946740663962") +// validationAlgorithm { +// algorithm +// id-GostR3410-94-bBis, +// parameters +// GostR3410-94-ValidationBisParameters: { +// x0 1376285941, +// c 3996757427 +// } +// } + + ); + + static private GOST3410ParamSetParameters cryptoProB = new GOST3410ParamSetParameters( + 1024, + new BigInteger("139454871199115825601409655107690713107041707059928031797758001454375765357722984094124368522288239833039114681648076688236921220737322672160740747771700911134550432053804647694904686120113087816240740184800477047157336662926249423571248823968542221753660143391485680840520336859458494803187341288580489525163"), + new BigInteger("79885141663410976897627118935756323747307951916507639758300472692338873533959"), + new BigInteger("42941826148615804143873447737955502392672345968607143066798112994089471231420027060385216699563848719957657284814898909770759462613437669456364882730370838934791080835932647976778601915343474400961034231316672578686920482194932878633360203384797092684342247621055760235016132614780652761028509445403338652341") +// validationAlgorithm { +// algorithm +// id-GostR3410-94-bBis, +// parameters +// GostR3410-94-ValidationBisParameters: { +// x0 1536654555, +// c 1855361757, +// d 14408629386140014567655 +//4902939282056547857802241461782996702017713059974755104394739915140 +//6115284791024439062735788342744854120601660303926203867703556828005 +//8957203818114895398976594425537561271800850306 +// } +// } +//} + ); + + static private GOST3410ParamSetParameters cryptoProXchA = new GOST3410ParamSetParameters( + 1024, + new BigInteger("142011741597563481196368286022318089743276138395243738762872573441927459393512718973631166078467600360848946623567625795282774719212241929071046134208380636394084512691828894000571524625445295769349356752728956831541775441763139384457191755096847107846595662547942312293338483924514339614727760681880609734239"), + new BigInteger("91771529896554605945588149018382750217296858393520724172743325725474374979801"), + new BigInteger("133531813272720673433859519948319001217942375967847486899482359599369642528734712461590403327731821410328012529253871914788598993103310567744136196364803064721377826656898686468463277710150809401182608770201615324990468332931294920912776241137878030224355746606283971659376426832674269780880061631528163475887") + ); + + static + { + params.put(CryptoProObjectIdentifiers.gostR3410_94_CryptoPro_A, cryptoProA); + params.put(CryptoProObjectIdentifiers.gostR3410_94_CryptoPro_B, cryptoProB); +// params.put(CryptoProObjectIdentifiers.gostR3410_94_CryptoPro_C, cryptoProC); +// params.put(CryptoProObjectIdentifiers.gostR3410_94_CryptoPro_D, cryptoProD); + params.put(CryptoProObjectIdentifiers.gostR3410_94_CryptoPro_XchA, cryptoProXchA); +// params.put(CryptoProObjectIdentifiers.gostR3410_94_CryptoPro_XchB, cryptoProXchA); +// params.put(CryptoProObjectIdentifiers.gostR3410_94_CryptoPro_XchC, cryptoProXchA); + + objIds.put("GostR3410-94-CryptoPro-A", CryptoProObjectIdentifiers.gostR3410_94_CryptoPro_A); + objIds.put("GostR3410-94-CryptoPro-B", CryptoProObjectIdentifiers.gostR3410_94_CryptoPro_B); + objIds.put("GostR3410-94-CryptoPro-XchA", CryptoProObjectIdentifiers.gostR3410_94_CryptoPro_XchA); + } + + /** + * return the GOST3410ParamSetParameters object for the given OID, null if it + * isn't present. + * + * @param oid an object identifier representing a named parameters, if present. + */ + public static GOST3410ParamSetParameters getByOID( + ASN1ObjectIdentifier oid) + { + return (GOST3410ParamSetParameters)params.get(oid); + } + + /** + * returns an enumeration containing the name strings for parameters + * contained in this structure. + */ + public static Enumeration getNames() + { + return objIds.keys(); + } + + public static GOST3410ParamSetParameters getByName( + String name) + { + ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)objIds.get(name); + + if (oid != null) + { + return (GOST3410ParamSetParameters)params.get(oid); + } + + return null; + } + + public static ASN1ObjectIdentifier getOID(String name) + { + return (ASN1ObjectIdentifier)objIds.get(name); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cryptopro/GOST3410ParamSetParameters.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cryptopro/GOST3410ParamSetParameters.java new file mode 100644 index 0000000..54e6a14 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cryptopro/GOST3410ParamSetParameters.java @@ -0,0 +1,105 @@ +package org.bc.asn1.cryptopro; + +import java.math.BigInteger; +import java.util.Enumeration; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERSequence; + +public class GOST3410ParamSetParameters + extends ASN1Object +{ + int keySize; + ASN1Integer p, q, a; + + public static GOST3410ParamSetParameters getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static GOST3410ParamSetParameters getInstance( + Object obj) + { + if(obj == null || obj instanceof GOST3410ParamSetParameters) + { + return (GOST3410ParamSetParameters)obj; + } + + if(obj instanceof ASN1Sequence) + { + return new GOST3410ParamSetParameters((ASN1Sequence)obj); + } + + throw new IllegalArgumentException("Invalid GOST3410Parameter: " + obj.getClass().getName()); + } + + public GOST3410ParamSetParameters( + int keySize, + BigInteger p, + BigInteger q, + BigInteger a) + { + this.keySize = keySize; + this.p = new ASN1Integer(p); + this.q = new ASN1Integer(q); + this.a = new ASN1Integer(a); + } + + public GOST3410ParamSetParameters( + ASN1Sequence seq) + { + Enumeration e = seq.getObjects(); + + keySize = ((ASN1Integer)e.nextElement()).getValue().intValue(); + p = (ASN1Integer)e.nextElement(); + q = (ASN1Integer)e.nextElement(); + a = (ASN1Integer)e.nextElement(); + } + + /** + * @deprecated use getKeySize + */ + public int getLKeySize() + { + return keySize; + } + + public int getKeySize() + { + return keySize; + } + + public BigInteger getP() + { + return p.getPositiveValue(); + } + + public BigInteger getQ() + { + return q.getPositiveValue(); + } + + public BigInteger getA() + { + return a.getPositiveValue(); + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(new ASN1Integer(keySize)); + v.add(p); + v.add(q); + v.add(a); + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cryptopro/GOST3410PublicKeyAlgParameters.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cryptopro/GOST3410PublicKeyAlgParameters.java new file mode 100644 index 0000000..d7bf09a --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/cryptopro/GOST3410PublicKeyAlgParameters.java @@ -0,0 +1,101 @@ +package org.bc.asn1.cryptopro; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1ObjectIdentifier; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERSequence; + +public class GOST3410PublicKeyAlgParameters + extends ASN1Object +{ + private ASN1ObjectIdentifier publicKeyParamSet; + private ASN1ObjectIdentifier digestParamSet; + private ASN1ObjectIdentifier encryptionParamSet; + + public static GOST3410PublicKeyAlgParameters getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static GOST3410PublicKeyAlgParameters getInstance( + Object obj) + { + if (obj instanceof GOST3410PublicKeyAlgParameters) + { + return (GOST3410PublicKeyAlgParameters)obj; + } + + if(obj != null) + { + return new GOST3410PublicKeyAlgParameters(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public GOST3410PublicKeyAlgParameters( + ASN1ObjectIdentifier publicKeyParamSet, + ASN1ObjectIdentifier digestParamSet) + { + this.publicKeyParamSet = publicKeyParamSet; + this.digestParamSet = digestParamSet; + this.encryptionParamSet = null; + } + + public GOST3410PublicKeyAlgParameters( + ASN1ObjectIdentifier publicKeyParamSet, + ASN1ObjectIdentifier digestParamSet, + ASN1ObjectIdentifier encryptionParamSet) + { + this.publicKeyParamSet = publicKeyParamSet; + this.digestParamSet = digestParamSet; + this.encryptionParamSet = encryptionParamSet; + } + + public GOST3410PublicKeyAlgParameters( + ASN1Sequence seq) + { + this.publicKeyParamSet = (ASN1ObjectIdentifier)seq.getObjectAt(0); + this.digestParamSet = (ASN1ObjectIdentifier)seq.getObjectAt(1); + + if (seq.size() > 2) + { + this.encryptionParamSet = (ASN1ObjectIdentifier)seq.getObjectAt(2); + } + } + + public ASN1ObjectIdentifier getPublicKeyParamSet() + { + return publicKeyParamSet; + } + + public ASN1ObjectIdentifier getDigestParamSet() + { + return digestParamSet; + } + + public ASN1ObjectIdentifier getEncryptionParamSet() + { + return encryptionParamSet; + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(publicKeyParamSet); + v.add(digestParamSet); + + if (encryptionParamSet != null) + { + v.add(encryptionParamSet); + } + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/eac/BidirectionalMap.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/eac/BidirectionalMap.java new file mode 100644 index 0000000..03e43a9 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/eac/BidirectionalMap.java @@ -0,0 +1,21 @@ +package org.bc.asn1.eac; + +import java.util.Hashtable; + +public class BidirectionalMap extends Hashtable{ + private static final long serialVersionUID = -7457289971962812909L; + + Hashtable reverseMap = new Hashtable(); + + public Object getReverse(Object o) + { + return reverseMap.get(o); + } + + public Object put(Object key, Object o) + { + reverseMap.put(o, key); + return super.put(key, o); + } + +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/eac/CVCertificate.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/eac/CVCertificate.java new file mode 100644 index 0000000..863573d --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/eac/CVCertificate.java @@ -0,0 +1,317 @@ +package org.bc.asn1.eac; + + +import java.io.IOException; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1InputStream; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1ObjectIdentifier; +import org.bc.asn1.ASN1ParsingException; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.DERApplicationSpecific; +import org.bc.asn1.DEROctetString; + + +/** + * an iso7816Certificate structure. + * + *
+ * Certificate ::= SEQUENCE { + * CertificateBody Iso7816CertificateBody, + * signature DER Application specific + * } + *+ */ +public class CVCertificate + extends ASN1Object +{ + private CertificateBody certificateBody; + private byte[] signature; + private int valid; + private static int bodyValid = 0x01; + private static int signValid = 0x02; + public static final byte version_1 = 0x0; + + public static String ReferenceEncoding = "ISO-8859-1"; + + /** + * Sets the values of the certificate (body and signature). + * + * @param appSpe is a DERApplicationSpecific object containing body and signature. + * @throws IOException if tags or value are incorrect. + */ + private void setPrivateData(DERApplicationSpecific appSpe) + throws IOException + { + valid = 0; + if (appSpe.getApplicationTag() == EACTags.CARDHOLDER_CERTIFICATE) + { + ASN1InputStream content = new ASN1InputStream(appSpe.getContents()); + ASN1Primitive tmpObj; + while ((tmpObj = content.readObject()) != null) + { + DERApplicationSpecific aSpe; + if (tmpObj instanceof DERApplicationSpecific) + { + aSpe = (DERApplicationSpecific)tmpObj; + switch (aSpe.getApplicationTag()) + { + case EACTags.CERTIFICATE_CONTENT_TEMPLATE: + certificateBody = CertificateBody.getInstance(aSpe); + valid |= bodyValid; + break; + case EACTags.STATIC_INTERNAL_AUTHENTIFICATION_ONE_STEP: + signature = aSpe.getContents(); + valid |= signValid; + break; + default: + throw new IOException("Invalid tag, not an Iso7816CertificateStructure :" + aSpe.getApplicationTag()); + } + } + else + { + throw new IOException("Invalid Object, not an Iso7816CertificateStructure"); + } + } + } + else + { + throw new IOException("not a CARDHOLDER_CERTIFICATE :" + appSpe.getApplicationTag()); + } + } + + /** + * Create an iso7816Certificate structure from an ASN1InputStream. + * + * @param aIS the byte stream to parse. + * @return the Iso7816CertificateStructure represented by the byte stream. + * @throws IOException if there is a problem parsing the data. + */ + public CVCertificate(ASN1InputStream aIS) + throws IOException + { + initFrom(aIS); + } + + private void initFrom(ASN1InputStream aIS) + throws IOException + { + ASN1Primitive obj; + while ((obj = aIS.readObject()) != null) + { + if (obj instanceof DERApplicationSpecific) + { + setPrivateData((DERApplicationSpecific)obj); + } + else + { + throw new IOException("Invalid Input Stream for creating an Iso7816CertificateStructure"); + } + } + } + + /** + * Create an iso7816Certificate structure from a DERApplicationSpecific. + * + * @param appSpe the DERApplicationSpecific object. + * @return the Iso7816CertificateStructure represented by the DERApplicationSpecific object. + * @throws IOException if there is a problem parsing the data. + */ + private CVCertificate(DERApplicationSpecific appSpe) + throws IOException + { + setPrivateData(appSpe); + } + + /** + * Create an iso7816Certificate structure from a body and its signature. + * + * @param body the Iso7816CertificateBody object containing the body. + * @param signature the byte array containing the signature + * @return the Iso7816CertificateStructure + * @throws IOException if there is a problem parsing the data. + */ + public CVCertificate(CertificateBody body, byte[] signature) + throws IOException + { + certificateBody = body; + this.signature = signature; + // patch remi + valid |= bodyValid; + valid |= signValid; + } + + /** + * Create an iso7816Certificate structure from an object. + * + * @param obj the Object to extract the certificate from. + * @return the Iso7816CertificateStructure represented by the byte stream. + * @throws IOException if there is a problem parsing the data. + */ + public static CVCertificate getInstance(Object obj) + { + if (obj instanceof CVCertificate) + { + return (CVCertificate)obj; + } + else if (obj != null) + { + try + { + return new CVCertificate(DERApplicationSpecific.getInstance(obj)); + } + catch (IOException e) + { + throw new ASN1ParsingException("unable to parse data: " + e.getMessage(), e); + } + } + + return null; + } + + /** + * Gives the signature of the whole body. Type of signature is given in + * the Iso7816CertificateBody.Iso7816PublicKey.ASN1ObjectIdentifier + * + * @return the signature of the body. + */ + public byte[] getSignature() + { + return signature; + } + + /** + * Gives the body of the certificate. + * + * @return the body. + */ + public CertificateBody getBody() + { + return certificateBody; + } + + /** + * @see org.bc.asn1.ASN1Object#toASN1Primitive() + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + if (valid != (signValid | bodyValid)) + { + return null; + } + v.add(certificateBody); + + try + { + v.add(new DERApplicationSpecific(false, EACTags.STATIC_INTERNAL_AUTHENTIFICATION_ONE_STEP, new DEROctetString(signature))); + } + catch (IOException e) + { + throw new IllegalStateException("unable to convert signature!"); + } + + return new DERApplicationSpecific(EACTags.CARDHOLDER_CERTIFICATE, v); + } + + /** + * @return the Holder authorization and role (CVCA, DV, IS). + */ + public ASN1ObjectIdentifier getHolderAuthorization() + throws IOException + { + CertificateHolderAuthorization cha = certificateBody.getCertificateHolderAuthorization(); + return cha.getOid(); + } + + /** + * @return the date of the certificate generation + */ + public PackedDate getEffectiveDate() + throws IOException + { + return certificateBody.getCertificateEffectiveDate(); + } + + + /** + * @return the type of certificate (request or profile) + * value is either Iso7816CertificateBody.profileType + * or Iso7816CertificateBody.requestType. Any other value + * is not valid. + */ + public int getCertificateType() + { + return this.certificateBody.getCertificateType(); + } + + /** + * @return the date of the certificate generation + */ + public PackedDate getExpirationDate() + throws IOException + { + return certificateBody.getCertificateExpirationDate(); + } + + + /** + * return a bits field coded on one byte. For signification of the + * several bit see Iso7816CertificateHolderAuthorization + * + * @return role and access rigth + * @throws IOException + * @see CertificateHolderAuthorization + */ + public int getRole() + throws IOException + { + CertificateHolderAuthorization cha = certificateBody.getCertificateHolderAuthorization(); + return cha.getAccessRights(); + } + + /** + * @return the Authority Reference field of the certificate + * @throws IOException + */ + public CertificationAuthorityReference getAuthorityReference() + throws IOException + { + return certificateBody.getCertificationAuthorityReference(); + } + + /** + * @return the Holder Reference Field of the certificate + * @throws IOException + */ + public CertificateHolderReference getHolderReference() + throws IOException + { + return certificateBody.getCertificateHolderReference(); + } + + /** + * @return the bits corresponding to the role intented for the certificate + * See Iso7816CertificateHolderAuthorization static int for values + * @throws IOException + */ + public int getHolderAuthorizationRole() + throws IOException + { + int rights = certificateBody.getCertificateHolderAuthorization().getAccessRights(); + return rights & 0xC0; + } + + /** + * @return the bits corresponding the authorizations contained in the certificate + * See Iso7816CertificateHolderAuthorization static int for values + * @throws IOException + */ + public Flags getHolderAuthorizationRights() + throws IOException + { + return new Flags(certificateBody.getCertificateHolderAuthorization().getAccessRights() & 0x1F); + } +} \ No newline at end of file diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/eac/CVCertificateRequest.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/eac/CVCertificateRequest.java new file mode 100644 index 0000000..785fa4f --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/eac/CVCertificateRequest.java @@ -0,0 +1,170 @@ +package org.bc.asn1.eac; + +import java.io.IOException; +import java.util.Enumeration; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1ObjectIdentifier; +import org.bc.asn1.ASN1ParsingException; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.BERTags; +import org.bc.asn1.DERApplicationSpecific; +import org.bc.asn1.DEROctetString; + +//import java.math.BigInteger; + + +public class CVCertificateRequest + extends ASN1Object +{ + private CertificateBody certificateBody; + + private byte[] innerSignature = null; + private byte[] outerSignature = null; + + private int valid; + + private static int bodyValid = 0x01; + private static int signValid = 0x02; + + private CVCertificateRequest(DERApplicationSpecific request) + throws IOException + { + if (request.getApplicationTag() == EACTags.AUTHENTIFICATION_DATA) + { + ASN1Sequence seq = ASN1Sequence.getInstance(request.getObject(BERTags.SEQUENCE)); + + initCertBody(DERApplicationSpecific.getInstance(seq.getObjectAt(0))); + + outerSignature = DERApplicationSpecific.getInstance(seq.getObjectAt(seq.size() - 1)).getContents(); + } + else + { + initCertBody(request); + } + } + + private void initCertBody(DERApplicationSpecific request) + throws IOException + { + if (request.getApplicationTag() == EACTags.CARDHOLDER_CERTIFICATE) + { + ASN1Sequence seq = ASN1Sequence.getInstance(request.getObject(BERTags.SEQUENCE)); + for (Enumeration en = seq.getObjects(); en.hasMoreElements();) + { + DERApplicationSpecific obj = DERApplicationSpecific.getInstance(en.nextElement()); + switch (obj.getApplicationTag()) + { + case EACTags.CERTIFICATE_CONTENT_TEMPLATE: + certificateBody = CertificateBody.getInstance(obj); + valid |= bodyValid; + break; + case EACTags.STATIC_INTERNAL_AUTHENTIFICATION_ONE_STEP: + innerSignature = obj.getContents(); + valid |= signValid; + break; + default: + throw new IOException("Invalid tag, not an CV Certificate Request element:" + obj.getApplicationTag()); + } + } + } + else + { + throw new IOException("not a CARDHOLDER_CERTIFICATE in request:" + request.getApplicationTag()); + } + } + + public static CVCertificateRequest getInstance(Object obj) + { + if (obj instanceof CVCertificateRequest) + { + return (CVCertificateRequest)obj; + } + else if (obj != null) + { + try + { + return new CVCertificateRequest(DERApplicationSpecific.getInstance(obj)); + } + catch (IOException e) + { + throw new ASN1ParsingException("unable to parse data: " + e.getMessage(), e); + } + } + + return null; + } + + ASN1ObjectIdentifier signOid = null; + ASN1ObjectIdentifier keyOid = null; + + public static byte[] ZeroArray = new byte[]{0}; + + + String strCertificateHolderReference; + + byte[] encodedAuthorityReference; + + int ProfileId; + + /** + * Returns the body of the certificate template + * + * @return the body. + */ + public CertificateBody getCertificateBody() + { + return certificateBody; + } + + /** + * Return the public key data object carried in the request + * @return the public key + */ + public PublicKeyDataObject getPublicKey() + { + return certificateBody.getPublicKey(); + } + + public byte[] getInnerSignature() + { + return innerSignature; + } + + public byte[] getOuterSignature() + { + return outerSignature; + } + + byte[] certificate = null; + protected String overSignerReference = null; + + public boolean hasOuterSignature() + { + return outerSignature != null; + } + + byte[] encoded; + + PublicKeyDataObject iso7816PubKey = null; + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(certificateBody); + + try + { + v.add(new DERApplicationSpecific(false, EACTags.STATIC_INTERNAL_AUTHENTIFICATION_ONE_STEP, new DEROctetString(innerSignature))); + } + catch (IOException e) + { + throw new IllegalStateException("unable to convert signature!"); + } + + return new DERApplicationSpecific(EACTags.CARDHOLDER_CERTIFICATE, v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/eac/CertificateBody.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/eac/CertificateBody.java new file mode 100644 index 0000000..5e902c8 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/eac/CertificateBody.java @@ -0,0 +1,460 @@ +package org.bc.asn1.eac; + +import java.io.IOException; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1InputStream; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.BERTags; +import org.bc.asn1.DERApplicationSpecific; +import org.bc.asn1.DEROctetString; + + +/** + * an Iso7816CertificateBody structure. + * + *
+ * CertificateBody ::= SEQUENCE { + * // version of the certificate format. Must be 0 (version 1) + * CertificateProfileIdentifer DERApplicationSpecific, + * //uniquely identifies the issuinng CA's signature key pair + * // contains the iso3166-1 alpha2 encoded country code, the + * // name of issuer and the sequence number of the key pair. + * CertificationAuthorityReference DERApplicationSpecific, + * // stores the encoded public key + * PublicKey Iso7816PublicKey, + * //associates the public key contained in the certificate with a unique name + * // contains the iso3166-1 alpha2 encoded country code, the + * // name of the holder and the sequence number of the key pair. + * certificateHolderReference DERApplicationSpecific, + * // Encodes the role of the holder (i.e. CVCA, DV, IS) and assigns read/write + * // access rights to data groups storing sensitive data + * certificateHolderAuthorization Iso7816CertificateHolderAuthorization, + * // the date of the certificate generation + * CertificateEffectiveDate DERApplicationSpecific, + * // the date after wich the certificate expires + * certificateExpirationDate DERApplicationSpecific + * } + *+ */ +public class CertificateBody + extends ASN1Object +{ + ASN1InputStream seq; + private DERApplicationSpecific certificateProfileIdentifier;// version of the certificate format. Must be 0 (version 1) + private DERApplicationSpecific certificationAuthorityReference;//uniquely identifies the issuinng CA's signature key pair + private PublicKeyDataObject publicKey;// stores the encoded public key + private DERApplicationSpecific certificateHolderReference;//associates the public key contained in the certificate with a unique name + private CertificateHolderAuthorization certificateHolderAuthorization;// Encodes the role of the holder (i.e. CVCA, DV, IS) and assigns read/write access rights to data groups storing sensitive data + private DERApplicationSpecific certificateEffectiveDate;// the date of the certificate generation + private DERApplicationSpecific certificateExpirationDate;// the date after wich the certificate expires + private int certificateType = 0;// bit field of initialized data. This will tell us if the data are valid. + private static final int CPI = 0x01;//certificate Profile Identifier + private static final int CAR = 0x02;//certification Authority Reference + private static final int PK = 0x04;//public Key + private static final int CHR = 0x08;//certificate Holder Reference + private static final int CHA = 0x10;//certificate Holder Authorization + private static final int CEfD = 0x20;//certificate Effective Date + private static final int CExD = 0x40;//certificate Expiration Date + + public static final int profileType = 0x7f;//Profile type Certificate + public static final int requestType = 0x0D;// Request type Certificate + + private void setIso7816CertificateBody(DERApplicationSpecific appSpe) + throws IOException + { + byte[] content; + if (appSpe.getApplicationTag() == EACTags.CERTIFICATE_CONTENT_TEMPLATE) + { + content = appSpe.getContents(); + } + else + { + throw new IOException("Bad tag : not an iso7816 CERTIFICATE_CONTENT_TEMPLATE"); + } + ASN1InputStream aIS = new ASN1InputStream(content); + ASN1Primitive obj; + while ((obj = aIS.readObject()) != null) + { + DERApplicationSpecific aSpe; + + if (obj instanceof DERApplicationSpecific) + { + aSpe = (DERApplicationSpecific)obj; + } + else + { + throw new IOException("Not a valid iso7816 content : not a DERApplicationSpecific Object :" + EACTags.encodeTag(appSpe) + obj.getClass()); + } + switch (aSpe.getApplicationTag()) + { + case EACTags.INTERCHANGE_PROFILE: + setCertificateProfileIdentifier(aSpe); + break; + case EACTags.ISSUER_IDENTIFICATION_NUMBER: + setCertificationAuthorityReference(aSpe); + break; + case EACTags.CARDHOLDER_PUBLIC_KEY_TEMPLATE: + setPublicKey(PublicKeyDataObject.getInstance(aSpe.getObject(BERTags.SEQUENCE))); + break; + case EACTags.CARDHOLDER_NAME: + setCertificateHolderReference(aSpe); + break; + case EACTags.CERTIFICATE_HOLDER_AUTHORIZATION_TEMPLATE: + setCertificateHolderAuthorization(new CertificateHolderAuthorization(aSpe)); + break; + case EACTags.APPLICATION_EFFECTIVE_DATE: + setCertificateEffectiveDate(aSpe); + break; + case EACTags.APPLICATION_EXPIRATION_DATE: + setCertificateExpirationDate(aSpe); + break; + default: + certificateType = 0; + throw new IOException("Not a valid iso7816 DERApplicationSpecific tag " + aSpe.getApplicationTag()); + } + } + } + + /** + * builds an Iso7816CertificateBody by settings each parameters. + * + * @param certificateProfileIdentifier + * @param certificationAuthorityReference + * + * @param publicKey + * @param certificateHolderReference + * @param certificateHolderAuthorization + * @param certificateEffectiveDate + * @param certificateExpirationDate + * @throws IOException + */ + public CertificateBody( + DERApplicationSpecific certificateProfileIdentifier, + CertificationAuthorityReference certificationAuthorityReference, + PublicKeyDataObject publicKey, + CertificateHolderReference certificateHolderReference, + CertificateHolderAuthorization certificateHolderAuthorization, + PackedDate certificateEffectiveDate, + PackedDate certificateExpirationDate + ) + { + setCertificateProfileIdentifier(certificateProfileIdentifier); + setCertificationAuthorityReference(new DERApplicationSpecific( + EACTags.ISSUER_IDENTIFICATION_NUMBER, certificationAuthorityReference.getEncoded())); + setPublicKey(publicKey); + setCertificateHolderReference(new DERApplicationSpecific( + EACTags.CARDHOLDER_NAME, certificateHolderReference.getEncoded())); + setCertificateHolderAuthorization(certificateHolderAuthorization); + try + { + setCertificateEffectiveDate(new DERApplicationSpecific( + false, EACTags.APPLICATION_EFFECTIVE_DATE, new DEROctetString(certificateEffectiveDate.getEncoding()))); + setCertificateExpirationDate(new DERApplicationSpecific( + false, EACTags.APPLICATION_EXPIRATION_DATE, new DEROctetString(certificateExpirationDate.getEncoding()))); + } + catch (IOException e) + { + throw new IllegalArgumentException("unable to encode dates: " + e.getMessage()); + } + } + + /** + * builds an Iso7816CertificateBody with an ASN1InputStream. + * + * @param obj DERApplicationSpecific containing the whole body. + * @throws IOException if the body is not valid. + */ + private CertificateBody(DERApplicationSpecific obj) + throws IOException + { + setIso7816CertificateBody(obj); + } + + /** + * create a profile type Iso7816CertificateBody. + * + * @return return the "profile" type certificate body. + * @throws IOException if the DERApplicationSpecific cannot be created. + */ + private ASN1Primitive profileToASN1Object() + throws IOException + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(certificateProfileIdentifier); + v.add(certificationAuthorityReference); + v.add(new DERApplicationSpecific(false, EACTags.CARDHOLDER_PUBLIC_KEY_TEMPLATE, publicKey)); + v.add(certificateHolderReference); + v.add(certificateHolderAuthorization); + v.add(certificateEffectiveDate); + v.add(certificateExpirationDate); + return new DERApplicationSpecific(EACTags.CERTIFICATE_CONTENT_TEMPLATE, v); + } + + private void setCertificateProfileIdentifier(DERApplicationSpecific certificateProfileIdentifier) + throws IllegalArgumentException { + if (certificateProfileIdentifier.getApplicationTag() == EACTags.INTERCHANGE_PROFILE) { + this.certificateProfileIdentifier = certificateProfileIdentifier; + certificateType |= CPI; + } + else + throw new IllegalArgumentException("Not an Iso7816Tags.INTERCHANGE_PROFILE tag :"+ EACTags.encodeTag(certificateProfileIdentifier)); + } + + private void setCertificateHolderReference(DERApplicationSpecific certificateHolderReference) + throws IllegalArgumentException { + if (certificateHolderReference.getApplicationTag() == EACTags.CARDHOLDER_NAME) { + this.certificateHolderReference = certificateHolderReference; + certificateType |= CHR; + } + else + throw new IllegalArgumentException("Not an Iso7816Tags.CARDHOLDER_NAME tag"); + } + + /** + * set the CertificationAuthorityReference. + * @param certificationAuthorityReference the DERApplicationSpecific containing the CertificationAuthorityReference. + * @throws IllegalArgumentException if the DERApplicationSpecific is not valid. + */ + private void setCertificationAuthorityReference( + DERApplicationSpecific certificationAuthorityReference) + throws IllegalArgumentException { + if (certificationAuthorityReference.getApplicationTag() == EACTags.ISSUER_IDENTIFICATION_NUMBER) { + this.certificationAuthorityReference = certificationAuthorityReference; + certificateType |= CAR; + } + else + throw new IllegalArgumentException("Not an Iso7816Tags.ISSUER_IDENTIFICATION_NUMBER tag"); + } + + /** + * set the public Key + * @param publicKey : the DERApplicationSpecific containing the public key + * @throws java.io.IOException + */ + private void setPublicKey(PublicKeyDataObject publicKey) + { + this.publicKey = PublicKeyDataObject.getInstance(publicKey); + this.certificateType |= PK; + } + + /** + * create a request type Iso7816CertificateBody. + * + * @return return the "request" type certificate body. + * @throws IOException if the DERApplicationSpecific cannot be created. + */ + private ASN1Primitive requestToASN1Object() + throws IOException + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(certificateProfileIdentifier); + v.add(new DERApplicationSpecific(false, EACTags.CARDHOLDER_PUBLIC_KEY_TEMPLATE, publicKey)); + v.add(certificateHolderReference); + return new DERApplicationSpecific(EACTags.CERTIFICATE_CONTENT_TEMPLATE, v); + } + + /** + * create a "request" or "profile" type Iso7816CertificateBody according to the variables sets. + * + * @return return the ASN1Primitive representing the "request" or "profile" type certificate body. + * @throws IOException if the DERApplicationSpecific cannot be created or if data are missings to create a valid certificate. + */ + public ASN1Primitive toASN1Primitive() + { + try + { + if (certificateType == profileType) + { + return profileToASN1Object(); + } + if (certificateType == requestType) + { + return requestToASN1Object(); + } + } + catch (IOException e) + { + return null; + } + return null; + } + + /** + * gives the type of the certificate (value should be profileType or requestType if all data are set). + * + * @return the int representing the data already set. + */ + public int getCertificateType() + { + return certificateType; + } + + /** + * Gives an instance of Iso7816CertificateBody taken from Object obj + * + * @param obj is the Object to extract the certificate body from. + * @return the Iso7816CertificateBody taken from Object obj. + * @throws IOException if object is not valid. + */ + public static CertificateBody getInstance(Object obj) + throws IOException + { + if (obj instanceof CertificateBody) + { + return (CertificateBody)obj; + } + else if (obj != null) + { + return new CertificateBody(DERApplicationSpecific.getInstance(obj)); + } + + return null; + } + + /** + * @return the date of the certificate generation + */ + public PackedDate getCertificateEffectiveDate() + { + if ((this.certificateType & CertificateBody.CEfD) == + CertificateBody.CEfD) + { + return new PackedDate(certificateEffectiveDate.getContents()); + } + return null; + } + + /** + * set the date of the certificate generation + * + * @param ced DERApplicationSpecific containing the date of the certificate generation + * @throws IllegalArgumentException if the tag is not Iso7816Tags.APPLICATION_EFFECTIVE_DATE + */ + private void setCertificateEffectiveDate(DERApplicationSpecific ced) + throws IllegalArgumentException + { + if (ced.getApplicationTag() == EACTags.APPLICATION_EFFECTIVE_DATE) + { + this.certificateEffectiveDate = ced; + certificateType |= CEfD; + } + else + { + throw new IllegalArgumentException("Not an Iso7816Tags.APPLICATION_EFFECTIVE_DATE tag :" + EACTags.encodeTag(ced)); + } + } + + /** + * @return the date after wich the certificate expires + */ + public PackedDate getCertificateExpirationDate() + throws IOException + { + if ((this.certificateType & CertificateBody.CExD) == + CertificateBody.CExD) + { + return new PackedDate(certificateExpirationDate.getContents()); + } + throw new IOException("certificate Expiration Date not set"); + } + + /** + * set the date after wich the certificate expires + * + * @param ced DERApplicationSpecific containing the date after wich the certificate expires + * @throws IllegalArgumentException if the tag is not Iso7816Tags.APPLICATION_EXPIRATION_DATE + */ + private void setCertificateExpirationDate(DERApplicationSpecific ced) + throws IllegalArgumentException + { + if (ced.getApplicationTag() == EACTags.APPLICATION_EXPIRATION_DATE) + { + this.certificateExpirationDate = ced; + certificateType |= CExD; + } + else + { + throw new IllegalArgumentException("Not an Iso7816Tags.APPLICATION_EXPIRATION_DATE tag"); + } + } + + /** + * the Iso7816CertificateHolderAuthorization encodes the role of the holder + * (i.e. CVCA, DV, IS) and assigns read/write access rights to data groups + * storing sensitive data. This functions returns the Certificate Holder + * Authorization + * + * @return the Iso7816CertificateHolderAuthorization + */ + public CertificateHolderAuthorization getCertificateHolderAuthorization() + throws IOException + { + if ((this.certificateType & CertificateBody.CHA) == + CertificateBody.CHA) + { + return certificateHolderAuthorization; + } + throw new IOException("Certificate Holder Authorisation not set"); + } + + /** + * set the CertificateHolderAuthorization + * + * @param cha the Certificate Holder Authorization + */ + private void setCertificateHolderAuthorization( + CertificateHolderAuthorization cha) + { + this.certificateHolderAuthorization = cha; + certificateType |= CHA; + } + + /** + * certificateHolderReference : associates the public key contained in the certificate with a unique name + * + * @return the certificateHolderReference. + */ + public CertificateHolderReference getCertificateHolderReference() + { + return new CertificateHolderReference(certificateHolderReference.getContents()); + } + + /** + * CertificateProfileIdentifier : version of the certificate format. Must be 0 (version 1) + * + * @return the CertificateProfileIdentifier + */ + public DERApplicationSpecific getCertificateProfileIdentifier() + { + return certificateProfileIdentifier; + } + + /** + * get the certificationAuthorityReference + * certificationAuthorityReference : uniquely identifies the issuinng CA's signature key pair + * + * @return the certificationAuthorityReference + */ + public CertificationAuthorityReference getCertificationAuthorityReference() + throws IOException + { + if ((this.certificateType & CertificateBody.CAR) == + CertificateBody.CAR) + { + return new CertificationAuthorityReference(certificationAuthorityReference.getContents()); + } + throw new IOException("Certification authority reference not set"); + } + + /** + * @return the PublicKey + */ + public PublicKeyDataObject getPublicKey() + { + return publicKey; + } +} \ No newline at end of file diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/eac/CertificateHolderAuthorization.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/eac/CertificateHolderAuthorization.java new file mode 100644 index 0000000..bd0d7af --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/eac/CertificateHolderAuthorization.java @@ -0,0 +1,185 @@ +package org.bc.asn1.eac; + +import java.io.IOException; +import java.util.Hashtable; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1InputStream; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1ObjectIdentifier; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.DERApplicationSpecific; +import org.bc.util.Integers; + +/** + * an Iso7816CertificateHolderAuthorization structure. + * + *
+ * Certificate Holder Authorization ::= SEQUENCE { + * // specifies the format and the rules for the evaluation of the authorization + * // level + * ASN1ObjectIdentifier oid, + * // access rights + * DERApplicationSpecific accessRights, + * } + *+ */ +public class CertificateHolderAuthorization + extends ASN1Object +{ + ASN1ObjectIdentifier oid; + DERApplicationSpecific accessRights; + public static final ASN1ObjectIdentifier id_role_EAC = EACObjectIdentifiers.bsi_de.branch("3.1.2.1"); + public static final int CVCA = 0xC0; + public static final int DV_DOMESTIC = 0x80; + public static final int DV_FOREIGN = 0x40; + public static final int IS = 0; + public static final int RADG4 = 0x02;//Read Access to DG4 (Iris) + public static final int RADG3 = 0x01;//Read Access to DG3 (fingerprint) + + static Hashtable RightsDecodeMap = new Hashtable(); + static BidirectionalMap AuthorizationRole = new BidirectionalMap(); + static Hashtable ReverseMap = new Hashtable(); + + static + { + RightsDecodeMap.put(Integers.valueOf(RADG4), "RADG4"); + RightsDecodeMap.put(Integers.valueOf(RADG3), "RADG3"); + + AuthorizationRole.put(Integers.valueOf(CVCA), "CVCA"); + AuthorizationRole.put(Integers.valueOf(DV_DOMESTIC), "DV_DOMESTIC"); + AuthorizationRole.put(Integers.valueOf(DV_FOREIGN), "DV_FOREIGN"); + AuthorizationRole.put(Integers.valueOf(IS), "IS"); + + /* + for (int i : RightsDecodeMap.keySet()) + ReverseMap.put(RightsDecodeMap.get(i), i); + + for (int i : AuthorizationRole.keySet()) + ReverseMap.put(AuthorizationRole.get(i), i); + */ + } + + public static String GetRoleDescription(int i) + { + return (String)AuthorizationRole.get(Integers.valueOf(i)); + } + + public static int GetFlag(String description) + { + Integer i = (Integer)AuthorizationRole.getReverse(description); + if (i == null) + { + throw new IllegalArgumentException("Unknown value " + description); + } + + return i.intValue(); + } + + private void setPrivateData(ASN1InputStream cha) + throws IOException + { + ASN1Primitive obj; + obj = cha.readObject(); + if (obj instanceof ASN1ObjectIdentifier) + { + this.oid = (ASN1ObjectIdentifier)obj; + } + else + { + throw new IllegalArgumentException("no Oid in CerticateHolderAuthorization"); + } + obj = cha.readObject(); + if (obj instanceof DERApplicationSpecific) + { + this.accessRights = (DERApplicationSpecific)obj; + } + else + { + throw new IllegalArgumentException("No access rights in CerticateHolderAuthorization"); + } + } + + + /** + * create an Iso7816CertificateHolderAuthorization according to the parameters + * + * @param oid Object Identifier : specifies the format and the rules for the + * evaluatioin of the authorization level. + * @param rights specifies the access rights + * @throws IOException + */ + public CertificateHolderAuthorization(ASN1ObjectIdentifier oid, int rights) + throws IOException + { + setOid(oid); + setAccessRights((byte)rights); + } + + /** + * create an Iso7816CertificateHolderAuthorization according to the {@link DERApplicationSpecific} + * + * @param aSpe the DERApplicationSpecific containing the data + * @throws IOException + */ + public CertificateHolderAuthorization(DERApplicationSpecific aSpe) + throws IOException + { + if (aSpe.getApplicationTag() == EACTags.CERTIFICATE_HOLDER_AUTHORIZATION_TEMPLATE) + { + setPrivateData(new ASN1InputStream(aSpe.getContents())); + } + } + + /** + * @return containing the access rights + */ + public int getAccessRights() + { + return accessRights.getContents()[0] & 0xff; + } + + /** + * create a DERApplicationSpecific and set the access rights to "rights" + * + * @param rights byte containing the rights. + */ + private void setAccessRights(byte rights) + { + byte[] accessRights = new byte[1]; + accessRights[0] = rights; + this.accessRights = new DERApplicationSpecific( + EACTags.getTag(EACTags.DISCRETIONARY_DATA), accessRights); + } + + /** + * @return the Object identifier + */ + public ASN1ObjectIdentifier getOid() + { + return oid; + } + + /** + * set the Object Identifier + * + * @param oid {@link ASN1ObjectIdentifier} containing the Object Identifier + */ + private void setOid(ASN1ObjectIdentifier oid) + { + this.oid = oid; + } + + /** + * return the Certificate Holder Authorization as a DERApplicationSpecific Object + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(oid); + v.add(accessRights); + + return new DERApplicationSpecific(EACTags.CERTIFICATE_HOLDER_AUTHORIZATION_TEMPLATE, v); + } +} \ No newline at end of file diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/eac/CertificateHolderReference.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/eac/CertificateHolderReference.java new file mode 100644 index 0000000..a7e4d20 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/eac/CertificateHolderReference.java @@ -0,0 +1,66 @@ +package org.bc.asn1.eac; + +import java.io.UnsupportedEncodingException; + +public class CertificateHolderReference +{ + private static final String ReferenceEncoding = "ISO-8859-1"; + + private String countryCode; + private String holderMnemonic; + private String sequenceNumber; + + public CertificateHolderReference(String countryCode, String holderMnemonic, String sequenceNumber) + { + this.countryCode = countryCode; + this.holderMnemonic = holderMnemonic; + this.sequenceNumber = sequenceNumber; + } + + CertificateHolderReference(byte[] contents) + { + try + { + String concat = new String(contents, ReferenceEncoding); + + this.countryCode = concat.substring(0, 2); + this.holderMnemonic = concat.substring(2, concat.length() - 5); + + this.sequenceNumber = concat.substring(concat.length() - 5); + } + catch (UnsupportedEncodingException e) + { + throw new IllegalStateException(e.toString()); + } + } + + public String getCountryCode() + { + return countryCode; + } + + public String getHolderMnemonic() + { + return holderMnemonic; + } + + public String getSequenceNumber() + { + return sequenceNumber; + } + + + public byte[] getEncoded() + { + String ref = countryCode + holderMnemonic + sequenceNumber; + + try + { + return ref.getBytes(ReferenceEncoding); + } + catch (UnsupportedEncodingException e) + { + throw new IllegalStateException(e.toString()); + } + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/eac/CertificationAuthorityReference.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/eac/CertificationAuthorityReference.java new file mode 100644 index 0000000..52fe45a --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/eac/CertificationAuthorityReference.java @@ -0,0 +1,15 @@ +package org.bc.asn1.eac; + +public class CertificationAuthorityReference + extends CertificateHolderReference +{ + public CertificationAuthorityReference(String countryCode, String holderMnemonic, String sequenceNumber) + { + super(countryCode, holderMnemonic, sequenceNumber); + } + + CertificationAuthorityReference(byte[] contents) + { + super(contents); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/eac/EACObjectIdentifiers.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/eac/EACObjectIdentifiers.java new file mode 100644 index 0000000..68f5962 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/eac/EACObjectIdentifiers.java @@ -0,0 +1,55 @@ +package org.bc.asn1.eac; + +import org.bc.asn1.ASN1ObjectIdentifier; + +public interface EACObjectIdentifiers +{ + // bsi-de OBJECT IDENTIFIER ::= { + // itu-t(0) identified-organization(4) etsi(0) + // reserved(127) etsi-identified-organization(0) 7 + // } + static final ASN1ObjectIdentifier bsi_de = new ASN1ObjectIdentifier("0.4.0.127.0.7"); + + // id-PK OBJECT IDENTIFIER ::= { + // bsi-de protocols(2) smartcard(2) 1 + // } + static final ASN1ObjectIdentifier id_PK = bsi_de.branch("2.2.1"); + + static final ASN1ObjectIdentifier id_PK_DH = id_PK.branch("1"); + static final ASN1ObjectIdentifier id_PK_ECDH = id_PK.branch("2"); + + // id-CA OBJECT IDENTIFIER ::= { + // bsi-de protocols(2) smartcard(2) 3 + // } + static final ASN1ObjectIdentifier id_CA = bsi_de.branch("2.2.3"); + static final ASN1ObjectIdentifier id_CA_DH = id_CA.branch("1"); + static final ASN1ObjectIdentifier id_CA_DH_3DES_CBC_CBC = id_CA_DH.branch("1"); + static final ASN1ObjectIdentifier id_CA_ECDH = id_CA.branch("2"); + static final ASN1ObjectIdentifier id_CA_ECDH_3DES_CBC_CBC = id_CA_ECDH.branch("1"); + + // + // id-TA OBJECT IDENTIFIER ::= { + // bsi-de protocols(2) smartcard(2) 2 + // } + static final ASN1ObjectIdentifier id_TA = bsi_de.branch("2.2.2"); + + static final ASN1ObjectIdentifier id_TA_RSA = id_TA.branch("1"); + static final ASN1ObjectIdentifier id_TA_RSA_v1_5_SHA_1 = id_TA_RSA .branch("1"); + static final ASN1ObjectIdentifier id_TA_RSA_v1_5_SHA_256 = id_TA_RSA.branch("2"); + static final ASN1ObjectIdentifier id_TA_RSA_PSS_SHA_1 = id_TA_RSA.branch("3"); + static final ASN1ObjectIdentifier id_TA_RSA_PSS_SHA_256 = id_TA_RSA.branch("4"); + static final ASN1ObjectIdentifier id_TA_RSA_v1_5_SHA_512 = id_TA_RSA.branch("5"); + static final ASN1ObjectIdentifier id_TA_RSA_PSS_SHA_512 = id_TA_RSA.branch("6"); + static final ASN1ObjectIdentifier id_TA_ECDSA = id_TA.branch("2"); + static final ASN1ObjectIdentifier id_TA_ECDSA_SHA_1 = id_TA_ECDSA.branch("1"); + static final ASN1ObjectIdentifier id_TA_ECDSA_SHA_224 = id_TA_ECDSA.branch("2"); + static final ASN1ObjectIdentifier id_TA_ECDSA_SHA_256 = id_TA_ECDSA.branch("3"); + static final ASN1ObjectIdentifier id_TA_ECDSA_SHA_384 = id_TA_ECDSA.branch("4"); + static final ASN1ObjectIdentifier id_TA_ECDSA_SHA_512 = id_TA_ECDSA.branch("5"); + + /** + * id-EAC-ePassport OBJECT IDENTIFIER ::= { + * bsi-de applications(3) mrtd(1) roles(2) 1} + */ + static final ASN1ObjectIdentifier id_EAC_ePassport = bsi_de.branch("3.1.2.1"); +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/eac/EACTags.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/eac/EACTags.java new file mode 100644 index 0000000..8e1e128 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/eac/EACTags.java @@ -0,0 +1,195 @@ +package org.bc.asn1.eac; + +import org.bc.asn1.BERTags; +import org.bc.asn1.DERApplicationSpecific; + +public class EACTags +{ + public static final int OBJECT_IDENTIFIER = 0x06; + public static final int COUNTRY_CODE_NATIONAL_DATA = 0x41; + public static final int ISSUER_IDENTIFICATION_NUMBER = 0x02; //0x42; + public static final int CARD_SERVICE_DATA = 0x43; + public static final int INITIAL_ACCESS_DATA = 0x44; + public static final int CARD_ISSUER_DATA = 0x45; + public static final int PRE_ISSUING_DATA = 0x46; + public static final int CARD_CAPABILITIES = 0x47; + public static final int STATUS_INFORMATION = 0x48; + public static final int EXTENDED_HEADER_LIST = 0x4D; + public static final int APPLICATION_IDENTIFIER = 0x4F; + public static final int APPLICATION_LABEL = 0x50; + public static final int FILE_REFERENCE = 0x51; + public static final int COMMAND_TO_PERFORM = 0x52; + public static final int DISCRETIONARY_DATA = 0x53; + public static final int OFFSET_DATA_OBJECT = 0x54; + public static final int TRACK1_APPLICATION = 0x56; + public static final int TRACK2_APPLICATION = 0x57; + public static final int TRACK3_APPLICATION = 0x58; + public static final int CARD_EXPIRATION_DATA = 0x59; + public static final int PRIMARY_ACCOUNT_NUMBER = 0x5A;// PAN + public static final int NAME = 0x5B; + public static final int TAG_LIST = 0x5C; + public static final int HEADER_LIST = 0x5D; + public static final int LOGIN_DATA = 0x5E; + public static final int CARDHOLDER_NAME = 0x20; // 0x5F20; + public static final int TRACK1_CARD = 0x5F21; + public static final int TRACK2_CARD = 0x5F22; + public static final int TRACK3_CARD = 0x5F23; + public static final int APPLICATION_EXPIRATION_DATE = 0x24; // 0x5F24; + public static final int APPLICATION_EFFECTIVE_DATE = 0x25; // 0x5F25; + public static final int CARD_EFFECTIVE_DATE = 0x5F26; + public static final int INTERCHANGE_CONTROL = 0x5F27; + public static final int COUNTRY_CODE = 0x5F28; + public static final int INTERCHANGE_PROFILE = 0x29; // 0x5F29; + public static final int CURRENCY_CODE = 0x5F2A; + public static final int DATE_OF_BIRTH = 0x5F2B; + public static final int CARDHOLDER_NATIONALITY = 0x5F2C; + public static final int LANGUAGE_PREFERENCES = 0x5F2D; + public static final int CARDHOLDER_BIOMETRIC_DATA = 0x5F2E; + public static final int PIN_USAGE_POLICY = 0x5F2F; + public static final int SERVICE_CODE = 0x5F30; + public static final int TRANSACTION_COUNTER = 0x5F32; + public static final int TRANSACTION_DATE = 0x5F33; + public static final int CARD_SEQUENCE_NUMBER = 0x5F34; + public static final int SEX = 0x5F35; + public static final int CURRENCY_EXPONENT = 0x5F36; + public static final int STATIC_INTERNAL_AUTHENTIFICATION_ONE_STEP = 0x37; // 0x5F37; + public static final int SIGNATURE = 0x5F37; + public static final int STATIC_INTERNAL_AUTHENTIFICATION_FIRST_DATA = 0x5F38; + public static final int STATIC_INTERNAL_AUTHENTIFICATION_SECOND_DATA = 0x5F39; + public static final int DYNAMIC_INTERNAL_AUTHENTIFICATION = 0x5F3A; + public static final int DYNAMIC_EXTERNAL_AUTHENTIFICATION = 0x5F3B; + public static final int DYNAMIC_MUTUAL_AUTHENTIFICATION = 0x5F3C; + public static final int CARDHOLDER_PORTRAIT_IMAGE = 0x5F40; + public static final int ELEMENT_LIST = 0x5F41; + public static final int ADDRESS = 0x5F42; + public static final int CARDHOLDER_HANDWRITTEN_SIGNATURE = 0x5F43; + public static final int APPLICATION_IMAGE = 0x5F44; + public static final int DISPLAY_IMAGE = 0x5F45; + public static final int TIMER = 0x5F46; + public static final int MESSAGE_REFERENCE = 0x5F47; + public static final int CARDHOLDER_PRIVATE_KEY = 0x5F48; + public static final int CARDHOLDER_PUBLIC_KEY = 0x5F49; + public static final int CERTIFICATION_AUTHORITY_PUBLIC_KEY = 0x5F4A; + public static final int DEPRECATED = 0x5F4B; + public static final int CERTIFICATE_HOLDER_AUTHORIZATION = 0x5F4C;// Not yet defined in iso7816. The allocation is requested + public static final int INTEGRATED_CIRCUIT_MANUFACTURER_ID = 0x5F4D; + public static final int CERTIFICATE_CONTENT = 0x5F4E; + public static final int UNIFORM_RESOURCE_LOCATOR = 0x5F50; + public static final int ANSWER_TO_RESET = 0x5F51; + public static final int HISTORICAL_BYTES = 0x5F52; + public static final int DIGITAL_SIGNATURE = 0x5F3D; + public static final int APPLICATION_TEMPLATE = 0x61; + public static final int FCP_TEMPLATE = 0x62; + public static final int WRAPPER = 0x63; + public static final int FMD_TEMPLATE = 0x64; + public static final int CARDHOLDER_RELATIVE_DATA = 0x65; + public static final int CARD_DATA = 0x66; + public static final int AUTHENTIFICATION_DATA = 0x67; + public static final int SPECIAL_USER_REQUIREMENTS = 0x68; + public static final int LOGIN_TEMPLATE = 0x6A; + public static final int QUALIFIED_NAME = 0x6B; + public static final int CARDHOLDER_IMAGE_TEMPLATE = 0x6C; + public static final int APPLICATION_IMAGE_TEMPLATE = 0x6D; + public static final int APPLICATION_RELATED_DATA = 0x6E; + public static final int FCI_TEMPLATE = 0x6F; + public static final int DISCRETIONARY_DATA_OBJECTS = 0x73; + public static final int COMPATIBLE_TAG_ALLOCATION_AUTHORITY = 0x78; + public static final int COEXISTANT_TAG_ALLOCATION_AUTHORITY = 0x79; + public static final int SECURITY_SUPPORT_TEMPLATE = 0x7A; + public static final int SECURITY_ENVIRONMENT_TEMPLATE = 0x7B; + public static final int DYNAMIC_AUTHENTIFICATION_TEMPLATE = 0x7C; + public static final int SECURE_MESSAGING_TEMPLATE = 0x7D; + public static final int NON_INTERINDUSTRY_DATA_OBJECT_NESTING_TEMPLATE = 0x7E; + public static final int DISPLAY_CONTROL = 0x7F20; + public static final int CARDHOLDER_CERTIFICATE = 0x21; // 0x7F21; + public static final int CV_CERTIFICATE = 0x7F21; + public static final int CARDHOLER_REQUIREMENTS_INCLUDED_FEATURES = 0x7F22; + public static final int CARDHOLER_REQUIREMENTS_EXCLUDED_FEATURES = 0x7F23; + public static final int BIOMETRIC_DATA_TEMPLATE = 0x7F2E; + public static final int DIGITAL_SIGNATURE_BLOCK = 0x7F3D; + public static final int CARDHOLDER_PRIVATE_KEY_TEMPLATE = 0x7F48; + public static final int CARDHOLDER_PUBLIC_KEY_TEMPLATE = 0x49; // 0x7F49; + public static final int CERTIFICATE_HOLDER_AUTHORIZATION_TEMPLATE = 0x4C; // 0x7F4C; + public static final int CERTIFICATE_CONTENT_TEMPLATE = 0x4E; // 0x7F4E; + public static final int CERTIFICATE_BODY = 0x4E; // 0x7F4E; + public static final int BIOMETRIC_INFORMATION_TEMPLATE = 0x7F60; + public static final int BIOMETRIC_INFORMATION_GROUP_TEMPLATE = 0x7F61; + + public static int getTag(int encodedTag) { + /* + int i; + for (i = 24; i>=0; i-=8) { + if (((0xFF<> i); + } + return 0; + */ + return decodeTag(encodedTag); + } + + public static int getTagNo(int tag) { + int i; + for (i = 24; i>=0; i -=8) { + if (((0xFF< 31) + { + retValue |= 0x1F; + retValue <<= 8; + + int currentByte = tag & 0x7F; + retValue |= currentByte; + tag >>= 7; + + while (tag > 0) + { + retValue |= 0x80; + retValue <<= 8; + + currentByte = tag & 0x7F; + tag >>= 7; + } + } + else + retValue |= tag; + + return retValue; + } + + public static int decodeTag(int tag) + { + int retValue = 0; + boolean multiBytes = false; + for (int i = 24; i>=0; i -=8) { + int currentByte = tag >> i & 0xFF; + if (currentByte == 0) + continue; + + if (multiBytes) + { + retValue <<= 7; + retValue |= currentByte & 0x7F; + } + else if ((currentByte & 0x1F) == 0x1F) + { + multiBytes = true; + } + else + return currentByte & 0x1F; // higher order bit are for DER.Constructed and type + } + return retValue; + } +} \ No newline at end of file diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/eac/ECDSAPublicKey.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/eac/ECDSAPublicKey.java new file mode 100644 index 0000000..70a34bc --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/eac/ECDSAPublicKey.java @@ -0,0 +1,341 @@ +package org.bc.asn1.eac; + +import java.math.BigInteger; +import java.util.Enumeration; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1ObjectIdentifier; +import org.bc.asn1.ASN1OctetString; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DEROctetString; +import org.bc.asn1.DERSequence; +import org.bc.asn1.DERTaggedObject; + +/** + * an Iso7816ECDSAPublicKeyStructure structure. + * + *
+ * Certificate Holder Authorization ::= SEQUENCE { + * ASN1TaggedObject primeModulusP; // OPTIONAL + * ASN1TaggedObject firstCoefA; // OPTIONAL + * ASN1TaggedObject secondCoefB; // OPTIONAL + * ASN1TaggedObject basePointG; // OPTIONAL + * ASN1TaggedObject orderOfBasePointR; // OPTIONAL + * ASN1TaggedObject publicPointY; //REQUIRED + * ASN1TaggedObject cofactorF; // OPTIONAL + * } + *+ */ +public class ECDSAPublicKey + extends PublicKeyDataObject +{ + private ASN1ObjectIdentifier usage; + private BigInteger primeModulusP; // OPTIONAL + private BigInteger firstCoefA; // OPTIONAL + private BigInteger secondCoefB; // OPTIONAL + private byte[] basePointG; // OPTIONAL + private BigInteger orderOfBasePointR; // OPTIONAL + private byte[] publicPointY; //REQUIRED + private BigInteger cofactorF; // OPTIONAL + private int options; + private static final int P = 0x01; + private static final int A = 0x02; + private static final int B = 0x04; + private static final int G = 0x08; + private static final int R = 0x10; + private static final int Y = 0x20; + private static final int F = 0x40; + + ECDSAPublicKey(ASN1Sequence seq) + throws IllegalArgumentException + { + Enumeration en = seq.getObjects(); + + this.usage = ASN1ObjectIdentifier.getInstance(en.nextElement()); + + options = 0; + while (en.hasMoreElements()) + { + Object obj = en.nextElement(); + + if (obj instanceof ASN1TaggedObject) + { + ASN1TaggedObject to = (ASN1TaggedObject)obj; + switch (to.getTagNo()) + { + case 0x1: + setPrimeModulusP(UnsignedInteger.getInstance(to).getValue()); + break; + case 0x2: + setFirstCoefA(UnsignedInteger.getInstance(to).getValue()); + break; + case 0x3: + setSecondCoefB(UnsignedInteger.getInstance(to).getValue()); + break; + case 0x4: + setBasePointG(ASN1OctetString.getInstance(to, false)); + break; + case 0x5: + setOrderOfBasePointR(UnsignedInteger.getInstance(to).getValue()); + break; + case 0x6: + setPublicPointY(ASN1OctetString.getInstance(to, false)); + break; + case 0x7: + setCofactorF(UnsignedInteger.getInstance(to).getValue()); + break; + default: + options = 0; + throw new IllegalArgumentException("Unknown Object Identifier!"); + } + } + else + { + throw new IllegalArgumentException("Unknown Object Identifier!"); + } + } + if (options != 0x20 && options != 0x7F) + { + throw new IllegalArgumentException("All options must be either present or absent!"); + } + } + + public ECDSAPublicKey(ASN1ObjectIdentifier usage, byte[] ppY) + throws IllegalArgumentException + { + this.usage = usage; + setPublicPointY(new DEROctetString(ppY)); + } + + public ECDSAPublicKey(ASN1ObjectIdentifier usage, BigInteger p, BigInteger a, BigInteger b, byte[] basePoint, BigInteger order, byte[] publicPoint, int cofactor) + { + this.usage = usage; + setPrimeModulusP(p); + setFirstCoefA(a); + setSecondCoefB(b); + setBasePointG(new DEROctetString(basePoint)); + setOrderOfBasePointR(order); + setPublicPointY(new DEROctetString(publicPoint)); + setCofactorF(BigInteger.valueOf(cofactor)); + } + + public ASN1ObjectIdentifier getUsage() + { + return usage; + } + + public byte[] getBasePointG() + { + if ((options & G) != 0) + { + return basePointG; + } + else + { + return null; + } + } + + private void setBasePointG(ASN1OctetString basePointG) + throws IllegalArgumentException + { + if ((options & G) == 0) + { + options |= G; + this.basePointG = basePointG.getOctets(); + } + else + { + throw new IllegalArgumentException("Base Point G already set"); + } + } + + public BigInteger getCofactorF() + { + if ((options & F) != 0) + { + return cofactorF; + } + else + { + return null; + } + } + + private void setCofactorF(BigInteger cofactorF) + throws IllegalArgumentException + { + if ((options & F) == 0) + { + options |= F; + this.cofactorF = cofactorF; + } + else + { + throw new IllegalArgumentException("Cofactor F already set"); + } + } + + public BigInteger getFirstCoefA() + { + if ((options & A) != 0) + { + return firstCoefA; + } + else + { + return null; + } + } + + private void setFirstCoefA(BigInteger firstCoefA) + throws IllegalArgumentException + { + if ((options & A) == 0) + { + options |= A; + this.firstCoefA = firstCoefA; + } + else + { + throw new IllegalArgumentException("First Coef A already set"); + } + } + + public BigInteger getOrderOfBasePointR() + { + if ((options & R) != 0) + { + return orderOfBasePointR; + } + else + { + return null; + } + } + + private void setOrderOfBasePointR(BigInteger orderOfBasePointR) + throws IllegalArgumentException + { + if ((options & R) == 0) + { + options |= R; + this.orderOfBasePointR = orderOfBasePointR; + } + else + { + throw new IllegalArgumentException("Order of base point R already set"); + } + } + + public BigInteger getPrimeModulusP() + { + if ((options & P) != 0) + { + return primeModulusP; + } + else + { + return null; + } + } + + private void setPrimeModulusP(BigInteger primeModulusP) + { + if ((options & P) == 0) + { + options |= P; + this.primeModulusP = primeModulusP; + } + else + { + throw new IllegalArgumentException("Prime Modulus P already set"); + } + } + + public byte[] getPublicPointY() + { + if ((options & Y) != 0) + { + return publicPointY; + } + else + { + return null; + } + } + + private void setPublicPointY(ASN1OctetString publicPointY) + throws IllegalArgumentException + { + if ((options & Y) == 0) + { + options |= Y; + this.publicPointY = publicPointY.getOctets(); + } + else + { + throw new IllegalArgumentException("Public Point Y already set"); + } + } + + public BigInteger getSecondCoefB() + { + if ((options & B) != 0) + { + return secondCoefB; + } + else + { + return null; + } + } + + private void setSecondCoefB(BigInteger secondCoefB) + throws IllegalArgumentException + { + if ((options & B) == 0) + { + options |= B; + this.secondCoefB = secondCoefB; + } + else + { + throw new IllegalArgumentException("Second Coef B already set"); + } + } + + public boolean hasParameters() + { + return primeModulusP != null; + } + + public ASN1EncodableVector getASN1EncodableVector(ASN1ObjectIdentifier oid, boolean publicPointOnly) + { + ASN1EncodableVector v = new ASN1EncodableVector(); + v.add(oid); + + if (!publicPointOnly) + { + v.add(new UnsignedInteger(0x01, getPrimeModulusP())); + v.add(new UnsignedInteger(0x02, getFirstCoefA())); + v.add(new UnsignedInteger(0x03, getSecondCoefB())); + v.add(new DERTaggedObject(false, 0x04, new DEROctetString(getBasePointG()))); + v.add(new UnsignedInteger(0x05, getOrderOfBasePointR())); + } + v.add(new DERTaggedObject(false, 0x06, new DEROctetString(getPublicPointY()))); + if (!publicPointOnly) + { + v.add(new UnsignedInteger(0x07, getCofactorF())); + } + + return v; + } + + public ASN1Primitive toASN1Primitive() + { + return new DERSequence(getASN1EncodableVector(usage, false)); + } +} \ No newline at end of file diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/eac/Flags.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/eac/Flags.java new file mode 100644 index 0000000..a5cc64c --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/eac/Flags.java @@ -0,0 +1,96 @@ +package org.bc.asn1.eac; + +import java.util.Enumeration; +import java.util.Hashtable; + + +public class Flags +{ + + int value = 0; + + public Flags() + { + + } + + public Flags(int v) + { + value = v; + } + + public void set(int flag) + { + value |= flag; + } + + public boolean isSet(int flag) + { + return (value & flag) != 0; + } + + public int getFlags() + { + return value; + } + + /* Java 1.5 + String decode(Map
+ * Certificate Holder Authorization ::= SEQUENCE { + * // modulus should be at least 1024bit and a multiple of 512. + * DERTaggedObject modulus, + * // access rights exponent + * DERTaggedObject accessRights, + * } + *+ */ +public class RSAPublicKey + extends PublicKeyDataObject +{ + private ASN1ObjectIdentifier usage; + private BigInteger modulus; + private BigInteger exponent; + private int valid = 0; + private static int modulusValid = 0x01; + private static int exponentValid = 0x02; + + RSAPublicKey(ASN1Sequence seq) + { + Enumeration en = seq.getObjects(); + + this.usage = ASN1ObjectIdentifier.getInstance(en.nextElement()); + + while (en.hasMoreElements()) + { + UnsignedInteger val = UnsignedInteger.getInstance(en.nextElement()); + + switch (val.getTagNo()) + { + case 0x1: + setModulus(val); + break; + case 0x2: + setExponent(val); + break; + default: + throw new IllegalArgumentException("Unknown DERTaggedObject :" + val.getTagNo() + "-> not an Iso7816RSAPublicKeyStructure"); + } + } + if (valid != 0x3) + { + throw new IllegalArgumentException("missing argument -> not an Iso7816RSAPublicKeyStructure"); + } + } + + public RSAPublicKey(ASN1ObjectIdentifier usage, BigInteger modulus, BigInteger exponent) + { + this.usage = usage; + this.modulus = modulus; + this.exponent = exponent; + } + + public ASN1ObjectIdentifier getUsage() + { + return usage; + } + + public BigInteger getModulus() + { + return modulus; + } + + public BigInteger getPublicExponent() + { + return exponent; + } + + private void setModulus(UnsignedInteger modulus) + { + if ((valid & modulusValid) == 0) + { + valid |= modulusValid; + this.modulus = modulus.getValue(); + } + else + { + throw new IllegalArgumentException("Modulus already set"); + } + } + + private void setExponent(UnsignedInteger exponent) + { + if ((valid & exponentValid) == 0) + { + valid |= exponentValid; + this.exponent = exponent.getValue(); + } + else + { + throw new IllegalArgumentException("Exponent already set"); + } + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(usage); + v.add(new UnsignedInteger(0x01, getModulus())); + v.add(new UnsignedInteger(0x02, getPublicExponent())); + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/eac/UnsignedInteger.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/eac/UnsignedInteger.java new file mode 100644 index 0000000..5ef307a --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/eac/UnsignedInteger.java @@ -0,0 +1,74 @@ +package org.bc.asn1.eac; + +import java.math.BigInteger; + +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1OctetString; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DEROctetString; +import org.bc.asn1.DERTaggedObject; + +public class UnsignedInteger + extends ASN1Object +{ + private int tagNo; + private BigInteger value; + + public UnsignedInteger(int tagNo, BigInteger value) + { + this.tagNo = tagNo; + this.value = value; + } + + private UnsignedInteger(ASN1TaggedObject obj) + { + this.tagNo = obj.getTagNo(); + this.value = new BigInteger(1, ASN1OctetString.getInstance(obj, false).getOctets()); + } + + public static UnsignedInteger getInstance(Object obj) + { + if (obj instanceof UnsignedInteger) + { + return (UnsignedInteger)obj; + } + if (obj != null) + { + return new UnsignedInteger(ASN1TaggedObject.getInstance(obj)); + } + + return null; + } + + private byte[] convertValue() + { + byte[] v = value.toByteArray(); + + if (v[0] == 0) + { + byte[] tmp = new byte[v.length - 1]; + + System.arraycopy(v, 1, tmp, 0, tmp.length); + + return tmp; + } + + return v; + } + + public int getTagNo() + { + return tagNo; + } + + public BigInteger getValue() + { + return value; + } + + public ASN1Primitive toASN1Primitive() + { + return new DERTaggedObject(false, tagNo, new DEROctetString(convertValue())); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/esf/CommitmentTypeIdentifier.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/esf/CommitmentTypeIdentifier.java new file mode 100644 index 0000000..5704a6e --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/esf/CommitmentTypeIdentifier.java @@ -0,0 +1,14 @@ +package org.bc.asn1.esf; + +import org.bc.asn1.ASN1ObjectIdentifier; +import org.bc.asn1.pkcs.PKCSObjectIdentifiers; + +public interface CommitmentTypeIdentifier +{ + public static final ASN1ObjectIdentifier proofOfOrigin = PKCSObjectIdentifiers.id_cti_ets_proofOfOrigin; + public static final ASN1ObjectIdentifier proofOfReceipt = PKCSObjectIdentifiers.id_cti_ets_proofOfReceipt; + public static final ASN1ObjectIdentifier proofOfDelivery = PKCSObjectIdentifiers.id_cti_ets_proofOfDelivery; + public static final ASN1ObjectIdentifier proofOfSender = PKCSObjectIdentifiers.id_cti_ets_proofOfSender; + public static final ASN1ObjectIdentifier proofOfApproval = PKCSObjectIdentifiers.id_cti_ets_proofOfApproval; + public static final ASN1ObjectIdentifier proofOfCreation = PKCSObjectIdentifiers.id_cti_ets_proofOfCreation; +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/esf/CommitmentTypeIndication.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/esf/CommitmentTypeIndication.java new file mode 100644 index 0000000..bf0e694 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/esf/CommitmentTypeIndication.java @@ -0,0 +1,83 @@ +package org.bc.asn1.esf; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1ObjectIdentifier; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DERSequence; + +public class CommitmentTypeIndication + extends ASN1Object +{ + private ASN1ObjectIdentifier commitmentTypeId; + private ASN1Sequence commitmentTypeQualifier; + + private CommitmentTypeIndication( + ASN1Sequence seq) + { + commitmentTypeId = (ASN1ObjectIdentifier)seq.getObjectAt(0); + + if (seq.size() > 1) + { + commitmentTypeQualifier = (ASN1Sequence)seq.getObjectAt(1); + } + } + + public CommitmentTypeIndication( + ASN1ObjectIdentifier commitmentTypeId) + { + this.commitmentTypeId = commitmentTypeId; + } + + public CommitmentTypeIndication( + ASN1ObjectIdentifier commitmentTypeId, + ASN1Sequence commitmentTypeQualifier) + { + this.commitmentTypeId = commitmentTypeId; + this.commitmentTypeQualifier = commitmentTypeQualifier; + } + + public static CommitmentTypeIndication getInstance( + Object obj) + { + if (obj == null || obj instanceof CommitmentTypeIndication) + { + return (CommitmentTypeIndication)obj; + } + + return new CommitmentTypeIndication(ASN1Sequence.getInstance(obj)); + } + + public ASN1ObjectIdentifier getCommitmentTypeId() + { + return commitmentTypeId; + } + + public ASN1Sequence getCommitmentTypeQualifier() + { + return commitmentTypeQualifier; + } + + /** + *
+ * CommitmentTypeIndication ::= SEQUENCE { + * commitmentTypeId CommitmentTypeIdentifier, + * commitmentTypeQualifier SEQUENCE SIZE (1..MAX) OF + * CommitmentTypeQualifier OPTIONAL } + *+ */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(commitmentTypeId); + + if (commitmentTypeQualifier != null) + { + v.add(commitmentTypeQualifier); + } + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/esf/CommitmentTypeQualifier.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/esf/CommitmentTypeQualifier.java new file mode 100644 index 0000000..aae8980 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/esf/CommitmentTypeQualifier.java @@ -0,0 +1,108 @@ +package org.bc.asn1.esf; + +import org.bc.asn1.ASN1Encodable; +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1ObjectIdentifier; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DERSequence; + +/** + * Commitment type qualifiers, used in the Commitment-Type-Indication attribute (RFC3126). + * + *
+ * CommitmentTypeQualifier ::= SEQUENCE { + * commitmentTypeIdentifier CommitmentTypeIdentifier, + * qualifier ANY DEFINED BY commitmentTypeIdentifier OPTIONAL } + *+ */ +public class CommitmentTypeQualifier + extends ASN1Object +{ + private ASN1ObjectIdentifier commitmentTypeIdentifier; + private ASN1Encodable qualifier; + + /** + * Creates a new
CommitmentTypeQualifier
instance.
+ *
+ * @param commitmentTypeIdentifier a CommitmentTypeIdentifier
value
+ */
+ public CommitmentTypeQualifier(
+ ASN1ObjectIdentifier commitmentTypeIdentifier)
+ {
+ this(commitmentTypeIdentifier, null);
+ }
+
+ /**
+ * Creates a new CommitmentTypeQualifier
instance.
+ *
+ * @param commitmentTypeIdentifier a CommitmentTypeIdentifier
value
+ * @param qualifier the qualifier, defined by the above field.
+ */
+ public CommitmentTypeQualifier(
+ ASN1ObjectIdentifier commitmentTypeIdentifier,
+ ASN1Encodable qualifier)
+ {
+ this.commitmentTypeIdentifier = commitmentTypeIdentifier;
+ this.qualifier = qualifier;
+ }
+
+ /**
+ * Creates a new CommitmentTypeQualifier
instance.
+ *
+ * @param as CommitmentTypeQualifier
structure
+ * encoded as an ASN1Sequence.
+ */
+ private CommitmentTypeQualifier(
+ ASN1Sequence as)
+ {
+ commitmentTypeIdentifier = (ASN1ObjectIdentifier)as.getObjectAt(0);
+
+ if (as.size() > 1)
+ {
+ qualifier = as.getObjectAt(1);
+ }
+ }
+
+ public static CommitmentTypeQualifier getInstance(Object as)
+ {
+ if (as instanceof CommitmentTypeQualifier)
+ {
+ return (CommitmentTypeQualifier)as;
+ }
+ else if (as != null)
+ {
+ return new CommitmentTypeQualifier(ASN1Sequence.getInstance(as));
+ }
+
+ return null;
+ }
+
+ public ASN1ObjectIdentifier getCommitmentTypeIdentifier()
+ {
+ return commitmentTypeIdentifier;
+ }
+
+ public ASN1Encodable getQualifier()
+ {
+ return qualifier;
+ }
+
+ /**
+ * Returns a DER-encodable representation of this instance.
+ *
+ * @return a ASN1Primitive
value
+ */
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector dev = new ASN1EncodableVector();
+ dev.add(commitmentTypeIdentifier);
+ if (qualifier != null)
+ {
+ dev.add(qualifier);
+ }
+
+ return new DERSequence(dev);
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/esf/CompleteRevocationRefs.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/esf/CompleteRevocationRefs.java
new file mode 100644
index 0000000..d28935f
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/esf/CompleteRevocationRefs.java
@@ -0,0 +1,65 @@
+package org.bc.asn1.esf;
+
+import java.util.Enumeration;
+
+import org.bc.asn1.ASN1Object;
+import org.bc.asn1.ASN1Primitive;
+import org.bc.asn1.ASN1Sequence;
+import org.bc.asn1.DERSequence;
+
+/**
+ * + * CompleteRevocationRefs ::= SEQUENCE OF CrlOcspRef + *+ */ +public class CompleteRevocationRefs + extends ASN1Object +{ + + private ASN1Sequence crlOcspRefs; + + public static CompleteRevocationRefs getInstance(Object obj) + { + if (obj instanceof CompleteRevocationRefs) + { + return (CompleteRevocationRefs)obj; + } + else if (obj != null) + { + return new CompleteRevocationRefs(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + private CompleteRevocationRefs(ASN1Sequence seq) + { + Enumeration seqEnum = seq.getObjects(); + while (seqEnum.hasMoreElements()) + { + CrlOcspRef.getInstance(seqEnum.nextElement()); + } + this.crlOcspRefs = seq; + } + + public CompleteRevocationRefs(CrlOcspRef[] crlOcspRefs) + { + this.crlOcspRefs = new DERSequence(crlOcspRefs); + } + + public CrlOcspRef[] getCrlOcspRefs() + { + CrlOcspRef[] result = new CrlOcspRef[this.crlOcspRefs.size()]; + for (int idx = 0; idx < result.length; idx++) + { + result[idx] = CrlOcspRef.getInstance(this.crlOcspRefs + .getObjectAt(idx)); + } + return result; + } + + public ASN1Primitive toASN1Primitive() + { + return this.crlOcspRefs; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/esf/CrlIdentifier.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/esf/CrlIdentifier.java new file mode 100644 index 0000000..21d070f --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/esf/CrlIdentifier.java @@ -0,0 +1,106 @@ +package org.bc.asn1.esf; + +import java.math.BigInteger; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1UTCTime; +import org.bc.asn1.DERSequence; +import org.bc.asn1.x500.X500Name; + +/** + *
+ * CrlIdentifier ::= SEQUENCE + * { + * crlissuer Name, + * crlIssuedTime UTCTime, + * crlNumber INTEGER OPTIONAL + * } + *+ */ +public class CrlIdentifier + extends ASN1Object +{ + private X500Name crlIssuer; + private ASN1UTCTime crlIssuedTime; + private ASN1Integer crlNumber; + + public static CrlIdentifier getInstance(Object obj) + { + if (obj instanceof CrlIdentifier) + { + return (CrlIdentifier)obj; + } + else if (obj != null) + { + return new CrlIdentifier(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + private CrlIdentifier(ASN1Sequence seq) + { + if (seq.size() < 2 || seq.size() > 3) + { + throw new IllegalArgumentException(); + } + this.crlIssuer = X500Name.getInstance(seq.getObjectAt(0)); + this.crlIssuedTime = ASN1UTCTime.getInstance(seq.getObjectAt(1)); + if (seq.size() > 2) + { + this.crlNumber = ASN1Integer.getInstance(seq.getObjectAt(2)); + } + } + + public CrlIdentifier(X500Name crlIssuer, ASN1UTCTime crlIssuedTime) + { + this(crlIssuer, crlIssuedTime, null); + } + + public CrlIdentifier(X500Name crlIssuer, ASN1UTCTime crlIssuedTime, + BigInteger crlNumber) + { + this.crlIssuer = crlIssuer; + this.crlIssuedTime = crlIssuedTime; + if (null != crlNumber) + { + this.crlNumber = new ASN1Integer(crlNumber); + } + } + + public X500Name getCrlIssuer() + { + return this.crlIssuer; + } + + public ASN1UTCTime getCrlIssuedTime() + { + return this.crlIssuedTime; + } + + public BigInteger getCrlNumber() + { + if (null == this.crlNumber) + { + return null; + } + return this.crlNumber.getValue(); + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + v.add(this.crlIssuer.toASN1Primitive()); + v.add(this.crlIssuedTime); + if (null != this.crlNumber) + { + v.add(this.crlNumber); + } + return new DERSequence(v); + } + +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/esf/CrlListID.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/esf/CrlListID.java new file mode 100644 index 0000000..9e162e5 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/esf/CrlListID.java @@ -0,0 +1,66 @@ +package org.bc.asn1.esf; + +import java.util.Enumeration; + +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DERSequence; + +/** + *
+ * CRLListID ::= SEQUENCE { + * crls SEQUENCE OF CrlValidatedID } + *+ */ +public class CrlListID + extends ASN1Object +{ + + private ASN1Sequence crls; + + public static CrlListID getInstance(Object obj) + { + if (obj instanceof CrlListID) + { + return (CrlListID)obj; + } + else if (obj != null) + { + return new CrlListID(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + private CrlListID(ASN1Sequence seq) + { + this.crls = (ASN1Sequence)seq.getObjectAt(0); + Enumeration e = this.crls.getObjects(); + while (e.hasMoreElements()) + { + CrlValidatedID.getInstance(e.nextElement()); + } + } + + public CrlListID(CrlValidatedID[] crls) + { + this.crls = new DERSequence(crls); + } + + public CrlValidatedID[] getCrls() + { + CrlValidatedID[] result = new CrlValidatedID[this.crls.size()]; + for (int idx = 0; idx < result.length; idx++) + { + result[idx] = CrlValidatedID + .getInstance(this.crls.getObjectAt(idx)); + } + return result; + } + + public ASN1Primitive toASN1Primitive() + { + return new DERSequence(this.crls); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/esf/CrlOcspRef.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/esf/CrlOcspRef.java new file mode 100644 index 0000000..37b1036 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/esf/CrlOcspRef.java @@ -0,0 +1,106 @@ +package org.bc.asn1.esf; + +import java.util.Enumeration; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DERSequence; +import org.bc.asn1.DERTaggedObject; + +/** + *
+ * CrlOcspRef ::= SEQUENCE { + * crlids [0] CRLListID OPTIONAL, + * ocspids [1] OcspListID OPTIONAL, + * otherRev [2] OtherRevRefs OPTIONAL + * } + *+ */ +public class CrlOcspRef + extends ASN1Object +{ + + private CrlListID crlids; + private OcspListID ocspids; + private OtherRevRefs otherRev; + + public static CrlOcspRef getInstance(Object obj) + { + if (obj instanceof CrlOcspRef) + { + return (CrlOcspRef)obj; + } + else if (obj != null) + { + return new CrlOcspRef(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + private CrlOcspRef(ASN1Sequence seq) + { + Enumeration e = seq.getObjects(); + while (e.hasMoreElements()) + { + DERTaggedObject o = (DERTaggedObject)e.nextElement(); + switch (o.getTagNo()) + { + case 0: + this.crlids = CrlListID.getInstance(o.getObject()); + break; + case 1: + this.ocspids = OcspListID.getInstance(o.getObject()); + break; + case 2: + this.otherRev = OtherRevRefs.getInstance(o.getObject()); + break; + default: + throw new IllegalArgumentException("illegal tag"); + } + } + } + + public CrlOcspRef(CrlListID crlids, OcspListID ocspids, + OtherRevRefs otherRev) + { + this.crlids = crlids; + this.ocspids = ocspids; + this.otherRev = otherRev; + } + + public CrlListID getCrlids() + { + return this.crlids; + } + + public OcspListID getOcspids() + { + return this.ocspids; + } + + public OtherRevRefs getOtherRev() + { + return this.otherRev; + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + if (null != this.crlids) + { + v.add(new DERTaggedObject(true, 0, this.crlids.toASN1Primitive())); + } + if (null != this.ocspids) + { + v.add(new DERTaggedObject(true, 1, this.ocspids.toASN1Primitive())); + } + if (null != this.otherRev) + { + v.add(new DERTaggedObject(true, 2, this.otherRev.toASN1Primitive())); + } + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/esf/CrlValidatedID.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/esf/CrlValidatedID.java new file mode 100644 index 0000000..ba3091f --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/esf/CrlValidatedID.java @@ -0,0 +1,82 @@ +package org.bc.asn1.esf; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DERSequence; + +/** + *
+ * CrlValidatedID ::= SEQUENCE { + * crlHash OtherHash, + * crlIdentifier CrlIdentifier OPTIONAL } + *+ */ +public class CrlValidatedID + extends ASN1Object +{ + + private OtherHash crlHash; + private CrlIdentifier crlIdentifier; + + public static CrlValidatedID getInstance(Object obj) + { + if (obj instanceof CrlValidatedID) + { + return (CrlValidatedID)obj; + } + else if (obj != null) + { + return new CrlValidatedID(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + private CrlValidatedID(ASN1Sequence seq) + { + if (seq.size() < 1 || seq.size() > 2) + { + throw new IllegalArgumentException("Bad sequence size: " + + seq.size()); + } + this.crlHash = OtherHash.getInstance(seq.getObjectAt(0)); + if (seq.size() > 1) + { + this.crlIdentifier = CrlIdentifier.getInstance(seq.getObjectAt(1)); + } + } + + public CrlValidatedID(OtherHash crlHash) + { + this(crlHash, null); + } + + public CrlValidatedID(OtherHash crlHash, CrlIdentifier crlIdentifier) + { + this.crlHash = crlHash; + this.crlIdentifier = crlIdentifier; + } + + public OtherHash getCrlHash() + { + return this.crlHash; + } + + public CrlIdentifier getCrlIdentifier() + { + return this.crlIdentifier; + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + v.add(this.crlHash.toASN1Primitive()); + if (null != this.crlIdentifier) + { + v.add(this.crlIdentifier.toASN1Primitive()); + } + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/esf/ESFAttributes.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/esf/ESFAttributes.java new file mode 100644 index 0000000..b78adc2 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/esf/ESFAttributes.java @@ -0,0 +1,22 @@ +package org.bc.asn1.esf; + +import org.bc.asn1.ASN1ObjectIdentifier; +import org.bc.asn1.pkcs.PKCSObjectIdentifiers; + +public interface ESFAttributes +{ + public static final ASN1ObjectIdentifier sigPolicyId = PKCSObjectIdentifiers.id_aa_ets_sigPolicyId; + public static final ASN1ObjectIdentifier commitmentType = PKCSObjectIdentifiers.id_aa_ets_commitmentType; + public static final ASN1ObjectIdentifier signerLocation = PKCSObjectIdentifiers.id_aa_ets_signerLocation; + public static final ASN1ObjectIdentifier signerAttr = PKCSObjectIdentifiers.id_aa_ets_signerAttr; + public static final ASN1ObjectIdentifier otherSigCert = PKCSObjectIdentifiers.id_aa_ets_otherSigCert; + public static final ASN1ObjectIdentifier contentTimestamp = PKCSObjectIdentifiers.id_aa_ets_contentTimestamp; + public static final ASN1ObjectIdentifier certificateRefs = PKCSObjectIdentifiers.id_aa_ets_certificateRefs; + public static final ASN1ObjectIdentifier revocationRefs = PKCSObjectIdentifiers.id_aa_ets_revocationRefs; + public static final ASN1ObjectIdentifier certValues = PKCSObjectIdentifiers.id_aa_ets_certValues; + public static final ASN1ObjectIdentifier revocationValues = PKCSObjectIdentifiers.id_aa_ets_revocationValues; + public static final ASN1ObjectIdentifier escTimeStamp = PKCSObjectIdentifiers.id_aa_ets_escTimeStamp; + public static final ASN1ObjectIdentifier certCRLTimestamp = PKCSObjectIdentifiers.id_aa_ets_certCRLTimestamp; + public static final ASN1ObjectIdentifier archiveTimestamp = PKCSObjectIdentifiers.id_aa_ets_archiveTimestamp; + public static final ASN1ObjectIdentifier archiveTimestampV2 = PKCSObjectIdentifiers.id_aa.branch("48"); +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/esf/OcspIdentifier.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/esf/OcspIdentifier.java new file mode 100644 index 0000000..7228685 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/esf/OcspIdentifier.java @@ -0,0 +1,73 @@ +package org.bc.asn1.esf; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1GeneralizedTime; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DERSequence; +import org.bc.asn1.ocsp.ResponderID; + +/** + *
+ * OcspIdentifier ::= SEQUENCE { + * ocspResponderID ResponderID, -- As in OCSP response data + * producedAt GeneralizedTime -- As in OCSP response data + * } + *+ */ +public class OcspIdentifier + extends ASN1Object +{ + private ResponderID ocspResponderID; + private ASN1GeneralizedTime producedAt; + + public static OcspIdentifier getInstance(Object obj) + { + if (obj instanceof OcspIdentifier) + { + return (OcspIdentifier)obj; + } + else if (obj != null) + { + return new OcspIdentifier(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + private OcspIdentifier(ASN1Sequence seq) + { + if (seq.size() != 2) + { + throw new IllegalArgumentException("Bad sequence size: " + + seq.size()); + } + this.ocspResponderID = ResponderID.getInstance(seq.getObjectAt(0)); + this.producedAt = (ASN1GeneralizedTime)seq.getObjectAt(1); + } + + public OcspIdentifier(ResponderID ocspResponderID, ASN1GeneralizedTime producedAt) + { + this.ocspResponderID = ocspResponderID; + this.producedAt = producedAt; + } + + public ResponderID getOcspResponderID() + { + return this.ocspResponderID; + } + + public ASN1GeneralizedTime getProducedAt() + { + return this.producedAt; + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + v.add(this.ocspResponderID); + v.add(this.producedAt); + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/esf/OcspListID.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/esf/OcspListID.java new file mode 100644 index 0000000..9b82583 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/esf/OcspListID.java @@ -0,0 +1,72 @@ +package org.bc.asn1.esf; + +import java.util.Enumeration; + +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DERSequence; + +/** + *
+ * OcspListID ::= SEQUENCE { + * ocspResponses SEQUENCE OF OcspResponsesID + * } + *+ */ +public class OcspListID + extends ASN1Object +{ + private ASN1Sequence ocspResponses; + + public static OcspListID getInstance(Object obj) + { + if (obj instanceof OcspListID) + { + return (OcspListID)obj; + } + else if (obj != null) + { + return new OcspListID(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + private OcspListID(ASN1Sequence seq) + { + if (seq.size() != 1) + { + throw new IllegalArgumentException("Bad sequence size: " + + seq.size()); + } + this.ocspResponses = (ASN1Sequence)seq.getObjectAt(0); + Enumeration e = this.ocspResponses.getObjects(); + while (e.hasMoreElements()) + { + OcspResponsesID.getInstance(e.nextElement()); + } + } + + public OcspListID(OcspResponsesID[] ocspResponses) + { + this.ocspResponses = new DERSequence(ocspResponses); + } + + public OcspResponsesID[] getOcspResponses() + { + OcspResponsesID[] result = new OcspResponsesID[this.ocspResponses + .size()]; + for (int idx = 0; idx < result.length; idx++) + { + result[idx] = OcspResponsesID.getInstance(this.ocspResponses + .getObjectAt(idx)); + } + return result; + } + + public ASN1Primitive toASN1Primitive() + { + return new DERSequence(this.ocspResponses); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/esf/OcspResponsesID.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/esf/OcspResponsesID.java new file mode 100644 index 0000000..2677f38 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/esf/OcspResponsesID.java @@ -0,0 +1,83 @@ +package org.bc.asn1.esf; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DERSequence; + +/** + *
+ * OcspResponsesID ::= SEQUENCE { + * ocspIdentifier OcspIdentifier, + * ocspRepHash OtherHash OPTIONAL + * } + *+ */ +public class OcspResponsesID + extends ASN1Object +{ + + private OcspIdentifier ocspIdentifier; + private OtherHash ocspRepHash; + + public static OcspResponsesID getInstance(Object obj) + { + if (obj instanceof OcspResponsesID) + { + return (OcspResponsesID)obj; + } + else if (obj != null) + { + return new OcspResponsesID(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + private OcspResponsesID(ASN1Sequence seq) + { + if (seq.size() < 1 || seq.size() > 2) + { + throw new IllegalArgumentException("Bad sequence size: " + + seq.size()); + } + this.ocspIdentifier = OcspIdentifier.getInstance(seq.getObjectAt(0)); + if (seq.size() > 1) + { + this.ocspRepHash = OtherHash.getInstance(seq.getObjectAt(1)); + } + } + + public OcspResponsesID(OcspIdentifier ocspIdentifier) + { + this(ocspIdentifier, null); + } + + public OcspResponsesID(OcspIdentifier ocspIdentifier, OtherHash ocspRepHash) + { + this.ocspIdentifier = ocspIdentifier; + this.ocspRepHash = ocspRepHash; + } + + public OcspIdentifier getOcspIdentifier() + { + return this.ocspIdentifier; + } + + public OtherHash getOcspRepHash() + { + return this.ocspRepHash; + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + v.add(this.ocspIdentifier); + if (null != this.ocspRepHash) + { + v.add(this.ocspRepHash); + } + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/esf/OtherHash.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/esf/OtherHash.java new file mode 100644 index 0000000..6e7969f --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/esf/OtherHash.java @@ -0,0 +1,81 @@ +package org.bc.asn1.esf; + +import org.bc.asn1.ASN1Choice; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1OctetString; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.DEROctetString; +import org.bc.asn1.oiw.OIWObjectIdentifiers; +import org.bc.asn1.x509.AlgorithmIdentifier; + +/** + *
+ * OtherHash ::= CHOICE { + * sha1Hash OtherHashValue, -- This contains a SHA-1 hash + * otherHash OtherHashAlgAndValue + * } + *+ */ +public class OtherHash + extends ASN1Object + implements ASN1Choice +{ + + private ASN1OctetString sha1Hash; + private OtherHashAlgAndValue otherHash; + + public static OtherHash getInstance(Object obj) + { + if (obj instanceof OtherHash) + { + return (OtherHash)obj; + } + if (obj instanceof ASN1OctetString) + { + return new OtherHash((ASN1OctetString)obj); + } + return new OtherHash(OtherHashAlgAndValue.getInstance(obj)); + } + + private OtherHash(ASN1OctetString sha1Hash) + { + this.sha1Hash = sha1Hash; + } + + public OtherHash(OtherHashAlgAndValue otherHash) + { + this.otherHash = otherHash; + } + + public OtherHash(byte[] sha1Hash) + { + this.sha1Hash = new DEROctetString(sha1Hash); + } + + public AlgorithmIdentifier getHashAlgorithm() + { + if (null == this.otherHash) + { + return new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1); + } + return this.otherHash.getHashAlgorithm(); + } + + public byte[] getHashValue() + { + if (null == this.otherHash) + { + return this.sha1Hash.getOctets(); + } + return this.otherHash.getHashValue().getOctets(); + } + + public ASN1Primitive toASN1Primitive() + { + if (null == this.otherHash) + { + return this.sha1Hash; + } + return this.otherHash.toASN1Primitive(); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/esf/OtherHashAlgAndValue.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/esf/OtherHashAlgAndValue.java new file mode 100644 index 0000000..39a050c --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/esf/OtherHashAlgAndValue.java @@ -0,0 +1,81 @@ +package org.bc.asn1.esf; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1OctetString; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DERSequence; +import org.bc.asn1.x509.AlgorithmIdentifier; + +public class OtherHashAlgAndValue + extends ASN1Object +{ + private AlgorithmIdentifier hashAlgorithm; + private ASN1OctetString hashValue; + + + public static OtherHashAlgAndValue getInstance( + Object obj) + { + if (obj instanceof OtherHashAlgAndValue) + { + return (OtherHashAlgAndValue) obj; + } + else if (obj != null) + { + return new OtherHashAlgAndValue(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + private OtherHashAlgAndValue( + ASN1Sequence seq) + { + if (seq.size() != 2) + { + throw new IllegalArgumentException("Bad sequence size: " + seq.size()); + } + + hashAlgorithm = AlgorithmIdentifier.getInstance(seq.getObjectAt(0)); + hashValue = ASN1OctetString.getInstance(seq.getObjectAt(1)); + } + + public OtherHashAlgAndValue( + AlgorithmIdentifier hashAlgorithm, + ASN1OctetString hashValue) + { + this.hashAlgorithm = hashAlgorithm; + this.hashValue = hashValue; + } + + public AlgorithmIdentifier getHashAlgorithm() + { + return hashAlgorithm; + } + + public ASN1OctetString getHashValue() + { + return hashValue; + } + + /** + *
+ * OtherHashAlgAndValue ::= SEQUENCE { + * hashAlgorithm AlgorithmIdentifier, + * hashValue OtherHashValue } + * + * OtherHashValue ::= OCTET STRING + *+ */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(hashAlgorithm); + v.add(hashValue); + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/esf/OtherRevRefs.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/esf/OtherRevRefs.java new file mode 100644 index 0000000..5bf1f0a --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/esf/OtherRevRefs.java @@ -0,0 +1,87 @@ +package org.bc.asn1.esf; + +import java.io.IOException; + +import org.bc.asn1.ASN1Encodable; +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Encoding; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1ObjectIdentifier; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DERSequence; + +/** + *
+ * OtherRevRefs ::= SEQUENCE { + * otherRevRefType OtherRevRefType, + * otherRevRefs ANY DEFINED BY otherRevRefType + * } + * + * OtherRevRefType ::= OBJECT IDENTIFIER + *+ */ +public class OtherRevRefs + extends ASN1Object +{ + + private ASN1ObjectIdentifier otherRevRefType; + private ASN1Encodable otherRevRefs; + + public static OtherRevRefs getInstance(Object obj) + { + if (obj instanceof OtherRevRefs) + { + return (OtherRevRefs)obj; + } + else if (obj != null) + { + return new OtherRevRefs(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + private OtherRevRefs(ASN1Sequence seq) + { + if (seq.size() != 2) + { + throw new IllegalArgumentException("Bad sequence size: " + + seq.size()); + } + this.otherRevRefType = new ASN1ObjectIdentifier(((ASN1ObjectIdentifier)seq.getObjectAt(0)).getId()); + try + { + this.otherRevRefs = ASN1Primitive.fromByteArray(seq.getObjectAt(1) + .toASN1Primitive().getEncoded(ASN1Encoding.DER)); + } + catch (IOException e) + { + throw new IllegalStateException(); + } + } + + public OtherRevRefs(ASN1ObjectIdentifier otherRevRefType, ASN1Encodable otherRevRefs) + { + this.otherRevRefType = otherRevRefType; + this.otherRevRefs = otherRevRefs; + } + + public ASN1ObjectIdentifier getOtherRevRefType() + { + return this.otherRevRefType; + } + + public ASN1Encodable getOtherRevRefs() + { + return this.otherRevRefs; + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + v.add(this.otherRevRefType); + v.add(this.otherRevRefs); + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/esf/OtherRevVals.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/esf/OtherRevVals.java new file mode 100644 index 0000000..05049cc --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/esf/OtherRevVals.java @@ -0,0 +1,89 @@ +package org.bc.asn1.esf; + +import java.io.IOException; + +import org.bc.asn1.ASN1Encodable; +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Encoding; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1ObjectIdentifier; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DERSequence; + +/** + *
+ * OtherRevVals ::= SEQUENCE { + * otherRevValType OtherRevValType, + * otherRevVals ANY DEFINED BY OtherRevValType + * } + * + * OtherRevValType ::= OBJECT IDENTIFIER + *+ */ +public class OtherRevVals + extends ASN1Object +{ + + private ASN1ObjectIdentifier otherRevValType; + + private ASN1Encodable otherRevVals; + + public static OtherRevVals getInstance(Object obj) + { + if (obj instanceof OtherRevVals) + { + return (OtherRevVals)obj; + } + if (obj != null) + { + return new OtherRevVals(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + private OtherRevVals(ASN1Sequence seq) + { + if (seq.size() != 2) + { + throw new IllegalArgumentException("Bad sequence size: " + + seq.size()); + } + this.otherRevValType = (ASN1ObjectIdentifier)seq.getObjectAt(0); + try + { + this.otherRevVals = ASN1Primitive.fromByteArray(seq.getObjectAt(1) + .toASN1Primitive().getEncoded(ASN1Encoding.DER)); + } + catch (IOException e) + { + throw new IllegalStateException(); + } + } + + public OtherRevVals(ASN1ObjectIdentifier otherRevValType, + ASN1Encodable otherRevVals) + { + this.otherRevValType = otherRevValType; + this.otherRevVals = otherRevVals; + } + + public ASN1ObjectIdentifier getOtherRevValType() + { + return this.otherRevValType; + } + + public ASN1Encodable getOtherRevVals() + { + return this.otherRevVals; + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + v.add(this.otherRevValType); + v.add(this.otherRevVals); + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/esf/RevocationValues.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/esf/RevocationValues.java new file mode 100644 index 0000000..bebc602 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/esf/RevocationValues.java @@ -0,0 +1,151 @@ +package org.bc.asn1.esf; + +import java.util.Enumeration; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DERSequence; +import org.bc.asn1.DERTaggedObject; +import org.bc.asn1.ocsp.BasicOCSPResponse; +import org.bc.asn1.x509.CertificateList; + +/** + *
+ * RevocationValues ::= SEQUENCE { + * crlVals [0] SEQUENCE OF CertificateList OPTIONAL, + * ocspVals [1] SEQUENCE OF BasicOCSPResponse OPTIONAL, + * otherRevVals [2] OtherRevVals OPTIONAL} + *+ */ +public class RevocationValues + extends ASN1Object +{ + + private ASN1Sequence crlVals; + private ASN1Sequence ocspVals; + private OtherRevVals otherRevVals; + + public static RevocationValues getInstance(Object obj) + { + if (obj instanceof RevocationValues) + { + return (RevocationValues)obj; + } + else if (obj != null) + { + return new RevocationValues(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + private RevocationValues(ASN1Sequence seq) + { + if (seq.size() > 3) + { + throw new IllegalArgumentException("Bad sequence size: " + + seq.size()); + } + Enumeration e = seq.getObjects(); + while (e.hasMoreElements()) + { + DERTaggedObject o = (DERTaggedObject)e.nextElement(); + switch (o.getTagNo()) + { + case 0: + ASN1Sequence crlValsSeq = (ASN1Sequence)o.getObject(); + Enumeration crlValsEnum = crlValsSeq.getObjects(); + while (crlValsEnum.hasMoreElements()) + { + CertificateList.getInstance(crlValsEnum.nextElement()); + } + this.crlVals = crlValsSeq; + break; + case 1: + ASN1Sequence ocspValsSeq = (ASN1Sequence)o.getObject(); + Enumeration ocspValsEnum = ocspValsSeq.getObjects(); + while (ocspValsEnum.hasMoreElements()) + { + BasicOCSPResponse.getInstance(ocspValsEnum.nextElement()); + } + this.ocspVals = ocspValsSeq; + break; + case 2: + this.otherRevVals = OtherRevVals.getInstance(o.getObject()); + break; + default: + throw new IllegalArgumentException("invalid tag: " + + o.getTagNo()); + } + } + } + + public RevocationValues(CertificateList[] crlVals, + BasicOCSPResponse[] ocspVals, OtherRevVals otherRevVals) + { + if (null != crlVals) + { + this.crlVals = new DERSequence(crlVals); + } + if (null != ocspVals) + { + this.ocspVals = new DERSequence(ocspVals); + } + this.otherRevVals = otherRevVals; + } + + public CertificateList[] getCrlVals() + { + if (null == this.crlVals) + { + return new CertificateList[0]; + } + CertificateList[] result = new CertificateList[this.crlVals.size()]; + for (int idx = 0; idx < result.length; idx++) + { + result[idx] = CertificateList.getInstance(this.crlVals + .getObjectAt(idx)); + } + return result; + } + + public BasicOCSPResponse[] getOcspVals() + { + if (null == this.ocspVals) + { + return new BasicOCSPResponse[0]; + } + BasicOCSPResponse[] result = new BasicOCSPResponse[this.ocspVals.size()]; + for (int idx = 0; idx < result.length; idx++) + { + result[idx] = BasicOCSPResponse.getInstance(this.ocspVals + .getObjectAt(idx)); + } + return result; + } + + public OtherRevVals getOtherRevVals() + { + return this.otherRevVals; + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + if (null != this.crlVals) + { + v.add(new DERTaggedObject(true, 0, this.crlVals)); + } + if (null != this.ocspVals) + { + v.add(new DERTaggedObject(true, 1, this.ocspVals)); + } + if (null != this.otherRevVals) + { + v.add(new DERTaggedObject(true, 2, this.otherRevVals.toASN1Primitive())); + } + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/esf/SPUserNotice.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/esf/SPUserNotice.java new file mode 100644 index 0000000..fe7086b --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/esf/SPUserNotice.java @@ -0,0 +1,99 @@ +package org.bc.asn1.esf; + +import java.util.Enumeration; + +import org.bc.asn1.ASN1Encodable; +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1String; +import org.bc.asn1.DERSequence; +import org.bc.asn1.x509.DisplayText; +import org.bc.asn1.x509.NoticeReference; + +public class SPUserNotice + extends ASN1Object +{ + private NoticeReference noticeRef; + private DisplayText explicitText; + + public static SPUserNotice getInstance( + Object obj) + { + if (obj instanceof SPUserNotice) + { + return (SPUserNotice)obj; + } + else if (obj != null) + { + return new SPUserNotice(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + private SPUserNotice( + ASN1Sequence seq) + { + Enumeration e = seq.getObjects(); + while (e.hasMoreElements()) + { + ASN1Encodable object = (ASN1Encodable)e.nextElement(); + if (object instanceof DisplayText || object instanceof ASN1String) + { + explicitText = DisplayText.getInstance(object); + } + else if (object instanceof NoticeReference || object instanceof ASN1Sequence) + { + noticeRef = NoticeReference.getInstance(object); + } + else + { + throw new IllegalArgumentException("Invalid element in 'SPUserNotice': " + object.getClass().getName()); + } + } + } + + public SPUserNotice( + NoticeReference noticeRef, + DisplayText explicitText) + { + this.noticeRef = noticeRef; + this.explicitText = explicitText; + } + + public NoticeReference getNoticeRef() + { + return noticeRef; + } + + public DisplayText getExplicitText() + { + return explicitText; + } + + /** + *
+ * SPUserNotice ::= SEQUENCE { + * noticeRef NoticeReference OPTIONAL, + * explicitText DisplayText OPTIONAL } + *+ */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + if (noticeRef != null) + { + v.add(noticeRef); + } + + if (explicitText != null) + { + v.add(explicitText); + } + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/esf/SPuri.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/esf/SPuri.java new file mode 100644 index 0000000..0aa95ba --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/esf/SPuri.java @@ -0,0 +1,45 @@ +package org.bc.asn1.esf; + +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.DERIA5String; + +public class SPuri +{ + private DERIA5String uri; + + public static SPuri getInstance( + Object obj) + { + if (obj instanceof SPuri) + { + return (SPuri) obj; + } + else if (obj instanceof DERIA5String) + { + return new SPuri(DERIA5String.getInstance(obj)); + } + + return null; + } + + public SPuri( + DERIA5String uri) + { + this.uri = uri; + } + + public DERIA5String getUri() + { + return uri; + } + + /** + *
+ * SPuri ::= IA5String + *+ */ + public ASN1Primitive toASN1Primitive() + { + return uri.toASN1Primitive(); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/esf/SigPolicyQualifierInfo.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/esf/SigPolicyQualifierInfo.java new file mode 100644 index 0000000..2fa7033 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/esf/SigPolicyQualifierInfo.java @@ -0,0 +1,75 @@ +package org.bc.asn1.esf; + +import org.bc.asn1.ASN1Encodable; +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1ObjectIdentifier; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DERSequence; + +public class SigPolicyQualifierInfo + extends ASN1Object +{ + private ASN1ObjectIdentifier sigPolicyQualifierId; + private ASN1Encodable sigQualifier; + + public SigPolicyQualifierInfo( + ASN1ObjectIdentifier sigPolicyQualifierId, + ASN1Encodable sigQualifier) + { + this.sigPolicyQualifierId = sigPolicyQualifierId; + this.sigQualifier = sigQualifier; + } + + private SigPolicyQualifierInfo( + ASN1Sequence seq) + { + sigPolicyQualifierId = ASN1ObjectIdentifier.getInstance(seq.getObjectAt(0)); + sigQualifier = seq.getObjectAt(1); + } + + public static SigPolicyQualifierInfo getInstance( + Object obj) + { + if (obj instanceof SigPolicyQualifierInfo) + { + return (SigPolicyQualifierInfo) obj; + } + else if (obj != null) + { + return new SigPolicyQualifierInfo(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public ASN1ObjectIdentifier getSigPolicyQualifierId() + { + return new ASN1ObjectIdentifier(sigPolicyQualifierId.getId()); + } + + public ASN1Encodable getSigQualifier() + { + return sigQualifier; + } + + /** + *
+ * SigPolicyQualifierInfo ::= SEQUENCE { + * sigPolicyQualifierId SigPolicyQualifierId, + * sigQualifier ANY DEFINED BY sigPolicyQualifierId } + * + * SigPolicyQualifierId ::= OBJECT IDENTIFIER + *+ */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(sigPolicyQualifierId); + v.add(sigQualifier); + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/esf/SigPolicyQualifiers.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/esf/SigPolicyQualifiers.java new file mode 100644 index 0000000..c8d2b40 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/esf/SigPolicyQualifiers.java @@ -0,0 +1,77 @@ +package org.bc.asn1.esf; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DERSequence; + +public class SigPolicyQualifiers + extends ASN1Object +{ + ASN1Sequence qualifiers; + + public static SigPolicyQualifiers getInstance( + Object obj) + { + if (obj instanceof SigPolicyQualifiers) + { + return (SigPolicyQualifiers) obj; + } + else if (obj instanceof ASN1Sequence) + { + return new SigPolicyQualifiers(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + private SigPolicyQualifiers( + ASN1Sequence seq) + { + qualifiers = seq; + } + + public SigPolicyQualifiers( + SigPolicyQualifierInfo[] qualifierInfos) + { + ASN1EncodableVector v = new ASN1EncodableVector(); + for (int i=0; i < qualifierInfos.length; i++) + { + v.add(qualifierInfos[i]); + } + qualifiers = new DERSequence(v); + } + + /** + * Return the number of qualifier info elements present. + * + * @return number of elements present. + */ + public int size() + { + return qualifiers.size(); + } + + /** + * Return the SigPolicyQualifierInfo at index i. + * + * @param i index of the info of interest + * @return the info at index i. + */ + public SigPolicyQualifierInfo getInfoAt( + int i) + { + return SigPolicyQualifierInfo.getInstance(qualifiers.getObjectAt(i)); + } + + /** + *
+ * SigPolicyQualifiers ::= SEQUENCE SIZE (1..MAX) OF SigPolicyQualifierInfo + *+ */ + public ASN1Primitive toASN1Primitive() + { + return qualifiers; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/esf/SignaturePolicyId.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/esf/SignaturePolicyId.java new file mode 100644 index 0000000..3aa4c3f --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/esf/SignaturePolicyId.java @@ -0,0 +1,103 @@ +package org.bc.asn1.esf; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1ObjectIdentifier; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DERSequence; + +public class SignaturePolicyId + extends ASN1Object +{ + private ASN1ObjectIdentifier sigPolicyId; + private OtherHashAlgAndValue sigPolicyHash; + private SigPolicyQualifiers sigPolicyQualifiers; + + + public static SignaturePolicyId getInstance( + Object obj) + { + if (obj instanceof SignaturePolicyId) + { + return (SignaturePolicyId)obj; + } + else if (obj != null) + { + return new SignaturePolicyId(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + private SignaturePolicyId( + ASN1Sequence seq) + { + if (seq.size() != 2 && seq.size() != 3) + { + throw new IllegalArgumentException("Bad sequence size: " + seq.size()); + } + + sigPolicyId = ASN1ObjectIdentifier.getInstance(seq.getObjectAt(0)); + sigPolicyHash = OtherHashAlgAndValue.getInstance(seq.getObjectAt(1)); + + if (seq.size() == 3) + { + sigPolicyQualifiers = SigPolicyQualifiers.getInstance(seq.getObjectAt(2)); + } + } + + public SignaturePolicyId( + ASN1ObjectIdentifier sigPolicyIdentifier, + OtherHashAlgAndValue sigPolicyHash) + { + this(sigPolicyIdentifier, sigPolicyHash, null); + } + + public SignaturePolicyId( + ASN1ObjectIdentifier sigPolicyId, + OtherHashAlgAndValue sigPolicyHash, + SigPolicyQualifiers sigPolicyQualifiers) + { + this.sigPolicyId = sigPolicyId; + this.sigPolicyHash = sigPolicyHash; + this.sigPolicyQualifiers = sigPolicyQualifiers; + } + + public ASN1ObjectIdentifier getSigPolicyId() + { + return new ASN1ObjectIdentifier(sigPolicyId.getId()); + } + + public OtherHashAlgAndValue getSigPolicyHash() + { + return sigPolicyHash; + } + + public SigPolicyQualifiers getSigPolicyQualifiers() + { + return sigPolicyQualifiers; + } + + /** + *
+ * SignaturePolicyId ::= SEQUENCE { + * sigPolicyId SigPolicyId, + * sigPolicyHash SigPolicyHash, + * sigPolicyQualifiers SEQUENCE SIZE (1..MAX) OF SigPolicyQualifierInfo OPTIONAL} + *+ */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(sigPolicyId); + v.add(sigPolicyHash); + if (sigPolicyQualifiers != null) + { + v.add(sigPolicyQualifiers); + } + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/esf/SignaturePolicyIdentifier.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/esf/SignaturePolicyIdentifier.java new file mode 100644 index 0000000..72005f1 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/esf/SignaturePolicyIdentifier.java @@ -0,0 +1,76 @@ +package org.bc.asn1.esf; + +import org.bc.asn1.ASN1Null; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.BERTags; +import org.bc.asn1.DERNull; + +public class SignaturePolicyIdentifier + extends ASN1Object +{ + private SignaturePolicyId signaturePolicyId; + private boolean isSignaturePolicyImplied; + + public static SignaturePolicyIdentifier getInstance( + Object obj) + { + if (obj instanceof SignaturePolicyIdentifier) + { + return (SignaturePolicyIdentifier)obj; + } + else if (obj instanceof ASN1Null || hasEncodedTagValue(obj, BERTags.NULL)) + { + return new SignaturePolicyIdentifier(); + } + else if (obj != null) + { + return new SignaturePolicyIdentifier(SignaturePolicyId.getInstance(obj)); + } + + return null; + } + + public SignaturePolicyIdentifier() + { + this.isSignaturePolicyImplied = true; + } + + public SignaturePolicyIdentifier( + SignaturePolicyId signaturePolicyId) + { + this.signaturePolicyId = signaturePolicyId; + this.isSignaturePolicyImplied = false; + } + + public SignaturePolicyId getSignaturePolicyId() + { + return signaturePolicyId; + } + + public boolean isSignaturePolicyImplied() + { + return isSignaturePolicyImplied; + } + + /** + *
+ * SignaturePolicyIdentifier ::= CHOICE{ + * SignaturePolicyId SignaturePolicyId, + * SignaturePolicyImplied SignaturePolicyImplied } + * + * SignaturePolicyImplied ::= NULL + *+ */ + public ASN1Primitive toASN1Primitive() + { + if (isSignaturePolicyImplied) + { + return DERNull.INSTANCE; + } + else + { + return signaturePolicyId.toASN1Primitive(); + } + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/esf/SignerAttribute.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/esf/SignerAttribute.java new file mode 100644 index 0000000..d6cb21e --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/esf/SignerAttribute.java @@ -0,0 +1,123 @@ +package org.bc.asn1.esf; + +import java.util.Enumeration; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERSequence; +import org.bc.asn1.DERTaggedObject; +import org.bc.asn1.x509.Attribute; +import org.bc.asn1.x509.AttributeCertificate; + + +public class SignerAttribute + extends ASN1Object +{ + private Object[] values; + + public static SignerAttribute getInstance( + Object o) + { + if (o instanceof SignerAttribute) + { + return (SignerAttribute) o; + } + else if (o != null) + { + return new SignerAttribute(ASN1Sequence.getInstance(o)); + } + + return null; + } + + private SignerAttribute( + ASN1Sequence seq) + { + int index = 0; + values = new Object[seq.size()]; + + for (Enumeration e = seq.getObjects(); e.hasMoreElements();) + { + ASN1TaggedObject taggedObject = ASN1TaggedObject.getInstance(e.nextElement()); + + if (taggedObject.getTagNo() == 0) + { + ASN1Sequence attrs = ASN1Sequence.getInstance(taggedObject, true); + Attribute[] attributes = new Attribute[attrs.size()]; + + for (int i = 0; i != attributes.length; i++) + { + attributes[i] = Attribute.getInstance(attrs.getObjectAt(i)); + } + values[index] = attributes; + } + else if (taggedObject.getTagNo() == 1) + { + values[index] = AttributeCertificate.getInstance(ASN1Sequence.getInstance(taggedObject, true)); + } + else + { + throw new IllegalArgumentException("illegal tag: " + taggedObject.getTagNo()); + } + index++; + } + } + + public SignerAttribute( + Attribute[] claimedAttributes) + { + this.values = new Object[1]; + this.values[0] = claimedAttributes; + } + + public SignerAttribute( + AttributeCertificate certifiedAttributes) + { + this.values = new Object[1]; + this.values[0] = certifiedAttributes; + } + + /** + * Return the sequence of choices - the array elements will either be of + * type Attribute[] or AttributeCertificate depending on what tag was used. + * + * @return array of choices. + */ + public Object[] getValues() + { + return values; + } + + /** + * + *
+ * SignerAttribute ::= SEQUENCE OF CHOICE { + * claimedAttributes [0] ClaimedAttributes, + * certifiedAttributes [1] CertifiedAttributes } + * + * ClaimedAttributes ::= SEQUENCE OF Attribute + * CertifiedAttributes ::= AttributeCertificate -- as defined in RFC 3281: see clause 4.1. + *+ */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + for (int i = 0; i != values.length; i++) + { + if (values[i] instanceof Attribute[]) + { + v.add(new DERTaggedObject(0, new DERSequence((Attribute[])values[i]))); + } + else + { + v.add(new DERTaggedObject(1, (AttributeCertificate)values[i])); + } + } + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/esf/SignerLocation.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/esf/SignerLocation.java new file mode 100644 index 0000000..37ffbd5 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/esf/SignerLocation.java @@ -0,0 +1,162 @@ +package org.bc.asn1.esf; + +import java.util.Enumeration; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DERSequence; +import org.bc.asn1.DERTaggedObject; +import org.bc.asn1.DERUTF8String; +import org.bc.asn1.x500.DirectoryString; + +/** + * Signer-Location attribute (RFC3126). + * + *
+ * SignerLocation ::= SEQUENCE { + * countryName [0] DirectoryString OPTIONAL, + * localityName [1] DirectoryString OPTIONAL, + * postalAddress [2] PostalAddress OPTIONAL } + * + * PostalAddress ::= SEQUENCE SIZE(1..6) OF DirectoryString + *+ */ +public class SignerLocation + extends ASN1Object +{ + private DERUTF8String countryName; + private DERUTF8String localityName; + private ASN1Sequence postalAddress; + + private SignerLocation( + ASN1Sequence seq) + { + Enumeration e = seq.getObjects(); + + while (e.hasMoreElements()) + { + DERTaggedObject o = (DERTaggedObject)e.nextElement(); + + switch (o.getTagNo()) + { + case 0: + DirectoryString countryNameDirectoryString = DirectoryString.getInstance(o, true); + this.countryName = new DERUTF8String(countryNameDirectoryString.getString()); + break; + case 1: + DirectoryString localityNameDirectoryString = DirectoryString.getInstance(o, true); + this.localityName = new DERUTF8String(localityNameDirectoryString.getString()); + break; + case 2: + if (o.isExplicit()) + { + this.postalAddress = ASN1Sequence.getInstance(o, true); + } + else // handle erroneous implicitly tagged sequences + { + this.postalAddress = ASN1Sequence.getInstance(o, false); + } + if (postalAddress != null && postalAddress.size() > 6) + { + throw new IllegalArgumentException("postal address must contain less than 6 strings"); + } + break; + default: + throw new IllegalArgumentException("illegal tag"); + } + } + } + + public SignerLocation( + DERUTF8String countryName, + DERUTF8String localityName, + ASN1Sequence postalAddress) + { + if (postalAddress != null && postalAddress.size() > 6) + { + throw new IllegalArgumentException("postal address must contain less than 6 strings"); + } + + if (countryName != null) + { + this.countryName = DERUTF8String.getInstance(countryName.toASN1Primitive()); + } + + if (localityName != null) + { + this.localityName = DERUTF8String.getInstance(localityName.toASN1Primitive()); + } + + if (postalAddress != null) + { + this.postalAddress = ASN1Sequence.getInstance(postalAddress.toASN1Primitive()); + } + } + + public static SignerLocation getInstance( + Object obj) + { + if (obj == null || obj instanceof SignerLocation) + { + return (SignerLocation)obj; + } + + return new SignerLocation(ASN1Sequence.getInstance(obj)); + } + + public DERUTF8String getCountryName() + { + return countryName; + } + + public DERUTF8String getLocalityName() + { + return localityName; + } + + public ASN1Sequence getPostalAddress() + { + return postalAddress; + } + + /** + *
+ * SignerLocation ::= SEQUENCE { + * countryName [0] DirectoryString OPTIONAL, + * localityName [1] DirectoryString OPTIONAL, + * postalAddress [2] PostalAddress OPTIONAL } + * + * PostalAddress ::= SEQUENCE SIZE(1..6) OF DirectoryString + * + * DirectoryString ::= CHOICE { + * teletexString TeletexString (SIZE (1..MAX)), + * printableString PrintableString (SIZE (1..MAX)), + * universalString UniversalString (SIZE (1..MAX)), + * utf8String UTF8String (SIZE (1.. MAX)), + * bmpString BMPString (SIZE (1..MAX)) } + *+ */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + if (countryName != null) + { + v.add(new DERTaggedObject(true, 0, countryName)); + } + + if (localityName != null) + { + v.add(new DERTaggedObject(true, 1, localityName)); + } + + if (postalAddress != null) + { + v.add(new DERTaggedObject(true, 2, postalAddress)); + } + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ess/ContentHints.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ess/ContentHints.java new file mode 100644 index 0000000..5c5a0c5 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ess/ContentHints.java @@ -0,0 +1,114 @@ +package org.bc.asn1.ess; + +import org.bc.asn1.ASN1Encodable; +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1ObjectIdentifier; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DERObjectIdentifier; +import org.bc.asn1.DERSequence; +import org.bc.asn1.DERUTF8String; + +public class ContentHints + extends ASN1Object +{ + private DERUTF8String contentDescription; + private ASN1ObjectIdentifier contentType; + + public static ContentHints getInstance(Object o) + { + if (o instanceof ContentHints) + { + return (ContentHints)o; + } + else if (o != null) + { + return new ContentHints(ASN1Sequence.getInstance(o)); + } + + return null; + } + + /** + * constructor + */ + private ContentHints(ASN1Sequence seq) + { + ASN1Encodable field = seq.getObjectAt(0); + if (field.toASN1Primitive() instanceof DERUTF8String) + { + contentDescription = DERUTF8String.getInstance(field); + contentType = ASN1ObjectIdentifier.getInstance(seq.getObjectAt(1)); + } + else + { + contentType = ASN1ObjectIdentifier.getInstance(seq.getObjectAt(0)); + } + } + + /** + * @deprecated use ASN1ObjectIdentifier + */ + public ContentHints( + DERObjectIdentifier contentType) + { + this(new ASN1ObjectIdentifier(contentType.getId())); + } + + /** + * @deprecated use ASN1ObjectIdentifier + */ + public ContentHints( + DERObjectIdentifier contentType, + DERUTF8String contentDescription) + { + this(new ASN1ObjectIdentifier(contentType.getId()), contentDescription); + } + + public ContentHints( + ASN1ObjectIdentifier contentType) + { + this.contentType = contentType; + this.contentDescription = null; + } + + public ContentHints( + ASN1ObjectIdentifier contentType, + DERUTF8String contentDescription) + { + this.contentType = contentType; + this.contentDescription = contentDescription; + } + + public ASN1ObjectIdentifier getContentType() + { + return contentType; + } + + public DERUTF8String getContentDescription() + { + return contentDescription; + } + + /** + *
+ * ContentHints ::= SEQUENCE { + * contentDescription UTF8String (SIZE (1..MAX)) OPTIONAL, + * contentType ContentType } + *+ */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + if (contentDescription != null) + { + v.add(contentDescription); + } + + v.add(contentType); + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ess/ContentIdentifier.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ess/ContentIdentifier.java new file mode 100644 index 0000000..57dbd9b --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ess/ContentIdentifier.java @@ -0,0 +1,63 @@ +package org.bc.asn1.ess; + +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1OctetString; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.DEROctetString; + +public class ContentIdentifier + extends ASN1Object +{ + ASN1OctetString value; + + public static ContentIdentifier getInstance(Object o) + { + if (o instanceof ContentIdentifier) + { + return (ContentIdentifier) o; + } + else if (o != null) + { + return new ContentIdentifier(ASN1OctetString.getInstance(o)); + } + + return null; + } + + /** + * Create from OCTET STRING whose octets represent the identifier. + */ + private ContentIdentifier( + ASN1OctetString value) + { + this.value = value; + } + + /** + * Create from byte array representing the identifier. + */ + public ContentIdentifier( + byte[] value) + { + this(new DEROctetString(value)); + } + + public ASN1OctetString getValue() + { + return value; + } + + /** + * The definition of ContentIdentifier is + *
+ * ContentIdentifier ::= OCTET STRING + *+ * id-aa-contentIdentifier OBJECT IDENTIFIER ::= { iso(1) + * member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9) + * smime(16) id-aa(2) 7 } + */ + public ASN1Primitive toASN1Primitive() + { + return value; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ess/ESSCertID.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ess/ESSCertID.java new file mode 100644 index 0000000..db5210a --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ess/ESSCertID.java @@ -0,0 +1,95 @@ +package org.bc.asn1.ess; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1OctetString; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DEROctetString; +import org.bc.asn1.DERSequence; +import org.bc.asn1.x509.IssuerSerial; + +public class ESSCertID + extends ASN1Object +{ + private ASN1OctetString certHash; + + private IssuerSerial issuerSerial; + + public static ESSCertID getInstance(Object o) + { + if (o instanceof ESSCertID) + { + return (ESSCertID)o; + } + else if (o != null) + { + return new ESSCertID(ASN1Sequence.getInstance(o)); + } + + return null; + } + + /** + * constructor + */ + private ESSCertID(ASN1Sequence seq) + { + if (seq.size() < 1 || seq.size() > 2) + { + throw new IllegalArgumentException("Bad sequence size: " + seq.size()); + } + + certHash = ASN1OctetString.getInstance(seq.getObjectAt(0)); + + if (seq.size() > 1) + { + issuerSerial = IssuerSerial.getInstance(seq.getObjectAt(1)); + } + } + + public ESSCertID( + byte[] hash) + { + certHash = new DEROctetString(hash); + } + + public ESSCertID( + byte[] hash, + IssuerSerial issuerSerial) + { + this.certHash = new DEROctetString(hash); + this.issuerSerial = issuerSerial; + } + + public byte[] getCertHash() + { + return certHash.getOctets(); + } + + public IssuerSerial getIssuerSerial() + { + return issuerSerial; + } + + /** + *
+ * ESSCertID ::= SEQUENCE { + * certHash Hash, + * issuerSerial IssuerSerial OPTIONAL } + *+ */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(certHash); + + if (issuerSerial != null) + { + v.add(issuerSerial); + } + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ess/ESSCertIDv2.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ess/ESSCertIDv2.java new file mode 100644 index 0000000..5715920 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ess/ESSCertIDv2.java @@ -0,0 +1,142 @@ +package org.bc.asn1.ess; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1OctetString; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DEROctetString; +import org.bc.asn1.DERSequence; +import org.bc.asn1.nist.NISTObjectIdentifiers; +import org.bc.asn1.x509.AlgorithmIdentifier; +import org.bc.asn1.x509.IssuerSerial; + +public class ESSCertIDv2 + extends ASN1Object +{ + private AlgorithmIdentifier hashAlgorithm; + private byte[] certHash; + private IssuerSerial issuerSerial; + private static final AlgorithmIdentifier DEFAULT_ALG_ID = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha256); + + public static ESSCertIDv2 getInstance( + Object o) + { + if (o instanceof ESSCertIDv2) + { + return (ESSCertIDv2) o; + } + else if (o != null) + { + return new ESSCertIDv2(ASN1Sequence.getInstance(o)); + } + + return null; + } + + private ESSCertIDv2( + ASN1Sequence seq) + { + if (seq.size() > 3) + { + throw new IllegalArgumentException("Bad sequence size: " + seq.size()); + } + + int count = 0; + + if (seq.getObjectAt(0) instanceof ASN1OctetString) + { + // Default value + this.hashAlgorithm = DEFAULT_ALG_ID; + } + else + { + this.hashAlgorithm = AlgorithmIdentifier.getInstance(seq.getObjectAt(count++).toASN1Primitive()); + } + + this.certHash = ASN1OctetString.getInstance(seq.getObjectAt(count++).toASN1Primitive()).getOctets(); + + if (seq.size() > count) + { + this.issuerSerial = IssuerSerial.getInstance(seq.getObjectAt(count)); + } + } + + public ESSCertIDv2( + AlgorithmIdentifier algId, + byte[] certHash) + { + this(algId, certHash, null); + } + + public ESSCertIDv2( + AlgorithmIdentifier algId, + byte[] certHash, + IssuerSerial issuerSerial) + { + if (algId == null) + { + // Default value + this.hashAlgorithm = DEFAULT_ALG_ID; + } + else + { + this.hashAlgorithm = algId; + } + + this.certHash = certHash; + this.issuerSerial = issuerSerial; + } + + public AlgorithmIdentifier getHashAlgorithm() + { + return this.hashAlgorithm; + } + + public byte[] getCertHash() + { + return certHash; + } + + public IssuerSerial getIssuerSerial() + { + return issuerSerial; + } + + /** + *
+ * ESSCertIDv2 ::= SEQUENCE { + * hashAlgorithm AlgorithmIdentifier + * DEFAULT {algorithm id-sha256}, + * certHash Hash, + * issuerSerial IssuerSerial OPTIONAL + * } + * + * Hash ::= OCTET STRING + * + * IssuerSerial ::= SEQUENCE { + * issuer GeneralNames, + * serialNumber CertificateSerialNumber + * } + *+ */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + if (!hashAlgorithm.equals(DEFAULT_ALG_ID)) + { + v.add(hashAlgorithm); + } + + v.add(new DEROctetString(certHash).toASN1Primitive()); + + if (issuerSerial != null) + { + v.add(issuerSerial); + } + + return new DERSequence(v); + } + +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ess/OtherCertID.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ess/OtherCertID.java new file mode 100644 index 0000000..b9d3429 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ess/OtherCertID.java @@ -0,0 +1,137 @@ +package org.bc.asn1.ess; + +import org.bc.asn1.ASN1Encodable; +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1OctetString; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DERSequence; +import org.bc.asn1.x509.AlgorithmIdentifier; +import org.bc.asn1.x509.DigestInfo; +import org.bc.asn1.x509.IssuerSerial; + +public class OtherCertID + extends ASN1Object +{ + private ASN1Encodable otherCertHash; + private IssuerSerial issuerSerial; + + public static OtherCertID getInstance(Object o) + { + if (o instanceof OtherCertID) + { + return (OtherCertID) o; + } + else if (o != null) + { + return new OtherCertID(ASN1Sequence.getInstance(o)); + } + + return null; + } + + /** + * constructor + */ + private OtherCertID(ASN1Sequence seq) + { + if (seq.size() < 1 || seq.size() > 2) + { + throw new IllegalArgumentException("Bad sequence size: " + + seq.size()); + } + + if (seq.getObjectAt(0).toASN1Primitive() instanceof ASN1OctetString) + { + otherCertHash = ASN1OctetString.getInstance(seq.getObjectAt(0)); + } + else + { + otherCertHash = DigestInfo.getInstance(seq.getObjectAt(0)); + + } + + if (seq.size() > 1) + { + issuerSerial = IssuerSerial.getInstance(seq.getObjectAt(1)); + } + } + + public OtherCertID( + AlgorithmIdentifier algId, + byte[] digest) + { + this.otherCertHash = new DigestInfo(algId, digest); + } + + public OtherCertID( + AlgorithmIdentifier algId, + byte[] digest, + IssuerSerial issuerSerial) + { + this.otherCertHash = new DigestInfo(algId, digest); + this.issuerSerial = issuerSerial; + } + + public AlgorithmIdentifier getAlgorithmHash() + { + if (otherCertHash.toASN1Primitive() instanceof ASN1OctetString) + { + // SHA-1 + return new AlgorithmIdentifier("1.3.14.3.2.26"); + } + else + { + return DigestInfo.getInstance(otherCertHash).getAlgorithmId(); + } + } + + public byte[] getCertHash() + { + if (otherCertHash.toASN1Primitive() instanceof ASN1OctetString) + { + // SHA-1 + return ((ASN1OctetString)otherCertHash.toASN1Primitive()).getOctets(); + } + else + { + return DigestInfo.getInstance(otherCertHash).getDigest(); + } + } + + public IssuerSerial getIssuerSerial() + { + return issuerSerial; + } + + /** + *
+ * OtherCertID ::= SEQUENCE { + * otherCertHash OtherHash, + * issuerSerial IssuerSerial OPTIONAL } + * + * OtherHash ::= CHOICE { + * sha1Hash OCTET STRING, + * otherHash OtherHashAlgAndValue } + * + * OtherHashAlgAndValue ::= SEQUENCE { + * hashAlgorithm AlgorithmIdentifier, + * hashValue OCTET STRING } + * + *+ */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(otherCertHash); + + if (issuerSerial != null) + { + v.add(issuerSerial); + } + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ess/OtherSigningCertificate.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ess/OtherSigningCertificate.java new file mode 100644 index 0000000..9ccc82f --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ess/OtherSigningCertificate.java @@ -0,0 +1,109 @@ +package org.bc.asn1.ess; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DERSequence; +import org.bc.asn1.x509.PolicyInformation; + +public class OtherSigningCertificate + extends ASN1Object +{ + ASN1Sequence certs; + ASN1Sequence policies; + + public static OtherSigningCertificate getInstance(Object o) + { + if (o instanceof OtherSigningCertificate) + { + return (OtherSigningCertificate) o; + } + else if (o != null) + { + return new OtherSigningCertificate(ASN1Sequence.getInstance(o)); + } + + return null; + } + + /** + * constructeurs + */ + private OtherSigningCertificate(ASN1Sequence seq) + { + if (seq.size() < 1 || seq.size() > 2) + { + throw new IllegalArgumentException("Bad sequence size: " + + seq.size()); + } + + this.certs = ASN1Sequence.getInstance(seq.getObjectAt(0)); + + if (seq.size() > 1) + { + this.policies = ASN1Sequence.getInstance(seq.getObjectAt(1)); + } + } + + public OtherSigningCertificate( + OtherCertID otherCertID) + { + certs = new DERSequence(otherCertID); + } + + public OtherCertID[] getCerts() + { + OtherCertID[] cs = new OtherCertID[certs.size()]; + + for (int i = 0; i != certs.size(); i++) + { + cs[i] = OtherCertID.getInstance(certs.getObjectAt(i)); + } + + return cs; + } + + public PolicyInformation[] getPolicies() + { + if (policies == null) + { + return null; + } + + PolicyInformation[] ps = new PolicyInformation[policies.size()]; + + for (int i = 0; i != policies.size(); i++) + { + ps[i] = PolicyInformation.getInstance(policies.getObjectAt(i)); + } + + return ps; + } + + /** + * The definition of OtherSigningCertificate is + *
+ * OtherSigningCertificate ::= SEQUENCE { + * certs SEQUENCE OF OtherCertID, + * policies SEQUENCE OF PolicyInformation OPTIONAL + * } + *+ * id-aa-ets-otherSigCert OBJECT IDENTIFIER ::= { iso(1) + * member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9) + * smime(16) id-aa(2) 19 } + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(certs); + + if (policies != null) + { + v.add(policies); + } + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ess/SigningCertificate.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ess/SigningCertificate.java new file mode 100644 index 0000000..03834ae --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ess/SigningCertificate.java @@ -0,0 +1,109 @@ +package org.bc.asn1.ess; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DERSequence; +import org.bc.asn1.x509.PolicyInformation; + + +public class SigningCertificate + extends ASN1Object +{ + ASN1Sequence certs; + ASN1Sequence policies; + + public static SigningCertificate getInstance(Object o) + { + if (o instanceof SigningCertificate) + { + return (SigningCertificate) o; + } + else if (o != null) + { + return new SigningCertificate(ASN1Sequence.getInstance(o)); + } + + return null; + } + + /** + * constructeurs + */ + private SigningCertificate(ASN1Sequence seq) + { + if (seq.size() < 1 || seq.size() > 2) + { + throw new IllegalArgumentException("Bad sequence size: " + + seq.size()); + } + this.certs = ASN1Sequence.getInstance(seq.getObjectAt(0)); + + if (seq.size() > 1) + { + this.policies = ASN1Sequence.getInstance(seq.getObjectAt(1)); + } + } + + public SigningCertificate( + ESSCertID essCertID) + { + certs = new DERSequence(essCertID); + } + + public ESSCertID[] getCerts() + { + ESSCertID[] cs = new ESSCertID[certs.size()]; + + for (int i = 0; i != certs.size(); i++) + { + cs[i] = ESSCertID.getInstance(certs.getObjectAt(i)); + } + + return cs; + } + + public PolicyInformation[] getPolicies() + { + if (policies == null) + { + return null; + } + + PolicyInformation[] ps = new PolicyInformation[policies.size()]; + + for (int i = 0; i != policies.size(); i++) + { + ps[i] = PolicyInformation.getInstance(policies.getObjectAt(i)); + } + + return ps; + } + + /** + * The definition of SigningCertificate is + *
+ * SigningCertificate ::= SEQUENCE { + * certs SEQUENCE OF ESSCertID, + * policies SEQUENCE OF PolicyInformation OPTIONAL + * } + *+ * id-aa-signingCertificate OBJECT IDENTIFIER ::= { iso(1) + * member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9) + * smime(16) id-aa(2) 12 } + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(certs); + + if (policies != null) + { + v.add(policies); + } + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ess/SigningCertificateV2.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ess/SigningCertificateV2.java new file mode 100644 index 0000000..7ea68ee --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ess/SigningCertificateV2.java @@ -0,0 +1,130 @@ +package org.bc.asn1.ess; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DERSequence; +import org.bc.asn1.x509.PolicyInformation; + +public class SigningCertificateV2 + extends ASN1Object +{ + ASN1Sequence certs; + ASN1Sequence policies; + + public static SigningCertificateV2 getInstance( + Object o) + { + if (o == null || o instanceof SigningCertificateV2) + { + return (SigningCertificateV2) o; + } + else if (o instanceof ASN1Sequence) + { + return new SigningCertificateV2((ASN1Sequence) o); + } + + return null; + } + + private SigningCertificateV2( + ASN1Sequence seq) + { + if (seq.size() < 1 || seq.size() > 2) + { + throw new IllegalArgumentException("Bad sequence size: " + seq.size()); + } + + this.certs = ASN1Sequence.getInstance(seq.getObjectAt(0)); + + if (seq.size() > 1) + { + this.policies = ASN1Sequence.getInstance(seq.getObjectAt(1)); + } + } + + public SigningCertificateV2( + ESSCertIDv2[] certs) + { + ASN1EncodableVector v = new ASN1EncodableVector(); + for (int i=0; i < certs.length; i++) + { + v.add(certs[i]); + } + this.certs = new DERSequence(v); + } + + public SigningCertificateV2( + ESSCertIDv2[] certs, + PolicyInformation[] policies) + { + ASN1EncodableVector v = new ASN1EncodableVector(); + for (int i=0; i < certs.length; i++) + { + v.add(certs[i]); + } + this.certs = new DERSequence(v); + + if (policies != null) + { + v = new ASN1EncodableVector(); + for (int i=0; i < policies.length; i++) + { + v.add(policies[i]); + } + this.policies = new DERSequence(v); + } + } + + public ESSCertIDv2[] getCerts() + { + ESSCertIDv2[] certIds = new ESSCertIDv2[certs.size()]; + for (int i = 0; i != certs.size(); i++) + { + certIds[i] = ESSCertIDv2.getInstance(certs.getObjectAt(i)); + } + return certIds; + } + + public PolicyInformation[] getPolicies() + { + if (policies == null) + { + return null; + } + + PolicyInformation[] policyInformations = new PolicyInformation[policies.size()]; + for (int i = 0; i != policies.size(); i++) + { + policyInformations[i] = PolicyInformation.getInstance(policies.getObjectAt(i)); + } + return policyInformations; + } + + /** + * The definition of SigningCertificateV2 is + *
+ * SigningCertificateV2 ::= SEQUENCE { + * certs SEQUENCE OF ESSCertIDv2, + * policies SEQUENCE OF PolicyInformation OPTIONAL + * } + *+ * id-aa-signingCertificateV2 OBJECT IDENTIFIER ::= { iso(1) + * member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9) + * smime(16) id-aa(2) 47 } + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(certs); + + if (policies != null) + { + v.add(policies); + } + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/gnu/GNUObjectIdentifiers.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/gnu/GNUObjectIdentifiers.java new file mode 100644 index 0000000..71b94be --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/gnu/GNUObjectIdentifiers.java @@ -0,0 +1,30 @@ +package org.bc.asn1.gnu; + +import org.bc.asn1.ASN1ObjectIdentifier; + +public interface GNUObjectIdentifiers +{ + public static final ASN1ObjectIdentifier GNU = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.1"); // GNU Radius + public static final ASN1ObjectIdentifier GnuPG = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.2"); // GnuPG (Ägypten) + public static final ASN1ObjectIdentifier notation = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.2.1"); // notation + public static final ASN1ObjectIdentifier pkaAddress = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.2.1.1"); // pkaAddress + public static final ASN1ObjectIdentifier GnuRadar = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.3"); // GNU Radar + public static final ASN1ObjectIdentifier digestAlgorithm = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.12"); // digestAlgorithm + public static final ASN1ObjectIdentifier Tiger_192 = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.12.2"); // TIGER/192 + public static final ASN1ObjectIdentifier encryptionAlgorithm = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.13"); // encryptionAlgorithm + public static final ASN1ObjectIdentifier Serpent = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.13.2"); // Serpent + public static final ASN1ObjectIdentifier Serpent_128_ECB = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.13.2.1"); // Serpent-128-ECB + public static final ASN1ObjectIdentifier Serpent_128_CBC = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.13.2.2"); // Serpent-128-CBC + public static final ASN1ObjectIdentifier Serpent_128_OFB = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.13.2.3"); // Serpent-128-OFB + public static final ASN1ObjectIdentifier Serpent_128_CFB = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.13.2.4"); // Serpent-128-CFB + public static final ASN1ObjectIdentifier Serpent_192_ECB = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.13.2.21"); // Serpent-192-ECB + public static final ASN1ObjectIdentifier Serpent_192_CBC = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.13.2.22"); // Serpent-192-CBC + public static final ASN1ObjectIdentifier Serpent_192_OFB = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.13.2.23"); // Serpent-192-OFB + public static final ASN1ObjectIdentifier Serpent_192_CFB = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.13.2.24"); // Serpent-192-CFB + public static final ASN1ObjectIdentifier Serpent_256_ECB = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.13.2.41"); // Serpent-256-ECB + public static final ASN1ObjectIdentifier Serpent_256_CBC = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.13.2.42"); // Serpent-256-CBC + public static final ASN1ObjectIdentifier Serpent_256_OFB = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.13.2.43"); // Serpent-256-OFB + public static final ASN1ObjectIdentifier Serpent_256_CFB = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.13.2.44"); // Serpent-256-CFB + public static final ASN1ObjectIdentifier CRC = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.14"); // CRC algorithms + public static final ASN1ObjectIdentifier CRC32 = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.14.1"); // CRC 32 +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/iana/IANAObjectIdentifiers.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/iana/IANAObjectIdentifiers.java new file mode 100644 index 0000000..b279381 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/iana/IANAObjectIdentifiers.java @@ -0,0 +1,20 @@ +package org.bc.asn1.iana; + +import org.bc.asn1.ASN1ObjectIdentifier; + +public interface IANAObjectIdentifiers +{ + // id-SHA1 OBJECT IDENTIFIER ::= + // {iso(1) identified-organization(3) dod(6) internet(1) security(5) mechanisms(5) ipsec(8) isakmpOakley(1)} + // + + static final ASN1ObjectIdentifier isakmpOakley = new ASN1ObjectIdentifier("1.3.6.1.5.5.8.1"); + + static final ASN1ObjectIdentifier hmacMD5 = new ASN1ObjectIdentifier(isakmpOakley + ".1"); + static final ASN1ObjectIdentifier hmacSHA1 = new ASN1ObjectIdentifier(isakmpOakley + ".2"); + + static final ASN1ObjectIdentifier hmacTIGER = new ASN1ObjectIdentifier(isakmpOakley + ".3"); + + static final ASN1ObjectIdentifier hmacRIPEMD160 = new ASN1ObjectIdentifier(isakmpOakley + ".4"); + +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/icao/CscaMasterList.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/icao/CscaMasterList.java new file mode 100644 index 0000000..5a00ef4 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/icao/CscaMasterList.java @@ -0,0 +1,112 @@ +package org.bc.asn1.icao; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1Set; +import org.bc.asn1.DERSequence; +import org.bc.asn1.DERSet; +import org.bc.asn1.x509.Certificate; + +/** + * The CscaMasterList object. This object can be wrapped in a + * CMSSignedData to be published in LDAP. + * + *
+ * CscaMasterList ::= SEQUENCE { + * version CscaMasterListVersion, + * certList SET OF Certificate } + * + * CscaMasterListVersion :: INTEGER {v0(0)} + *+ */ + +public class CscaMasterList + extends ASN1Object +{ + private ASN1Integer version = new ASN1Integer(0); + private Certificate[] certList; + + public static CscaMasterList getInstance( + Object obj) + { + if (obj instanceof CscaMasterList) + { + return (CscaMasterList)obj; + } + else if (obj != null) + { + return new CscaMasterList(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + private CscaMasterList( + ASN1Sequence seq) + { + if (seq == null || seq.size() == 0) + { + throw new IllegalArgumentException( + "null or empty sequence passed."); + } + if (seq.size() != 2) { + throw new IllegalArgumentException( + "Incorrect sequence size: " + seq.size()); + } + + version = ASN1Integer.getInstance(seq.getObjectAt(0)); + ASN1Set certSet = ASN1Set.getInstance(seq.getObjectAt(1)); + certList = new Certificate[certSet.size()]; + for (int i = 0; i < certList.length; i++) { + certList[i] + = Certificate.getInstance(certSet.getObjectAt(i)); + } + } + + public CscaMasterList( + Certificate[] certStructs) + { + certList = copyCertList(certStructs); + } + + public int getVersion() + { + return version.getValue().intValue(); + } + + public Certificate[] getCertStructs() + { + return copyCertList(certList); + } + + private Certificate[] copyCertList(Certificate[] orig) + { + Certificate[] certs = new Certificate[orig.length]; + + for (int i = 0; i != certs.length; i++) + { + certs[i] = orig[i]; + } + + return certs; + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector seq = new ASN1EncodableVector(); + + seq.add(version); + + ASN1EncodableVector certSet = new ASN1EncodableVector(); + for (int i = 0; i < certList.length; i++) + { + certSet.add(certList[i]); + } + seq.add(new DERSet(certSet)); + + return new DERSequence(seq); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/icao/DataGroupHash.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/icao/DataGroupHash.java new file mode 100644 index 0000000..4876e4c --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/icao/DataGroupHash.java @@ -0,0 +1,97 @@ +package org.bc.asn1.icao; + +import java.util.Enumeration; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1OctetString; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DERSequence; + +/** + * The DataGroupHash object. + *
+ * DataGroupHash ::= SEQUENCE { + * dataGroupNumber DataGroupNumber, + * dataGroupHashValue OCTET STRING } + * + * DataGroupNumber ::= INTEGER { + * dataGroup1 (1), + * dataGroup1 (2), + * dataGroup1 (3), + * dataGroup1 (4), + * dataGroup1 (5), + * dataGroup1 (6), + * dataGroup1 (7), + * dataGroup1 (8), + * dataGroup1 (9), + * dataGroup1 (10), + * dataGroup1 (11), + * dataGroup1 (12), + * dataGroup1 (13), + * dataGroup1 (14), + * dataGroup1 (15), + * dataGroup1 (16) } + * + *+ */ +public class DataGroupHash + extends ASN1Object +{ + ASN1Integer dataGroupNumber; + ASN1OctetString dataGroupHashValue; + + public static DataGroupHash getInstance( + Object obj) + { + if (obj instanceof DataGroupHash) + { + return (DataGroupHash)obj; + } + else if (obj != null) + { + return new DataGroupHash(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + private DataGroupHash(ASN1Sequence seq) + { + Enumeration e = seq.getObjects(); + + // dataGroupNumber + dataGroupNumber = ASN1Integer.getInstance(e.nextElement()); + // dataGroupHashValue + dataGroupHashValue = ASN1OctetString.getInstance(e.nextElement()); + } + + public DataGroupHash( + int dataGroupNumber, + ASN1OctetString dataGroupHashValue) + { + this.dataGroupNumber = new ASN1Integer(dataGroupNumber); + this.dataGroupHashValue = dataGroupHashValue; + } + + public int getDataGroupNumber() + { + return dataGroupNumber.getValue().intValue(); + } + + public ASN1OctetString getDataGroupHashValue() + { + return dataGroupHashValue; + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector seq = new ASN1EncodableVector(); + seq.add(dataGroupNumber); + seq.add(dataGroupHashValue); + + return new DERSequence(seq); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/icao/ICAOObjectIdentifiers.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/icao/ICAOObjectIdentifiers.java new file mode 100644 index 0000000..aed81a4 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/icao/ICAOObjectIdentifiers.java @@ -0,0 +1,33 @@ +package org.bc.asn1.icao; + +import org.bc.asn1.ASN1ObjectIdentifier; + +public interface ICAOObjectIdentifiers +{ + // + // base id + // + static final ASN1ObjectIdentifier id_icao = new ASN1ObjectIdentifier("2.23.136"); + + static final ASN1ObjectIdentifier id_icao_mrtd = id_icao.branch("1"); + static final ASN1ObjectIdentifier id_icao_mrtd_security = id_icao_mrtd.branch("1"); + + // LDS security object, see ICAO Doc 9303-Volume 2-Section IV-A3.2 + static final ASN1ObjectIdentifier id_icao_ldsSecurityObject = id_icao_mrtd_security.branch("1"); + + // CSCA master list, see TR CSCA Countersigning and Master List issuance + static final ASN1ObjectIdentifier id_icao_cscaMasterList = id_icao_mrtd_security.branch("2"); + static final ASN1ObjectIdentifier id_icao_cscaMasterListSigningKey = id_icao_mrtd_security.branch("3"); + + // document type list, see draft TR LDS and PKI Maintenance, par. 3.2.1 + static final ASN1ObjectIdentifier id_icao_documentTypeList = id_icao_mrtd_security.branch("4"); + + // Active Authentication protocol, see draft TR LDS and PKI Maintenance, + // par. 5.2.2 + static final ASN1ObjectIdentifier id_icao_aaProtocolObject = id_icao_mrtd_security.branch("5"); + + // CSCA name change and key reoll-over, see draft TR LDS and PKI + // Maintenance, par. 3.2.1 + static final ASN1ObjectIdentifier id_icao_extensions = id_icao_mrtd_security.branch("6"); + static final ASN1ObjectIdentifier id_icao_extensions_namechangekeyrollover = id_icao_extensions.branch("1"); +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/icao/LDSSecurityObject.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/icao/LDSSecurityObject.java new file mode 100644 index 0000000..e7bad61 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/icao/LDSSecurityObject.java @@ -0,0 +1,159 @@ +package org.bc.asn1.icao; + +import java.util.Enumeration; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DERSequence; +import org.bc.asn1.x509.AlgorithmIdentifier; + +/** + * The LDSSecurityObject object (V1.8). + *
+ * LDSSecurityObject ::= SEQUENCE { + * version LDSSecurityObjectVersion, + * hashAlgorithm DigestAlgorithmIdentifier, + * dataGroupHashValues SEQUENCE SIZE (2..ub-DataGroups) OF DataHashGroup, + * ldsVersionInfo LDSVersionInfo OPTIONAL + * -- if present, version MUST be v1 } + * + * DigestAlgorithmIdentifier ::= AlgorithmIdentifier, + * + * LDSSecurityObjectVersion :: INTEGER {V0(0)} + *+ */ + +public class LDSSecurityObject + extends ASN1Object + implements ICAOObjectIdentifiers +{ + public static final int ub_DataGroups = 16; + + private ASN1Integer version = new ASN1Integer(0); + private AlgorithmIdentifier digestAlgorithmIdentifier; + private DataGroupHash[] datagroupHash; + private LDSVersionInfo versionInfo; + + public static LDSSecurityObject getInstance( + Object obj) + { + if (obj instanceof LDSSecurityObject) + { + return (LDSSecurityObject)obj; + } + else if (obj != null) + { + return new LDSSecurityObject(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + private LDSSecurityObject( + ASN1Sequence seq) + { + if (seq == null || seq.size() == 0) + { + throw new IllegalArgumentException("null or empty sequence passed."); + } + + Enumeration e = seq.getObjects(); + + // version + version = ASN1Integer.getInstance(e.nextElement()); + // digestAlgorithmIdentifier + digestAlgorithmIdentifier = AlgorithmIdentifier.getInstance(e.nextElement()); + + ASN1Sequence datagroupHashSeq = ASN1Sequence.getInstance(e.nextElement()); + + if (version.getValue().intValue() == 1) + { + versionInfo = LDSVersionInfo.getInstance(e.nextElement()); + } + + checkDatagroupHashSeqSize(datagroupHashSeq.size()); + + datagroupHash = new DataGroupHash[datagroupHashSeq.size()]; + for (int i= 0; i< datagroupHashSeq.size();i++) + { + datagroupHash[i] = DataGroupHash.getInstance(datagroupHashSeq.getObjectAt(i)); + } + } + + public LDSSecurityObject( + AlgorithmIdentifier digestAlgorithmIdentifier, + DataGroupHash[] datagroupHash) + { + this.version = new ASN1Integer(0); + this.digestAlgorithmIdentifier = digestAlgorithmIdentifier; + this.datagroupHash = datagroupHash; + + checkDatagroupHashSeqSize(datagroupHash.length); + } + + public LDSSecurityObject( + AlgorithmIdentifier digestAlgorithmIdentifier, + DataGroupHash[] datagroupHash, + LDSVersionInfo versionInfo) + { + this.version = new ASN1Integer(1); + this.digestAlgorithmIdentifier = digestAlgorithmIdentifier; + this.datagroupHash = datagroupHash; + this.versionInfo = versionInfo; + + checkDatagroupHashSeqSize(datagroupHash.length); + } + + private void checkDatagroupHashSeqSize(int size) + { + if ((size < 2) || (size > ub_DataGroups)) + { + throw new IllegalArgumentException("wrong size in DataGroupHashValues : not in (2.."+ ub_DataGroups +")"); + } + } + + public int getVersion() + { + return version.getValue().intValue(); + } + + public AlgorithmIdentifier getDigestAlgorithmIdentifier() + { + return digestAlgorithmIdentifier; + } + + public DataGroupHash[] getDatagroupHash() + { + return datagroupHash; + } + + public LDSVersionInfo getVersionInfo() + { + return versionInfo; + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector seq = new ASN1EncodableVector(); + + seq.add(version); + seq.add(digestAlgorithmIdentifier); + + ASN1EncodableVector seqname = new ASN1EncodableVector(); + for (int i = 0; i < datagroupHash.length; i++) + { + seqname.add(datagroupHash[i]); + } + seq.add(new DERSequence(seqname)); + + if (versionInfo != null) + { + seq.add(versionInfo); + } + + return new DERSequence(seq); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/icao/LDSVersionInfo.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/icao/LDSVersionInfo.java new file mode 100644 index 0000000..2840bdf --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/icao/LDSVersionInfo.java @@ -0,0 +1,75 @@ +package org.bc.asn1.icao; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DERPrintableString; +import org.bc.asn1.DERSequence; + +public class LDSVersionInfo + extends ASN1Object +{ + private DERPrintableString ldsVersion; + private DERPrintableString unicodeVersion; + + public LDSVersionInfo(String ldsVersion, String unicodeVersion) + { + this.ldsVersion = new DERPrintableString(ldsVersion); + this.unicodeVersion = new DERPrintableString(unicodeVersion); + } + + private LDSVersionInfo(ASN1Sequence seq) + { + if (seq.size() != 2) + { + throw new IllegalArgumentException("sequence wrong size for LDSVersionInfo"); + } + + this.ldsVersion = DERPrintableString.getInstance(seq.getObjectAt(0)); + this.unicodeVersion = DERPrintableString.getInstance(seq.getObjectAt(1)); + } + + public static LDSVersionInfo getInstance(Object obj) + { + if (obj instanceof LDSVersionInfo) + { + return (LDSVersionInfo)obj; + } + else if (obj != null) + { + return new LDSVersionInfo(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public String getLdsVersion() + { + return ldsVersion.getString(); + } + + public String getUnicodeVersion() + { + return unicodeVersion.getString(); + } + + /** + *
+ * LDSVersionInfo ::= SEQUENCE { + * ldsVersion PRINTABLE STRING + * unicodeVersion PRINTABLE STRING + * } + *+ * @return + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(ldsVersion); + v.add(unicodeVersion); + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/isismtt/ISISMTTObjectIdentifiers.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/isismtt/ISISMTTObjectIdentifiers.java new file mode 100644 index 0000000..4ef723f --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/isismtt/ISISMTTObjectIdentifiers.java @@ -0,0 +1,180 @@ +package org.bc.asn1.isismtt; + +import org.bc.asn1.ASN1ObjectIdentifier; + +public interface ISISMTTObjectIdentifiers +{ + + static final ASN1ObjectIdentifier id_isismtt = new ASN1ObjectIdentifier("1.3.36.8"); + + static final ASN1ObjectIdentifier id_isismtt_cp = id_isismtt.branch("1"); + + /** + * The id-isismtt-cp-accredited OID indicates that the certificate is a + * qualified certificate according to Directive 1999/93/EC of the European + * Parliament and of the Council of 13 December 1999 on a Community + * Framework for Electronic Signatures, which additionally conforms the + * special requirements of the SigG and has been issued by an accredited CA. + */ + static final ASN1ObjectIdentifier id_isismtt_cp_accredited = id_isismtt_cp.branch("1"); + + static final ASN1ObjectIdentifier id_isismtt_at = id_isismtt.branch("3"); + + /** + * Certificate extensionDate of certificate generation + * + *
+ * DateOfCertGenSyntax ::= GeneralizedTime + *+ */ + static final ASN1ObjectIdentifier id_isismtt_at_dateOfCertGen = id_isismtt_at.branch("1"); + + /** + * Attribute to indicate that the certificate holder may sign in the name of + * a third person. May also be used as extension in a certificate. + */ + static final ASN1ObjectIdentifier id_isismtt_at_procuration = id_isismtt_at.branch("2"); + + /** + * Attribute to indicate admissions to certain professions. May be used as + * attribute in attribute certificate or as extension in a certificate + */ + static final ASN1ObjectIdentifier id_isismtt_at_admission = id_isismtt_at.branch("3"); + + /** + * Monetary limit for transactions. The QcEuMonetaryLimit QC statement MUST + * be used in new certificates in place of the extension/attribute + * MonetaryLimit since January 1, 2004. For the sake of backward + * compatibility with certificates already in use, SigG conforming + * components MUST support MonetaryLimit (as well as QcEuLimitValue). + */ + static final ASN1ObjectIdentifier id_isismtt_at_monetaryLimit = id_isismtt_at.branch("4"); + + /** + * A declaration of majority. May be used as attribute in attribute + * certificate or as extension in a certificate + */ + static final ASN1ObjectIdentifier id_isismtt_at_declarationOfMajority = id_isismtt_at.branch("5"); + + /** + * + * Serial number of the smart card containing the corresponding private key + * + *
+ * ICCSNSyntax ::= OCTET STRING (SIZE(8..20)) + *+ */ + static final ASN1ObjectIdentifier id_isismtt_at_iCCSN = id_isismtt_at.branch("6"); + + /** + * + * Reference for a file of a smartcard that stores the public key of this + * certificate and that is used as �security anchor�. + * + *
+ * PKReferenceSyntax ::= OCTET STRING (SIZE(20)) + *+ */ + static final ASN1ObjectIdentifier id_isismtt_at_PKReference = id_isismtt_at.branch("7"); + + /** + * Some other restriction regarding the usage of this certificate. May be + * used as attribute in attribute certificate or as extension in a + * certificate. + * + *
+ * RestrictionSyntax ::= DirectoryString (SIZE(1..1024)) + *+ * + * @see org.bc.asn1.isismtt.x509.Restriction + */ + static final ASN1ObjectIdentifier id_isismtt_at_restriction = id_isismtt_at.branch("8"); + + /** + * + * (Single)Request extension: Clients may include this extension in a + * (single) Request to request the responder to send the certificate in the + * response message along with the status information. Besides the LDAP + * service, this extension provides another mechanism for the distribution + * of certificates, which MAY optionally be provided by certificate + * repositories. + * + *
+ * RetrieveIfAllowed ::= BOOLEAN + * + *+ */ + static final ASN1ObjectIdentifier id_isismtt_at_retrieveIfAllowed = id_isismtt_at.branch("9"); + + /** + * SingleOCSPResponse extension: The certificate requested by the client by + * inserting the RetrieveIfAllowed extension in the request, will be + * returned in this extension. + * + * @see org.bc.asn1.isismtt.ocsp.RequestedCertificate + */ + static final ASN1ObjectIdentifier id_isismtt_at_requestedCertificate = id_isismtt_at.branch("10"); + + /** + * Base ObjectIdentifier for naming authorities + */ + static final ASN1ObjectIdentifier id_isismtt_at_namingAuthorities = id_isismtt_at.branch("11"); + + /** + * SingleOCSPResponse extension: Date, when certificate has been published + * in the directory and status information has become available. Currently, + * accrediting authorities enforce that SigG-conforming OCSP servers include + * this extension in the responses. + * + *
+ * CertInDirSince ::= GeneralizedTime + *+ */ + static final ASN1ObjectIdentifier id_isismtt_at_certInDirSince = id_isismtt_at.branch("12"); + + /** + * Hash of a certificate in OCSP. + * + * @see org.bc.asn1.isismtt.ocsp.CertHash + */ + static final ASN1ObjectIdentifier id_isismtt_at_certHash = id_isismtt_at.branch("13"); + + /** + *
+ * NameAtBirth ::= DirectoryString(SIZE(1..64) + *+ * + * Used in + * {@link org.bc.asn1.x509.SubjectDirectoryAttributes SubjectDirectoryAttributes} + */ + static final ASN1ObjectIdentifier id_isismtt_at_nameAtBirth = id_isismtt_at.branch("14"); + + /** + * Some other information of non-restrictive nature regarding the usage of + * this certificate. May be used as attribute in atribute certificate or as + * extension in a certificate. + * + *
+ * AdditionalInformationSyntax ::= DirectoryString (SIZE(1..2048)) + *+ * + * @see org.bc.asn1.isismtt.x509.AdditionalInformationSyntax + */ + static final ASN1ObjectIdentifier id_isismtt_at_additionalInformation = id_isismtt_at.branch("15"); + + /** + * Indicates that an attribute certificate exists, which limits the + * usability of this public key certificate. Whenever verifying a signature + * with the help of this certificate, the content of the corresponding + * attribute certificate should be concerned. This extension MUST be + * included in a PKC, if a corresponding attribute certificate (having the + * PKC as base certificate) contains some attribute that restricts the + * usability of the PKC too. Attribute certificates with restricting content + * MUST always be included in the signed document. + * + *
+ * LiabilityLimitationFlagSyntax ::= BOOLEAN + *+ */ + static final ASN1ObjectIdentifier id_isismtt_at_liabilityLimitationFlag = new ASN1ObjectIdentifier("0.2.262.1.10.12.0"); +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/isismtt/ocsp/CertHash.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/isismtt/ocsp/CertHash.java new file mode 100644 index 0000000..cd78d04 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/isismtt/ocsp/CertHash.java @@ -0,0 +1,124 @@ +package org.bc.asn1.isismtt.ocsp; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DEROctetString; +import org.bc.asn1.DERSequence; +import org.bc.asn1.x509.AlgorithmIdentifier; + +/** + * ISIS-MTT PROFILE: The responder may include this extension in a response to + * send the hash of the requested certificate to the responder. This hash is + * cryptographically bound to the certificate and serves as evidence that the + * certificate is known to the responder (i.e. it has been issued and is present + * in the directory). Hence, this extension is a means to provide a positive + * statement of availability as described in T8.[8]. As explained in T13.[1], + * clients may rely on this information to be able to validate signatures after + * the expiry of the corresponding certificate. Hence, clients MUST support this + * extension. If a positive statement of availability is to be delivered, this + * extension syntax and OID MUST be used. + * + * + *
+ * CertHash ::= SEQUENCE { + * hashAlgorithm AlgorithmIdentifier, + * certificateHash OCTET STRING + * } + *+ */ +public class CertHash + extends ASN1Object +{ + + private AlgorithmIdentifier hashAlgorithm; + private byte[] certificateHash; + + public static CertHash getInstance(Object obj) + { + if (obj == null || obj instanceof CertHash) + { + return (CertHash)obj; + } + + if (obj instanceof ASN1Sequence) + { + return new CertHash((ASN1Sequence)obj); + } + + throw new IllegalArgumentException("illegal object in getInstance: " + + obj.getClass().getName()); + } + + /** + * Constructor from ASN1Sequence. + * + * The sequence is of type CertHash: + * + *
+ * CertHash ::= SEQUENCE { + * hashAlgorithm AlgorithmIdentifier, + * certificateHash OCTET STRING + * } + *+ * + * @param seq The ASN.1 sequence. + */ + private CertHash(ASN1Sequence seq) + { + if (seq.size() != 2) + { + throw new IllegalArgumentException("Bad sequence size: " + + seq.size()); + } + hashAlgorithm = AlgorithmIdentifier.getInstance(seq.getObjectAt(0)); + certificateHash = DEROctetString.getInstance(seq.getObjectAt(1)).getOctets(); + } + + /** + * Constructor from a given details. + * + * @param hashAlgorithm The hash algorithm identifier. + * @param certificateHash The hash of the whole DER encoding of the certificate. + */ + public CertHash(AlgorithmIdentifier hashAlgorithm, byte[] certificateHash) + { + this.hashAlgorithm = hashAlgorithm; + this.certificateHash = new byte[certificateHash.length]; + System.arraycopy(certificateHash, 0, this.certificateHash, 0, + certificateHash.length); + } + + public AlgorithmIdentifier getHashAlgorithm() + { + return hashAlgorithm; + } + + public byte[] getCertificateHash() + { + return certificateHash; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * + * Returns: + * + *
+ * CertHash ::= SEQUENCE { + * hashAlgorithm AlgorithmIdentifier, + * certificateHash OCTET STRING + * } + *+ * + * @return a DERObject + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector vec = new ASN1EncodableVector(); + vec.add(hashAlgorithm); + vec.add(new DEROctetString(certificateHash)); + return new DERSequence(vec); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/isismtt/ocsp/RequestedCertificate.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/isismtt/ocsp/RequestedCertificate.java new file mode 100644 index 0000000..20234eb --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/isismtt/ocsp/RequestedCertificate.java @@ -0,0 +1,183 @@ +package org.bc.asn1.isismtt.ocsp; + +import java.io.IOException; + +import org.bc.asn1.ASN1Choice; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1OctetString; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DEROctetString; +import org.bc.asn1.DERTaggedObject; +import org.bc.asn1.x509.Certificate; + +/** + * ISIS-MTT-Optional: The certificate requested by the client by inserting the + * RetrieveIfAllowed extension in the request, will be returned in this + * extension. + * + * ISIS-MTT-SigG: The signature act allows publishing certificates only then, + * when the certificate owner gives his explicit permission. Accordingly, there + * may be �nondownloadable� certificates, about which the responder must provide + * status information, but MUST NOT include them in the response. Clients may + * get therefore the following three kind of answers on a single request + * including the RetrieveIfAllowed extension: + *
+ * RequestedCertificate ::= CHOICE { + * Certificate Certificate, + * publicKeyCertificate [0] EXPLICIT OCTET STRING, + * attributeCertificate [1] EXPLICIT OCTET STRING + * } + *+ */ +public class RequestedCertificate + extends ASN1Object + implements ASN1Choice +{ + public static final int certificate = -1; + public static final int publicKeyCertificate = 0; + public static final int attributeCertificate = 1; + + private Certificate cert; + private byte[] publicKeyCert; + private byte[] attributeCert; + + public static RequestedCertificate getInstance(Object obj) + { + if (obj == null || obj instanceof RequestedCertificate) + { + return (RequestedCertificate)obj; + } + + if (obj instanceof ASN1Sequence) + { + return new RequestedCertificate(Certificate.getInstance(obj)); + } + if (obj instanceof ASN1TaggedObject) + { + return new RequestedCertificate((ASN1TaggedObject)obj); + } + + throw new IllegalArgumentException("illegal object in getInstance: " + + obj.getClass().getName()); + } + + public static RequestedCertificate getInstance(ASN1TaggedObject obj, boolean explicit) + { + if (!explicit) + { + throw new IllegalArgumentException("choice item must be explicitly tagged"); + } + + return getInstance(obj.getObject()); + } + + private RequestedCertificate(ASN1TaggedObject tagged) + { + if (tagged.getTagNo() == publicKeyCertificate) + { + publicKeyCert = ASN1OctetString.getInstance(tagged, true).getOctets(); + } + else if (tagged.getTagNo() == attributeCertificate) + { + attributeCert = ASN1OctetString.getInstance(tagged, true).getOctets(); + } + else + { + throw new IllegalArgumentException("unknown tag number: " + tagged.getTagNo()); + } + } + + /** + * Constructor from a given details. + * + * Only one parameter can be given. All other must be
null
.
+ *
+ * @param certificate Given as Certificate
+ */
+ public RequestedCertificate(Certificate certificate)
+ {
+ this.cert = certificate;
+ }
+
+ public RequestedCertificate(int type, byte[] certificateOctets)
+ {
+ this(new DERTaggedObject(type, new DEROctetString(certificateOctets)));
+ }
+
+ public int getType()
+ {
+ if (cert != null)
+ {
+ return certificate;
+ }
+ if (publicKeyCert != null)
+ {
+ return publicKeyCertificate;
+ }
+ return attributeCertificate;
+ }
+
+ public byte[] getCertificateBytes()
+ {
+ if (cert != null)
+ {
+ try
+ {
+ return cert.getEncoded();
+ }
+ catch (IOException e)
+ {
+ throw new IllegalStateException("can't decode certificate: " + e);
+ }
+ }
+ if (publicKeyCert != null)
+ {
+ return publicKeyCert;
+ }
+ return attributeCert;
+ }
+
+ /**
+ * Produce an object suitable for an ASN1OutputStream.
+ *
+ * Returns:
+ *
+ * + * RequestedCertificate ::= CHOICE { + * Certificate Certificate, + * publicKeyCertificate [0] EXPLICIT OCTET STRING, + * attributeCertificate [1] EXPLICIT OCTET STRING + * } + *+ * + * @return a DERObject + */ + public ASN1Primitive toASN1Primitive() + { + if (publicKeyCert != null) + { + return new DERTaggedObject(0, new DEROctetString(publicKeyCert)); + } + if (attributeCert != null) + { + return new DERTaggedObject(1, new DEROctetString(attributeCert)); + } + return cert.toASN1Primitive(); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/isismtt/x509/AdditionalInformationSyntax.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/isismtt/x509/AdditionalInformationSyntax.java new file mode 100644 index 0000000..a7a8d82 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/isismtt/x509/AdditionalInformationSyntax.java @@ -0,0 +1,70 @@ +package org.bc.asn1.isismtt.x509; + +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.x500.DirectoryString; + +/** + * Some other information of non-restrictive nature regarding the usage of this + * certificate. + * + *
+ * AdditionalInformationSyntax ::= DirectoryString (SIZE(1..2048)) + *+ */ +public class AdditionalInformationSyntax + extends ASN1Object +{ + private DirectoryString information; + + public static AdditionalInformationSyntax getInstance(Object obj) + { + if (obj instanceof AdditionalInformationSyntax) + { + return (AdditionalInformationSyntax)obj; + } + + if (obj != null) + { + return new AdditionalInformationSyntax(DirectoryString.getInstance(obj)); + } + + return null; + } + + private AdditionalInformationSyntax(DirectoryString information) + { + this.information = information; + } + + /** + * Constructor from a given details. + * + * @param information The describtion of the information. + */ + public AdditionalInformationSyntax(String information) + { + this(new DirectoryString(information)); + } + + public DirectoryString getInformation() + { + return information; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * + * Returns: + * + *
+ * AdditionalInformationSyntax ::= DirectoryString (SIZE(1..2048)) + *+ * + * @return a DERObject + */ + public ASN1Primitive toASN1Primitive() + { + return information.toASN1Primitive(); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/isismtt/x509/AdmissionSyntax.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/isismtt/x509/AdmissionSyntax.java new file mode 100644 index 0000000..6364644 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/isismtt/x509/AdmissionSyntax.java @@ -0,0 +1,280 @@ +package org.bc.asn1.isismtt.x509; + +import java.util.Enumeration; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DERSequence; +import org.bc.asn1.x509.GeneralName; + +/** + * Attribute to indicate admissions to certain professions. + * + *
+ * AdmissionSyntax ::= SEQUENCE + * { + * admissionAuthority GeneralName OPTIONAL, + * contentsOfAdmissions SEQUENCE OF Admissions + * } + * + * Admissions ::= SEQUENCE + * { + * admissionAuthority [0] EXPLICIT GeneralName OPTIONAL + * namingAuthority [1] EXPLICIT NamingAuthority OPTIONAL + * professionInfos SEQUENCE OF ProfessionInfo + * } + * + * NamingAuthority ::= SEQUENCE + * { + * namingAuthorityId OBJECT IDENTIFIER OPTIONAL, + * namingAuthorityUrl IA5String OPTIONAL, + * namingAuthorityText DirectoryString(SIZE(1..128)) OPTIONAL + * } + * + * ProfessionInfo ::= SEQUENCE + * { + * namingAuthority [0] EXPLICIT NamingAuthority OPTIONAL, + * professionItems SEQUENCE OF DirectoryString (SIZE(1..128)), + * professionOIDs SEQUENCE OF OBJECT IDENTIFIER OPTIONAL, + * registrationNumber PrintableString(SIZE(1..128)) OPTIONAL, + * addProfessionInfo OCTET STRING OPTIONAL + * } + *+ * + * + * ISIS-MTT PROFILE: The relatively complex structure of AdmissionSyntax + * supports the following concepts and requirements: + *
+ * AdmissionSyntax ::= SEQUENCE + * { + * admissionAuthority GeneralName OPTIONAL, + * contentsOfAdmissions SEQUENCE OF Admissions + * } + * + * Admissions ::= SEQUENCE + * { + * admissionAuthority [0] EXPLICIT GeneralName OPTIONAL + * namingAuthority [1] EXPLICIT NamingAuthority OPTIONAL + * professionInfos SEQUENCE OF ProfessionInfo + * } + * + * NamingAuthority ::= SEQUENCE + * { + * namingAuthorityId OBJECT IDENTIFIER OPTIONAL, + * namingAuthorityUrl IA5String OPTIONAL, + * namingAuthorityText DirectoryString(SIZE(1..128)) OPTIONAL + * } + * + * ProfessionInfo ::= SEQUENCE + * { + * namingAuthority [0] EXPLICIT NamingAuthority OPTIONAL, + * professionItems SEQUENCE OF DirectoryString (SIZE(1..128)), + * professionOIDs SEQUENCE OF OBJECT IDENTIFIER OPTIONAL, + * registrationNumber PrintableString(SIZE(1..128)) OPTIONAL, + * addProfessionInfo OCTET STRING OPTIONAL + * } + *+ * + * @param seq The ASN.1 sequence. + */ + private AdmissionSyntax(ASN1Sequence seq) + { + switch (seq.size()) + { + case 1: + contentsOfAdmissions = DERSequence.getInstance(seq.getObjectAt(0)); + break; + case 2: + admissionAuthority = GeneralName.getInstance(seq.getObjectAt(0)); + contentsOfAdmissions = DERSequence.getInstance(seq.getObjectAt(1)); + break; + default: + throw new IllegalArgumentException("Bad sequence size: " + seq.size()); + } + } + + /** + * Constructor from given details. + * + * @param admissionAuthority The admission authority. + * @param contentsOfAdmissions The admissions. + */ + public AdmissionSyntax(GeneralName admissionAuthority, ASN1Sequence contentsOfAdmissions) + { + this.admissionAuthority = admissionAuthority; + this.contentsOfAdmissions = contentsOfAdmissions; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * + * Returns: + * + *
+ * AdmissionSyntax ::= SEQUENCE + * { + * admissionAuthority GeneralName OPTIONAL, + * contentsOfAdmissions SEQUENCE OF Admissions + * } + * + * Admissions ::= SEQUENCE + * { + * admissionAuthority [0] EXPLICIT GeneralName OPTIONAL + * namingAuthority [1] EXPLICIT NamingAuthority OPTIONAL + * professionInfos SEQUENCE OF ProfessionInfo + * } + * + * NamingAuthority ::= SEQUENCE + * { + * namingAuthorityId OBJECT IDENTIFIER OPTIONAL, + * namingAuthorityUrl IA5String OPTIONAL, + * namingAuthorityText DirectoryString(SIZE(1..128)) OPTIONAL + * } + * + * ProfessionInfo ::= SEQUENCE + * { + * namingAuthority [0] EXPLICIT NamingAuthority OPTIONAL, + * professionItems SEQUENCE OF DirectoryString (SIZE(1..128)), + * professionOIDs SEQUENCE OF OBJECT IDENTIFIER OPTIONAL, + * registrationNumber PrintableString(SIZE(1..128)) OPTIONAL, + * addProfessionInfo OCTET STRING OPTIONAL + * } + *+ * + * @return a DERObject + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector vec = new ASN1EncodableVector(); + if (admissionAuthority != null) + { + vec.add(admissionAuthority); + } + vec.add(contentsOfAdmissions); + return new DERSequence(vec); + } + + /** + * @return Returns the admissionAuthority if present, null otherwise. + */ + public GeneralName getAdmissionAuthority() + { + return admissionAuthority; + } + + /** + * @return Returns the contentsOfAdmissions. + */ + public Admissions[] getContentsOfAdmissions() + { + Admissions[] admissions = new Admissions[contentsOfAdmissions.size()]; + int count = 0; + for (Enumeration e = contentsOfAdmissions.getObjects(); e.hasMoreElements();) + { + admissions[count++] = Admissions.getInstance(e.nextElement()); + } + return admissions; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/isismtt/x509/Admissions.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/isismtt/x509/Admissions.java new file mode 100644 index 0000000..9f40db6 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/isismtt/x509/Admissions.java @@ -0,0 +1,189 @@ +package org.bc.asn1.isismtt.x509; + +import java.util.Enumeration; + +import org.bc.asn1.ASN1Encodable; +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERSequence; +import org.bc.asn1.DERTaggedObject; +import org.bc.asn1.x509.GeneralName; + +/** + * An Admissions structure. + * + *
+ * Admissions ::= SEQUENCE + * { + * admissionAuthority [0] EXPLICIT GeneralName OPTIONAL + * namingAuthority [1] EXPLICIT NamingAuthority OPTIONAL + * professionInfos SEQUENCE OF ProfessionInfo + * } + * + *+ * + * @see org.bc.asn1.isismtt.x509.AdmissionSyntax + * @see org.bc.asn1.isismtt.x509.ProfessionInfo + * @see org.bc.asn1.isismtt.x509.NamingAuthority + */ +public class Admissions + extends ASN1Object +{ + + private GeneralName admissionAuthority; + + private NamingAuthority namingAuthority; + + private ASN1Sequence professionInfos; + + public static Admissions getInstance(Object obj) + { + if (obj == null || obj instanceof Admissions) + { + return (Admissions)obj; + } + + if (obj instanceof ASN1Sequence) + { + return new Admissions((ASN1Sequence)obj); + } + + throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); + } + + /** + * Constructor from ASN1Sequence. + * + * The sequence is of type ProcurationSyntax: + * + *
+ * Admissions ::= SEQUENCE + * { + * admissionAuthority [0] EXPLICIT GeneralName OPTIONAL + * namingAuthority [1] EXPLICIT NamingAuthority OPTIONAL + * professionInfos SEQUENCE OF ProfessionInfo + * } + *+ * + * @param seq The ASN.1 sequence. + */ + private Admissions(ASN1Sequence seq) + { + if (seq.size() > 3) + { + throw new IllegalArgumentException("Bad sequence size: " + + seq.size()); + } + Enumeration e = seq.getObjects(); + + ASN1Encodable o = (ASN1Encodable)e.nextElement(); + if (o instanceof ASN1TaggedObject) + { + switch (((ASN1TaggedObject)o).getTagNo()) + { + case 0: + admissionAuthority = GeneralName.getInstance((ASN1TaggedObject)o, true); + break; + case 1: + namingAuthority = NamingAuthority.getInstance((ASN1TaggedObject)o, true); + break; + default: + throw new IllegalArgumentException("Bad tag number: " + ((ASN1TaggedObject)o).getTagNo()); + } + o = (ASN1Encodable)e.nextElement(); + } + if (o instanceof ASN1TaggedObject) + { + switch (((ASN1TaggedObject)o).getTagNo()) + { + case 1: + namingAuthority = NamingAuthority.getInstance((ASN1TaggedObject)o, true); + break; + default: + throw new IllegalArgumentException("Bad tag number: " + ((ASN1TaggedObject)o).getTagNo()); + } + o = (ASN1Encodable)e.nextElement(); + } + professionInfos = ASN1Sequence.getInstance(o); + if (e.hasMoreElements()) + { + throw new IllegalArgumentException("Bad object encountered: " + + e.nextElement().getClass()); + } + } + + /** + * Constructor from a given details. + * + * Parameter
professionInfos
is mandatory.
+ *
+ * @param admissionAuthority The admission authority.
+ * @param namingAuthority The naming authority.
+ * @param professionInfos The profession infos.
+ */
+ public Admissions(GeneralName admissionAuthority,
+ NamingAuthority namingAuthority, ProfessionInfo[] professionInfos)
+ {
+ this.admissionAuthority = admissionAuthority;
+ this.namingAuthority = namingAuthority;
+ this.professionInfos = new DERSequence(professionInfos);
+ }
+
+ public GeneralName getAdmissionAuthority()
+ {
+ return admissionAuthority;
+ }
+
+ public NamingAuthority getNamingAuthority()
+ {
+ return namingAuthority;
+ }
+
+ public ProfessionInfo[] getProfessionInfos()
+ {
+ ProfessionInfo[] infos = new ProfessionInfo[professionInfos.size()];
+ int count = 0;
+ for (Enumeration e = professionInfos.getObjects(); e.hasMoreElements();)
+ {
+ infos[count++] = ProfessionInfo.getInstance(e.nextElement());
+ }
+ return infos;
+ }
+
+ /**
+ * Produce an object suitable for an ASN1OutputStream.
+ *
+ * Returns:
+ *
+ * + * Admissions ::= SEQUENCE + * { + * admissionAuthority [0] EXPLICIT GeneralName OPTIONAL + * namingAuthority [1] EXPLICIT NamingAuthority OPTIONAL + * professionInfos SEQUENCE OF ProfessionInfo + * } + * + *+ * + * @return an ASN1Primitive + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector vec = new ASN1EncodableVector(); + + if (admissionAuthority != null) + { + vec.add(new DERTaggedObject(true, 0, admissionAuthority)); + } + if (namingAuthority != null) + { + vec.add(new DERTaggedObject(true, 1, namingAuthority)); + } + vec.add(professionInfos); + + return new DERSequence(vec); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/isismtt/x509/DeclarationOfMajority.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/isismtt/x509/DeclarationOfMajority.java new file mode 100644 index 0000000..ccd3bf7 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/isismtt/x509/DeclarationOfMajority.java @@ -0,0 +1,164 @@ +package org.bc.asn1.isismtt.x509; + +import org.bc.asn1.ASN1Boolean; +import org.bc.asn1.ASN1Choice; +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1GeneralizedTime; +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERPrintableString; +import org.bc.asn1.DERSequence; +import org.bc.asn1.DERTaggedObject; + +/** + * A declaration of majority. + * + *
+ * DeclarationOfMajoritySyntax ::= CHOICE + * { + * notYoungerThan [0] IMPLICIT INTEGER, + * fullAgeAtCountry [1] IMPLICIT SEQUENCE + * { + * fullAge BOOLEAN DEFAULT TRUE, + * country PrintableString (SIZE(2)) + * } + * dateOfBirth [2] IMPLICIT GeneralizedTime + * } + *+ * + * fullAgeAtCountry indicates the majority of the owner with respect to the laws + * of a specific country. + */ +public class DeclarationOfMajority + extends ASN1Object + implements ASN1Choice +{ + public static final int notYoungerThan = 0; + public static final int fullAgeAtCountry = 1; + public static final int dateOfBirth = 2; + + private ASN1TaggedObject declaration; + + public DeclarationOfMajority(int notYoungerThan) + { + declaration = new DERTaggedObject(false, 0, new ASN1Integer(notYoungerThan)); + } + + public DeclarationOfMajority(boolean fullAge, String country) + { + if (country.length() > 2) + { + throw new IllegalArgumentException("country can only be 2 characters"); + } + + if (fullAge) + { + declaration = new DERTaggedObject(false, 1, new DERSequence(new DERPrintableString(country, true))); + } + else + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(ASN1Boolean.FALSE); + v.add(new DERPrintableString(country, true)); + + declaration = new DERTaggedObject(false, 1, new DERSequence(v)); + } + } + + public DeclarationOfMajority(ASN1GeneralizedTime dateOfBirth) + { + declaration = new DERTaggedObject(false, 2, dateOfBirth); + } + + public static DeclarationOfMajority getInstance(Object obj) + { + if (obj == null || obj instanceof DeclarationOfMajority) + { + return (DeclarationOfMajority)obj; + } + + if (obj instanceof ASN1TaggedObject) + { + return new DeclarationOfMajority((ASN1TaggedObject)obj); + } + + throw new IllegalArgumentException("illegal object in getInstance: " + + obj.getClass().getName()); + } + + private DeclarationOfMajority(ASN1TaggedObject o) + { + if (o.getTagNo() > 2) + { + throw new IllegalArgumentException("Bad tag number: " + o.getTagNo()); + } + declaration = o; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * + * Returns: + * + *
+ * DeclarationOfMajoritySyntax ::= CHOICE + * { + * notYoungerThan [0] IMPLICIT INTEGER, + * fullAgeAtCountry [1] IMPLICIT SEQUENCE + * { + * fullAge BOOLEAN DEFAULT TRUE, + * country PrintableString (SIZE(2)) + * } + * dateOfBirth [2] IMPLICIT GeneralizedTime + * } + *+ * + * @return a DERObject + */ + public ASN1Primitive toASN1Primitive() + { + return declaration; + } + + public int getType() + { + return declaration.getTagNo(); + } + + /** + * @return notYoungerThan if that's what we are, -1 otherwise + */ + public int notYoungerThan() + { + if (declaration.getTagNo() != 0) + { + return -1; + } + + return ASN1Integer.getInstance(declaration, false).getValue().intValue(); + } + + public ASN1Sequence fullAgeAtCountry() + { + if (declaration.getTagNo() != 1) + { + return null; + } + + return ASN1Sequence.getInstance(declaration, false); + } + + public ASN1GeneralizedTime getDateOfBirth() + { + if (declaration.getTagNo() != 2) + { + return null; + } + + return ASN1GeneralizedTime.getInstance(declaration, false); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/isismtt/x509/MonetaryLimit.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/isismtt/x509/MonetaryLimit.java new file mode 100644 index 0000000..8b84d2b --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/isismtt/x509/MonetaryLimit.java @@ -0,0 +1,131 @@ +package org.bc.asn1.isismtt.x509; + +import java.math.BigInteger; +import java.util.Enumeration; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DERPrintableString; +import org.bc.asn1.DERSequence; + +/** + * Monetary limit for transactions. The QcEuMonetaryLimit QC statement MUST be + * used in new certificates in place of the extension/attribute MonetaryLimit + * since January 1, 2004. For the sake of backward compatibility with + * certificates already in use, components SHOULD support MonetaryLimit (as well + * as QcEuLimitValue). + * + * Indicates a monetary limit within which the certificate holder is authorized + * to act. (This value DOES NOT express a limit on the liability of the + * certification authority). + * + *
+ * MonetaryLimitSyntax ::= SEQUENCE + * { + * currency PrintableString (SIZE(3)), + * amount INTEGER, + * exponent INTEGER + * } + *+ * + * currency must be the ISO code. + * + * value = amount�10*exponent + */ +public class MonetaryLimit + extends ASN1Object +{ + DERPrintableString currency; + ASN1Integer amount; + ASN1Integer exponent; + + public static MonetaryLimit getInstance(Object obj) + { + if (obj == null || obj instanceof MonetaryLimit) + { + return (MonetaryLimit)obj; + } + + if (obj instanceof ASN1Sequence) + { + return new MonetaryLimit(ASN1Sequence.getInstance(obj)); + } + + throw new IllegalArgumentException("unknown object in getInstance"); + } + + private MonetaryLimit(ASN1Sequence seq) + { + if (seq.size() != 3) + { + throw new IllegalArgumentException("Bad sequence size: " + + seq.size()); + } + Enumeration e = seq.getObjects(); + currency = DERPrintableString.getInstance(e.nextElement()); + amount = ASN1Integer.getInstance(e.nextElement()); + exponent = ASN1Integer.getInstance(e.nextElement()); + } + + /** + * Constructor from a given details. + * + * + * value = amount�10^exponent + * + * @param currency The currency. Must be the ISO code. + * @param amount The amount + * @param exponent The exponent + */ + public MonetaryLimit(String currency, int amount, int exponent) + { + this.currency = new DERPrintableString(currency, true); + this.amount = new ASN1Integer(amount); + this.exponent = new ASN1Integer(exponent); + } + + public String getCurrency() + { + return currency.getString(); + } + + public BigInteger getAmount() + { + return amount.getValue(); + } + + public BigInteger getExponent() + { + return exponent.getValue(); + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * + * Returns: + * + *
+ * MonetaryLimitSyntax ::= SEQUENCE + * { + * currency PrintableString (SIZE(3)), + * amount INTEGER, + * exponent INTEGER + * } + *+ * + * @return a DERObject + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector seq = new ASN1EncodableVector(); + seq.add(currency); + seq.add(amount); + seq.add(exponent); + + return new DERSequence(seq); + } + +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/isismtt/x509/NamingAuthority.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/isismtt/x509/NamingAuthority.java new file mode 100644 index 0000000..61c73f5 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/isismtt/x509/NamingAuthority.java @@ -0,0 +1,244 @@ +package org.bc.asn1.isismtt.x509; + +import java.util.Enumeration; + +import org.bc.asn1.ASN1Encodable; +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1ObjectIdentifier; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1String; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERIA5String; +import org.bc.asn1.DERObjectIdentifier; +import org.bc.asn1.DERSequence; +import org.bc.asn1.isismtt.ISISMTTObjectIdentifiers; +import org.bc.asn1.x500.DirectoryString; + +/** + * Names of authorities which are responsible for the administration of title + * registers. + * + *
+ * NamingAuthority ::= SEQUENCE + * { + * namingAuthorityId OBJECT IDENTIFIER OPTIONAL, + * namingAuthorityUrl IA5String OPTIONAL, + * namingAuthorityText DirectoryString(SIZE(1..128)) OPTIONAL + * } + *+ * @see org.bc.asn1.isismtt.x509.AdmissionSyntax + * + */ +public class NamingAuthority + extends ASN1Object +{ + + /** + * Profession OIDs should always be defined under the OID branch of the + * responsible naming authority. At the time of this writing, the work group + * �Recht, Wirtschaft, Steuern� (�Law, Economy, Taxes�) is registered as the + * first naming authority under the OID id-isismtt-at-namingAuthorities. + */ + public static final ASN1ObjectIdentifier id_isismtt_at_namingAuthorities_RechtWirtschaftSteuern = + new ASN1ObjectIdentifier(ISISMTTObjectIdentifiers.id_isismtt_at_namingAuthorities + ".1"); + + private ASN1ObjectIdentifier namingAuthorityId; + private String namingAuthorityUrl; + private DirectoryString namingAuthorityText; + + public static NamingAuthority getInstance(Object obj) + { + if (obj == null || obj instanceof NamingAuthority) + { + return (NamingAuthority)obj; + } + + if (obj instanceof ASN1Sequence) + { + return new NamingAuthority((ASN1Sequence)obj); + } + + throw new IllegalArgumentException("illegal object in getInstance: " + + obj.getClass().getName()); + } + + public static NamingAuthority getInstance(ASN1TaggedObject obj, boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + /** + * Constructor from ASN1Sequence. + * + * + *
+ * NamingAuthority ::= SEQUENCE + * { + * namingAuthorityId OBJECT IDENTIFIER OPTIONAL, + * namingAuthorityUrl IA5String OPTIONAL, + * namingAuthorityText DirectoryString(SIZE(1..128)) OPTIONAL + * } + *+ * + * @param seq The ASN.1 sequence. + */ + private NamingAuthority(ASN1Sequence seq) + { + + if (seq.size() > 3) + { + throw new IllegalArgumentException("Bad sequence size: " + + seq.size()); + } + + Enumeration e = seq.getObjects(); + + if (e.hasMoreElements()) + { + ASN1Encodable o = (ASN1Encodable)e.nextElement(); + if (o instanceof ASN1ObjectIdentifier) + { + namingAuthorityId = (ASN1ObjectIdentifier)o; + } + else if (o instanceof DERIA5String) + { + namingAuthorityUrl = DERIA5String.getInstance(o).getString(); + } + else if (o instanceof ASN1String) + { + namingAuthorityText = DirectoryString.getInstance(o); + } + else + { + throw new IllegalArgumentException("Bad object encountered: " + + o.getClass()); + } + } + if (e.hasMoreElements()) + { + ASN1Encodable o = (ASN1Encodable)e.nextElement(); + if (o instanceof DERIA5String) + { + namingAuthorityUrl = DERIA5String.getInstance(o).getString(); + } + else if (o instanceof ASN1String) + { + namingAuthorityText = DirectoryString.getInstance(o); + } + else + { + throw new IllegalArgumentException("Bad object encountered: " + + o.getClass()); + } + } + if (e.hasMoreElements()) + { + ASN1Encodable o = (ASN1Encodable)e.nextElement(); + if (o instanceof ASN1String) + { + namingAuthorityText = DirectoryString.getInstance(o); + } + else + { + throw new IllegalArgumentException("Bad object encountered: " + + o.getClass()); + } + + } + } + + /** + * @return Returns the namingAuthorityId. + */ + public ASN1ObjectIdentifier getNamingAuthorityId() + { + return namingAuthorityId; + } + + /** + * @return Returns the namingAuthorityText. + */ + public DirectoryString getNamingAuthorityText() + { + return namingAuthorityText; + } + + /** + * @return Returns the namingAuthorityUrl. + */ + public String getNamingAuthorityUrl() + { + return namingAuthorityUrl; + } + + /** + * Constructor from given details. + * + * All parameters can be combined. + * + * @param namingAuthorityId ObjectIdentifier for naming authority. + * @param namingAuthorityUrl URL for naming authority. + * @param namingAuthorityText Textual representation of naming authority. + * @deprecated use ASN1ObjectIdentifier method + */ + public NamingAuthority(DERObjectIdentifier namingAuthorityId, + String namingAuthorityUrl, DirectoryString namingAuthorityText) + { + this.namingAuthorityId = new ASN1ObjectIdentifier(namingAuthorityId.getId()); + this.namingAuthorityUrl = namingAuthorityUrl; + this.namingAuthorityText = namingAuthorityText; + } + + /** + * Constructor from given details. + * + * All parameters can be combined. + * + * @param namingAuthorityId ObjectIdentifier for naming authority. + * @param namingAuthorityUrl URL for naming authority. + * @param namingAuthorityText Textual representation of naming authority. + */ + public NamingAuthority(ASN1ObjectIdentifier namingAuthorityId, + String namingAuthorityUrl, DirectoryString namingAuthorityText) + { + this.namingAuthorityId = namingAuthorityId; + this.namingAuthorityUrl = namingAuthorityUrl; + this.namingAuthorityText = namingAuthorityText; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * + * Returns: + * + *
+ * NamingAuthority ::= SEQUENCE + * { + * namingAuthorityId OBJECT IDENTIFIER OPTIONAL, + * namingAuthorityUrl IA5String OPTIONAL, + * namingAuthorityText DirectoryString(SIZE(1..128)) OPTIONAL + * } + *+ * + * @return a DERObject + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector vec = new ASN1EncodableVector(); + if (namingAuthorityId != null) + { + vec.add(namingAuthorityId); + } + if (namingAuthorityUrl != null) + { + vec.add(new DERIA5String(namingAuthorityUrl, true)); + } + if (namingAuthorityText != null) + { + vec.add(namingAuthorityText); + } + return new DERSequence(vec); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/isismtt/x509/ProcurationSyntax.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/isismtt/x509/ProcurationSyntax.java new file mode 100644 index 0000000..16303cc --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/isismtt/x509/ProcurationSyntax.java @@ -0,0 +1,240 @@ +package org.bc.asn1.isismtt.x509; + +import java.util.Enumeration; + +import org.bc.asn1.ASN1Encodable; +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERPrintableString; +import org.bc.asn1.DERSequence; +import org.bc.asn1.DERTaggedObject; +import org.bc.asn1.x500.DirectoryString; +import org.bc.asn1.x509.GeneralName; +import org.bc.asn1.x509.IssuerSerial; + +/** + * Attribute to indicate that the certificate holder may sign in the name of a + * third person. + *
+ * ISIS-MTT PROFILE: The corresponding ProcurationSyntax contains either the + * name of the person who is represented (subcomponent thirdPerson) or a + * reference to his/her base certificate (in the component signingFor, + * subcomponent certRef), furthermore the optional components country and + * typeSubstitution to indicate the country whose laws apply, and respectively + * the type of procuration (e.g. manager, procuration, custody). + *
+ * ISIS-MTT PROFILE: The GeneralName MUST be of type directoryName and MAY only + * contain: - RFC3039 attributes, except pseudonym (countryName, commonName, + * surname, givenName, serialNumber, organizationName, organizationalUnitName, + * stateOrProvincename, localityName, postalAddress) and - SubjectDirectoryName + * attributes (title, dateOfBirth, placeOfBirth, gender, countryOfCitizenship, + * countryOfResidence and NameAtBirth). + * + *
+ * ProcurationSyntax ::= SEQUENCE { + * country [1] EXPLICIT PrintableString(SIZE(2)) OPTIONAL, + * typeOfSubstitution [2] EXPLICIT DirectoryString (SIZE(1..128)) OPTIONAL, + * signingFor [3] EXPLICIT SigningFor + * } + * + * SigningFor ::= CHOICE + * { + * thirdPerson GeneralName, + * certRef IssuerSerial + * } + *+ * + */ +public class ProcurationSyntax + extends ASN1Object +{ + private String country; + private DirectoryString typeOfSubstitution; + + private GeneralName thirdPerson; + private IssuerSerial certRef; + + public static ProcurationSyntax getInstance(Object obj) + { + if (obj == null || obj instanceof ProcurationSyntax) + { + return (ProcurationSyntax)obj; + } + + if (obj instanceof ASN1Sequence) + { + return new ProcurationSyntax((ASN1Sequence)obj); + } + + throw new IllegalArgumentException("illegal object in getInstance: " + + obj.getClass().getName()); + } + + /** + * Constructor from ASN1Sequence. + * + * The sequence is of type ProcurationSyntax: + * + *
+ * ProcurationSyntax ::= SEQUENCE { + * country [1] EXPLICIT PrintableString(SIZE(2)) OPTIONAL, + * typeOfSubstitution [2] EXPLICIT DirectoryString (SIZE(1..128)) OPTIONAL, + * signingFor [3] EXPLICIT SigningFor + * } + * + * SigningFor ::= CHOICE + * { + * thirdPerson GeneralName, + * certRef IssuerSerial + * } + *+ * + * @param seq The ASN.1 sequence. + */ + private ProcurationSyntax(ASN1Sequence seq) + { + if (seq.size() < 1 || seq.size() > 3) + { + throw new IllegalArgumentException("Bad sequence size: " + seq.size()); + } + Enumeration e = seq.getObjects(); + + while (e.hasMoreElements()) + { + ASN1TaggedObject o = ASN1TaggedObject.getInstance(e.nextElement()); + switch (o.getTagNo()) + { + case 1: + country = DERPrintableString.getInstance(o, true).getString(); + break; + case 2: + typeOfSubstitution = DirectoryString.getInstance(o, true); + break; + case 3: + ASN1Encodable signingFor = o.getObject(); + if (signingFor instanceof ASN1TaggedObject) + { + thirdPerson = GeneralName.getInstance(signingFor); + } + else + { + certRef = IssuerSerial.getInstance(signingFor); + } + break; + default: + throw new IllegalArgumentException("Bad tag number: " + o.getTagNo()); + } + } + } + + /** + * Constructor from a given details. + * + * + * Either
generalName
or certRef
MUST be
+ * null
.
+ *
+ * @param country The country code whose laws apply.
+ * @param typeOfSubstitution The type of procuration.
+ * @param certRef Reference to certificate of the person who is represented.
+ */
+ public ProcurationSyntax(
+ String country,
+ DirectoryString typeOfSubstitution,
+ IssuerSerial certRef)
+ {
+ this.country = country;
+ this.typeOfSubstitution = typeOfSubstitution;
+ this.thirdPerson = null;
+ this.certRef = certRef;
+ }
+
+ /**
+ * Constructor from a given details.
+ *
+ *
+ * Either generalName
or certRef
MUST be
+ * null
.
+ *
+ * @param country The country code whose laws apply.
+ * @param typeOfSubstitution The type of procuration.
+ * @param thirdPerson The GeneralName of the person who is represented.
+ */
+ public ProcurationSyntax(
+ String country,
+ DirectoryString typeOfSubstitution,
+ GeneralName thirdPerson)
+ {
+ this.country = country;
+ this.typeOfSubstitution = typeOfSubstitution;
+ this.thirdPerson = thirdPerson;
+ this.certRef = null;
+ }
+
+ public String getCountry()
+ {
+ return country;
+ }
+
+ public DirectoryString getTypeOfSubstitution()
+ {
+ return typeOfSubstitution;
+ }
+
+ public GeneralName getThirdPerson()
+ {
+ return thirdPerson;
+ }
+
+ public IssuerSerial getCertRef()
+ {
+ return certRef;
+ }
+
+ /**
+ * Produce an object suitable for an ASN1OutputStream.
+ *
+ * Returns:
+ *
+ * + * ProcurationSyntax ::= SEQUENCE { + * country [1] EXPLICIT PrintableString(SIZE(2)) OPTIONAL, + * typeOfSubstitution [2] EXPLICIT DirectoryString (SIZE(1..128)) OPTIONAL, + * signingFor [3] EXPLICIT SigningFor + * } + * + * SigningFor ::= CHOICE + * { + * thirdPerson GeneralName, + * certRef IssuerSerial + * } + *+ * + * @return a DERObject + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector vec = new ASN1EncodableVector(); + if (country != null) + { + vec.add(new DERTaggedObject(true, 1, new DERPrintableString(country, true))); + } + if (typeOfSubstitution != null) + { + vec.add(new DERTaggedObject(true, 2, typeOfSubstitution)); + } + if (thirdPerson != null) + { + vec.add(new DERTaggedObject(true, 3, thirdPerson)); + } + else + { + vec.add(new DERTaggedObject(true, 3, certRef)); + } + + return new DERSequence(vec); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/isismtt/x509/ProfessionInfo.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/isismtt/x509/ProfessionInfo.java new file mode 100644 index 0000000..b72e35f --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/isismtt/x509/ProfessionInfo.java @@ -0,0 +1,408 @@ +package org.bc.asn1.isismtt.x509; + +import java.util.Enumeration; + +import org.bc.asn1.ASN1Encodable; +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1ObjectIdentifier; +import org.bc.asn1.ASN1OctetString; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DEROctetString; +import org.bc.asn1.DERPrintableString; +import org.bc.asn1.DERSequence; +import org.bc.asn1.DERTaggedObject; +import org.bc.asn1.x500.DirectoryString; + +/** + * Professions, specializations, disciplines, fields of activity, etc. + * + *
+ * ProfessionInfo ::= SEQUENCE + * { + * namingAuthority [0] EXPLICIT NamingAuthority OPTIONAL, + * professionItems SEQUENCE OF DirectoryString (SIZE(1..128)), + * professionOIDs SEQUENCE OF OBJECT IDENTIFIER OPTIONAL, + * registrationNumber PrintableString(SIZE(1..128)) OPTIONAL, + * addProfessionInfo OCTET STRING OPTIONAL + * } + *+ * + * @see org.bc.asn1.isismtt.x509.AdmissionSyntax + */ +public class ProfessionInfo + extends ASN1Object +{ + + /** + * Rechtsanw�ltin + */ + public static final ASN1ObjectIdentifier Rechtsanwltin = new ASN1ObjectIdentifier( + NamingAuthority.id_isismtt_at_namingAuthorities_RechtWirtschaftSteuern + ".1"); + + /** + * Rechtsanwalt + */ + public static final ASN1ObjectIdentifier Rechtsanwalt = new ASN1ObjectIdentifier( + NamingAuthority.id_isismtt_at_namingAuthorities_RechtWirtschaftSteuern + ".2"); + + /** + * Rechtsbeistand + */ + public static final ASN1ObjectIdentifier Rechtsbeistand = new ASN1ObjectIdentifier( + NamingAuthority.id_isismtt_at_namingAuthorities_RechtWirtschaftSteuern + ".3"); + + /** + * Steuerberaterin + */ + public static final ASN1ObjectIdentifier Steuerberaterin = new ASN1ObjectIdentifier( + NamingAuthority.id_isismtt_at_namingAuthorities_RechtWirtschaftSteuern + ".4"); + + /** + * Steuerberater + */ + public static final ASN1ObjectIdentifier Steuerberater = new ASN1ObjectIdentifier( + NamingAuthority.id_isismtt_at_namingAuthorities_RechtWirtschaftSteuern + ".5"); + + /** + * Steuerbevollm�chtigte + */ + public static final ASN1ObjectIdentifier Steuerbevollmchtigte = new ASN1ObjectIdentifier( + NamingAuthority.id_isismtt_at_namingAuthorities_RechtWirtschaftSteuern + ".6"); + + /** + * Steuerbevollm�chtigter + */ + public static final ASN1ObjectIdentifier Steuerbevollmchtigter = new ASN1ObjectIdentifier( + NamingAuthority.id_isismtt_at_namingAuthorities_RechtWirtschaftSteuern + ".7"); + + /** + * Notarin + */ + public static final ASN1ObjectIdentifier Notarin = new ASN1ObjectIdentifier( + NamingAuthority.id_isismtt_at_namingAuthorities_RechtWirtschaftSteuern + ".8"); + + /** + * Notar + */ + public static final ASN1ObjectIdentifier Notar = new ASN1ObjectIdentifier( + NamingAuthority.id_isismtt_at_namingAuthorities_RechtWirtschaftSteuern + ".9"); + + /** + * Notarvertreterin + */ + public static final ASN1ObjectIdentifier Notarvertreterin = new ASN1ObjectIdentifier( + NamingAuthority.id_isismtt_at_namingAuthorities_RechtWirtschaftSteuern + ".10"); + + /** + * Notarvertreter + */ + public static final ASN1ObjectIdentifier Notarvertreter = new ASN1ObjectIdentifier( + NamingAuthority.id_isismtt_at_namingAuthorities_RechtWirtschaftSteuern + ".11"); + + /** + * Notariatsverwalterin + */ + public static final ASN1ObjectIdentifier Notariatsverwalterin = new ASN1ObjectIdentifier( + NamingAuthority.id_isismtt_at_namingAuthorities_RechtWirtschaftSteuern + ".12"); + + /** + * Notariatsverwalter + */ + public static final ASN1ObjectIdentifier Notariatsverwalter = new ASN1ObjectIdentifier( + NamingAuthority.id_isismtt_at_namingAuthorities_RechtWirtschaftSteuern + ".13"); + + /** + * Wirtschaftspr�ferin + */ + public static final ASN1ObjectIdentifier Wirtschaftsprferin = new ASN1ObjectIdentifier( + NamingAuthority.id_isismtt_at_namingAuthorities_RechtWirtschaftSteuern + ".14"); + + /** + * Wirtschaftspr�fer + */ + public static final ASN1ObjectIdentifier Wirtschaftsprfer = new ASN1ObjectIdentifier( + NamingAuthority.id_isismtt_at_namingAuthorities_RechtWirtschaftSteuern + ".15"); + + /** + * Vereidigte Buchpr�ferin + */ + public static final ASN1ObjectIdentifier VereidigteBuchprferin = new ASN1ObjectIdentifier( + NamingAuthority.id_isismtt_at_namingAuthorities_RechtWirtschaftSteuern + ".16"); + + /** + * Vereidigter Buchpr�fer + */ + public static final ASN1ObjectIdentifier VereidigterBuchprfer = new ASN1ObjectIdentifier( + NamingAuthority.id_isismtt_at_namingAuthorities_RechtWirtschaftSteuern + ".17"); + + /** + * Patentanw�ltin + */ + public static final ASN1ObjectIdentifier Patentanwltin = new ASN1ObjectIdentifier( + NamingAuthority.id_isismtt_at_namingAuthorities_RechtWirtschaftSteuern + ".18"); + + /** + * Patentanwalt + */ + public static final ASN1ObjectIdentifier Patentanwalt = new ASN1ObjectIdentifier( + NamingAuthority.id_isismtt_at_namingAuthorities_RechtWirtschaftSteuern + ".19"); + + private NamingAuthority namingAuthority; + + private ASN1Sequence professionItems; + + private ASN1Sequence professionOIDs; + + private String registrationNumber; + + private ASN1OctetString addProfessionInfo; + + public static ProfessionInfo getInstance(Object obj) + { + if (obj == null || obj instanceof ProfessionInfo) + { + return (ProfessionInfo)obj; + } + + if (obj instanceof ASN1Sequence) + { + return new ProfessionInfo((ASN1Sequence)obj); + } + + throw new IllegalArgumentException("illegal object in getInstance: " + + obj.getClass().getName()); + } + + /** + * Constructor from ASN1Sequence. + * + * + *
+ * ProfessionInfo ::= SEQUENCE + * { + * namingAuthority [0] EXPLICIT NamingAuthority OPTIONAL, + * professionItems SEQUENCE OF DirectoryString (SIZE(1..128)), + * professionOIDs SEQUENCE OF OBJECT IDENTIFIER OPTIONAL, + * registrationNumber PrintableString(SIZE(1..128)) OPTIONAL, + * addProfessionInfo OCTET STRING OPTIONAL + * } + *+ * + * @param seq The ASN.1 sequence. + */ + private ProfessionInfo(ASN1Sequence seq) + { + if (seq.size() > 5) + { + throw new IllegalArgumentException("Bad sequence size: " + + seq.size()); + } + + Enumeration e = seq.getObjects(); + + ASN1Encodable o = (ASN1Encodable)e.nextElement(); + + if (o instanceof ASN1TaggedObject) + { + if (((ASN1TaggedObject)o).getTagNo() != 0) + { + throw new IllegalArgumentException("Bad tag number: " + + ((ASN1TaggedObject)o).getTagNo()); + } + namingAuthority = NamingAuthority.getInstance((ASN1TaggedObject)o, true); + o = (ASN1Encodable)e.nextElement(); + } + + professionItems = ASN1Sequence.getInstance(o); + + if (e.hasMoreElements()) + { + o = (ASN1Encodable)e.nextElement(); + if (o instanceof ASN1Sequence) + { + professionOIDs = ASN1Sequence.getInstance(o); + } + else if (o instanceof DERPrintableString) + { + registrationNumber = DERPrintableString.getInstance(o).getString(); + } + else if (o instanceof ASN1OctetString) + { + addProfessionInfo = ASN1OctetString.getInstance(o); + } + else + { + throw new IllegalArgumentException("Bad object encountered: " + + o.getClass()); + } + } + if (e.hasMoreElements()) + { + o = (ASN1Encodable)e.nextElement(); + if (o instanceof DERPrintableString) + { + registrationNumber = DERPrintableString.getInstance(o).getString(); + } + else if (o instanceof DEROctetString) + { + addProfessionInfo = (DEROctetString)o; + } + else + { + throw new IllegalArgumentException("Bad object encountered: " + + o.getClass()); + } + } + if (e.hasMoreElements()) + { + o = (ASN1Encodable)e.nextElement(); + if (o instanceof DEROctetString) + { + addProfessionInfo = (DEROctetString)o; + } + else + { + throw new IllegalArgumentException("Bad object encountered: " + + o.getClass()); + } + } + + } + + /** + * Constructor from given details. + * + *
professionItems
is mandatory, all other parameters are
+ * optional.
+ *
+ * @param namingAuthority The naming authority.
+ * @param professionItems Directory strings of the profession.
+ * @param professionOIDs DERObjectIdentfier objects for the
+ * profession.
+ * @param registrationNumber Registration number.
+ * @param addProfessionInfo Additional infos in encoded form.
+ */
+ public ProfessionInfo(NamingAuthority namingAuthority,
+ DirectoryString[] professionItems, ASN1ObjectIdentifier[] professionOIDs,
+ String registrationNumber, ASN1OctetString addProfessionInfo)
+ {
+ this.namingAuthority = namingAuthority;
+ ASN1EncodableVector v = new ASN1EncodableVector();
+ for (int i = 0; i != professionItems.length; i++)
+ {
+ v.add(professionItems[i]);
+ }
+ this.professionItems = new DERSequence(v);
+ if (professionOIDs != null)
+ {
+ v = new ASN1EncodableVector();
+ for (int i = 0; i != professionOIDs.length; i++)
+ {
+ v.add(professionOIDs[i]);
+ }
+ this.professionOIDs = new DERSequence(v);
+ }
+ this.registrationNumber = registrationNumber;
+ this.addProfessionInfo = addProfessionInfo;
+ }
+
+ /**
+ * Produce an object suitable for an ASN1OutputStream.
+ *
+ * Returns:
+ *
+ * + * ProfessionInfo ::= SEQUENCE + * { + * namingAuthority [0] EXPLICIT NamingAuthority OPTIONAL, + * professionItems SEQUENCE OF DirectoryString (SIZE(1..128)), + * professionOIDs SEQUENCE OF OBJECT IDENTIFIER OPTIONAL, + * registrationNumber PrintableString(SIZE(1..128)) OPTIONAL, + * addProfessionInfo OCTET STRING OPTIONAL + * } + *+ * + * @return a DERObject + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector vec = new ASN1EncodableVector(); + if (namingAuthority != null) + { + vec.add(new DERTaggedObject(true, 0, namingAuthority)); + } + vec.add(professionItems); + if (professionOIDs != null) + { + vec.add(professionOIDs); + } + if (registrationNumber != null) + { + vec.add(new DERPrintableString(registrationNumber, true)); + } + if (addProfessionInfo != null) + { + vec.add(addProfessionInfo); + } + return new DERSequence(vec); + } + + /** + * @return Returns the addProfessionInfo. + */ + public ASN1OctetString getAddProfessionInfo() + { + return addProfessionInfo; + } + + /** + * @return Returns the namingAuthority. + */ + public NamingAuthority getNamingAuthority() + { + return namingAuthority; + } + + /** + * @return Returns the professionItems. + */ + public DirectoryString[] getProfessionItems() + { + DirectoryString[] items = new DirectoryString[professionItems.size()]; + int count = 0; + for (Enumeration e = professionItems.getObjects(); e.hasMoreElements();) + { + items[count++] = DirectoryString.getInstance(e.nextElement()); + } + return items; + } + + /** + * @return Returns the professionOIDs. + */ + public ASN1ObjectIdentifier[] getProfessionOIDs() + { + if (professionOIDs == null) + { + return new ASN1ObjectIdentifier[0]; + } + ASN1ObjectIdentifier[] oids = new ASN1ObjectIdentifier[professionOIDs.size()]; + int count = 0; + for (Enumeration e = professionOIDs.getObjects(); e.hasMoreElements();) + { + oids[count++] = ASN1ObjectIdentifier.getInstance(e.nextElement()); + } + return oids; + } + + /** + * @return Returns the registrationNumber. + */ + public String getRegistrationNumber() + { + return registrationNumber; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/isismtt/x509/Restriction.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/isismtt/x509/Restriction.java new file mode 100644 index 0000000..1fc1fe1 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/isismtt/x509/Restriction.java @@ -0,0 +1,81 @@ +package org.bc.asn1.isismtt.x509; + +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.x500.DirectoryString; + +/** + * Some other restriction regarding the usage of this certificate. + * + *
+ * RestrictionSyntax ::= DirectoryString (SIZE(1..1024)) + *+ */ +public class Restriction + extends ASN1Object +{ + private DirectoryString restriction; + + public static Restriction getInstance(Object obj) + { + if (obj instanceof Restriction) + { + return (Restriction)obj; + } + + if (obj != null) + { + return new Restriction(DirectoryString.getInstance(obj)); + } + + return null; + } + + /** + * Constructor from DirectoryString. + * + * The DirectoryString is of type RestrictionSyntax: + * + *
+ * RestrictionSyntax ::= DirectoryString (SIZE(1..1024)) + *+ * + * @param restriction A DirectoryString. + */ + private Restriction(DirectoryString restriction) + { + this.restriction = restriction; + } + + /** + * Constructor from a given details. + * + * @param restriction The describtion of the restriction. + */ + public Restriction(String restriction) + { + this.restriction = new DirectoryString(restriction); + } + + public DirectoryString getRestriction() + { + return restriction; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * + * Returns: + * + *
+ * RestrictionSyntax ::= DirectoryString (SIZE(1..1024)) + * + *+ * + * @return a DERObject + */ + public ASN1Primitive toASN1Primitive() + { + return restriction.toASN1Primitive(); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/kisa/KISAObjectIdentifiers.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/kisa/KISAObjectIdentifiers.java new file mode 100644 index 0000000..9dca72d --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/kisa/KISAObjectIdentifiers.java @@ -0,0 +1,9 @@ +package org.bc.asn1.kisa; + +import org.bc.asn1.ASN1ObjectIdentifier; + +public interface KISAObjectIdentifiers +{ + public static final ASN1ObjectIdentifier id_seedCBC = new ASN1ObjectIdentifier("1.2.410.200004.1.4"); + public static final ASN1ObjectIdentifier id_npki_app_cmsSeed_wrap = new ASN1ObjectIdentifier("1.2.410.200004.7.1.1.1"); +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/microsoft/MicrosoftObjectIdentifiers.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/microsoft/MicrosoftObjectIdentifiers.java new file mode 100644 index 0000000..b1fc25b --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/microsoft/MicrosoftObjectIdentifiers.java @@ -0,0 +1,17 @@ +package org.bc.asn1.microsoft; + +import org.bc.asn1.ASN1ObjectIdentifier; + +public interface MicrosoftObjectIdentifiers +{ + // + // Microsoft + // iso(1) identified-organization(3) dod(6) internet(1) private(4) enterprise(1) microsoft(311) + // + static final ASN1ObjectIdentifier microsoft = new ASN1ObjectIdentifier("1.3.6.1.4.1.311"); + static final ASN1ObjectIdentifier microsoftCertTemplateV1 = microsoft.branch("20.2"); + static final ASN1ObjectIdentifier microsoftCaVersion = microsoft.branch("21.1"); + static final ASN1ObjectIdentifier microsoftPrevCaCertHash = microsoft.branch("21.2"); + static final ASN1ObjectIdentifier microsoftCertTemplateV2 = microsoft.branch("21.7"); + static final ASN1ObjectIdentifier microsoftAppPolicies = microsoft.branch("21.10"); +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/misc/CAST5CBCParameters.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/misc/CAST5CBCParameters.java new file mode 100644 index 0000000..ebaaadd --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/misc/CAST5CBCParameters.java @@ -0,0 +1,78 @@ +package org.bc.asn1.misc; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1OctetString; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DEROctetString; +import org.bc.asn1.DERSequence; + +public class CAST5CBCParameters + extends ASN1Object +{ + ASN1Integer keyLength; + ASN1OctetString iv; + + public static CAST5CBCParameters getInstance( + Object o) + { + if (o instanceof CAST5CBCParameters) + { + return (CAST5CBCParameters)o; + } + else if (o != null) + { + return new CAST5CBCParameters(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public CAST5CBCParameters( + byte[] iv, + int keyLength) + { + this.iv = new DEROctetString(iv); + this.keyLength = new ASN1Integer(keyLength); + } + + public CAST5CBCParameters( + ASN1Sequence seq) + { + iv = (ASN1OctetString)seq.getObjectAt(0); + keyLength = (ASN1Integer)seq.getObjectAt(1); + } + + public byte[] getIV() + { + return iv.getOctets(); + } + + public int getKeyLength() + { + return keyLength.getValue().intValue(); + } + + /** + * Produce an object suitable for an ASN1OutputStream. + *
+ * cast5CBCParameters ::= SEQUENCE { + * iv OCTET STRING DEFAULT 0, + * -- Initialization vector + * keyLength INTEGER + * -- Key length, in bits + * } + *+ */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(iv); + v.add(keyLength); + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/misc/IDEACBCPar.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/misc/IDEACBCPar.java new file mode 100644 index 0000000..4dceee3 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/misc/IDEACBCPar.java @@ -0,0 +1,81 @@ +package org.bc.asn1.misc; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1OctetString; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DEROctetString; +import org.bc.asn1.DERSequence; + +public class IDEACBCPar + extends ASN1Object +{ + ASN1OctetString iv; + + public static IDEACBCPar getInstance( + Object o) + { + if (o instanceof IDEACBCPar) + { + return (IDEACBCPar)o; + } + else if (o != null) + { + return new IDEACBCPar(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public IDEACBCPar( + byte[] iv) + { + this.iv = new DEROctetString(iv); + } + + public IDEACBCPar( + ASN1Sequence seq) + { + if (seq.size() == 1) + { + iv = (ASN1OctetString)seq.getObjectAt(0); + } + else + { + iv = null; + } + } + + public byte[] getIV() + { + if (iv != null) + { + return iv.getOctets(); + } + else + { + return null; + } + } + + /** + * Produce an object suitable for an ASN1OutputStream. + *
+ * IDEA-CBCPar ::= SEQUENCE { + * iv OCTET STRING OPTIONAL -- exactly 8 octets + * } + *+ */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + if (iv != null) + { + v.add(iv); + } + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/misc/MiscObjectIdentifiers.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/misc/MiscObjectIdentifiers.java new file mode 100644 index 0000000..8454186 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/misc/MiscObjectIdentifiers.java @@ -0,0 +1,47 @@ +package org.bc.asn1.misc; + +import org.bc.asn1.ASN1ObjectIdentifier; + +public interface MiscObjectIdentifiers +{ + // + // Netscape + // iso/itu(2) joint-assign(16) us(840) uscompany(1) netscape(113730) cert-extensions(1) } + // + static final ASN1ObjectIdentifier netscape = new ASN1ObjectIdentifier("2.16.840.1.113730.1"); + static final ASN1ObjectIdentifier netscapeCertType = netscape.branch("1"); + static final ASN1ObjectIdentifier netscapeBaseURL = netscape.branch("2"); + static final ASN1ObjectIdentifier netscapeRevocationURL = netscape.branch("3"); + static final ASN1ObjectIdentifier netscapeCARevocationURL = netscape.branch("4"); + static final ASN1ObjectIdentifier netscapeRenewalURL = netscape.branch("7"); + static final ASN1ObjectIdentifier netscapeCApolicyURL = netscape.branch("8"); + static final ASN1ObjectIdentifier netscapeSSLServerName = netscape.branch("12"); + static final ASN1ObjectIdentifier netscapeCertComment = netscape.branch("13"); + + // + // Verisign + // iso/itu(2) joint-assign(16) us(840) uscompany(1) verisign(113733) cert-extensions(1) } + // + static final ASN1ObjectIdentifier verisign = new ASN1ObjectIdentifier("2.16.840.1.113733.1"); + + // + // CZAG - country, zip, age, and gender + // + static final ASN1ObjectIdentifier verisignCzagExtension = verisign.branch("6.3"); + // D&B D-U-N-S number + static final ASN1ObjectIdentifier verisignDnbDunsNumber = verisign.branch("6.15"); + + // + // Novell + // iso/itu(2) country(16) us(840) organization(1) novell(113719) + // + static final ASN1ObjectIdentifier novell = new ASN1ObjectIdentifier("2.16.840.1.113719"); + static final ASN1ObjectIdentifier novellSecurityAttribs = novell.branch("1.9.4.1"); + + // + // Entrust + // iso(1) member-body(16) us(840) nortelnetworks(113533) entrust(7) + // + static final ASN1ObjectIdentifier entrust = new ASN1ObjectIdentifier("1.2.840.113533.7"); + static final ASN1ObjectIdentifier entrustVersionExtension = entrust.branch("65.0"); +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/misc/NetscapeCertType.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/misc/NetscapeCertType.java new file mode 100644 index 0000000..63b53bc --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/misc/NetscapeCertType.java @@ -0,0 +1,54 @@ +package org.bc.asn1.misc; + +import org.bc.asn1.DERBitString; + +/** + * The NetscapeCertType object. + *
+ * NetscapeCertType ::= BIT STRING { + * SSLClient (0), + * SSLServer (1), + * S/MIME (2), + * Object Signing (3), + * Reserved (4), + * SSL CA (5), + * S/MIME CA (6), + * Object Signing CA (7) } + *+ */ +public class NetscapeCertType + extends DERBitString +{ + public static final int sslClient = (1 << 7); + public static final int sslServer = (1 << 6); + public static final int smime = (1 << 5); + public static final int objectSigning = (1 << 4); + public static final int reserved = (1 << 3); + public static final int sslCA = (1 << 2); + public static final int smimeCA = (1 << 1); + public static final int objectSigningCA = (1 << 0); + + /** + * Basic constructor. + * + * @param usage - the bitwise OR of the Key Usage flags giving the + * allowed uses for the key. + * e.g. (X509NetscapeCertType.sslCA | X509NetscapeCertType.smimeCA) + */ + public NetscapeCertType( + int usage) + { + super(getBytes(usage), getPadBits(usage)); + } + + public NetscapeCertType( + DERBitString usage) + { + super(usage.getBytes(), usage.getPadBits()); + } + + public String toString() + { + return "NetscapeCertType: 0x" + Integer.toHexString(data[0] & 0xff); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/misc/NetscapeRevocationURL.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/misc/NetscapeRevocationURL.java new file mode 100644 index 0000000..d0cf0ba --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/misc/NetscapeRevocationURL.java @@ -0,0 +1,18 @@ +package org.bc.asn1.misc; + +import org.bc.asn1.DERIA5String; + +public class NetscapeRevocationURL + extends DERIA5String +{ + public NetscapeRevocationURL( + DERIA5String str) + { + super(str.getString()); + } + + public String toString() + { + return "NetscapeRevocationURL: " + this.getString(); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/misc/VerisignCzagExtension.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/misc/VerisignCzagExtension.java new file mode 100644 index 0000000..2005898 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/misc/VerisignCzagExtension.java @@ -0,0 +1,18 @@ +package org.bc.asn1.misc; + +import org.bc.asn1.DERIA5String; + +public class VerisignCzagExtension + extends DERIA5String +{ + public VerisignCzagExtension( + DERIA5String str) + { + super(str.getString()); + } + + public String toString() + { + return "VerisignCzagExtension: " + this.getString(); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/mozilla/PublicKeyAndChallenge.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/mozilla/PublicKeyAndChallenge.java new file mode 100644 index 0000000..94e9f41 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/mozilla/PublicKeyAndChallenge.java @@ -0,0 +1,63 @@ +package org.bc.asn1.mozilla; + +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DERIA5String; +import org.bc.asn1.x509.SubjectPublicKeyInfo; + +/** + * This is designed to parse + * the PublicKeyAndChallenge created by the KEYGEN tag included by + * Mozilla based browsers. + *
+ * PublicKeyAndChallenge ::= SEQUENCE { + * spki SubjectPublicKeyInfo, + * challenge IA5STRING + * } + * + *+ */ +public class PublicKeyAndChallenge + extends ASN1Object +{ + private ASN1Sequence pkacSeq; + private SubjectPublicKeyInfo spki; + private DERIA5String challenge; + + public static PublicKeyAndChallenge getInstance(Object obj) + { + if (obj instanceof PublicKeyAndChallenge) + { + return (PublicKeyAndChallenge)obj; + } + else if (obj != null) + { + return new PublicKeyAndChallenge(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + private PublicKeyAndChallenge(ASN1Sequence seq) + { + pkacSeq = seq; + spki = SubjectPublicKeyInfo.getInstance(seq.getObjectAt(0)); + challenge = DERIA5String.getInstance(seq.getObjectAt(1)); + } + + public ASN1Primitive toASN1Primitive() + { + return pkacSeq; + } + + public SubjectPublicKeyInfo getSubjectPublicKeyInfo() + { + return spki; + } + + public DERIA5String getChallenge() + { + return challenge; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/nist/NISTNamedCurves.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/nist/NISTNamedCurves.java new file mode 100644 index 0000000..225589d --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/nist/NISTNamedCurves.java @@ -0,0 +1,96 @@ +package org.bc.asn1.nist; + +import java.util.Enumeration; +import java.util.Hashtable; + +import org.bc.asn1.ASN1ObjectIdentifier; +import org.bc.asn1.sec.SECNamedCurves; +import org.bc.asn1.sec.SECObjectIdentifiers; +import org.bc.asn1.x9.X9ECParameters; +import org.bc.util.Strings; + +/** + * Utility class for fetching curves using their NIST names as published in FIPS-PUB 186-2 + */ +public class NISTNamedCurves +{ + static final Hashtable objIds = new Hashtable(); + static final Hashtable names = new Hashtable(); + + static void defineCurve(String name, ASN1ObjectIdentifier oid) + { + objIds.put(name, oid); + names.put(oid, name); + } + + static + { + // TODO Missing the "K-" curves + + defineCurve("B-571", SECObjectIdentifiers.sect571r1); + defineCurve("B-409", SECObjectIdentifiers.sect409r1); + defineCurve("B-283", SECObjectIdentifiers.sect283r1); + defineCurve("B-233", SECObjectIdentifiers.sect233r1); + defineCurve("B-163", SECObjectIdentifiers.sect163r2); + defineCurve("P-521", SECObjectIdentifiers.secp521r1); + defineCurve("P-384", SECObjectIdentifiers.secp384r1); + defineCurve("P-256", SECObjectIdentifiers.secp256r1); + defineCurve("P-224", SECObjectIdentifiers.secp224r1); + defineCurve("P-192", SECObjectIdentifiers.secp192r1); + } + + public static X9ECParameters getByName( + String name) + { + ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)objIds.get(Strings.toUpperCase(name)); + + if (oid != null) + { + return getByOID(oid); + } + + return null; + } + + /** + * return the X9ECParameters object for the named curve represented by + * the passed in object identifier. Null if the curve isn't present. + * + * @param oid an object identifier representing a named curve, if present. + */ + public static X9ECParameters getByOID( + ASN1ObjectIdentifier oid) + { + return SECNamedCurves.getByOID(oid); + } + + /** + * return the object identifier signified by the passed in name. Null + * if there is no object identifier associated with name. + * + * @return the object identifier associated with name, if present. + */ + public static ASN1ObjectIdentifier getOID( + String name) + { + return (ASN1ObjectIdentifier)objIds.get(Strings.toUpperCase(name)); + } + + /** + * return the named curve name represented by the given object identifier. + */ + public static String getName( + ASN1ObjectIdentifier oid) + { + return (String)names.get(oid); + } + + /** + * returns an enumeration containing the name strings for curves + * contained in this structure. + */ + public static Enumeration getNames() + { + return objIds.keys(); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/nist/NISTObjectIdentifiers.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/nist/NISTObjectIdentifiers.java new file mode 100644 index 0000000..32f7784 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/nist/NISTObjectIdentifiers.java @@ -0,0 +1,56 @@ +package org.bc.asn1.nist; + +import org.bc.asn1.ASN1ObjectIdentifier; + +public interface NISTObjectIdentifiers +{ + // + // NIST + // iso/itu(2) joint-assign(16) us(840) organization(1) gov(101) csor(3) + + // + // nistalgorithms(4) + // + static final ASN1ObjectIdentifier nistAlgorithm = new ASN1ObjectIdentifier("2.16.840.1.101.3.4"); + + static final ASN1ObjectIdentifier id_sha256 = nistAlgorithm.branch("2.1"); + static final ASN1ObjectIdentifier id_sha384 = nistAlgorithm.branch("2.2"); + static final ASN1ObjectIdentifier id_sha512 = nistAlgorithm.branch("2.3"); + static final ASN1ObjectIdentifier id_sha224 = nistAlgorithm.branch("2.4"); + + static final ASN1ObjectIdentifier aes = nistAlgorithm.branch("1"); + + static final ASN1ObjectIdentifier id_aes128_ECB = aes.branch("1"); + static final ASN1ObjectIdentifier id_aes128_CBC = aes.branch("2"); + static final ASN1ObjectIdentifier id_aes128_OFB = aes.branch("3"); + static final ASN1ObjectIdentifier id_aes128_CFB = aes.branch("4"); + static final ASN1ObjectIdentifier id_aes128_wrap = aes.branch("5"); + static final ASN1ObjectIdentifier id_aes128_GCM = aes.branch("6"); + static final ASN1ObjectIdentifier id_aes128_CCM = aes.branch("7"); + + static final ASN1ObjectIdentifier id_aes192_ECB = aes.branch("21"); + static final ASN1ObjectIdentifier id_aes192_CBC = aes.branch("22"); + static final ASN1ObjectIdentifier id_aes192_OFB = aes.branch("23"); + static final ASN1ObjectIdentifier id_aes192_CFB = aes.branch("24"); + static final ASN1ObjectIdentifier id_aes192_wrap = aes.branch("25"); + static final ASN1ObjectIdentifier id_aes192_GCM = aes.branch("26"); + static final ASN1ObjectIdentifier id_aes192_CCM = aes.branch("27"); + + static final ASN1ObjectIdentifier id_aes256_ECB = aes.branch("41"); + static final ASN1ObjectIdentifier id_aes256_CBC = aes.branch("42"); + static final ASN1ObjectIdentifier id_aes256_OFB = aes.branch("43"); + static final ASN1ObjectIdentifier id_aes256_CFB = aes.branch("44"); + static final ASN1ObjectIdentifier id_aes256_wrap = aes.branch("45"); + static final ASN1ObjectIdentifier id_aes256_GCM = aes.branch("46"); + static final ASN1ObjectIdentifier id_aes256_CCM = aes.branch("47"); + + // + // signatures + // + static final ASN1ObjectIdentifier id_dsa_with_sha2 = nistAlgorithm.branch("3"); + + static final ASN1ObjectIdentifier dsa_with_sha224 = id_dsa_with_sha2.branch("1"); + static final ASN1ObjectIdentifier dsa_with_sha256 = id_dsa_with_sha2.branch("2"); + static final ASN1ObjectIdentifier dsa_with_sha384 = id_dsa_with_sha2.branch("3"); + static final ASN1ObjectIdentifier dsa_with_sha512 = id_dsa_with_sha2.branch("4"); +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ntt/NTTObjectIdentifiers.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ntt/NTTObjectIdentifiers.java new file mode 100644 index 0000000..89f1e2d --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ntt/NTTObjectIdentifiers.java @@ -0,0 +1,17 @@ +package org.bc.asn1.ntt; + +import org.bc.asn1.ASN1ObjectIdentifier; + +/** + * From RFC 3657 + */ +public interface NTTObjectIdentifiers +{ + public static final ASN1ObjectIdentifier id_camellia128_cbc = new ASN1ObjectIdentifier("1.2.392.200011.61.1.1.1.2"); + public static final ASN1ObjectIdentifier id_camellia192_cbc = new ASN1ObjectIdentifier("1.2.392.200011.61.1.1.1.3"); + public static final ASN1ObjectIdentifier id_camellia256_cbc = new ASN1ObjectIdentifier("1.2.392.200011.61.1.1.1.4"); + + public static final ASN1ObjectIdentifier id_camellia128_wrap = new ASN1ObjectIdentifier("1.2.392.200011.61.1.1.3.2"); + public static final ASN1ObjectIdentifier id_camellia192_wrap = new ASN1ObjectIdentifier("1.2.392.200011.61.1.1.3.3"); + public static final ASN1ObjectIdentifier id_camellia256_wrap = new ASN1ObjectIdentifier("1.2.392.200011.61.1.1.3.4"); +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ocsp/BasicOCSPResponse.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ocsp/BasicOCSPResponse.java new file mode 100644 index 0000000..cd8e0a8 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ocsp/BasicOCSPResponse.java @@ -0,0 +1,112 @@ +package org.bc.asn1.ocsp; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERBitString; +import org.bc.asn1.DERSequence; +import org.bc.asn1.DERTaggedObject; +import org.bc.asn1.x509.AlgorithmIdentifier; + +public class BasicOCSPResponse + extends ASN1Object +{ + private ResponseData tbsResponseData; + private AlgorithmIdentifier signatureAlgorithm; + private DERBitString signature; + private ASN1Sequence certs; + + public BasicOCSPResponse( + ResponseData tbsResponseData, + AlgorithmIdentifier signatureAlgorithm, + DERBitString signature, + ASN1Sequence certs) + { + this.tbsResponseData = tbsResponseData; + this.signatureAlgorithm = signatureAlgorithm; + this.signature = signature; + this.certs = certs; + } + + private BasicOCSPResponse( + ASN1Sequence seq) + { + this.tbsResponseData = ResponseData.getInstance(seq.getObjectAt(0)); + this.signatureAlgorithm = AlgorithmIdentifier.getInstance(seq.getObjectAt(1)); + this.signature = (DERBitString)seq.getObjectAt(2); + + if (seq.size() > 3) + { + this.certs = ASN1Sequence.getInstance((ASN1TaggedObject)seq.getObjectAt(3), true); + } + } + + public static BasicOCSPResponse getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static BasicOCSPResponse getInstance( + Object obj) + { + if (obj instanceof BasicOCSPResponse) + { + return (BasicOCSPResponse)obj; + } + else if (obj != null) + { + return new BasicOCSPResponse(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public ResponseData getTbsResponseData() + { + return tbsResponseData; + } + + public AlgorithmIdentifier getSignatureAlgorithm() + { + return signatureAlgorithm; + } + + public DERBitString getSignature() + { + return signature; + } + + public ASN1Sequence getCerts() + { + return certs; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + *
+ * BasicOCSPResponse ::= SEQUENCE { + * tbsResponseData ResponseData, + * signatureAlgorithm AlgorithmIdentifier, + * signature BIT STRING, + * certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL } + *+ */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(tbsResponseData); + v.add(signatureAlgorithm); + v.add(signature); + if (certs != null) + { + v.add(new DERTaggedObject(true, 0, certs)); + } + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ocsp/CertID.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ocsp/CertID.java new file mode 100644 index 0000000..69597cf --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ocsp/CertID.java @@ -0,0 +1,105 @@ +package org.bc.asn1.ocsp; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1OctetString; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERSequence; +import org.bc.asn1.x509.AlgorithmIdentifier; + +public class CertID + extends ASN1Object +{ + AlgorithmIdentifier hashAlgorithm; + ASN1OctetString issuerNameHash; + ASN1OctetString issuerKeyHash; + ASN1Integer serialNumber; + + public CertID( + AlgorithmIdentifier hashAlgorithm, + ASN1OctetString issuerNameHash, + ASN1OctetString issuerKeyHash, + ASN1Integer serialNumber) + { + this.hashAlgorithm = hashAlgorithm; + this.issuerNameHash = issuerNameHash; + this.issuerKeyHash = issuerKeyHash; + this.serialNumber = serialNumber; + } + + private CertID( + ASN1Sequence seq) + { + hashAlgorithm = AlgorithmIdentifier.getInstance(seq.getObjectAt(0)); + issuerNameHash = (ASN1OctetString)seq.getObjectAt(1); + issuerKeyHash = (ASN1OctetString)seq.getObjectAt(2); + serialNumber = (ASN1Integer)seq.getObjectAt(3); + } + + public static CertID getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static CertID getInstance( + Object obj) + { + if (obj instanceof CertID) + { + return (CertID)obj; + } + else if (obj != null) + { + return new CertID(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public AlgorithmIdentifier getHashAlgorithm() + { + return hashAlgorithm; + } + + public ASN1OctetString getIssuerNameHash() + { + return issuerNameHash; + } + + public ASN1OctetString getIssuerKeyHash() + { + return issuerKeyHash; + } + + public ASN1Integer getSerialNumber() + { + return serialNumber; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + *
+ * CertID ::= SEQUENCE { + * hashAlgorithm AlgorithmIdentifier, + * issuerNameHash OCTET STRING, -- Hash of Issuer's DN + * issuerKeyHash OCTET STRING, -- Hash of Issuers public key + * serialNumber CertificateSerialNumber } + *+ */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(hashAlgorithm); + v.add(issuerNameHash); + v.add(issuerKeyHash); + v.add(serialNumber); + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ocsp/CertStatus.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ocsp/CertStatus.java new file mode 100644 index 0000000..2a86e6d --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ocsp/CertStatus.java @@ -0,0 +1,105 @@ +package org.bc.asn1.ocsp; + +import org.bc.asn1.ASN1Choice; +import org.bc.asn1.ASN1Encodable; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERNull; +import org.bc.asn1.DERTaggedObject; + +public class CertStatus + extends ASN1Object + implements ASN1Choice +{ + private int tagNo; + private ASN1Encodable value; + + /** + * create a CertStatus object with a tag of zero. + */ + public CertStatus() + { + tagNo = 0; + value = DERNull.INSTANCE; + } + + public CertStatus( + RevokedInfo info) + { + tagNo = 1; + value = info; + } + + public CertStatus( + int tagNo, + ASN1Encodable value) + { + this.tagNo = tagNo; + this.value = value; + } + + public CertStatus( + ASN1TaggedObject choice) + { + this.tagNo = choice.getTagNo(); + + switch (choice.getTagNo()) + { + case 0: + value = DERNull.INSTANCE; + break; + case 1: + value = RevokedInfo.getInstance(choice, false); + break; + case 2: + value = DERNull.INSTANCE; + } + } + + public static CertStatus getInstance( + Object obj) + { + if (obj == null || obj instanceof CertStatus) + { + return (CertStatus)obj; + } + else if (obj instanceof ASN1TaggedObject) + { + return new CertStatus((ASN1TaggedObject)obj); + } + + throw new IllegalArgumentException("unknown object in factory: " + obj.getClass().getName()); + } + + public static CertStatus getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(obj.getObject()); // must be explicitly tagged + } + + public int getTagNo() + { + return tagNo; + } + + public ASN1Encodable getStatus() + { + return value; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + *
+ * CertStatus ::= CHOICE { + * good [0] IMPLICIT NULL, + * revoked [1] IMPLICIT RevokedInfo, + * unknown [2] IMPLICIT UnknownInfo } + *+ */ + public ASN1Primitive toASN1Primitive() + { + return new DERTaggedObject(false, tagNo, value); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ocsp/CrlID.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ocsp/CrlID.java new file mode 100644 index 0000000..e506539 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ocsp/CrlID.java @@ -0,0 +1,111 @@ +package org.bc.asn1.ocsp; + +import java.util.Enumeration; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1GeneralizedTime; +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERGeneralizedTime; +import org.bc.asn1.DERIA5String; +import org.bc.asn1.DERSequence; +import org.bc.asn1.DERTaggedObject; + +public class CrlID + extends ASN1Object +{ + private DERIA5String crlUrl; + private ASN1Integer crlNum; + private ASN1GeneralizedTime crlTime; + + private CrlID( + ASN1Sequence seq) + { + Enumeration e = seq.getObjects(); + + while (e.hasMoreElements()) + { + ASN1TaggedObject o = (ASN1TaggedObject)e.nextElement(); + + switch (o.getTagNo()) + { + case 0: + crlUrl = DERIA5String.getInstance(o, true); + break; + case 1: + crlNum = ASN1Integer.getInstance(o, true); + break; + case 2: + crlTime = DERGeneralizedTime.getInstance(o, true); + break; + default: + throw new IllegalArgumentException( + "unknown tag number: " + o.getTagNo()); + } + } + } + + public static CrlID getInstance( + Object obj) + { + if (obj instanceof CrlID) + { + return (CrlID)obj; + } + else if (obj != null) + { + return new CrlID(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public DERIA5String getCrlUrl() + { + return crlUrl; + } + + public ASN1Integer getCrlNum() + { + return crlNum; + } + + public ASN1GeneralizedTime getCrlTime() + { + return crlTime; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + *
+ * CrlID ::= SEQUENCE { + * crlUrl [0] EXPLICIT IA5String OPTIONAL, + * crlNum [1] EXPLICIT INTEGER OPTIONAL, + * crlTime [2] EXPLICIT GeneralizedTime OPTIONAL } + *+ */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + if (crlUrl != null) + { + v.add(new DERTaggedObject(true, 0, crlUrl)); + } + + if (crlNum != null) + { + v.add(new DERTaggedObject(true, 1, crlNum)); + } + + if (crlTime != null) + { + v.add(new DERTaggedObject(true, 2, crlTime)); + } + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ocsp/OCSPObjectIdentifiers.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ocsp/OCSPObjectIdentifiers.java new file mode 100644 index 0000000..88c1bfe --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ocsp/OCSPObjectIdentifiers.java @@ -0,0 +1,22 @@ +package org.bc.asn1.ocsp; + +import org.bc.asn1.ASN1ObjectIdentifier; + +public interface OCSPObjectIdentifiers +{ + public static final String pkix_ocsp = "1.3.6.1.5.5.7.48.1"; + + public static final ASN1ObjectIdentifier id_pkix_ocsp = new ASN1ObjectIdentifier(pkix_ocsp); + public static final ASN1ObjectIdentifier id_pkix_ocsp_basic = new ASN1ObjectIdentifier(pkix_ocsp + ".1"); + + // + // extensions + // + public static final ASN1ObjectIdentifier id_pkix_ocsp_nonce = new ASN1ObjectIdentifier(pkix_ocsp + ".2"); + public static final ASN1ObjectIdentifier id_pkix_ocsp_crl = new ASN1ObjectIdentifier(pkix_ocsp + ".3"); + + public static final ASN1ObjectIdentifier id_pkix_ocsp_response = new ASN1ObjectIdentifier(pkix_ocsp + ".4"); + public static final ASN1ObjectIdentifier id_pkix_ocsp_nocheck = new ASN1ObjectIdentifier(pkix_ocsp + ".5"); + public static final ASN1ObjectIdentifier id_pkix_ocsp_archive_cutoff = new ASN1ObjectIdentifier(pkix_ocsp + ".6"); + public static final ASN1ObjectIdentifier id_pkix_ocsp_service_locator = new ASN1ObjectIdentifier(pkix_ocsp + ".7"); +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ocsp/OCSPRequest.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ocsp/OCSPRequest.java new file mode 100644 index 0000000..29db1d6 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ocsp/OCSPRequest.java @@ -0,0 +1,90 @@ +package org.bc.asn1.ocsp; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERSequence; +import org.bc.asn1.DERTaggedObject; + +public class OCSPRequest + extends ASN1Object +{ + TBSRequest tbsRequest; + Signature optionalSignature; + + public OCSPRequest( + TBSRequest tbsRequest, + Signature optionalSignature) + { + this.tbsRequest = tbsRequest; + this.optionalSignature = optionalSignature; + } + + private OCSPRequest( + ASN1Sequence seq) + { + tbsRequest = TBSRequest.getInstance(seq.getObjectAt(0)); + + if (seq.size() == 2) + { + optionalSignature = Signature.getInstance( + (ASN1TaggedObject)seq.getObjectAt(1), true); + } + } + + public static OCSPRequest getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static OCSPRequest getInstance( + Object obj) + { + if (obj instanceof OCSPRequest) + { + return (OCSPRequest)obj; + } + else if (obj != null) + { + return new OCSPRequest(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public TBSRequest getTbsRequest() + { + return tbsRequest; + } + + public Signature getOptionalSignature() + { + return optionalSignature; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + *
+ * OCSPRequest ::= SEQUENCE { + * tbsRequest TBSRequest, + * optionalSignature [0] EXPLICIT Signature OPTIONAL } + *+ */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(tbsRequest); + + if (optionalSignature != null) + { + v.add(new DERTaggedObject(true, 0, optionalSignature)); + } + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ocsp/OCSPResponse.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ocsp/OCSPResponse.java new file mode 100644 index 0000000..65e1297 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ocsp/OCSPResponse.java @@ -0,0 +1,90 @@ +package org.bc.asn1.ocsp; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERSequence; +import org.bc.asn1.DERTaggedObject; + +public class OCSPResponse + extends ASN1Object +{ + OCSPResponseStatus responseStatus; + ResponseBytes responseBytes; + + public OCSPResponse( + OCSPResponseStatus responseStatus, + ResponseBytes responseBytes) + { + this.responseStatus = responseStatus; + this.responseBytes = responseBytes; + } + + private OCSPResponse( + ASN1Sequence seq) + { + responseStatus = OCSPResponseStatus.getInstance(seq.getObjectAt(0)); + + if (seq.size() == 2) + { + responseBytes = ResponseBytes.getInstance( + (ASN1TaggedObject)seq.getObjectAt(1), true); + } + } + + public static OCSPResponse getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static OCSPResponse getInstance( + Object obj) + { + if (obj instanceof OCSPResponse) + { + return (OCSPResponse)obj; + } + else if (obj != null) + { + return new OCSPResponse(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public OCSPResponseStatus getResponseStatus() + { + return responseStatus; + } + + public ResponseBytes getResponseBytes() + { + return responseBytes; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + *
+ * OCSPResponse ::= SEQUENCE { + * responseStatus OCSPResponseStatus, + * responseBytes [0] EXPLICIT ResponseBytes OPTIONAL } + *+ */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(responseStatus); + + if (responseBytes != null) + { + v.add(new DERTaggedObject(true, 0, responseBytes)); + } + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ocsp/OCSPResponseStatus.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ocsp/OCSPResponseStatus.java new file mode 100644 index 0000000..30147b5 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ocsp/OCSPResponseStatus.java @@ -0,0 +1,71 @@ +package org.bc.asn1.ocsp; + +import java.math.BigInteger; + +import org.bc.asn1.ASN1Enumerated; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; + +public class OCSPResponseStatus + extends ASN1Object +{ + public static final int SUCCESSFUL = 0; + public static final int MALFORMED_REQUEST = 1; + public static final int INTERNAL_ERROR = 2; + public static final int TRY_LATER = 3; + public static final int SIG_REQUIRED = 5; + public static final int UNAUTHORIZED = 6; + + private ASN1Enumerated value; + + /** + * The OCSPResponseStatus enumeration. + *
+ * OCSPResponseStatus ::= ENUMERATED { + * successful (0), --Response has valid confirmations + * malformedRequest (1), --Illegal confirmation request + * internalError (2), --Internal error in issuer + * tryLater (3), --Try again later + * --(4) is not used + * sigRequired (5), --Must sign the request + * unauthorized (6) --Request unauthorized + * } + *+ */ + public OCSPResponseStatus( + int value) + { + this(new ASN1Enumerated(value)); + } + + private OCSPResponseStatus( + ASN1Enumerated value) + { + this.value = value; + } + + public static OCSPResponseStatus getInstance( + Object obj) + { + if (obj instanceof OCSPResponseStatus) + { + return (OCSPResponseStatus)obj; + } + else if (obj != null) + { + return new OCSPResponseStatus(ASN1Enumerated.getInstance(obj)); + } + + return null; + } + + public BigInteger getValue() + { + return value.getValue(); + } + + public ASN1Primitive toASN1Primitive() + { + return value; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ocsp/Request.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ocsp/Request.java new file mode 100644 index 0000000..af50458 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ocsp/Request.java @@ -0,0 +1,91 @@ +package org.bc.asn1.ocsp; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERSequence; +import org.bc.asn1.DERTaggedObject; +import org.bc.asn1.x509.Extensions; + +public class Request + extends ASN1Object +{ + CertID reqCert; + Extensions singleRequestExtensions; + + public Request( + CertID reqCert, + Extensions singleRequestExtensions) + { + this.reqCert = reqCert; + this.singleRequestExtensions = singleRequestExtensions; + } + + private Request( + ASN1Sequence seq) + { + reqCert = CertID.getInstance(seq.getObjectAt(0)); + + if (seq.size() == 2) + { + singleRequestExtensions = Extensions.getInstance( + (ASN1TaggedObject)seq.getObjectAt(1), true); + } + } + + public static Request getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static Request getInstance( + Object obj) + { + if (obj instanceof Request) + { + return (Request)obj; + } + else if (obj != null) + { + return new Request(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public CertID getReqCert() + { + return reqCert; + } + + public Extensions getSingleRequestExtensions() + { + return singleRequestExtensions; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + *
+ * Request ::= SEQUENCE { + * reqCert CertID, + * singleRequestExtensions [0] EXPLICIT Extensions OPTIONAL } + *+ */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(reqCert); + + if (singleRequestExtensions != null) + { + v.add(new DERTaggedObject(true, 0, singleRequestExtensions)); + } + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ocsp/ResponderID.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ocsp/ResponderID.java new file mode 100644 index 0000000..65adcab --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ocsp/ResponderID.java @@ -0,0 +1,104 @@ +package org.bc.asn1.ocsp; + +import org.bc.asn1.ASN1Choice; +import org.bc.asn1.ASN1Encodable; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1OctetString; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DEROctetString; +import org.bc.asn1.DERTaggedObject; +import org.bc.asn1.x500.X500Name; + +public class ResponderID + extends ASN1Object + implements ASN1Choice +{ + private ASN1Encodable value; + + public ResponderID( + ASN1OctetString value) + { + this.value = value; + } + + public ResponderID( + X500Name value) + { + this.value = value; + } + + public static ResponderID getInstance( + Object obj) + { + if (obj instanceof ResponderID) + { + return (ResponderID)obj; + } + else if (obj instanceof DEROctetString) + { + return new ResponderID((DEROctetString)obj); + } + else if (obj instanceof ASN1TaggedObject) + { + ASN1TaggedObject o = (ASN1TaggedObject)obj; + + if (o.getTagNo() == 1) + { + return new ResponderID(X500Name.getInstance(o, true)); + } + else + { + return new ResponderID(ASN1OctetString.getInstance(o, true)); + } + } + + return new ResponderID(X500Name.getInstance(obj)); + } + + public static ResponderID getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(obj.getObject()); // must be explicitly tagged + } + + public byte[] getKeyHash() + { + if (this.value instanceof ASN1OctetString) + { + ASN1OctetString octetString = (ASN1OctetString)this.value; + return octetString.getOctets(); + } + + return null; + } + + public X500Name getName() + { + if (this.value instanceof ASN1OctetString) + { + return null; + } + + return X500Name.getInstance(value); + } + + /** + * Produce an object suitable for an ASN1OutputStream. + *
+ * ResponderID ::= CHOICE { + * byName [1] Name, + * byKey [2] KeyHash } + *+ */ + public ASN1Primitive toASN1Primitive() + { + if (value instanceof ASN1OctetString) + { + return new DERTaggedObject(true, 2, value); + } + + return new DERTaggedObject(true, 1, value); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ocsp/ResponseBytes.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ocsp/ResponseBytes.java new file mode 100644 index 0000000..3433929 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ocsp/ResponseBytes.java @@ -0,0 +1,82 @@ +package org.bc.asn1.ocsp; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1ObjectIdentifier; +import org.bc.asn1.ASN1OctetString; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERSequence; + +public class ResponseBytes + extends ASN1Object +{ + ASN1ObjectIdentifier responseType; + ASN1OctetString response; + + public ResponseBytes( + ASN1ObjectIdentifier responseType, + ASN1OctetString response) + { + this.responseType = responseType; + this.response = response; + } + + public ResponseBytes( + ASN1Sequence seq) + { + responseType = (ASN1ObjectIdentifier)seq.getObjectAt(0); + response = (ASN1OctetString)seq.getObjectAt(1); + } + + public static ResponseBytes getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static ResponseBytes getInstance( + Object obj) + { + if (obj == null || obj instanceof ResponseBytes) + { + return (ResponseBytes)obj; + } + else if (obj instanceof ASN1Sequence) + { + return new ResponseBytes((ASN1Sequence)obj); + } + + throw new IllegalArgumentException("unknown object in factory: " + obj.getClass().getName()); + } + + public ASN1ObjectIdentifier getResponseType() + { + return responseType; + } + + public ASN1OctetString getResponse() + { + return response; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + *
+ * ResponseBytes ::= SEQUENCE { + * responseType OBJECT IDENTIFIER, + * response OCTET STRING } + *+ */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(responseType); + v.add(response); + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ocsp/ResponseData.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ocsp/ResponseData.java new file mode 100644 index 0000000..115382b --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ocsp/ResponseData.java @@ -0,0 +1,182 @@ +package org.bc.asn1.ocsp; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1GeneralizedTime; +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERGeneralizedTime; +import org.bc.asn1.DERSequence; +import org.bc.asn1.DERTaggedObject; +import org.bc.asn1.x509.Extensions; +import org.bc.asn1.x509.X509Extensions; + +public class ResponseData + extends ASN1Object +{ + private static final ASN1Integer V1 = new ASN1Integer(0); + + private boolean versionPresent; + + private ASN1Integer version; + private ResponderID responderID; + private ASN1GeneralizedTime producedAt; + private ASN1Sequence responses; + private Extensions responseExtensions; + + public ResponseData( + ASN1Integer version, + ResponderID responderID, + ASN1GeneralizedTime producedAt, + ASN1Sequence responses, + Extensions responseExtensions) + { + this.version = version; + this.responderID = responderID; + this.producedAt = producedAt; + this.responses = responses; + this.responseExtensions = responseExtensions; + } + + /** + * @deprecated use method taking Extensions + * @param responderID + * @param producedAt + * @param responses + * @param responseExtensions + */ + public ResponseData( + ResponderID responderID, + DERGeneralizedTime producedAt, + ASN1Sequence responses, + X509Extensions responseExtensions) + { + this(V1, responderID, ASN1GeneralizedTime.getInstance(producedAt), responses, Extensions.getInstance(responseExtensions)); + } + + public ResponseData( + ResponderID responderID, + ASN1GeneralizedTime producedAt, + ASN1Sequence responses, + Extensions responseExtensions) + { + this(V1, responderID, producedAt, responses, responseExtensions); + } + + private ResponseData( + ASN1Sequence seq) + { + int index = 0; + + if (seq.getObjectAt(0) instanceof ASN1TaggedObject) + { + ASN1TaggedObject o = (ASN1TaggedObject)seq.getObjectAt(0); + + if (o.getTagNo() == 0) + { + this.versionPresent = true; + this.version = ASN1Integer.getInstance( + (ASN1TaggedObject)seq.getObjectAt(0), true); + index++; + } + else + { + this.version = V1; + } + } + else + { + this.version = V1; + } + + this.responderID = ResponderID.getInstance(seq.getObjectAt(index++)); + this.producedAt = ASN1GeneralizedTime.getInstance(seq.getObjectAt(index++)); + this.responses = (ASN1Sequence)seq.getObjectAt(index++); + + if (seq.size() > index) + { + this.responseExtensions = Extensions.getInstance( + (ASN1TaggedObject)seq.getObjectAt(index), true); + } + } + + public static ResponseData getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static ResponseData getInstance( + Object obj) + { + if (obj instanceof ResponseData) + { + return (ResponseData)obj; + } + else if (obj != null) + { + return new ResponseData(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public ASN1Integer getVersion() + { + return version; + } + + public ResponderID getResponderID() + { + return responderID; + } + + public ASN1GeneralizedTime getProducedAt() + { + return producedAt; + } + + public ASN1Sequence getResponses() + { + return responses; + } + + public Extensions getResponseExtensions() + { + return responseExtensions; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + *
+ * ResponseData ::= SEQUENCE { + * version [0] EXPLICIT Version DEFAULT v1, + * responderID ResponderID, + * producedAt GeneralizedTime, + * responses SEQUENCE OF SingleResponse, + * responseExtensions [1] EXPLICIT Extensions OPTIONAL } + *+ */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + if (versionPresent || !version.equals(V1)) + { + v.add(new DERTaggedObject(true, 0, version)); + } + + v.add(responderID); + v.add(producedAt); + v.add(responses); + if (responseExtensions != null) + { + v.add(new DERTaggedObject(true, 1, responseExtensions)); + } + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ocsp/RevokedInfo.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ocsp/RevokedInfo.java new file mode 100644 index 0000000..4cbed3a --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ocsp/RevokedInfo.java @@ -0,0 +1,92 @@ +package org.bc.asn1.ocsp; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1GeneralizedTime; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DEREnumerated; +import org.bc.asn1.DERSequence; +import org.bc.asn1.DERTaggedObject; +import org.bc.asn1.x509.CRLReason; + +public class RevokedInfo + extends ASN1Object +{ + private ASN1GeneralizedTime revocationTime; + private CRLReason revocationReason; + + public RevokedInfo( + ASN1GeneralizedTime revocationTime, + CRLReason revocationReason) + { + this.revocationTime = revocationTime; + this.revocationReason = revocationReason; + } + + private RevokedInfo( + ASN1Sequence seq) + { + this.revocationTime = ASN1GeneralizedTime.getInstance(seq.getObjectAt(0)); + + if (seq.size() > 1) + { + this.revocationReason = CRLReason.getInstance(DEREnumerated.getInstance( + (ASN1TaggedObject)seq.getObjectAt(1), true)); + } + } + + public static RevokedInfo getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static RevokedInfo getInstance( + Object obj) + { + if (obj instanceof RevokedInfo) + { + return (RevokedInfo)obj; + } + else if (obj != null) + { + return new RevokedInfo(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public ASN1GeneralizedTime getRevocationTime() + { + return revocationTime; + } + + public CRLReason getRevocationReason() + { + return revocationReason; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + *
+ * RevokedInfo ::= SEQUENCE { + * revocationTime GeneralizedTime, + * revocationReason [0] EXPLICIT CRLReason OPTIONAL } + *+ */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(revocationTime); + if (revocationReason != null) + { + v.add(new DERTaggedObject(true, 0, revocationReason)); + } + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ocsp/ServiceLocator.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ocsp/ServiceLocator.java new file mode 100644 index 0000000..f7f3694 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ocsp/ServiceLocator.java @@ -0,0 +1,36 @@ +package org.bc.asn1.ocsp; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.DERSequence; +import org.bc.asn1.x500.X500Name; + +public class ServiceLocator + extends ASN1Object +{ + X500Name issuer; + ASN1Primitive locator; + + /** + * Produce an object suitable for an ASN1OutputStream. + *
+ * ServiceLocator ::= SEQUENCE { + * issuer Name, + * locator AuthorityInfoAccessSyntax OPTIONAL } + *+ */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(issuer); + + if (locator != null) + { + v.add(locator); + } + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ocsp/Signature.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ocsp/Signature.java new file mode 100644 index 0000000..a35101c --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ocsp/Signature.java @@ -0,0 +1,111 @@ +package org.bc.asn1.ocsp; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERBitString; +import org.bc.asn1.DERSequence; +import org.bc.asn1.DERTaggedObject; +import org.bc.asn1.x509.AlgorithmIdentifier; + +public class Signature + extends ASN1Object +{ + AlgorithmIdentifier signatureAlgorithm; + DERBitString signature; + ASN1Sequence certs; + + public Signature( + AlgorithmIdentifier signatureAlgorithm, + DERBitString signature) + { + this.signatureAlgorithm = signatureAlgorithm; + this.signature = signature; + } + + public Signature( + AlgorithmIdentifier signatureAlgorithm, + DERBitString signature, + ASN1Sequence certs) + { + this.signatureAlgorithm = signatureAlgorithm; + this.signature = signature; + this.certs = certs; + } + + private Signature( + ASN1Sequence seq) + { + signatureAlgorithm = AlgorithmIdentifier.getInstance(seq.getObjectAt(0)); + signature = (DERBitString)seq.getObjectAt(1); + + if (seq.size() == 3) + { + certs = ASN1Sequence.getInstance( + (ASN1TaggedObject)seq.getObjectAt(2), true); + } + } + + public static Signature getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static Signature getInstance( + Object obj) + { + if (obj instanceof Signature) + { + return (Signature)obj; + } + else if (obj != null) + { + return new Signature(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public AlgorithmIdentifier getSignatureAlgorithm() + { + return signatureAlgorithm; + } + + public DERBitString getSignature() + { + return signature; + } + + public ASN1Sequence getCerts() + { + return certs; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + *
+ * Signature ::= SEQUENCE { + * signatureAlgorithm AlgorithmIdentifier, + * signature BIT STRING, + * certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL} + *+ */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(signatureAlgorithm); + v.add(signature); + + if (certs != null) + { + v.add(new DERTaggedObject(true, 0, certs)); + } + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ocsp/SingleResponse.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ocsp/SingleResponse.java new file mode 100644 index 0000000..9c9e53d --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ocsp/SingleResponse.java @@ -0,0 +1,181 @@ +package org.bc.asn1.ocsp; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1GeneralizedTime; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERGeneralizedTime; +import org.bc.asn1.DERSequence; +import org.bc.asn1.DERTaggedObject; +import org.bc.asn1.x509.Extensions; +import org.bc.asn1.x509.X509Extensions; + +public class SingleResponse + extends ASN1Object +{ + private CertID certID; + private CertStatus certStatus; + private ASN1GeneralizedTime thisUpdate; + private ASN1GeneralizedTime nextUpdate; + private Extensions singleExtensions; + + /** + * @deprecated use method taking ASN1GeneralizedTime and Extensions + * @param certID + * @param certStatus + * @param thisUpdate + * @param nextUpdate + * @param singleExtensions + */ + public SingleResponse( + CertID certID, + CertStatus certStatus, + DERGeneralizedTime thisUpdate, + DERGeneralizedTime nextUpdate, + X509Extensions singleExtensions) + { + this(certID, certStatus, thisUpdate, nextUpdate, Extensions.getInstance(singleExtensions)); + } + + /** + * @deprecated use method taking ASN1GeneralizedTime and Extensions + * @param certID + * @param certStatus + * @param thisUpdate + * @param nextUpdate + * @param singleExtensions + */ + public SingleResponse( + CertID certID, + CertStatus certStatus, + DERGeneralizedTime thisUpdate, + DERGeneralizedTime nextUpdate, + Extensions singleExtensions) + { + this(certID, certStatus, ASN1GeneralizedTime.getInstance(thisUpdate), ASN1GeneralizedTime.getInstance(nextUpdate), Extensions.getInstance(singleExtensions)); + } + + public SingleResponse( + CertID certID, + CertStatus certStatus, + ASN1GeneralizedTime thisUpdate, + ASN1GeneralizedTime nextUpdate, + Extensions singleExtensions) + { + this.certID = certID; + this.certStatus = certStatus; + this.thisUpdate = thisUpdate; + this.nextUpdate = nextUpdate; + this.singleExtensions = singleExtensions; + } + + private SingleResponse( + ASN1Sequence seq) + { + this.certID = CertID.getInstance(seq.getObjectAt(0)); + this.certStatus = CertStatus.getInstance(seq.getObjectAt(1)); + this.thisUpdate = ASN1GeneralizedTime.getInstance(seq.getObjectAt(2)); + + if (seq.size() > 4) + { + this.nextUpdate = ASN1GeneralizedTime.getInstance( + (ASN1TaggedObject)seq.getObjectAt(3), true); + this.singleExtensions = Extensions.getInstance( + (ASN1TaggedObject)seq.getObjectAt(4), true); + } + else if (seq.size() > 3) + { + ASN1TaggedObject o = (ASN1TaggedObject)seq.getObjectAt(3); + + if (o.getTagNo() == 0) + { + this.nextUpdate = ASN1GeneralizedTime.getInstance(o, true); + } + else + { + this.singleExtensions = Extensions.getInstance(o, true); + } + } + } + + public static SingleResponse getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static SingleResponse getInstance( + Object obj) + { + if (obj instanceof SingleResponse) + { + return (SingleResponse)obj; + } + else if (obj != null) + { + return new SingleResponse(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public CertID getCertID() + { + return certID; + } + + public CertStatus getCertStatus() + { + return certStatus; + } + + public ASN1GeneralizedTime getThisUpdate() + { + return thisUpdate; + } + + public ASN1GeneralizedTime getNextUpdate() + { + return nextUpdate; + } + + public Extensions getSingleExtensions() + { + return singleExtensions; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + *
+ * SingleResponse ::= SEQUENCE { + * certID CertID, + * certStatus CertStatus, + * thisUpdate GeneralizedTime, + * nextUpdate [0] EXPLICIT GeneralizedTime OPTIONAL, + * singleExtensions [1] EXPLICIT Extensions OPTIONAL } + *+ */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(certID); + v.add(certStatus); + v.add(thisUpdate); + + if (nextUpdate != null) + { + v.add(new DERTaggedObject(true, 0, nextUpdate)); + } + + if (singleExtensions != null) + { + v.add(new DERTaggedObject(true, 1, singleExtensions)); + } + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ocsp/TBSRequest.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ocsp/TBSRequest.java new file mode 100644 index 0000000..1e5cd38 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ocsp/TBSRequest.java @@ -0,0 +1,172 @@ +package org.bc.asn1.ocsp; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERSequence; +import org.bc.asn1.DERTaggedObject; +import org.bc.asn1.x509.Extensions; +import org.bc.asn1.x509.GeneralName; +import org.bc.asn1.x509.X509Extensions; + +public class TBSRequest + extends ASN1Object +{ + private static final ASN1Integer V1 = new ASN1Integer(0); + + ASN1Integer version; + GeneralName requestorName; + ASN1Sequence requestList; + Extensions requestExtensions; + + boolean versionSet; + + /** + * @deprecated use method taking Extensions + * @param requestorName + * @param requestList + * @param requestExtensions + */ + public TBSRequest( + GeneralName requestorName, + ASN1Sequence requestList, + X509Extensions requestExtensions) + { + this.version = V1; + this.requestorName = requestorName; + this.requestList = requestList; + this.requestExtensions = Extensions.getInstance(requestExtensions); + } + + public TBSRequest( + GeneralName requestorName, + ASN1Sequence requestList, + Extensions requestExtensions) + { + this.version = V1; + this.requestorName = requestorName; + this.requestList = requestList; + this.requestExtensions = requestExtensions; + } + + private TBSRequest( + ASN1Sequence seq) + { + int index = 0; + + if (seq.getObjectAt(0) instanceof ASN1TaggedObject) + { + ASN1TaggedObject o = (ASN1TaggedObject)seq.getObjectAt(0); + + if (o.getTagNo() == 0) + { + versionSet = true; + version = ASN1Integer.getInstance((ASN1TaggedObject)seq.getObjectAt(0), true); + index++; + } + else + { + version = V1; + } + } + else + { + version = V1; + } + + if (seq.getObjectAt(index) instanceof ASN1TaggedObject) + { + requestorName = GeneralName.getInstance((ASN1TaggedObject)seq.getObjectAt(index++), true); + } + + requestList = (ASN1Sequence)seq.getObjectAt(index++); + + if (seq.size() == (index + 1)) + { + requestExtensions = Extensions.getInstance((ASN1TaggedObject)seq.getObjectAt(index), true); + } + } + + public static TBSRequest getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static TBSRequest getInstance( + Object obj) + { + if (obj instanceof TBSRequest) + { + return (TBSRequest)obj; + } + else if (obj != null) + { + return new TBSRequest(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public ASN1Integer getVersion() + { + return version; + } + + public GeneralName getRequestorName() + { + return requestorName; + } + + public ASN1Sequence getRequestList() + { + return requestList; + } + + public Extensions getRequestExtensions() + { + return requestExtensions; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + *
+ * TBSRequest ::= SEQUENCE { + * version [0] EXPLICIT Version DEFAULT v1, + * requestorName [1] EXPLICIT GeneralName OPTIONAL, + * requestList SEQUENCE OF Request, + * requestExtensions [2] EXPLICIT Extensions OPTIONAL } + *+ */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + // + // if default don't include - unless explicitly provided. Not strictly correct + // but required for some requests + // + if (!version.equals(V1) || versionSet) + { + v.add(new DERTaggedObject(true, 0, version)); + } + + if (requestorName != null) + { + v.add(new DERTaggedObject(true, 1, requestorName)); + } + + v.add(requestList); + + if (requestExtensions != null) + { + v.add(new DERTaggedObject(true, 2, requestExtensions)); + } + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/oiw/ElGamalParameter.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/oiw/ElGamalParameter.java new file mode 100644 index 0000000..2237092 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/oiw/ElGamalParameter.java @@ -0,0 +1,54 @@ +package org.bc.asn1.oiw; + +import java.math.BigInteger; +import java.util.Enumeration; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DERSequence; + +public class ElGamalParameter + extends ASN1Object +{ + ASN1Integer p, g; + + public ElGamalParameter( + BigInteger p, + BigInteger g) + { + this.p = new ASN1Integer(p); + this.g = new ASN1Integer(g); + } + + public ElGamalParameter( + ASN1Sequence seq) + { + Enumeration e = seq.getObjects(); + + p = (ASN1Integer)e.nextElement(); + g = (ASN1Integer)e.nextElement(); + } + + public BigInteger getP() + { + return p.getPositiveValue(); + } + + public BigInteger getG() + { + return g.getPositiveValue(); + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(p); + v.add(g); + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/oiw/OIWObjectIdentifiers.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/oiw/OIWObjectIdentifiers.java new file mode 100644 index 0000000..da7a754 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/oiw/OIWObjectIdentifiers.java @@ -0,0 +1,31 @@ +package org.bc.asn1.oiw; + +import org.bc.asn1.ASN1ObjectIdentifier; + +public interface OIWObjectIdentifiers +{ + // id-SHA1 OBJECT IDENTIFIER ::= + // {iso(1) identified-organization(3) oiw(14) secsig(3) algorithms(2) 26 } // + static final ASN1ObjectIdentifier md4WithRSA = new ASN1ObjectIdentifier("1.3.14.3.2.2"); + static final ASN1ObjectIdentifier md5WithRSA = new ASN1ObjectIdentifier("1.3.14.3.2.3"); + static final ASN1ObjectIdentifier md4WithRSAEncryption = new ASN1ObjectIdentifier("1.3.14.3.2.4"); + + static final ASN1ObjectIdentifier desECB = new ASN1ObjectIdentifier("1.3.14.3.2.6"); + static final ASN1ObjectIdentifier desCBC = new ASN1ObjectIdentifier("1.3.14.3.2.7"); + static final ASN1ObjectIdentifier desOFB = new ASN1ObjectIdentifier("1.3.14.3.2.8"); + static final ASN1ObjectIdentifier desCFB = new ASN1ObjectIdentifier("1.3.14.3.2.9"); + + static final ASN1ObjectIdentifier desEDE = new ASN1ObjectIdentifier("1.3.14.3.2.17"); + + static final ASN1ObjectIdentifier idSHA1 = new ASN1ObjectIdentifier("1.3.14.3.2.26"); + + static final ASN1ObjectIdentifier dsaWithSHA1 = new ASN1ObjectIdentifier("1.3.14.3.2.27"); + + static final ASN1ObjectIdentifier sha1WithRSA = new ASN1ObjectIdentifier("1.3.14.3.2.29"); + + // ElGamal Algorithm OBJECT IDENTIFIER ::= + // {iso(1) identified-organization(3) oiw(14) dirservsig(7) algorithm(2) encryption(1) 1 } + // + static final ASN1ObjectIdentifier elGamalAlgorithm = new ASN1ObjectIdentifier("1.3.14.7.2.1.1"); + +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/pkcs/Attribute.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/pkcs/Attribute.java new file mode 100644 index 0000000..88841fb --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/pkcs/Attribute.java @@ -0,0 +1,88 @@ +package org.bc.asn1.pkcs; + +import org.bc.asn1.ASN1Encodable; +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1ObjectIdentifier; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1Set; +import org.bc.asn1.DERSequence; + +public class Attribute + extends ASN1Object +{ + private ASN1ObjectIdentifier attrType; + private ASN1Set attrValues; + + /** + * return an Attribute object from the given object. + * + * @param o the object we want converted. + * @exception IllegalArgumentException if the object cannot be converted. + */ + public static Attribute getInstance( + Object o) + { + if (o == null || o instanceof Attribute) + { + return (Attribute)o; + } + + if (o instanceof ASN1Sequence) + { + return new Attribute((ASN1Sequence)o); + } + + throw new IllegalArgumentException("unknown object in factory: " + o.getClass().getName()); + } + + public Attribute( + ASN1Sequence seq) + { + attrType = (ASN1ObjectIdentifier)seq.getObjectAt(0); + attrValues = (ASN1Set)seq.getObjectAt(1); + } + + public Attribute( + ASN1ObjectIdentifier attrType, + ASN1Set attrValues) + { + this.attrType = attrType; + this.attrValues = attrValues; + } + + public ASN1ObjectIdentifier getAttrType() + { + return attrType; + } + + public ASN1Set getAttrValues() + { + return attrValues; + } + + public ASN1Encodable[] getAttributeValues() + { + return attrValues.toArray(); + } + + /** + * Produce an object suitable for an ASN1OutputStream. + *
+ * Attribute ::= SEQUENCE { + * attrType OBJECT IDENTIFIER, + * attrValues SET OF AttributeValue + * } + *+ */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(attrType); + v.add(attrValues); + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/pkcs/AuthenticatedSafe.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/pkcs/AuthenticatedSafe.java new file mode 100644 index 0000000..3ebdc60 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/pkcs/AuthenticatedSafe.java @@ -0,0 +1,74 @@ +package org.bc.asn1.pkcs; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.BERSequence; +import org.bc.asn1.DLSequence; + +public class AuthenticatedSafe + extends ASN1Object +{ + private ContentInfo[] info; + private boolean isBer = true; + + private AuthenticatedSafe( + ASN1Sequence seq) + { + info = new ContentInfo[seq.size()]; + + for (int i = 0; i != info.length; i++) + { + info[i] = ContentInfo.getInstance(seq.getObjectAt(i)); + } + + isBer = seq instanceof BERSequence; + } + + public static AuthenticatedSafe getInstance( + Object o) + { + if (o instanceof AuthenticatedSafe) + { + return (AuthenticatedSafe)o; + } + + if (o != null) + { + return new AuthenticatedSafe(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public AuthenticatedSafe( + ContentInfo[] info) + { + this.info = info; + } + + public ContentInfo[] getContentInfo() + { + return info; + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + for (int i = 0; i != info.length; i++) + { + v.add(info[i]); + } + + if (isBer) + { + return new BERSequence(v); + } + else + { + return new DLSequence(v); + } + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/pkcs/CRLBag.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/pkcs/CRLBag.java new file mode 100644 index 0000000..6f43aa4 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/pkcs/CRLBag.java @@ -0,0 +1,82 @@ +package org.bc.asn1.pkcs; + +import org.bc.asn1.ASN1Encodable; +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1ObjectIdentifier; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DERSequence; +import org.bc.asn1.DERTaggedObject; + +public class CRLBag + extends ASN1Object +{ + private ASN1ObjectIdentifier crlId; + private ASN1Encodable crlValue; + + private CRLBag( + ASN1Sequence seq) + { + this.crlId = (ASN1ObjectIdentifier)seq.getObjectAt(0); + this.crlValue = ((DERTaggedObject)seq.getObjectAt(1)).getObject(); + } + + public static CRLBag getInstance(Object o) + { + if (o instanceof CRLBag) + { + return (CRLBag)o; + } + else if (o != null) + { + return new CRLBag(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public CRLBag( + ASN1ObjectIdentifier crlId, + ASN1Encodable crlValue) + { + this.crlId = crlId; + this.crlValue = crlValue; + } + + public ASN1ObjectIdentifier getcrlId() + { + return crlId; + } + + public ASN1Encodable getCRLValue() + { + return crlValue; + } + + /** + *
+ CRLBag ::= SEQUENCE { + crlId BAG-TYPE.&id ({CRLTypes}), + crlValue [0] EXPLICIT BAG-TYPE.&Type ({CRLTypes}{@crlId}) + } + + x509CRL BAG-TYPE ::= {OCTET STRING IDENTIFIED BY {certTypes 1} + -- DER-encoded X.509 CRL stored in OCTET STRING + + CRLTypes BAG-TYPE ::= { + x509CRL, + ... -- For future extensions + } ++ */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(crlId); + v.add(new DERTaggedObject(0, crlValue)); + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/pkcs/CertBag.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/pkcs/CertBag.java new file mode 100644 index 0000000..df269c3 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/pkcs/CertBag.java @@ -0,0 +1,66 @@ +package org.bc.asn1.pkcs; + +import org.bc.asn1.ASN1Encodable; +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1ObjectIdentifier; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DERSequence; +import org.bc.asn1.DERTaggedObject; + +public class CertBag + extends ASN1Object +{ + private ASN1ObjectIdentifier certId; + private ASN1Encodable certValue; + + private CertBag( + ASN1Sequence seq) + { + this.certId = (ASN1ObjectIdentifier)seq.getObjectAt(0); + this.certValue = ((DERTaggedObject)seq.getObjectAt(1)).getObject(); + } + + public static CertBag getInstance(Object o) + { + if (o instanceof CertBag) + { + return (CertBag)o; + } + else if (o != null) + { + return new CertBag(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public CertBag( + ASN1ObjectIdentifier certId, + ASN1Encodable certValue) + { + this.certId = certId; + this.certValue = certValue; + } + + public ASN1ObjectIdentifier getCertId() + { + return certId; + } + + public ASN1Encodable getCertValue() + { + return certValue; + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(certId); + v.add(new DERTaggedObject(0, certValue)); + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/pkcs/CertificationRequest.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/pkcs/CertificationRequest.java new file mode 100644 index 0000000..58288d5 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/pkcs/CertificationRequest.java @@ -0,0 +1,91 @@ +package org.bc.asn1.pkcs; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DERBitString; +import org.bc.asn1.DERSequence; +import org.bc.asn1.x509.AlgorithmIdentifier; + +/** + * PKCS10 Certification request object. + *
+ * CertificationRequest ::= SEQUENCE { + * certificationRequestInfo CertificationRequestInfo, + * signatureAlgorithm AlgorithmIdentifier{{ SignatureAlgorithms }}, + * signature BIT STRING + * } + *+ */ +public class CertificationRequest + extends ASN1Object +{ + protected CertificationRequestInfo reqInfo = null; + protected AlgorithmIdentifier sigAlgId = null; + protected DERBitString sigBits = null; + + public static CertificationRequest getInstance(Object o) + { + if (o instanceof CertificationRequest) + { + return (CertificationRequest)o; + } + + if (o != null) + { + return new CertificationRequest(ASN1Sequence.getInstance(o)); + } + + return null; + } + + protected CertificationRequest() + { + } + + public CertificationRequest( + CertificationRequestInfo requestInfo, + AlgorithmIdentifier algorithm, + DERBitString signature) + { + this.reqInfo = requestInfo; + this.sigAlgId = algorithm; + this.sigBits = signature; + } + + public CertificationRequest( + ASN1Sequence seq) + { + reqInfo = CertificationRequestInfo.getInstance(seq.getObjectAt(0)); + sigAlgId = AlgorithmIdentifier.getInstance(seq.getObjectAt(1)); + sigBits = (DERBitString)seq.getObjectAt(2); + } + + public CertificationRequestInfo getCertificationRequestInfo() + { + return reqInfo; + } + + public AlgorithmIdentifier getSignatureAlgorithm() + { + return sigAlgId; + } + + public DERBitString getSignature() + { + return sigBits; + } + + public ASN1Primitive toASN1Primitive() + { + // Construct the CertificateRequest + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(reqInfo); + v.add(sigAlgId); + v.add(sigBits); + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/pkcs/CertificationRequestInfo.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/pkcs/CertificationRequestInfo.java new file mode 100644 index 0000000..9c85de3 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/pkcs/CertificationRequestInfo.java @@ -0,0 +1,148 @@ +package org.bc.asn1.pkcs; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1Set; +import org.bc.asn1.DERSequence; +import org.bc.asn1.DERTaggedObject; +import org.bc.asn1.x500.X500Name; +import org.bc.asn1.x509.SubjectPublicKeyInfo; +import org.bc.asn1.x509.X509Name; + +/** + * PKCS10 CertificationRequestInfo object. + *
+ * CertificationRequestInfo ::= SEQUENCE { + * version INTEGER { v1(0) } (v1,...), + * subject Name, + * subjectPKInfo SubjectPublicKeyInfo{{ PKInfoAlgorithms }}, + * attributes [0] Attributes{{ CRIAttributes }} + * } + * + * Attributes { ATTRIBUTE:IOSet } ::= SET OF Attribute{{ IOSet }} + * + * Attribute { ATTRIBUTE:IOSet } ::= SEQUENCE { + * type ATTRIBUTE.&id({IOSet}), + * values SET SIZE(1..MAX) OF ATTRIBUTE.&Type({IOSet}{\@type}) + * } + *+ */ +public class CertificationRequestInfo + extends ASN1Object +{ + ASN1Integer version = new ASN1Integer(0); + X500Name subject; + SubjectPublicKeyInfo subjectPKInfo; + ASN1Set attributes = null; + + public static CertificationRequestInfo getInstance( + Object obj) + { + if (obj instanceof CertificationRequestInfo) + { + return (CertificationRequestInfo)obj; + } + else if (obj != null) + { + return new CertificationRequestInfo(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public CertificationRequestInfo( + X500Name subject, + SubjectPublicKeyInfo pkInfo, + ASN1Set attributes) + { + this.subject = subject; + this.subjectPKInfo = pkInfo; + this.attributes = attributes; + + if ((subject == null) || (version == null) || (subjectPKInfo == null)) + { + throw new IllegalArgumentException("Not all mandatory fields set in CertificationRequestInfo generator."); + } + } + + /** + * @deprecated use X500Name method. + */ + public CertificationRequestInfo( + X509Name subject, + SubjectPublicKeyInfo pkInfo, + ASN1Set attributes) + { + this.subject = X500Name.getInstance(subject.toASN1Primitive()); + this.subjectPKInfo = pkInfo; + this.attributes = attributes; + + if ((subject == null) || (version == null) || (subjectPKInfo == null)) + { + throw new IllegalArgumentException("Not all mandatory fields set in CertificationRequestInfo generator."); + } + } + + public CertificationRequestInfo( + ASN1Sequence seq) + { + version = (ASN1Integer)seq.getObjectAt(0); + + subject = X500Name.getInstance(seq.getObjectAt(1)); + subjectPKInfo = SubjectPublicKeyInfo.getInstance(seq.getObjectAt(2)); + + // + // some CertificationRequestInfo objects seem to treat this field + // as optional. + // + if (seq.size() > 3) + { + DERTaggedObject tagobj = (DERTaggedObject)seq.getObjectAt(3); + attributes = ASN1Set.getInstance(tagobj, false); + } + + if ((subject == null) || (version == null) || (subjectPKInfo == null)) + { + throw new IllegalArgumentException("Not all mandatory fields set in CertificationRequestInfo generator."); + } + } + + public ASN1Integer getVersion() + { + return version; + } + + public X500Name getSubject() + { + return subject; + } + + public SubjectPublicKeyInfo getSubjectPublicKeyInfo() + { + return subjectPKInfo; + } + + public ASN1Set getAttributes() + { + return attributes; + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(version); + v.add(subject); + v.add(subjectPKInfo); + + if (attributes != null) + { + v.add(new DERTaggedObject(false, 0, attributes)); + } + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/pkcs/ContentInfo.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/pkcs/ContentInfo.java new file mode 100644 index 0000000..699c89d --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/pkcs/ContentInfo.java @@ -0,0 +1,102 @@ +package org.bc.asn1.pkcs; + +import java.util.Enumeration; + +import org.bc.asn1.ASN1Encodable; +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1ObjectIdentifier; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.BERSequence; +import org.bc.asn1.BERTaggedObject; +import org.bc.asn1.DLSequence; + +public class ContentInfo + extends ASN1Object + implements PKCSObjectIdentifiers +{ + private ASN1ObjectIdentifier contentType; + private ASN1Encodable content; + private boolean isBer = true; + + public static ContentInfo getInstance( + Object obj) + { + if (obj instanceof ContentInfo) + { + return (ContentInfo)obj; + } + + if (obj != null) + { + return new ContentInfo(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + private ContentInfo( + ASN1Sequence seq) + { + Enumeration e = seq.getObjects(); + + contentType = (ASN1ObjectIdentifier)e.nextElement(); + + if (e.hasMoreElements()) + { + content = ((ASN1TaggedObject)e.nextElement()).getObject(); + } + + isBer = seq instanceof BERSequence; + } + + public ContentInfo( + ASN1ObjectIdentifier contentType, + ASN1Encodable content) + { + this.contentType = contentType; + this.content = content; + } + + public ASN1ObjectIdentifier getContentType() + { + return contentType; + } + + public ASN1Encodable getContent() + { + return content; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + *
+ * ContentInfo ::= SEQUENCE { + * contentType ContentType, + * content + * [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL } + *+ */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(contentType); + + if (content != null) + { + v.add(new BERTaggedObject(true, 0, content)); + } + + if (isBer) + { + return new BERSequence(v); + } + else + { + return new DLSequence(v); + } + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/pkcs/DHParameter.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/pkcs/DHParameter.java new file mode 100644 index 0000000..d026762 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/pkcs/DHParameter.java @@ -0,0 +1,104 @@ +package org.bc.asn1.pkcs; + +import java.math.BigInteger; +import java.util.Enumeration; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DERSequence; + +public class DHParameter + extends ASN1Object +{ + ASN1Integer p, g, l; + + public DHParameter( + BigInteger p, + BigInteger g, + int l) + { + this.p = new ASN1Integer(p); + this.g = new ASN1Integer(g); + + if (l != 0) + { + this.l = new ASN1Integer(l); + } + else + { + this.l = null; + } + } + + public static DHParameter getInstance( + Object obj) + { + if (obj instanceof DHParameter) + { + return (DHParameter)obj; + } + + if (obj != null) + { + return new DHParameter(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + private DHParameter( + ASN1Sequence seq) + { + Enumeration e = seq.getObjects(); + + p = ASN1Integer.getInstance(e.nextElement()); + g = ASN1Integer.getInstance(e.nextElement()); + + if (e.hasMoreElements()) + { + l = (ASN1Integer)e.nextElement(); + } + else + { + l = null; + } + } + + public BigInteger getP() + { + return p.getPositiveValue(); + } + + public BigInteger getG() + { + return g.getPositiveValue(); + } + + public BigInteger getL() + { + if (l == null) + { + return null; + } + + return l.getPositiveValue(); + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(p); + v.add(g); + + if (this.getL() != null) + { + v.add(l); + } + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/pkcs/EncryptedData.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/pkcs/EncryptedData.java new file mode 100644 index 0000000..3da0bd7 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/pkcs/EncryptedData.java @@ -0,0 +1,115 @@ +package org.bc.asn1.pkcs; + +import org.bc.asn1.ASN1Encodable; +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1ObjectIdentifier; +import org.bc.asn1.ASN1OctetString; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.BERSequence; +import org.bc.asn1.BERTaggedObject; +import org.bc.asn1.x509.AlgorithmIdentifier; + +/** + * The EncryptedData object. + *
+ * EncryptedData ::= SEQUENCE { + * version Version, + * encryptedContentInfo EncryptedContentInfo + * } + * + * + * EncryptedContentInfo ::= SEQUENCE { + * contentType ContentType, + * contentEncryptionAlgorithm ContentEncryptionAlgorithmIdentifier, + * encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL + * } + * + * EncryptedContent ::= OCTET STRING + *+ */ +public class EncryptedData + extends ASN1Object +{ + ASN1Sequence data; + ASN1ObjectIdentifier bagId; + ASN1Primitive bagValue; + + public static EncryptedData getInstance( + Object obj) + { + if (obj instanceof EncryptedData) + { + return (EncryptedData)obj; + } + + if (obj != null) + { + return new EncryptedData(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + private EncryptedData( + ASN1Sequence seq) + { + int version = ((ASN1Integer)seq.getObjectAt(0)).getValue().intValue(); + + if (version != 0) + { + throw new IllegalArgumentException("sequence not version 0"); + } + + this.data = ASN1Sequence.getInstance(seq.getObjectAt(1)); + } + + public EncryptedData( + ASN1ObjectIdentifier contentType, + AlgorithmIdentifier encryptionAlgorithm, + ASN1Encodable content) + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(contentType); + v.add(encryptionAlgorithm.toASN1Primitive()); + v.add(new BERTaggedObject(false, 0, content)); + + data = new BERSequence(v); + } + + public ASN1ObjectIdentifier getContentType() + { + return ASN1ObjectIdentifier.getInstance(data.getObjectAt(0)); + } + + public AlgorithmIdentifier getEncryptionAlgorithm() + { + return AlgorithmIdentifier.getInstance(data.getObjectAt(1)); + } + + public ASN1OctetString getContent() + { + if (data.size() == 3) + { + ASN1TaggedObject o = ASN1TaggedObject.getInstance(data.getObjectAt(2)); + + return ASN1OctetString.getInstance(o, false); + } + + return null; + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(new ASN1Integer(0)); + v.add(data); + + return new BERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/pkcs/EncryptedPrivateKeyInfo.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/pkcs/EncryptedPrivateKeyInfo.java new file mode 100644 index 0000000..03b908f --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/pkcs/EncryptedPrivateKeyInfo.java @@ -0,0 +1,86 @@ +package org.bc.asn1.pkcs; + +import java.util.Enumeration; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1OctetString; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DEROctetString; +import org.bc.asn1.DERSequence; +import org.bc.asn1.x509.AlgorithmIdentifier; + +public class EncryptedPrivateKeyInfo + extends ASN1Object +{ + private AlgorithmIdentifier algId; + private ASN1OctetString data; + + private EncryptedPrivateKeyInfo( + ASN1Sequence seq) + { + Enumeration e = seq.getObjects(); + + algId = AlgorithmIdentifier.getInstance(e.nextElement()); + data = ASN1OctetString.getInstance(e.nextElement()); + } + + public EncryptedPrivateKeyInfo( + AlgorithmIdentifier algId, + byte[] encoding) + { + this.algId = algId; + this.data = new DEROctetString(encoding); + } + + public static EncryptedPrivateKeyInfo getInstance( + Object obj) + { + if (obj instanceof EncryptedPrivateKeyInfo) + { + return (EncryptedPrivateKeyInfo)obj; + } + else if (obj != null) + { + return new EncryptedPrivateKeyInfo(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public AlgorithmIdentifier getEncryptionAlgorithm() + { + return algId; + } + + public byte[] getEncryptedData() + { + return data.getOctets(); + } + + /** + * Produce an object suitable for an ASN1OutputStream. + *
+ * EncryptedPrivateKeyInfo ::= SEQUENCE { + * encryptionAlgorithm AlgorithmIdentifier {{KeyEncryptionAlgorithms}}, + * encryptedData EncryptedData + * } + * + * EncryptedData ::= OCTET STRING + * + * KeyEncryptionAlgorithms ALGORITHM-IDENTIFIER ::= { + * ... -- For local profiles + * } + *+ */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(algId); + v.add(data); + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/pkcs/EncryptionScheme.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/pkcs/EncryptionScheme.java new file mode 100644 index 0000000..87a9f31 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/pkcs/EncryptionScheme.java @@ -0,0 +1,55 @@ +package org.bc.asn1.pkcs; + +import org.bc.asn1.ASN1Encodable; +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1ObjectIdentifier; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DERSequence; +import org.bc.asn1.x509.AlgorithmIdentifier; + +public class EncryptionScheme + extends AlgorithmIdentifier +{ + public EncryptionScheme( + ASN1ObjectIdentifier objectId, + ASN1Encodable parameters) + { + super(objectId, parameters); + } + + EncryptionScheme( + ASN1Sequence seq) + { + this((ASN1ObjectIdentifier)seq.getObjectAt(0), seq.getObjectAt(1)); + } + + public static final AlgorithmIdentifier getInstance(Object obj) + { + if (obj instanceof EncryptionScheme) + { + return (EncryptionScheme)obj; + } + else if (obj instanceof ASN1Sequence) + { + return new EncryptionScheme((ASN1Sequence)obj); + } + + throw new IllegalArgumentException("unknown object in factory: " + obj.getClass().getName()); + } + + public ASN1Primitive getObject() + { + return (ASN1Primitive)getParameters(); + } + + public ASN1Primitive getASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(getObjectId()); + v.add(getParameters()); + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/pkcs/IssuerAndSerialNumber.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/pkcs/IssuerAndSerialNumber.java new file mode 100644 index 0000000..3476caa --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/pkcs/IssuerAndSerialNumber.java @@ -0,0 +1,85 @@ +package org.bc.asn1.pkcs; + +import java.math.BigInteger; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DERSequence; +import org.bc.asn1.x500.X500Name; +import org.bc.asn1.x509.X509Name; + +public class IssuerAndSerialNumber + extends ASN1Object +{ + X500Name name; + ASN1Integer certSerialNumber; + + public static IssuerAndSerialNumber getInstance( + Object obj) + { + if (obj instanceof IssuerAndSerialNumber) + { + return (IssuerAndSerialNumber)obj; + } + else if (obj != null) + { + return new IssuerAndSerialNumber(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + private IssuerAndSerialNumber( + ASN1Sequence seq) + { + this.name = X500Name.getInstance(seq.getObjectAt(0)); + this.certSerialNumber = (ASN1Integer)seq.getObjectAt(1); + } + + public IssuerAndSerialNumber( + X509Name name, + BigInteger certSerialNumber) + { + this.name = X500Name.getInstance(name.toASN1Primitive()); + this.certSerialNumber = new ASN1Integer(certSerialNumber); + } + + public IssuerAndSerialNumber( + X509Name name, + ASN1Integer certSerialNumber) + { + this.name = X500Name.getInstance(name.toASN1Primitive()); + this.certSerialNumber = certSerialNumber; + } + + public IssuerAndSerialNumber( + X500Name name, + BigInteger certSerialNumber) + { + this.name = name; + this.certSerialNumber = new ASN1Integer(certSerialNumber); + } + + public X500Name getName() + { + return name; + } + + public ASN1Integer getCertificateSerialNumber() + { + return certSerialNumber; + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(name); + v.add(certSerialNumber); + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/pkcs/KeyDerivationFunc.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/pkcs/KeyDerivationFunc.java new file mode 100644 index 0000000..18a7498 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/pkcs/KeyDerivationFunc.java @@ -0,0 +1,23 @@ +package org.bc.asn1.pkcs; + +import org.bc.asn1.ASN1Encodable; +import org.bc.asn1.ASN1ObjectIdentifier; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.x509.AlgorithmIdentifier; + +public class KeyDerivationFunc + extends AlgorithmIdentifier +{ + KeyDerivationFunc( + ASN1Sequence seq) + { + super(seq); + } + + public KeyDerivationFunc( + ASN1ObjectIdentifier id, + ASN1Encodable params) + { + super(id, params); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/pkcs/MacData.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/pkcs/MacData.java new file mode 100644 index 0000000..d89539b --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/pkcs/MacData.java @@ -0,0 +1,106 @@ +package org.bc.asn1.pkcs; + +import java.math.BigInteger; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1OctetString; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DEROctetString; +import org.bc.asn1.DERSequence; +import org.bc.asn1.x509.DigestInfo; + +public class MacData + extends ASN1Object +{ + private static final BigInteger ONE = BigInteger.valueOf(1); + + DigestInfo digInfo; + byte[] salt; + BigInteger iterationCount; + + public static MacData getInstance( + Object obj) + { + if (obj instanceof MacData) + { + return (MacData)obj; + } + else if (obj != null) + { + return new MacData(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + private MacData( + ASN1Sequence seq) + { + this.digInfo = DigestInfo.getInstance(seq.getObjectAt(0)); + + this.salt = ((ASN1OctetString)seq.getObjectAt(1)).getOctets(); + + if (seq.size() == 3) + { + this.iterationCount = ((ASN1Integer)seq.getObjectAt(2)).getValue(); + } + else + { + this.iterationCount = ONE; + } + } + + public MacData( + DigestInfo digInfo, + byte[] salt, + int iterationCount) + { + this.digInfo = digInfo; + this.salt = salt; + this.iterationCount = BigInteger.valueOf(iterationCount); + } + + public DigestInfo getMac() + { + return digInfo; + } + + public byte[] getSalt() + { + return salt; + } + + public BigInteger getIterationCount() + { + return iterationCount; + } + + /** + *
+ * MacData ::= SEQUENCE { + * mac DigestInfo, + * macSalt OCTET STRING, + * iterations INTEGER DEFAULT 1 + * -- Note: The default is for historic reasons and its use is deprecated. A + * -- higher value, like 1024 is recommended. + *+ * @return the basic ASN1Primitive construction. + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(digInfo); + v.add(new DEROctetString(salt)); + + if (!iterationCount.equals(ONE)) + { + v.add(new ASN1Integer(iterationCount)); + } + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/pkcs/PBEParameter.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/pkcs/PBEParameter.java new file mode 100644 index 0000000..dc7f914 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/pkcs/PBEParameter.java @@ -0,0 +1,73 @@ +package org.bc.asn1.pkcs; + +import java.math.BigInteger; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1OctetString; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DEROctetString; +import org.bc.asn1.DERSequence; + +public class PBEParameter + extends ASN1Object +{ + ASN1Integer iterations; + ASN1OctetString salt; + + public PBEParameter( + byte[] salt, + int iterations) + { + if (salt.length != 8) + { + throw new IllegalArgumentException("salt length must be 8"); + } + this.salt = new DEROctetString(salt); + this.iterations = new ASN1Integer(iterations); + } + + private PBEParameter( + ASN1Sequence seq) + { + salt = (ASN1OctetString)seq.getObjectAt(0); + iterations = (ASN1Integer)seq.getObjectAt(1); + } + + public static PBEParameter getInstance( + Object obj) + { + if (obj instanceof PBEParameter) + { + return (PBEParameter)obj; + } + else if (obj != null) + { + return new PBEParameter(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public BigInteger getIterationCount() + { + return iterations.getValue(); + } + + public byte[] getSalt() + { + return salt.getOctets(); + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(salt); + v.add(iterations); + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/pkcs/PBES2Algorithms.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/pkcs/PBES2Algorithms.java new file mode 100644 index 0000000..842a046 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/pkcs/PBES2Algorithms.java @@ -0,0 +1,77 @@ +package org.bc.asn1.pkcs; + +import java.util.Enumeration; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1ObjectIdentifier; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DERSequence; +import org.bc.asn1.x509.AlgorithmIdentifier; + +/** + * @deprecated - use AlgorithmIdentifier and PBES2Parameters + */ +public class PBES2Algorithms + extends AlgorithmIdentifier implements PKCSObjectIdentifiers +{ + private ASN1ObjectIdentifier objectId; + private KeyDerivationFunc func; + private EncryptionScheme scheme; + + public PBES2Algorithms( + ASN1Sequence obj) + { + super(obj); + + Enumeration e = obj.getObjects(); + + objectId = (ASN1ObjectIdentifier)e.nextElement(); + + ASN1Sequence seq = (ASN1Sequence)e.nextElement(); + + e = seq.getObjects(); + + ASN1Sequence funcSeq = (ASN1Sequence)e.nextElement(); + + if (funcSeq.getObjectAt(0).equals(id_PBKDF2)) + { + func = new KeyDerivationFunc(id_PBKDF2, PBKDF2Params.getInstance(funcSeq.getObjectAt(1))); + } + else + { + func = new KeyDerivationFunc(funcSeq); + } + + scheme = new EncryptionScheme((ASN1Sequence)e.nextElement()); + } + + public ASN1ObjectIdentifier getObjectId() + { + return objectId; + } + + public KeyDerivationFunc getKeyDerivationFunc() + { + return func; + } + + public EncryptionScheme getEncryptionScheme() + { + return scheme; + } + + public ASN1Primitive getASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector subV = new ASN1EncodableVector(); + + v.add(objectId); + + subV.add(func); + subV.add(scheme); + v.add(new DERSequence(subV)); + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/pkcs/PBES2Parameters.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/pkcs/PBES2Parameters.java new file mode 100644 index 0000000..037e400 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/pkcs/PBES2Parameters.java @@ -0,0 +1,72 @@ +package org.bc.asn1.pkcs; + +import java.util.Enumeration; + +import org.bc.asn1.ASN1Encodable; +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DERSequence; + +public class PBES2Parameters + extends ASN1Object + implements PKCSObjectIdentifiers +{ + private KeyDerivationFunc func; + private EncryptionScheme scheme; + + public static PBES2Parameters getInstance( + Object obj) + { + if (obj== null || obj instanceof PBES2Parameters) + { + return (PBES2Parameters)obj; + } + + if (obj instanceof ASN1Sequence) + { + return new PBES2Parameters((ASN1Sequence)obj); + } + + throw new IllegalArgumentException("unknown object in factory: " + obj.getClass().getName()); + } + + public PBES2Parameters( + ASN1Sequence obj) + { + Enumeration e = obj.getObjects(); + ASN1Sequence funcSeq = ASN1Sequence.getInstance(((ASN1Encodable)e.nextElement()).toASN1Primitive()); + + if (funcSeq.getObjectAt(0).equals(id_PBKDF2)) + { + func = new KeyDerivationFunc(id_PBKDF2, PBKDF2Params.getInstance(funcSeq.getObjectAt(1))); + } + else + { + func = new KeyDerivationFunc(funcSeq); + } + + scheme = (EncryptionScheme)EncryptionScheme.getInstance(e.nextElement()); + } + + public KeyDerivationFunc getKeyDerivationFunc() + { + return func; + } + + public EncryptionScheme getEncryptionScheme() + { + return scheme; + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(func); + v.add(scheme); + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/pkcs/PBKDF2Params.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/pkcs/PBKDF2Params.java new file mode 100644 index 0000000..bcd3cbc --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/pkcs/PBKDF2Params.java @@ -0,0 +1,108 @@ +package org.bc.asn1.pkcs; + +import java.math.BigInteger; +import java.util.Enumeration; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1OctetString; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DEROctetString; +import org.bc.asn1.DERSequence; + +public class PBKDF2Params + extends ASN1Object +{ + private ASN1OctetString octStr; + private ASN1Integer iterationCount; + private ASN1Integer keyLength; + + public static PBKDF2Params getInstance( + Object obj) + { + if (obj instanceof PBKDF2Params) + { + return (PBKDF2Params)obj; + } + + if (obj != null) + { + return new PBKDF2Params(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public PBKDF2Params( + byte[] salt, + int iterationCount) + { + this.octStr = new DEROctetString(salt); + this.iterationCount = new ASN1Integer(iterationCount); + } + + public PBKDF2Params( + byte[] salt, + int iterationCount, + int keyLength) + { + this(salt, iterationCount); + + this.keyLength = new ASN1Integer(keyLength); + } + + private PBKDF2Params( + ASN1Sequence seq) + { + Enumeration e = seq.getObjects(); + + octStr = (ASN1OctetString)e.nextElement(); + iterationCount = (ASN1Integer)e.nextElement(); + + if (e.hasMoreElements()) + { + keyLength = (ASN1Integer)e.nextElement(); + } + else + { + keyLength = null; + } + } + + public byte[] getSalt() + { + return octStr.getOctets(); + } + + public BigInteger getIterationCount() + { + return iterationCount.getValue(); + } + + public BigInteger getKeyLength() + { + if (keyLength != null) + { + return keyLength.getValue(); + } + + return null; + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(octStr); + v.add(iterationCount); + + if (keyLength != null) + { + v.add(keyLength); + } + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/pkcs/PKCS12PBEParams.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/pkcs/PKCS12PBEParams.java new file mode 100644 index 0000000..48d1ad3 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/pkcs/PKCS12PBEParams.java @@ -0,0 +1,69 @@ +package org.bc.asn1.pkcs; + +import java.math.BigInteger; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1OctetString; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DEROctetString; +import org.bc.asn1.DERSequence; + +public class PKCS12PBEParams + extends ASN1Object +{ + ASN1Integer iterations; + ASN1OctetString iv; + + public PKCS12PBEParams( + byte[] salt, + int iterations) + { + this.iv = new DEROctetString(salt); + this.iterations = new ASN1Integer(iterations); + } + + private PKCS12PBEParams( + ASN1Sequence seq) + { + iv = (ASN1OctetString)seq.getObjectAt(0); + iterations = ASN1Integer.getInstance(seq.getObjectAt(1)); + } + + public static PKCS12PBEParams getInstance( + Object obj) + { + if (obj instanceof PKCS12PBEParams) + { + return (PKCS12PBEParams)obj; + } + else if (obj != null) + { + return new PKCS12PBEParams(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public BigInteger getIterations() + { + return iterations.getValue(); + } + + public byte[] getIV() + { + return iv.getOctets(); + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(iv); + v.add(iterations); + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/pkcs/PKCSObjectIdentifiers.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/pkcs/PKCSObjectIdentifiers.java new file mode 100644 index 0000000..911e9e0 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/pkcs/PKCSObjectIdentifiers.java @@ -0,0 +1,258 @@ +package org.bc.asn1.pkcs; + +import org.bc.asn1.ASN1ObjectIdentifier; + +public interface PKCSObjectIdentifiers +{ + // + // pkcs-1 OBJECT IDENTIFIER ::= { + // iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 1 } + // + static final ASN1ObjectIdentifier pkcs_1 = new ASN1ObjectIdentifier("1.2.840.113549.1.1"); + static final ASN1ObjectIdentifier rsaEncryption = pkcs_1.branch("1"); + static final ASN1ObjectIdentifier md2WithRSAEncryption = pkcs_1.branch("2"); + static final ASN1ObjectIdentifier md4WithRSAEncryption = pkcs_1.branch("3"); + static final ASN1ObjectIdentifier md5WithRSAEncryption = pkcs_1.branch("4"); + static final ASN1ObjectIdentifier sha1WithRSAEncryption = pkcs_1.branch("5"); + static final ASN1ObjectIdentifier srsaOAEPEncryptionSET = pkcs_1.branch("6"); + static final ASN1ObjectIdentifier id_RSAES_OAEP = pkcs_1.branch("7"); + static final ASN1ObjectIdentifier id_mgf1 = pkcs_1.branch("8"); + static final ASN1ObjectIdentifier id_pSpecified = pkcs_1.branch("9"); + static final ASN1ObjectIdentifier id_RSASSA_PSS = pkcs_1.branch("10"); + static final ASN1ObjectIdentifier sha256WithRSAEncryption = pkcs_1.branch("11"); + static final ASN1ObjectIdentifier sha384WithRSAEncryption = pkcs_1.branch("12"); + static final ASN1ObjectIdentifier sha512WithRSAEncryption = pkcs_1.branch("13"); + static final ASN1ObjectIdentifier sha224WithRSAEncryption = pkcs_1.branch("14"); + + // + // pkcs-3 OBJECT IDENTIFIER ::= { + // iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 3 } + // + static final ASN1ObjectIdentifier pkcs_3 = new ASN1ObjectIdentifier("1.2.840.113549.1.3"); + static final ASN1ObjectIdentifier dhKeyAgreement = pkcs_3.branch("1"); + + // + // pkcs-5 OBJECT IDENTIFIER ::= { + // iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 5 } + // + static final ASN1ObjectIdentifier pkcs_5 = new ASN1ObjectIdentifier("1.2.840.113549.1.5"); + + static final ASN1ObjectIdentifier pbeWithMD2AndDES_CBC = pkcs_5.branch("1"); + static final ASN1ObjectIdentifier pbeWithMD2AndRC2_CBC = pkcs_5.branch("4"); + static final ASN1ObjectIdentifier pbeWithMD5AndDES_CBC = pkcs_5.branch("3"); + static final ASN1ObjectIdentifier pbeWithMD5AndRC2_CBC = pkcs_5.branch("6"); + static final ASN1ObjectIdentifier pbeWithSHA1AndDES_CBC = pkcs_5.branch("10"); + static final ASN1ObjectIdentifier pbeWithSHA1AndRC2_CBC = pkcs_5.branch("11"); + + static final ASN1ObjectIdentifier id_PBES2 = pkcs_5.branch("13"); + + static final ASN1ObjectIdentifier id_PBKDF2 = pkcs_5.branch("12"); + + // + // encryptionAlgorithm OBJECT IDENTIFIER ::= { + // iso(1) member-body(2) us(840) rsadsi(113549) 3 } + // + static final ASN1ObjectIdentifier encryptionAlgorithm = new ASN1ObjectIdentifier("1.2.840.113549.3"); + + static final ASN1ObjectIdentifier des_EDE3_CBC = encryptionAlgorithm.branch("7"); + static final ASN1ObjectIdentifier RC2_CBC = encryptionAlgorithm.branch("2"); + static final ASN1ObjectIdentifier rc4 = encryptionAlgorithm.branch("4"); + + // + // object identifiers for digests + // + static final ASN1ObjectIdentifier digestAlgorithm = new ASN1ObjectIdentifier("1.2.840.113549.2"); + // + // md2 OBJECT IDENTIFIER ::= + // {iso(1) member-body(2) US(840) rsadsi(113549) digestAlgorithm(2) 2} + // + static final ASN1ObjectIdentifier md2 = digestAlgorithm.branch("2"); + + // + // md4 OBJECT IDENTIFIER ::= + // {iso(1) member-body(2) US(840) rsadsi(113549) digestAlgorithm(2) 4} + // + static final ASN1ObjectIdentifier md4 = digestAlgorithm.branch("4"); + + // + // md5 OBJECT IDENTIFIER ::= + // {iso(1) member-body(2) US(840) rsadsi(113549) digestAlgorithm(2) 5} + // + static final ASN1ObjectIdentifier md5 = digestAlgorithm.branch("5"); + + static final ASN1ObjectIdentifier id_hmacWithSHA1 = digestAlgorithm.branch("7"); + static final ASN1ObjectIdentifier id_hmacWithSHA224 = digestAlgorithm.branch("8"); + static final ASN1ObjectIdentifier id_hmacWithSHA256 = digestAlgorithm.branch("9"); + static final ASN1ObjectIdentifier id_hmacWithSHA384 = digestAlgorithm.branch("10"); + static final ASN1ObjectIdentifier id_hmacWithSHA512 = digestAlgorithm.branch("11"); + + // + // pkcs-7 OBJECT IDENTIFIER ::= { + // iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 7 } + // + static final String pkcs_7 = "1.2.840.113549.1.7"; + static final ASN1ObjectIdentifier data = new ASN1ObjectIdentifier(pkcs_7 + ".1"); + static final ASN1ObjectIdentifier signedData = new ASN1ObjectIdentifier(pkcs_7 + ".2"); + static final ASN1ObjectIdentifier envelopedData = new ASN1ObjectIdentifier(pkcs_7 + ".3"); + static final ASN1ObjectIdentifier signedAndEnvelopedData = new ASN1ObjectIdentifier(pkcs_7 + ".4"); + static final ASN1ObjectIdentifier digestedData = new ASN1ObjectIdentifier(pkcs_7 + ".5"); + static final ASN1ObjectIdentifier encryptedData = new ASN1ObjectIdentifier(pkcs_7 + ".6"); + + // + // pkcs-9 OBJECT IDENTIFIER ::= { + // iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 9 } + // + static final ASN1ObjectIdentifier pkcs_9 = new ASN1ObjectIdentifier("1.2.840.113549.1.9"); + + static final ASN1ObjectIdentifier pkcs_9_at_emailAddress = pkcs_9.branch("1"); + static final ASN1ObjectIdentifier pkcs_9_at_unstructuredName = pkcs_9.branch("2"); + static final ASN1ObjectIdentifier pkcs_9_at_contentType = pkcs_9.branch("3"); + static final ASN1ObjectIdentifier pkcs_9_at_messageDigest = pkcs_9.branch("4"); + static final ASN1ObjectIdentifier pkcs_9_at_signingTime = pkcs_9.branch("5"); + static final ASN1ObjectIdentifier pkcs_9_at_counterSignature = pkcs_9.branch("6"); + static final ASN1ObjectIdentifier pkcs_9_at_challengePassword = pkcs_9.branch("7"); + static final ASN1ObjectIdentifier pkcs_9_at_unstructuredAddress = pkcs_9.branch("8"); + static final ASN1ObjectIdentifier pkcs_9_at_extendedCertificateAttributes = pkcs_9.branch("9"); + + static final ASN1ObjectIdentifier pkcs_9_at_signingDescription = pkcs_9.branch("13"); + static final ASN1ObjectIdentifier pkcs_9_at_extensionRequest = pkcs_9.branch("14"); + static final ASN1ObjectIdentifier pkcs_9_at_smimeCapabilities = pkcs_9.branch("15"); + + static final ASN1ObjectIdentifier pkcs_9_at_friendlyName = pkcs_9.branch("20"); + static final ASN1ObjectIdentifier pkcs_9_at_localKeyId = pkcs_9.branch("21"); + + /** @deprecated use x509Certificate instead */ + static final ASN1ObjectIdentifier x509certType = pkcs_9.branch("22.1"); + + static final ASN1ObjectIdentifier certTypes = pkcs_9.branch("22"); + static final ASN1ObjectIdentifier x509Certificate = certTypes.branch("1"); + static final ASN1ObjectIdentifier sdsiCertificate = certTypes.branch("2"); + + static final ASN1ObjectIdentifier crlTypes = pkcs_9.branch("23"); + static final ASN1ObjectIdentifier x509Crl = crlTypes.branch("1"); + + static final ASN1ObjectIdentifier id_alg_PWRI_KEK = pkcs_9.branch("16.3.9"); + + // + // SMIME capability sub oids. + // + static final ASN1ObjectIdentifier preferSignedData = pkcs_9.branch("15.1"); + static final ASN1ObjectIdentifier canNotDecryptAny = pkcs_9.branch("15.2"); + static final ASN1ObjectIdentifier sMIMECapabilitiesVersions = pkcs_9.branch("15.3"); + + // + // id-ct OBJECT IDENTIFIER ::= {iso(1) member-body(2) usa(840) + // rsadsi(113549) pkcs(1) pkcs-9(9) smime(16) ct(1)} + // + static final ASN1ObjectIdentifier id_ct = new ASN1ObjectIdentifier("1.2.840.113549.1.9.16.1"); + + static final ASN1ObjectIdentifier id_ct_authData = id_ct.branch("2"); + static final ASN1ObjectIdentifier id_ct_TSTInfo = id_ct.branch("4"); + static final ASN1ObjectIdentifier id_ct_compressedData = id_ct.branch("9"); + static final ASN1ObjectIdentifier id_ct_authEnvelopedData = id_ct.branch("23"); + static final ASN1ObjectIdentifier id_ct_timestampedData = id_ct.branch("31"); + + // + // id-cti OBJECT IDENTIFIER ::= {iso(1) member-body(2) usa(840) + // rsadsi(113549) pkcs(1) pkcs-9(9) smime(16) cti(6)} + // + static final ASN1ObjectIdentifier id_cti = new ASN1ObjectIdentifier("1.2.840.113549.1.9.16.6"); + + static final ASN1ObjectIdentifier id_cti_ets_proofOfOrigin = id_cti.branch("1"); + static final ASN1ObjectIdentifier id_cti_ets_proofOfReceipt = id_cti.branch("2"); + static final ASN1ObjectIdentifier id_cti_ets_proofOfDelivery = id_cti.branch("3"); + static final ASN1ObjectIdentifier id_cti_ets_proofOfSender = id_cti.branch("4"); + static final ASN1ObjectIdentifier id_cti_ets_proofOfApproval = id_cti.branch("5"); + static final ASN1ObjectIdentifier id_cti_ets_proofOfCreation = id_cti.branch("6"); + + // + // id-aa OBJECT IDENTIFIER ::= {iso(1) member-body(2) usa(840) + // rsadsi(113549) pkcs(1) pkcs-9(9) smime(16) attributes(2)} + // + static final ASN1ObjectIdentifier id_aa = new ASN1ObjectIdentifier("1.2.840.113549.1.9.16.2"); + + + static final ASN1ObjectIdentifier id_aa_receiptRequest = id_aa.branch("1"); + + static final ASN1ObjectIdentifier id_aa_contentHint = id_aa.branch("4"); // See RFC 2634 + static final ASN1ObjectIdentifier id_aa_msgSigDigest = id_aa.branch("5"); + static final ASN1ObjectIdentifier id_aa_contentReference = id_aa.branch("10"); + /* + * id-aa-encrypKeyPref OBJECT IDENTIFIER ::= {id-aa 11} + * + */ + static final ASN1ObjectIdentifier id_aa_encrypKeyPref = id_aa.branch("11"); + static final ASN1ObjectIdentifier id_aa_signingCertificate = id_aa.branch("12"); + static final ASN1ObjectIdentifier id_aa_signingCertificateV2 = id_aa.branch("47"); + + static final ASN1ObjectIdentifier id_aa_contentIdentifier = id_aa.branch("7"); // See RFC 2634 + + /* + * RFC 3126 + */ + static final ASN1ObjectIdentifier id_aa_signatureTimeStampToken = id_aa.branch("14"); + + static final ASN1ObjectIdentifier id_aa_ets_sigPolicyId = id_aa.branch("15"); + static final ASN1ObjectIdentifier id_aa_ets_commitmentType = id_aa.branch("16"); + static final ASN1ObjectIdentifier id_aa_ets_signerLocation = id_aa.branch("17"); + static final ASN1ObjectIdentifier id_aa_ets_signerAttr = id_aa.branch("18"); + static final ASN1ObjectIdentifier id_aa_ets_otherSigCert = id_aa.branch("19"); + static final ASN1ObjectIdentifier id_aa_ets_contentTimestamp = id_aa.branch("20"); + static final ASN1ObjectIdentifier id_aa_ets_certificateRefs = id_aa.branch("21"); + static final ASN1ObjectIdentifier id_aa_ets_revocationRefs = id_aa.branch("22"); + static final ASN1ObjectIdentifier id_aa_ets_certValues = id_aa.branch("23"); + static final ASN1ObjectIdentifier id_aa_ets_revocationValues = id_aa.branch("24"); + static final ASN1ObjectIdentifier id_aa_ets_escTimeStamp = id_aa.branch("25"); + static final ASN1ObjectIdentifier id_aa_ets_certCRLTimestamp = id_aa.branch("26"); + static final ASN1ObjectIdentifier id_aa_ets_archiveTimestamp = id_aa.branch("27"); + + /** @deprecated use id_aa_ets_sigPolicyId instead */ + static final ASN1ObjectIdentifier id_aa_sigPolicyId = id_aa_ets_sigPolicyId; + /** @deprecated use id_aa_ets_commitmentType instead */ + static final ASN1ObjectIdentifier id_aa_commitmentType = id_aa_ets_commitmentType; + /** @deprecated use id_aa_ets_signerLocation instead */ + static final ASN1ObjectIdentifier id_aa_signerLocation = id_aa_ets_signerLocation; + /** @deprecated use id_aa_ets_otherSigCert instead */ + static final ASN1ObjectIdentifier id_aa_otherSigCert = id_aa_ets_otherSigCert; + + // + // id-spq OBJECT IDENTIFIER ::= {iso(1) member-body(2) usa(840) + // rsadsi(113549) pkcs(1) pkcs-9(9) smime(16) id-spq(5)} + // + final String id_spq = "1.2.840.113549.1.9.16.5"; + + static final ASN1ObjectIdentifier id_spq_ets_uri = new ASN1ObjectIdentifier(id_spq + ".1"); + static final ASN1ObjectIdentifier id_spq_ets_unotice = new ASN1ObjectIdentifier(id_spq + ".2"); + + // + // pkcs-12 OBJECT IDENTIFIER ::= { + // iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 12 } + // + static final ASN1ObjectIdentifier pkcs_12 = new ASN1ObjectIdentifier("1.2.840.113549.1.12"); + static final ASN1ObjectIdentifier bagtypes = pkcs_12.branch("10.1"); + + static final ASN1ObjectIdentifier keyBag = bagtypes.branch("1"); + static final ASN1ObjectIdentifier pkcs8ShroudedKeyBag = bagtypes.branch("2"); + static final ASN1ObjectIdentifier certBag = bagtypes.branch("3"); + static final ASN1ObjectIdentifier crlBag = bagtypes.branch("4"); + static final ASN1ObjectIdentifier secretBag = bagtypes.branch("5"); + static final ASN1ObjectIdentifier safeContentsBag = bagtypes.branch("6"); + + static final ASN1ObjectIdentifier pkcs_12PbeIds = pkcs_12.branch("1"); + + static final ASN1ObjectIdentifier pbeWithSHAAnd128BitRC4 = pkcs_12PbeIds.branch("1"); + static final ASN1ObjectIdentifier pbeWithSHAAnd40BitRC4 = pkcs_12PbeIds.branch("2"); + static final ASN1ObjectIdentifier pbeWithSHAAnd3_KeyTripleDES_CBC = pkcs_12PbeIds.branch("3"); + static final ASN1ObjectIdentifier pbeWithSHAAnd2_KeyTripleDES_CBC = pkcs_12PbeIds.branch("4"); + static final ASN1ObjectIdentifier pbeWithSHAAnd128BitRC2_CBC = pkcs_12PbeIds.branch("5"); + static final ASN1ObjectIdentifier pbeWithSHAAnd40BitRC2_CBC = pkcs_12PbeIds.branch("6"); + + /** + * @deprecated use pbeWithSHAAnd40BitRC2_CBC + */ + static final ASN1ObjectIdentifier pbewithSHAAnd40BitRC2_CBC = pkcs_12PbeIds.branch("6"); + + static final ASN1ObjectIdentifier id_alg_CMS3DESwrap = new ASN1ObjectIdentifier("1.2.840.113549.1.9.16.3.6"); + static final ASN1ObjectIdentifier id_alg_CMSRC2wrap = new ASN1ObjectIdentifier("1.2.840.113549.1.9.16.3.7"); +} + diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/pkcs/Pfx.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/pkcs/Pfx.java new file mode 100644 index 0000000..f6d386d --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/pkcs/Pfx.java @@ -0,0 +1,87 @@ +package org.bc.asn1.pkcs; + +import java.math.BigInteger; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.BERSequence; + +/** + * the infamous Pfx from PKCS12 + */ +public class Pfx + extends ASN1Object + implements PKCSObjectIdentifiers +{ + private ContentInfo contentInfo; + private MacData macData = null; + + private Pfx( + ASN1Sequence seq) + { + BigInteger version = ((ASN1Integer)seq.getObjectAt(0)).getValue(); + if (version.intValue() != 3) + { + throw new IllegalArgumentException("wrong version for PFX PDU"); + } + + contentInfo = ContentInfo.getInstance(seq.getObjectAt(1)); + + if (seq.size() == 3) + { + macData = MacData.getInstance(seq.getObjectAt(2)); + } + } + + public static Pfx getInstance( + Object obj) + { + if (obj instanceof Pfx) + { + return (Pfx)obj; + } + + if (obj != null) + { + return new Pfx(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public Pfx( + ContentInfo contentInfo, + MacData macData) + { + this.contentInfo = contentInfo; + this.macData = macData; + } + + public ContentInfo getAuthSafe() + { + return contentInfo; + } + + public MacData getMacData() + { + return macData; + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(new ASN1Integer(3)); + v.add(contentInfo); + + if (macData != null) + { + v.add(macData); + } + + return new BERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/pkcs/PrivateKeyInfo.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/pkcs/PrivateKeyInfo.java new file mode 100644 index 0000000..10e708d --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/pkcs/PrivateKeyInfo.java @@ -0,0 +1,160 @@ +package org.bc.asn1.pkcs; + +import java.io.IOException; +import java.math.BigInteger; +import java.util.Enumeration; + +import org.bc.asn1.ASN1Encodable; +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Encoding; +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1OctetString; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1Set; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DEROctetString; +import org.bc.asn1.DERSequence; +import org.bc.asn1.DERTaggedObject; +import org.bc.asn1.x509.AlgorithmIdentifier; + +public class PrivateKeyInfo + extends ASN1Object +{ + private ASN1OctetString privKey; + private AlgorithmIdentifier algId; + private ASN1Set attributes; + + public static PrivateKeyInfo getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static PrivateKeyInfo getInstance( + Object obj) + { + if (obj instanceof PrivateKeyInfo) + { + return (PrivateKeyInfo)obj; + } + else if (obj != null) + { + return new PrivateKeyInfo(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public PrivateKeyInfo( + AlgorithmIdentifier algId, + ASN1Encodable privateKey) + throws IOException + { + this(algId, privateKey, null); + } + + public PrivateKeyInfo( + AlgorithmIdentifier algId, + ASN1Encodable privateKey, + ASN1Set attributes) + throws IOException + { + this.privKey = new DEROctetString(privateKey.toASN1Primitive().getEncoded(ASN1Encoding.DER)); + this.algId = algId; + this.attributes = attributes; + } + + public PrivateKeyInfo( + ASN1Sequence seq) + { + Enumeration e = seq.getObjects(); + + BigInteger version = ((ASN1Integer)e.nextElement()).getValue(); + if (version.intValue() != 0) + { + throw new IllegalArgumentException("wrong version for private key info"); + } + + algId = AlgorithmIdentifier.getInstance(e.nextElement()); + privKey = ASN1OctetString.getInstance(e.nextElement()); + + if (e.hasMoreElements()) + { + attributes = ASN1Set.getInstance((ASN1TaggedObject)e.nextElement(), false); + } + } + + public AlgorithmIdentifier getPrivateKeyAlgorithm() + { + return algId; + } + /** + * @deprecated use getPrivateKeyAlgorithm() + */ + public AlgorithmIdentifier getAlgorithmId() + { + return algId; + } + + public ASN1Encodable parsePrivateKey() + throws IOException + { + return ASN1Primitive.fromByteArray(privKey.getOctets()); + } + + /** + * @deprecated use parsePrivateKey() + */ + public ASN1Primitive getPrivateKey() + { + try + { + return parsePrivateKey().toASN1Primitive(); + } + catch (IOException e) + { + throw new IllegalStateException("unable to parse private key"); + } + } + + public ASN1Set getAttributes() + { + return attributes; + } + + /** + * write out an RSA private key with its associated information + * as described in PKCS8. + *
+ * PrivateKeyInfo ::= SEQUENCE { + * version Version, + * privateKeyAlgorithm AlgorithmIdentifier {{PrivateKeyAlgorithms}}, + * privateKey PrivateKey, + * attributes [0] IMPLICIT Attributes OPTIONAL + * } + * Version ::= INTEGER {v1(0)} (v1,...) + * + * PrivateKey ::= OCTET STRING + * + * Attributes ::= SET OF Attribute + *+ */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(new ASN1Integer(0)); + v.add(algId); + v.add(privKey); + + if (attributes != null) + { + v.add(new DERTaggedObject(false, 0, attributes)); + } + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/pkcs/RC2CBCParameter.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/pkcs/RC2CBCParameter.java new file mode 100644 index 0000000..d4e5e4b --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/pkcs/RC2CBCParameter.java @@ -0,0 +1,93 @@ +package org.bc.asn1.pkcs; + +import java.math.BigInteger; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1OctetString; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DEROctetString; +import org.bc.asn1.DERSequence; + +public class RC2CBCParameter + extends ASN1Object +{ + ASN1Integer version; + ASN1OctetString iv; + + public static RC2CBCParameter getInstance( + Object o) + { + if (o instanceof RC2CBCParameter) + { + return (RC2CBCParameter)o; + } + if (o != null) + { + return new RC2CBCParameter(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public RC2CBCParameter( + byte[] iv) + { + this.version = null; + this.iv = new DEROctetString(iv); + } + + public RC2CBCParameter( + int parameterVersion, + byte[] iv) + { + this.version = new ASN1Integer(parameterVersion); + this.iv = new DEROctetString(iv); + } + + private RC2CBCParameter( + ASN1Sequence seq) + { + if (seq.size() == 1) + { + version = null; + iv = (ASN1OctetString)seq.getObjectAt(0); + } + else + { + version = (ASN1Integer)seq.getObjectAt(0); + iv = (ASN1OctetString)seq.getObjectAt(1); + } + } + + public BigInteger getRC2ParameterVersion() + { + if (version == null) + { + return null; + } + + return version.getValue(); + } + + public byte[] getIV() + { + return iv.getOctets(); + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + if (version != null) + { + v.add(version); + } + + v.add(iv); + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/pkcs/RSAESOAEPparams.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/pkcs/RSAESOAEPparams.java new file mode 100644 index 0000000..a9263f7 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/pkcs/RSAESOAEPparams.java @@ -0,0 +1,151 @@ +package org.bc.asn1.pkcs; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERNull; +import org.bc.asn1.DEROctetString; +import org.bc.asn1.DERSequence; +import org.bc.asn1.DERTaggedObject; +import org.bc.asn1.oiw.OIWObjectIdentifiers; +import org.bc.asn1.x509.AlgorithmIdentifier; + +public class RSAESOAEPparams + extends ASN1Object +{ + private AlgorithmIdentifier hashAlgorithm; + private AlgorithmIdentifier maskGenAlgorithm; + private AlgorithmIdentifier pSourceAlgorithm; + + public final static AlgorithmIdentifier DEFAULT_HASH_ALGORITHM = new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1, DERNull.INSTANCE); + public final static AlgorithmIdentifier DEFAULT_MASK_GEN_FUNCTION = new AlgorithmIdentifier(PKCSObjectIdentifiers.id_mgf1, DEFAULT_HASH_ALGORITHM); + public final static AlgorithmIdentifier DEFAULT_P_SOURCE_ALGORITHM = new AlgorithmIdentifier(PKCSObjectIdentifiers.id_pSpecified, new DEROctetString(new byte[0])); + + public static RSAESOAEPparams getInstance( + Object obj) + { + if (obj instanceof RSAESOAEPparams) + { + return (RSAESOAEPparams)obj; + } + else if (obj != null) + { + return new RSAESOAEPparams(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + /** + * The default version + */ + public RSAESOAEPparams() + { + hashAlgorithm = DEFAULT_HASH_ALGORITHM; + maskGenAlgorithm = DEFAULT_MASK_GEN_FUNCTION; + pSourceAlgorithm = DEFAULT_P_SOURCE_ALGORITHM; + } + + public RSAESOAEPparams( + AlgorithmIdentifier hashAlgorithm, + AlgorithmIdentifier maskGenAlgorithm, + AlgorithmIdentifier pSourceAlgorithm) + { + this.hashAlgorithm = hashAlgorithm; + this.maskGenAlgorithm = maskGenAlgorithm; + this.pSourceAlgorithm = pSourceAlgorithm; + } + + public RSAESOAEPparams( + ASN1Sequence seq) + { + hashAlgorithm = DEFAULT_HASH_ALGORITHM; + maskGenAlgorithm = DEFAULT_MASK_GEN_FUNCTION; + pSourceAlgorithm = DEFAULT_P_SOURCE_ALGORITHM; + + for (int i = 0; i != seq.size(); i++) + { + ASN1TaggedObject o = (ASN1TaggedObject)seq.getObjectAt(i); + + switch (o.getTagNo()) + { + case 0: + hashAlgorithm = AlgorithmIdentifier.getInstance(o, true); + break; + case 1: + maskGenAlgorithm = AlgorithmIdentifier.getInstance(o, true); + break; + case 2: + pSourceAlgorithm = AlgorithmIdentifier.getInstance(o, true); + break; + default: + throw new IllegalArgumentException("unknown tag"); + } + } + } + + public AlgorithmIdentifier getHashAlgorithm() + { + return hashAlgorithm; + } + + public AlgorithmIdentifier getMaskGenAlgorithm() + { + return maskGenAlgorithm; + } + + public AlgorithmIdentifier getPSourceAlgorithm() + { + return pSourceAlgorithm; + } + + /** + *
+ * RSAES-OAEP-params ::= SEQUENCE { + * hashAlgorithm [0] OAEP-PSSDigestAlgorithms DEFAULT sha1, + * maskGenAlgorithm [1] PKCS1MGFAlgorithms DEFAULT mgf1SHA1, + * pSourceAlgorithm [2] PKCS1PSourceAlgorithms DEFAULT pSpecifiedEmpty + * } + * + * OAEP-PSSDigestAlgorithms ALGORITHM-IDENTIFIER ::= { + * { OID id-sha1 PARAMETERS NULL }| + * { OID id-sha256 PARAMETERS NULL }| + * { OID id-sha384 PARAMETERS NULL }| + * { OID id-sha512 PARAMETERS NULL }, + * ... -- Allows for future expansion -- + * } + * PKCS1MGFAlgorithms ALGORITHM-IDENTIFIER ::= { + * { OID id-mgf1 PARAMETERS OAEP-PSSDigestAlgorithms }, + * ... -- Allows for future expansion -- + * } + * PKCS1PSourceAlgorithms ALGORITHM-IDENTIFIER ::= { + * { OID id-pSpecified PARAMETERS OCTET STRING }, + * ... -- Allows for future expansion -- + * } + *+ * @return the asn1 primitive representing the parameters. + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + if (!hashAlgorithm.equals(DEFAULT_HASH_ALGORITHM)) + { + v.add(new DERTaggedObject(true, 0, hashAlgorithm)); + } + + if (!maskGenAlgorithm.equals(DEFAULT_MASK_GEN_FUNCTION)) + { + v.add(new DERTaggedObject(true, 1, maskGenAlgorithm)); + } + + if (!pSourceAlgorithm.equals(DEFAULT_P_SOURCE_ALGORITHM)) + { + v.add(new DERTaggedObject(true, 2, pSourceAlgorithm)); + } + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/pkcs/RSAPrivateKey.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/pkcs/RSAPrivateKey.java new file mode 100644 index 0000000..76c004e --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/pkcs/RSAPrivateKey.java @@ -0,0 +1,187 @@ +package org.bc.asn1.pkcs; + +import java.math.BigInteger; +import java.util.Enumeration; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERSequence; + +public class RSAPrivateKey + extends ASN1Object +{ + private BigInteger version; + private BigInteger modulus; + private BigInteger publicExponent; + private BigInteger privateExponent; + private BigInteger prime1; + private BigInteger prime2; + private BigInteger exponent1; + private BigInteger exponent2; + private BigInteger coefficient; + private ASN1Sequence otherPrimeInfos = null; + + public static RSAPrivateKey getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static RSAPrivateKey getInstance( + Object obj) + { + if (obj instanceof RSAPrivateKey) + { + return (RSAPrivateKey)obj; + } + + if (obj != null) + { + return new RSAPrivateKey(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public RSAPrivateKey( + BigInteger modulus, + BigInteger publicExponent, + BigInteger privateExponent, + BigInteger prime1, + BigInteger prime2, + BigInteger exponent1, + BigInteger exponent2, + BigInteger coefficient) + { + this.version = BigInteger.valueOf(0); + this.modulus = modulus; + this.publicExponent = publicExponent; + this.privateExponent = privateExponent; + this.prime1 = prime1; + this.prime2 = prime2; + this.exponent1 = exponent1; + this.exponent2 = exponent2; + this.coefficient = coefficient; + } + + private RSAPrivateKey( + ASN1Sequence seq) + { + Enumeration e = seq.getObjects(); + + BigInteger v = ((ASN1Integer)e.nextElement()).getValue(); + if (v.intValue() != 0 && v.intValue() != 1) + { + throw new IllegalArgumentException("wrong version for RSA private key"); + } + + version = v; + modulus = ((ASN1Integer)e.nextElement()).getValue(); + publicExponent = ((ASN1Integer)e.nextElement()).getValue(); + privateExponent = ((ASN1Integer)e.nextElement()).getValue(); + prime1 = ((ASN1Integer)e.nextElement()).getValue(); + prime2 = ((ASN1Integer)e.nextElement()).getValue(); + exponent1 = ((ASN1Integer)e.nextElement()).getValue(); + exponent2 = ((ASN1Integer)e.nextElement()).getValue(); + coefficient = ((ASN1Integer)e.nextElement()).getValue(); + + if (e.hasMoreElements()) + { + otherPrimeInfos = (ASN1Sequence)e.nextElement(); + } + } + + public BigInteger getVersion() + { + return version; + } + + public BigInteger getModulus() + { + return modulus; + } + + public BigInteger getPublicExponent() + { + return publicExponent; + } + + public BigInteger getPrivateExponent() + { + return privateExponent; + } + + public BigInteger getPrime1() + { + return prime1; + } + + public BigInteger getPrime2() + { + return prime2; + } + + public BigInteger getExponent1() + { + return exponent1; + } + + public BigInteger getExponent2() + { + return exponent2; + } + + public BigInteger getCoefficient() + { + return coefficient; + } + + /** + * This outputs the key in PKCS1v2 format. + *
+ * RSAPrivateKey ::= SEQUENCE { + * version Version, + * modulus INTEGER, -- n + * publicExponent INTEGER, -- e + * privateExponent INTEGER, -- d + * prime1 INTEGER, -- p + * prime2 INTEGER, -- q + * exponent1 INTEGER, -- d mod (p-1) + * exponent2 INTEGER, -- d mod (q-1) + * coefficient INTEGER, -- (inverse of q) mod p + * otherPrimeInfos OtherPrimeInfos OPTIONAL + * } + * + * Version ::= INTEGER { two-prime(0), multi(1) } + * (CONSTRAINED BY {-- version must be multi if otherPrimeInfos present --}) + *+ *
+ * This routine is written to output PKCS1 version 2.1, private keys. + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(new ASN1Integer(version)); // version + v.add(new ASN1Integer(getModulus())); + v.add(new ASN1Integer(getPublicExponent())); + v.add(new ASN1Integer(getPrivateExponent())); + v.add(new ASN1Integer(getPrime1())); + v.add(new ASN1Integer(getPrime2())); + v.add(new ASN1Integer(getExponent1())); + v.add(new ASN1Integer(getExponent2())); + v.add(new ASN1Integer(getCoefficient())); + + if (otherPrimeInfos != null) + { + v.add(otherPrimeInfos); + } + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/pkcs/RSAPrivateKeyStructure.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/pkcs/RSAPrivateKeyStructure.java new file mode 100644 index 0000000..22c78c0 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/pkcs/RSAPrivateKeyStructure.java @@ -0,0 +1,189 @@ +package org.bc.asn1.pkcs; + +import java.math.BigInteger; +import java.util.Enumeration; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERSequence; + +/** + * @deprecated use RSAPrivateKey + */ +public class RSAPrivateKeyStructure + extends ASN1Object +{ + private int version; + private BigInteger modulus; + private BigInteger publicExponent; + private BigInteger privateExponent; + private BigInteger prime1; + private BigInteger prime2; + private BigInteger exponent1; + private BigInteger exponent2; + private BigInteger coefficient; + private ASN1Sequence otherPrimeInfos = null; + + public static RSAPrivateKeyStructure getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static RSAPrivateKeyStructure getInstance( + Object obj) + { + if (obj instanceof RSAPrivateKeyStructure) + { + return (RSAPrivateKeyStructure)obj; + } + else if (obj instanceof ASN1Sequence) + { + return new RSAPrivateKeyStructure((ASN1Sequence)obj); + } + + throw new IllegalArgumentException("unknown object in factory: " + obj.getClass().getName()); + } + + public RSAPrivateKeyStructure( + BigInteger modulus, + BigInteger publicExponent, + BigInteger privateExponent, + BigInteger prime1, + BigInteger prime2, + BigInteger exponent1, + BigInteger exponent2, + BigInteger coefficient) + { + this.version = 0; + this.modulus = modulus; + this.publicExponent = publicExponent; + this.privateExponent = privateExponent; + this.prime1 = prime1; + this.prime2 = prime2; + this.exponent1 = exponent1; + this.exponent2 = exponent2; + this.coefficient = coefficient; + } + + public RSAPrivateKeyStructure( + ASN1Sequence seq) + { + Enumeration e = seq.getObjects(); + + BigInteger v = ((ASN1Integer)e.nextElement()).getValue(); + if (v.intValue() != 0 && v.intValue() != 1) + { + throw new IllegalArgumentException("wrong version for RSA private key"); + } + + version = v.intValue(); + modulus = ((ASN1Integer)e.nextElement()).getValue(); + publicExponent = ((ASN1Integer)e.nextElement()).getValue(); + privateExponent = ((ASN1Integer)e.nextElement()).getValue(); + prime1 = ((ASN1Integer)e.nextElement()).getValue(); + prime2 = ((ASN1Integer)e.nextElement()).getValue(); + exponent1 = ((ASN1Integer)e.nextElement()).getValue(); + exponent2 = ((ASN1Integer)e.nextElement()).getValue(); + coefficient = ((ASN1Integer)e.nextElement()).getValue(); + + if (e.hasMoreElements()) + { + otherPrimeInfos = (ASN1Sequence)e.nextElement(); + } + } + + public int getVersion() + { + return version; + } + + public BigInteger getModulus() + { + return modulus; + } + + public BigInteger getPublicExponent() + { + return publicExponent; + } + + public BigInteger getPrivateExponent() + { + return privateExponent; + } + + public BigInteger getPrime1() + { + return prime1; + } + + public BigInteger getPrime2() + { + return prime2; + } + + public BigInteger getExponent1() + { + return exponent1; + } + + public BigInteger getExponent2() + { + return exponent2; + } + + public BigInteger getCoefficient() + { + return coefficient; + } + + /** + * This outputs the key in PKCS1v2 format. + *
+ * RSAPrivateKey ::= SEQUENCE { + * version Version, + * modulus INTEGER, -- n + * publicExponent INTEGER, -- e + * privateExponent INTEGER, -- d + * prime1 INTEGER, -- p + * prime2 INTEGER, -- q + * exponent1 INTEGER, -- d mod (p-1) + * exponent2 INTEGER, -- d mod (q-1) + * coefficient INTEGER, -- (inverse of q) mod p + * otherPrimeInfos OtherPrimeInfos OPTIONAL + * } + * + * Version ::= INTEGER { two-prime(0), multi(1) } + * (CONSTRAINED BY {-- version must be multi if otherPrimeInfos present --}) + *+ *
+ * This routine is written to output PKCS1 version 2.1, private keys. + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(new ASN1Integer(version)); // version + v.add(new ASN1Integer(getModulus())); + v.add(new ASN1Integer(getPublicExponent())); + v.add(new ASN1Integer(getPrivateExponent())); + v.add(new ASN1Integer(getPrime1())); + v.add(new ASN1Integer(getPrime2())); + v.add(new ASN1Integer(getExponent1())); + v.add(new ASN1Integer(getExponent2())); + v.add(new ASN1Integer(getCoefficient())); + + if (otherPrimeInfos != null) + { + v.add(otherPrimeInfos); + } + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/pkcs/RSAPublicKey.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/pkcs/RSAPublicKey.java new file mode 100644 index 0000000..a5d9d45 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/pkcs/RSAPublicKey.java @@ -0,0 +1,95 @@ +package org.bc.asn1.pkcs; + +import java.math.BigInteger; +import java.util.Enumeration; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERSequence; + +public class RSAPublicKey + extends ASN1Object +{ + private BigInteger modulus; + private BigInteger publicExponent; + + public static RSAPublicKey getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static RSAPublicKey getInstance( + Object obj) + { + if (obj instanceof RSAPublicKey) + { + return (RSAPublicKey)obj; + } + + if (obj != null) + { + return new RSAPublicKey(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public RSAPublicKey( + BigInteger modulus, + BigInteger publicExponent) + { + this.modulus = modulus; + this.publicExponent = publicExponent; + } + + private RSAPublicKey( + ASN1Sequence seq) + { + if (seq.size() != 2) + { + throw new IllegalArgumentException("Bad sequence size: " + + seq.size()); + } + + Enumeration e = seq.getObjects(); + + modulus = ASN1Integer.getInstance(e.nextElement()).getPositiveValue(); + publicExponent = ASN1Integer.getInstance(e.nextElement()).getPositiveValue(); + } + + public BigInteger getModulus() + { + return modulus; + } + + public BigInteger getPublicExponent() + { + return publicExponent; + } + + /** + * This outputs the key in PKCS1v2 format. + *
+ * RSAPublicKey ::= SEQUENCE { + * modulus INTEGER, -- n + * publicExponent INTEGER, -- e + * } + *+ *
+ */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(new ASN1Integer(getModulus())); + v.add(new ASN1Integer(getPublicExponent())); + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/pkcs/RSASSAPSSparams.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/pkcs/RSASSAPSSparams.java new file mode 100644 index 0000000..3a25dce --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/pkcs/RSASSAPSSparams.java @@ -0,0 +1,172 @@ +package org.bc.asn1.pkcs; + +import java.math.BigInteger; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERNull; +import org.bc.asn1.DERSequence; +import org.bc.asn1.DERTaggedObject; +import org.bc.asn1.oiw.OIWObjectIdentifiers; +import org.bc.asn1.x509.AlgorithmIdentifier; + +public class RSASSAPSSparams + extends ASN1Object +{ + private AlgorithmIdentifier hashAlgorithm; + private AlgorithmIdentifier maskGenAlgorithm; + private ASN1Integer saltLength; + private ASN1Integer trailerField; + + public final static AlgorithmIdentifier DEFAULT_HASH_ALGORITHM = new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1, DERNull.INSTANCE); + public final static AlgorithmIdentifier DEFAULT_MASK_GEN_FUNCTION = new AlgorithmIdentifier(PKCSObjectIdentifiers.id_mgf1, DEFAULT_HASH_ALGORITHM); + public final static ASN1Integer DEFAULT_SALT_LENGTH = new ASN1Integer(20); + public final static ASN1Integer DEFAULT_TRAILER_FIELD = new ASN1Integer(1); + + public static RSASSAPSSparams getInstance( + Object obj) + { + if (obj instanceof RSASSAPSSparams) + { + return (RSASSAPSSparams)obj; + } + else if (obj != null) + { + return new RSASSAPSSparams(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + /** + * The default version + */ + public RSASSAPSSparams() + { + hashAlgorithm = DEFAULT_HASH_ALGORITHM; + maskGenAlgorithm = DEFAULT_MASK_GEN_FUNCTION; + saltLength = DEFAULT_SALT_LENGTH; + trailerField = DEFAULT_TRAILER_FIELD; + } + + public RSASSAPSSparams( + AlgorithmIdentifier hashAlgorithm, + AlgorithmIdentifier maskGenAlgorithm, + ASN1Integer saltLength, + ASN1Integer trailerField) + { + this.hashAlgorithm = hashAlgorithm; + this.maskGenAlgorithm = maskGenAlgorithm; + this.saltLength = saltLength; + this.trailerField = trailerField; + } + + private RSASSAPSSparams( + ASN1Sequence seq) + { + hashAlgorithm = DEFAULT_HASH_ALGORITHM; + maskGenAlgorithm = DEFAULT_MASK_GEN_FUNCTION; + saltLength = DEFAULT_SALT_LENGTH; + trailerField = DEFAULT_TRAILER_FIELD; + + for (int i = 0; i != seq.size(); i++) + { + ASN1TaggedObject o = (ASN1TaggedObject)seq.getObjectAt(i); + + switch (o.getTagNo()) + { + case 0: + hashAlgorithm = AlgorithmIdentifier.getInstance(o, true); + break; + case 1: + maskGenAlgorithm = AlgorithmIdentifier.getInstance(o, true); + break; + case 2: + saltLength = ASN1Integer.getInstance(o, true); + break; + case 3: + trailerField = ASN1Integer.getInstance(o, true); + break; + default: + throw new IllegalArgumentException("unknown tag"); + } + } + } + + public AlgorithmIdentifier getHashAlgorithm() + { + return hashAlgorithm; + } + + public AlgorithmIdentifier getMaskGenAlgorithm() + { + return maskGenAlgorithm; + } + + public BigInteger getSaltLength() + { + return saltLength.getValue(); + } + + public BigInteger getTrailerField() + { + return trailerField.getValue(); + } + + /** + *
+ * RSASSA-PSS-params ::= SEQUENCE { + * hashAlgorithm [0] OAEP-PSSDigestAlgorithms DEFAULT sha1, + * maskGenAlgorithm [1] PKCS1MGFAlgorithms DEFAULT mgf1SHA1, + * saltLength [2] INTEGER DEFAULT 20, + * trailerField [3] TrailerField DEFAULT trailerFieldBC + * } + * + * OAEP-PSSDigestAlgorithms ALGORITHM-IDENTIFIER ::= { + * { OID id-sha1 PARAMETERS NULL }| + * { OID id-sha256 PARAMETERS NULL }| + * { OID id-sha384 PARAMETERS NULL }| + * { OID id-sha512 PARAMETERS NULL }, + * ... -- Allows for future expansion -- + * } + * + * PKCS1MGFAlgorithms ALGORITHM-IDENTIFIER ::= { + * { OID id-mgf1 PARAMETERS OAEP-PSSDigestAlgorithms }, + * ... -- Allows for future expansion -- + * } + * + * TrailerField ::= INTEGER { trailerFieldBC(1) } + *+ * @return the asn1 primitive representing the parameters. + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + if (!hashAlgorithm.equals(DEFAULT_HASH_ALGORITHM)) + { + v.add(new DERTaggedObject(true, 0, hashAlgorithm)); + } + + if (!maskGenAlgorithm.equals(DEFAULT_MASK_GEN_FUNCTION)) + { + v.add(new DERTaggedObject(true, 1, maskGenAlgorithm)); + } + + if (!saltLength.equals(DEFAULT_SALT_LENGTH)) + { + v.add(new DERTaggedObject(true, 2, saltLength)); + } + + if (!trailerField.equals(DEFAULT_TRAILER_FIELD)) + { + v.add(new DERTaggedObject(true, 3, trailerField)); + } + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/pkcs/SafeBag.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/pkcs/SafeBag.java new file mode 100644 index 0000000..cfd17c3 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/pkcs/SafeBag.java @@ -0,0 +1,96 @@ +package org.bc.asn1.pkcs; + +import org.bc.asn1.ASN1Encodable; +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1ObjectIdentifier; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1Set; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DLSequence; +import org.bc.asn1.DLTaggedObject; + +public class SafeBag + extends ASN1Object +{ + private ASN1ObjectIdentifier bagId; + private ASN1Encodable bagValue; + private ASN1Set bagAttributes; + + public SafeBag( + ASN1ObjectIdentifier oid, + ASN1Encodable obj) + { + this.bagId = oid; + this.bagValue = obj; + this.bagAttributes = null; + } + + public SafeBag( + ASN1ObjectIdentifier oid, + ASN1Encodable obj, + ASN1Set bagAttributes) + { + this.bagId = oid; + this.bagValue = obj; + this.bagAttributes = bagAttributes; + } + + public static SafeBag getInstance( + Object obj) + { + if (obj instanceof SafeBag) + { + return (SafeBag)obj; + } + + if (obj != null) + { + return new SafeBag(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + private SafeBag( + ASN1Sequence seq) + { + this.bagId = (ASN1ObjectIdentifier)seq.getObjectAt(0); + this.bagValue = ((ASN1TaggedObject)seq.getObjectAt(1)).getObject(); + if (seq.size() == 3) + { + this.bagAttributes = (ASN1Set)seq.getObjectAt(2); + } + } + + public ASN1ObjectIdentifier getBagId() + { + return bagId; + } + + public ASN1Encodable getBagValue() + { + return bagValue; + } + + public ASN1Set getBagAttributes() + { + return bagAttributes; + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(bagId); + v.add(new DLTaggedObject(true, 0, bagValue)); + + if (bagAttributes != null) + { + v.add(bagAttributes); + } + + return new DLSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/pkcs/SignedData.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/pkcs/SignedData.java new file mode 100644 index 0000000..ab9c823 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/pkcs/SignedData.java @@ -0,0 +1,167 @@ +package org.bc.asn1.pkcs; + +import java.util.Enumeration; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1Set; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.BERSequence; +import org.bc.asn1.DERTaggedObject; + +/** + * a PKCS#7 signed data object. + */ +public class SignedData + extends ASN1Object + implements PKCSObjectIdentifiers +{ + private ASN1Integer version; + private ASN1Set digestAlgorithms; + private ContentInfo contentInfo; + private ASN1Set certificates; + private ASN1Set crls; + private ASN1Set signerInfos; + + public static SignedData getInstance( + Object o) + { + if (o instanceof SignedData) + { + return (SignedData)o; + } + else if (o != null) + { + return new SignedData(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public SignedData( + ASN1Integer _version, + ASN1Set _digestAlgorithms, + ContentInfo _contentInfo, + ASN1Set _certificates, + ASN1Set _crls, + ASN1Set _signerInfos) + { + version = _version; + digestAlgorithms = _digestAlgorithms; + contentInfo = _contentInfo; + certificates = _certificates; + crls = _crls; + signerInfos = _signerInfos; + } + + public SignedData( + ASN1Sequence seq) + { + Enumeration e = seq.getObjects(); + + version = (ASN1Integer)e.nextElement(); + digestAlgorithms = ((ASN1Set)e.nextElement()); + contentInfo = ContentInfo.getInstance(e.nextElement()); + + while (e.hasMoreElements()) + { + ASN1Primitive o = (ASN1Primitive)e.nextElement(); + + // + // an interesting feature of SignedData is that there appear to be varying implementations... + // for the moment we ignore anything which doesn't fit. + // + if (o instanceof ASN1TaggedObject) + { + ASN1TaggedObject tagged = (ASN1TaggedObject)o; + + switch (tagged.getTagNo()) + { + case 0: + certificates = ASN1Set.getInstance(tagged, false); + break; + case 1: + crls = ASN1Set.getInstance(tagged, false); + break; + default: + throw new IllegalArgumentException("unknown tag value " + tagged.getTagNo()); + } + } + else + { + signerInfos = (ASN1Set)o; + } + } + } + + public ASN1Integer getVersion() + { + return version; + } + + public ASN1Set getDigestAlgorithms() + { + return digestAlgorithms; + } + + public ContentInfo getContentInfo() + { + return contentInfo; + } + + public ASN1Set getCertificates() + { + return certificates; + } + + public ASN1Set getCRLs() + { + return crls; + } + + public ASN1Set getSignerInfos() + { + return signerInfos; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + *
+ * SignedData ::= SEQUENCE { + * version Version, + * digestAlgorithms DigestAlgorithmIdentifiers, + * contentInfo ContentInfo, + * certificates + * [0] IMPLICIT ExtendedCertificatesAndCertificates + * OPTIONAL, + * crls + * [1] IMPLICIT CertificateRevocationLists OPTIONAL, + * signerInfos SignerInfos } + *+ */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(version); + v.add(digestAlgorithms); + v.add(contentInfo); + + if (certificates != null) + { + v.add(new DERTaggedObject(false, 0, certificates)); + } + + if (crls != null) + { + v.add(new DERTaggedObject(false, 1, crls)); + } + + v.add(signerInfos); + + return new BERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/pkcs/SignerInfo.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/pkcs/SignerInfo.java new file mode 100644 index 0000000..6cbfa4e --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/pkcs/SignerInfo.java @@ -0,0 +1,178 @@ +package org.bc.asn1.pkcs; + +import java.util.Enumeration; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1OctetString; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1Set; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DEROctetString; +import org.bc.asn1.DERSequence; +import org.bc.asn1.DERTaggedObject; +import org.bc.asn1.x509.AlgorithmIdentifier; + +/** + * a PKCS#7 signer info object. + */ +public class SignerInfo + extends ASN1Object +{ + private ASN1Integer version; + private IssuerAndSerialNumber issuerAndSerialNumber; + private AlgorithmIdentifier digAlgorithm; + private ASN1Set authenticatedAttributes; + private AlgorithmIdentifier digEncryptionAlgorithm; + private ASN1OctetString encryptedDigest; + private ASN1Set unauthenticatedAttributes; + + public static SignerInfo getInstance( + Object o) + { + if (o instanceof SignerInfo) + { + return (SignerInfo)o; + } + else if (o instanceof ASN1Sequence) + { + return new SignerInfo((ASN1Sequence)o); + } + + throw new IllegalArgumentException("unknown object in factory: " + o.getClass().getName()); + } + + public SignerInfo( + ASN1Integer version, + IssuerAndSerialNumber issuerAndSerialNumber, + AlgorithmIdentifier digAlgorithm, + ASN1Set authenticatedAttributes, + AlgorithmIdentifier digEncryptionAlgorithm, + ASN1OctetString encryptedDigest, + ASN1Set unauthenticatedAttributes) + { + this.version = version; + this.issuerAndSerialNumber = issuerAndSerialNumber; + this.digAlgorithm = digAlgorithm; + this.authenticatedAttributes = authenticatedAttributes; + this.digEncryptionAlgorithm = digEncryptionAlgorithm; + this.encryptedDigest = encryptedDigest; + this.unauthenticatedAttributes = unauthenticatedAttributes; + } + + public SignerInfo( + ASN1Sequence seq) + { + Enumeration e = seq.getObjects(); + + version = (ASN1Integer)e.nextElement(); + issuerAndSerialNumber = IssuerAndSerialNumber.getInstance(e.nextElement()); + digAlgorithm = AlgorithmIdentifier.getInstance(e.nextElement()); + + Object obj = e.nextElement(); + + if (obj instanceof ASN1TaggedObject) + { + authenticatedAttributes = ASN1Set.getInstance((ASN1TaggedObject)obj, false); + + digEncryptionAlgorithm = AlgorithmIdentifier.getInstance(e.nextElement()); + } + else + { + authenticatedAttributes = null; + digEncryptionAlgorithm = AlgorithmIdentifier.getInstance(obj); + } + + encryptedDigest = DEROctetString.getInstance(e.nextElement()); + + if (e.hasMoreElements()) + { + unauthenticatedAttributes = ASN1Set.getInstance((ASN1TaggedObject)e.nextElement(), false); + } + else + { + unauthenticatedAttributes = null; + } + } + + public ASN1Integer getVersion() + { + return version; + } + + public IssuerAndSerialNumber getIssuerAndSerialNumber() + { + return issuerAndSerialNumber; + } + + public ASN1Set getAuthenticatedAttributes() + { + return authenticatedAttributes; + } + + public AlgorithmIdentifier getDigestAlgorithm() + { + return digAlgorithm; + } + + public ASN1OctetString getEncryptedDigest() + { + return encryptedDigest; + } + + public AlgorithmIdentifier getDigestEncryptionAlgorithm() + { + return digEncryptionAlgorithm; + } + + public ASN1Set getUnauthenticatedAttributes() + { + return unauthenticatedAttributes; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + *
+ * SignerInfo ::= SEQUENCE { + * version Version, + * issuerAndSerialNumber IssuerAndSerialNumber, + * digestAlgorithm DigestAlgorithmIdentifier, + * authenticatedAttributes [0] IMPLICIT Attributes OPTIONAL, + * digestEncryptionAlgorithm DigestEncryptionAlgorithmIdentifier, + * encryptedDigest EncryptedDigest, + * unauthenticatedAttributes [1] IMPLICIT Attributes OPTIONAL + * } + * + * EncryptedDigest ::= OCTET STRING + * + * DigestAlgorithmIdentifier ::= AlgorithmIdentifier + * + * DigestEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier + *+ */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(version); + v.add(issuerAndSerialNumber); + v.add(digAlgorithm); + + if (authenticatedAttributes != null) + { + v.add(new DERTaggedObject(false, 0, authenticatedAttributes)); + } + + v.add(digEncryptionAlgorithm); + v.add(encryptedDigest); + + if (unauthenticatedAttributes != null) + { + v.add(new DERTaggedObject(false, 1, unauthenticatedAttributes)); + } + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/sec/ECPrivateKey.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/sec/ECPrivateKey.java new file mode 100644 index 0000000..d6cfc2f --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/sec/ECPrivateKey.java @@ -0,0 +1,143 @@ +package org.bc.asn1.sec; + +import java.math.BigInteger; +import java.util.Enumeration; + +import org.bc.asn1.ASN1Encodable; +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1OctetString; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERBitString; +import org.bc.asn1.DEROctetString; +import org.bc.asn1.DERSequence; +import org.bc.asn1.DERTaggedObject; +import org.bc.util.BigIntegers; + +/** + * the elliptic curve private key object from SEC 1 + */ +public class ECPrivateKey + extends ASN1Object +{ + private ASN1Sequence seq; + + private ECPrivateKey( + ASN1Sequence seq) + { + this.seq = seq; + } + + public static ECPrivateKey getInstance( + Object obj) + { + if (obj instanceof ECPrivateKey) + { + return (ECPrivateKey)obj; + } + + if (obj != null) + { + return new ECPrivateKey(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public ECPrivateKey( + BigInteger key) + { + byte[] bytes = BigIntegers.asUnsignedByteArray(key); + + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(new ASN1Integer(1)); + v.add(new DEROctetString(bytes)); + + seq = new DERSequence(v); + } + + public ECPrivateKey( + BigInteger key, + ASN1Object parameters) + { + this(key, null, parameters); + } + + public ECPrivateKey( + BigInteger key, + DERBitString publicKey, + ASN1Object parameters) + { + byte[] bytes = BigIntegers.asUnsignedByteArray(key); + + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(new ASN1Integer(1)); + v.add(new DEROctetString(bytes)); + + if (parameters != null) + { + v.add(new DERTaggedObject(true, 0, parameters)); + } + + if (publicKey != null) + { + v.add(new DERTaggedObject(true, 1, publicKey)); + } + + seq = new DERSequence(v); + } + + public BigInteger getKey() + { + ASN1OctetString octs = (ASN1OctetString)seq.getObjectAt(1); + + return new BigInteger(1, octs.getOctets()); + } + + public DERBitString getPublicKey() + { + return (DERBitString)getObjectInTag(1); + } + + public ASN1Primitive getParameters() + { + return getObjectInTag(0); + } + + private ASN1Primitive getObjectInTag(int tagNo) + { + Enumeration e = seq.getObjects(); + + while (e.hasMoreElements()) + { + ASN1Encodable obj = (ASN1Encodable)e.nextElement(); + + if (obj instanceof ASN1TaggedObject) + { + ASN1TaggedObject tag = (ASN1TaggedObject)obj; + if (tag.getTagNo() == tagNo) + { + return tag.getObject().toASN1Primitive(); + } + } + } + return null; + } + + /** + * ECPrivateKey ::= SEQUENCE { + * version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1), + * privateKey OCTET STRING, + * parameters [0] Parameters OPTIONAL, + * publicKey [1] BIT STRING OPTIONAL } + */ + public ASN1Primitive toASN1Primitive() + { + return seq; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/sec/ECPrivateKeyStructure.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/sec/ECPrivateKeyStructure.java new file mode 100644 index 0000000..bd47d13 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/sec/ECPrivateKeyStructure.java @@ -0,0 +1,128 @@ +package org.bc.asn1.sec; + +import java.math.BigInteger; +import java.util.Enumeration; + +import org.bc.asn1.ASN1Encodable; +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1OctetString; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERBitString; +import org.bc.asn1.DEROctetString; +import org.bc.asn1.DERSequence; +import org.bc.asn1.DERTaggedObject; +import org.bc.util.BigIntegers; + +/** + * the elliptic curve private key object from SEC 1 + * @deprecated use ECPrivateKey + */ +public class ECPrivateKeyStructure + extends ASN1Object +{ + private ASN1Sequence seq; + + public ECPrivateKeyStructure( + ASN1Sequence seq) + { + this.seq = seq; + } + + public ECPrivateKeyStructure( + BigInteger key) + { + byte[] bytes = BigIntegers.asUnsignedByteArray(key); + + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(new ASN1Integer(1)); + v.add(new DEROctetString(bytes)); + + seq = new DERSequence(v); + } + + public ECPrivateKeyStructure( + BigInteger key, + ASN1Encodable parameters) + { + this(key, null, parameters); + } + + public ECPrivateKeyStructure( + BigInteger key, + DERBitString publicKey, + ASN1Encodable parameters) + { + byte[] bytes = BigIntegers.asUnsignedByteArray(key); + + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(new ASN1Integer(1)); + v.add(new DEROctetString(bytes)); + + if (parameters != null) + { + v.add(new DERTaggedObject(true, 0, parameters)); + } + + if (publicKey != null) + { + v.add(new DERTaggedObject(true, 1, publicKey)); + } + + seq = new DERSequence(v); + } + + public BigInteger getKey() + { + ASN1OctetString octs = (ASN1OctetString)seq.getObjectAt(1); + + return new BigInteger(1, octs.getOctets()); + } + + public DERBitString getPublicKey() + { + return (DERBitString)getObjectInTag(1); + } + + public ASN1Primitive getParameters() + { + return getObjectInTag(0); + } + + private ASN1Primitive getObjectInTag(int tagNo) + { + Enumeration e = seq.getObjects(); + + while (e.hasMoreElements()) + { + ASN1Encodable obj = (ASN1Encodable)e.nextElement(); + + if (obj instanceof ASN1TaggedObject) + { + ASN1TaggedObject tag = (ASN1TaggedObject)obj; + if (tag.getTagNo() == tagNo) + { + return (ASN1Primitive)((ASN1Encodable)tag.getObject()).toASN1Primitive(); + } + } + } + return null; + } + + /** + * ECPrivateKey ::= SEQUENCE { + * version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1), + * privateKey OCTET STRING, + * parameters [0] Parameters OPTIONAL, + * publicKey [1] BIT STRING OPTIONAL } + */ + public ASN1Primitive toASN1Primitive() + { + return seq; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/sec/SECNamedCurves.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/sec/SECNamedCurves.java new file mode 100644 index 0000000..c8ec3fa --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/sec/SECNamedCurves.java @@ -0,0 +1,1029 @@ +package org.bc.asn1.sec; + +import java.math.BigInteger; +import java.util.Enumeration; +import java.util.Hashtable; + +import org.bc.asn1.ASN1ObjectIdentifier; +import org.bc.asn1.x9.X9ECParameters; +import org.bc.asn1.x9.X9ECParametersHolder; +import org.bc.math.ec.ECConstants; +import org.bc.math.ec.ECCurve; +import org.bc.math.ec.ECPoint; +import org.bc.util.Strings; +import org.bc.util.encoders.Hex; + +public class SECNamedCurves +{ + private static BigInteger fromHex( + String hex) + { + return new BigInteger(1, Hex.decode(hex)); + } + + /* + * secp112r1 + */ + static X9ECParametersHolder secp112r1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + // p = (2^128 - 3) / 76439 + BigInteger p = fromHex("DB7C2ABF62E35E668076BEAD208B"); + BigInteger a = fromHex("DB7C2ABF62E35E668076BEAD2088"); + BigInteger b = fromHex("659EF8BA043916EEDE8911702B22"); + byte[] S = Hex.decode("00F50B028E4D696E676875615175290472783FB1"); + BigInteger n = fromHex("DB7C2ABF62E35E7628DFAC6561C5"); + BigInteger h = BigInteger.valueOf(1); + + ECCurve curve = new ECCurve.Fp(p, a, b); + //ECPoint G = curve.decodePoint(Hex.decode("02" + //+ "09487239995A5EE76B55F9C2F098")); + ECPoint G = curve.decodePoint(Hex.decode("04" + + "09487239995A5EE76B55F9C2F098" + + "A89CE5AF8724C0A23E0E0FF77500")); + + return new X9ECParameters(curve, G, n, h, S); + } + }; + + /* + * secp112r2 + */ + static X9ECParametersHolder secp112r2 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + // p = (2^128 - 3) / 76439 + BigInteger p = fromHex("DB7C2ABF62E35E668076BEAD208B"); + BigInteger a = fromHex("6127C24C05F38A0AAAF65C0EF02C"); + BigInteger b = fromHex("51DEF1815DB5ED74FCC34C85D709"); + byte[] S = Hex.decode("002757A1114D696E6768756151755316C05E0BD4"); + BigInteger n = fromHex("36DF0AAFD8B8D7597CA10520D04B"); + BigInteger h = BigInteger.valueOf(4); + + ECCurve curve = new ECCurve.Fp(p, a, b); + //ECPoint G = curve.decodePoint(Hex.decode("03" + //+ "4BA30AB5E892B4E1649DD0928643")); + ECPoint G = curve.decodePoint(Hex.decode("04" + + "4BA30AB5E892B4E1649DD0928643" + + "ADCD46F5882E3747DEF36E956E97")); + + return new X9ECParameters(curve, G, n, h, S); + } + }; + + /* + * secp128r1 + */ + static X9ECParametersHolder secp128r1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + // p = 2^128 - 2^97 - 1 + BigInteger p = fromHex("FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFF"); + BigInteger a = fromHex("FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFC"); + BigInteger b = fromHex("E87579C11079F43DD824993C2CEE5ED3"); + byte[] S = Hex.decode("000E0D4D696E6768756151750CC03A4473D03679"); + BigInteger n = fromHex("FFFFFFFE0000000075A30D1B9038A115"); + BigInteger h = BigInteger.valueOf(1); + + ECCurve curve = new ECCurve.Fp(p, a, b); + //ECPoint G = curve.decodePoint(Hex.decode("03" + //+ "161FF7528B899B2D0C28607CA52C5B86")); + ECPoint G = curve.decodePoint(Hex.decode("04" + + "161FF7528B899B2D0C28607CA52C5B86" + + "CF5AC8395BAFEB13C02DA292DDED7A83")); + + return new X9ECParameters(curve, G, n, h, S); + } + }; + + /* + * secp128r2 + */ + static X9ECParametersHolder secp128r2 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + // p = 2^128 - 2^97 - 1 + BigInteger p = fromHex("FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFF"); + BigInteger a = fromHex("D6031998D1B3BBFEBF59CC9BBFF9AEE1"); + BigInteger b = fromHex("5EEEFCA380D02919DC2C6558BB6D8A5D"); + byte[] S = Hex.decode("004D696E67687561517512D8F03431FCE63B88F4"); + BigInteger n = fromHex("3FFFFFFF7FFFFFFFBE0024720613B5A3"); + BigInteger h = BigInteger.valueOf(4); + + ECCurve curve = new ECCurve.Fp(p, a, b); + //ECPoint G = curve.decodePoint(Hex.decode("02" + //+ "7B6AA5D85E572983E6FB32A7CDEBC140")); + ECPoint G = curve.decodePoint(Hex.decode("04" + + "7B6AA5D85E572983E6FB32A7CDEBC140" + + "27B6916A894D3AEE7106FE805FC34B44")); + + return new X9ECParameters(curve, G, n, h, S); + } + }; + + /* + * secp160k1 + */ + static X9ECParametersHolder secp160k1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + // p = 2^160 - 2^32 - 2^14 - 2^12 - 2^9 - 2^8 - 2^7 - 2^3 - 2^2 - 1 + BigInteger p = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC73"); + BigInteger a = ECConstants.ZERO; + BigInteger b = BigInteger.valueOf(7); + byte[] S = null; + BigInteger n = fromHex("0100000000000000000001B8FA16DFAB9ACA16B6B3"); + BigInteger h = BigInteger.valueOf(1); + + ECCurve curve = new ECCurve.Fp(p, a, b); +// ECPoint G = curve.decodePoint(Hex.decode("02" +// + "3B4C382CE37AA192A4019E763036F4F5DD4D7EBB")); + ECPoint G = curve.decodePoint(Hex.decode("04" + + "3B4C382CE37AA192A4019E763036F4F5DD4D7EBB" + + "938CF935318FDCED6BC28286531733C3F03C4FEE")); + + return new X9ECParameters(curve, G, n, h, S); + } + }; + + /* + * secp160r1 + */ + static X9ECParametersHolder secp160r1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + // p = 2^160 - 2^31 - 1 + BigInteger p = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFF"); + BigInteger a = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFC"); + BigInteger b = fromHex("1C97BEFC54BD7A8B65ACF89F81D4D4ADC565FA45"); + byte[] S = Hex.decode("1053CDE42C14D696E67687561517533BF3F83345"); + BigInteger n = fromHex("0100000000000000000001F4C8F927AED3CA752257"); + BigInteger h = BigInteger.valueOf(1); + + ECCurve curve = new ECCurve.Fp(p, a, b); + //ECPoint G = curve.decodePoint(Hex.decode("02" + //+ "4A96B5688EF573284664698968C38BB913CBFC82")); + ECPoint G = curve.decodePoint(Hex.decode("04" + + "4A96B5688EF573284664698968C38BB913CBFC82" + + "23A628553168947D59DCC912042351377AC5FB32")); + + return new X9ECParameters(curve, G, n, h, S); + } + }; + + /* + * secp160r2 + */ + static X9ECParametersHolder secp160r2 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + // p = 2^160 - 2^32 - 2^14 - 2^12 - 2^9 - 2^8 - 2^7 - 2^3 - 2^2 - 1 + BigInteger p = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC73"); + BigInteger a = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC70"); + BigInteger b = fromHex("B4E134D3FB59EB8BAB57274904664D5AF50388BA"); + byte[] S = Hex.decode("B99B99B099B323E02709A4D696E6768756151751"); + BigInteger n = fromHex("0100000000000000000000351EE786A818F3A1A16B"); + BigInteger h = BigInteger.valueOf(1); + + ECCurve curve = new ECCurve.Fp(p, a, b); + //ECPoint G = curve.decodePoint(Hex.decode("02" + //+ "52DCB034293A117E1F4FF11B30F7199D3144CE6D")); + ECPoint G = curve.decodePoint(Hex.decode("04" + + "52DCB034293A117E1F4FF11B30F7199D3144CE6D" + + "FEAFFEF2E331F296E071FA0DF9982CFEA7D43F2E")); + + return new X9ECParameters(curve, G, n, h, S); + } + }; + + /* + * secp192k1 + */ + static X9ECParametersHolder secp192k1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + // p = 2^192 - 2^32 - 2^12 - 2^8 - 2^7 - 2^6 - 2^3 - 1 + BigInteger p = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFEE37"); + BigInteger a = ECConstants.ZERO; + BigInteger b = BigInteger.valueOf(3); + byte[] S = null; + BigInteger n = fromHex("FFFFFFFFFFFFFFFFFFFFFFFE26F2FC170F69466A74DEFD8D"); + BigInteger h = BigInteger.valueOf(1); + + ECCurve curve = new ECCurve.Fp(p, a, b); + //ECPoint G = curve.decodePoint(Hex.decode("03" + //+ "DB4FF10EC057E9AE26B07D0280B7F4341DA5D1B1EAE06C7D")); + ECPoint G = curve.decodePoint(Hex.decode("04" + + "DB4FF10EC057E9AE26B07D0280B7F4341DA5D1B1EAE06C7D" + + "9B2F2F6D9C5628A7844163D015BE86344082AA88D95E2F9D")); + + return new X9ECParameters(curve, G, n, h, S); + } + }; + + /* + * secp192r1 + */ + static X9ECParametersHolder secp192r1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + // p = 2^192 - 2^64 - 1 + BigInteger p = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF"); + BigInteger a = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFC"); + BigInteger b = fromHex("64210519E59C80E70FA7E9AB72243049FEB8DEECC146B9B1"); + byte[] S = Hex.decode("3045AE6FC8422F64ED579528D38120EAE12196D5"); + BigInteger n = fromHex("FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22831"); + BigInteger h = BigInteger.valueOf(1); + + ECCurve curve = new ECCurve.Fp(p, a, b); + //ECPoint G = curve.decodePoint(Hex.decode("03" + //+ "188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012")); + ECPoint G = curve.decodePoint(Hex.decode("04" + + "188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012" + + "07192B95FFC8DA78631011ED6B24CDD573F977A11E794811")); + + return new X9ECParameters(curve, G, n, h, S); + } + }; + + /* + * secp224k1 + */ + static X9ECParametersHolder secp224k1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + // p = 2^224 - 2^32 - 2^12 - 2^11 - 2^9 - 2^7 - 2^4 - 2 - 1 + BigInteger p = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFE56D"); + BigInteger a = ECConstants.ZERO; + BigInteger b = BigInteger.valueOf(5); + byte[] S = null; + BigInteger n = fromHex("010000000000000000000000000001DCE8D2EC6184CAF0A971769FB1F7"); + BigInteger h = BigInteger.valueOf(1); + + ECCurve curve = new ECCurve.Fp(p, a, b); + //ECPoint G = curve.decodePoint(Hex.decode("03" + //+ "A1455B334DF099DF30FC28A169A467E9E47075A90F7E650EB6B7A45C")); + ECPoint G = curve.decodePoint(Hex.decode("04" + + "A1455B334DF099DF30FC28A169A467E9E47075A90F7E650EB6B7A45C" + + "7E089FED7FBA344282CAFBD6F7E319F7C0B0BD59E2CA4BDB556D61A5")); + + return new X9ECParameters(curve, G, n, h, S); + } + }; + + /* + * secp224r1 + */ + static X9ECParametersHolder secp224r1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + // p = 2^224 - 2^96 + 1 + BigInteger p = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000001"); + BigInteger a = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFE"); + BigInteger b = fromHex("B4050A850C04B3ABF54132565044B0B7D7BFD8BA270B39432355FFB4"); + byte[] S = Hex.decode("BD71344799D5C7FCDC45B59FA3B9AB8F6A948BC5"); + BigInteger n = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A3D"); + BigInteger h = BigInteger.valueOf(1); + + ECCurve curve = new ECCurve.Fp(p, a, b); + //ECPoint G = curve.decodePoint(Hex.decode("02" + //+ "B70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21")); + ECPoint G = curve.decodePoint(Hex.decode("04" + + "B70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21" + + "BD376388B5F723FB4C22DFE6CD4375A05A07476444D5819985007E34")); + + return new X9ECParameters(curve, G, n, h, S); + } + }; + + /* + * secp256k1 + */ + static X9ECParametersHolder secp256k1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + // p = 2^256 - 2^32 - 2^9 - 2^8 - 2^7 - 2^6 - 2^4 - 1 + BigInteger p = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F"); + BigInteger a = ECConstants.ZERO; + BigInteger b = BigInteger.valueOf(7); + byte[] S = null; + BigInteger n = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141"); + BigInteger h = BigInteger.valueOf(1); + + ECCurve curve = new ECCurve.Fp(p, a, b); + //ECPoint G = curve.decodePoint(Hex.decode("02" + //+ "79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798")); + ECPoint G = curve.decodePoint(Hex.decode("04" + + "79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798" + + "483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8")); + + return new X9ECParameters(curve, G, n, h, S); + } + }; + + /* + * secp256r1 + */ + static X9ECParametersHolder secp256r1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + // p = 2^224 (2^32 - 1) + 2^192 + 2^96 - 1 + BigInteger p = fromHex("FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF"); + BigInteger a = fromHex("FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC"); + BigInteger b = fromHex("5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B"); + byte[] S = Hex.decode("C49D360886E704936A6678E1139D26B7819F7E90"); + BigInteger n = fromHex("FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551"); + BigInteger h = BigInteger.valueOf(1); + + ECCurve curve = new ECCurve.Fp(p, a, b); + //ECPoint G = curve.decodePoint(Hex.decode("03" + //+ "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296")); + ECPoint G = curve.decodePoint(Hex.decode("04" + + "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296" + + "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5")); + + return new X9ECParameters(curve, G, n, h, S); + } + }; + + /* + * secp384r1 + */ + static X9ECParametersHolder secp384r1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + // p = 2^384 - 2^128 - 2^96 + 2^32 - 1 + BigInteger p = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF"); + BigInteger a = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFC"); + BigInteger b = fromHex("B3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF"); + byte[] S = Hex.decode("A335926AA319A27A1D00896A6773A4827ACDAC73"); + BigInteger n = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973"); + BigInteger h = BigInteger.valueOf(1); + + ECCurve curve = new ECCurve.Fp(p, a, b); + //ECPoint G = curve.decodePoint(Hex.decode("03" + //+ "AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB7")); + ECPoint G = curve.decodePoint(Hex.decode("04" + + "AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB7" + + "3617DE4A96262C6F5D9E98BF9292DC29F8F41DBD289A147CE9DA3113B5F0B8C00A60B1CE1D7E819D7A431D7C90EA0E5F")); + + return new X9ECParameters(curve, G, n, h, S); + } + }; + + /* + * secp521r1 + */ + static X9ECParametersHolder secp521r1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + // p = 2^521 - 1 + BigInteger p = fromHex("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"); + BigInteger a = fromHex("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC"); + BigInteger b = fromHex("0051953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00"); + byte[] S = Hex.decode("D09E8800291CB85396CC6717393284AAA0DA64BA"); + BigInteger n = fromHex("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409"); + BigInteger h = BigInteger.valueOf(1); + + ECCurve curve = new ECCurve.Fp(p, a, b); + //ECPoint G = curve.decodePoint(Hex.decode("02" + //+ "00C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66")); + ECPoint G = curve.decodePoint(Hex.decode("04" + + "00C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66" + + "011839296A789A3BC0045C8A5FB42C7D1BD998F54449579B446817AFBD17273E662C97EE72995EF42640C550B9013FAD0761353C7086A272C24088BE94769FD16650")); + + return new X9ECParameters(curve, G, n, h, S); + } + }; + + /* + * sect113r1 + */ + static X9ECParametersHolder sect113r1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + int m = 113; + int k = 9; + + BigInteger a = fromHex("003088250CA6E7C7FE649CE85820F7"); + BigInteger b = fromHex("00E8BEE4D3E2260744188BE0E9C723"); + byte[] S = Hex.decode("10E723AB14D696E6768756151756FEBF8FCB49A9"); + BigInteger n = fromHex("0100000000000000D9CCEC8A39E56F"); + BigInteger h = BigInteger.valueOf(2); + + ECCurve curve = new ECCurve.F2m(m, k, a, b, n, h); + //ECPoint G = curve.decodePoint(Hex.decode("03" + //+ "009D73616F35F4AB1407D73562C10F")); + ECPoint G = curve.decodePoint(Hex.decode("04" + + "009D73616F35F4AB1407D73562C10F" + + "00A52830277958EE84D1315ED31886")); + + return new X9ECParameters(curve, G, n, h, S); + } + }; + + /* + * sect113r2 + */ + static X9ECParametersHolder sect113r2 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + int m = 113; + int k = 9; + + BigInteger a = fromHex("00689918DBEC7E5A0DD6DFC0AA55C7"); + BigInteger b = fromHex("0095E9A9EC9B297BD4BF36E059184F"); + byte[] S = Hex.decode("10C0FB15760860DEF1EEF4D696E676875615175D"); + BigInteger n = fromHex("010000000000000108789B2496AF93"); + BigInteger h = BigInteger.valueOf(2); + + ECCurve curve = new ECCurve.F2m(m, k, a, b, n, h); + //ECPoint G = curve.decodePoint(Hex.decode("03" + //+ "01A57A6A7B26CA5EF52FCDB8164797")); + ECPoint G = curve.decodePoint(Hex.decode("04" + + "01A57A6A7B26CA5EF52FCDB8164797" + + "00B3ADC94ED1FE674C06E695BABA1D")); + + return new X9ECParameters(curve, G, n, h, S); + } + }; + + /* + * sect131r1 + */ + static X9ECParametersHolder sect131r1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + int m = 131; + int k1 = 2; + int k2 = 3; + int k3 = 8; + + BigInteger a = fromHex("07A11B09A76B562144418FF3FF8C2570B8"); + BigInteger b = fromHex("0217C05610884B63B9C6C7291678F9D341"); + byte[] S = Hex.decode("4D696E676875615175985BD3ADBADA21B43A97E2"); + BigInteger n = fromHex("0400000000000000023123953A9464B54D"); + BigInteger h = BigInteger.valueOf(2); + + ECCurve curve = new ECCurve.F2m(m, k1, k2, k3, a, b, n, h); + //ECPoint G = curve.decodePoint(Hex.decode("03" + //+ "0081BAF91FDF9833C40F9C181343638399")); + ECPoint G = curve.decodePoint(Hex.decode("04" + + "0081BAF91FDF9833C40F9C181343638399" + + "078C6E7EA38C001F73C8134B1B4EF9E150")); + + return new X9ECParameters(curve, G, n, h, S); + } + }; + + /* + * sect131r2 + */ + static X9ECParametersHolder sect131r2 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + int m = 131; + int k1 = 2; + int k2 = 3; + int k3 = 8; + + BigInteger a = fromHex("03E5A88919D7CAFCBF415F07C2176573B2"); + BigInteger b = fromHex("04B8266A46C55657AC734CE38F018F2192"); + byte[] S = Hex.decode("985BD3ADBAD4D696E676875615175A21B43A97E3"); + BigInteger n = fromHex("0400000000000000016954A233049BA98F"); + BigInteger h = BigInteger.valueOf(2); + + ECCurve curve = new ECCurve.F2m(m, k1, k2, k3, a, b, n, h); + //ECPoint G = curve.decodePoint(Hex.decode("03" + //+ "0356DCD8F2F95031AD652D23951BB366A8")); + ECPoint G = curve.decodePoint(Hex.decode("04" + + "0356DCD8F2F95031AD652D23951BB366A8" + + "0648F06D867940A5366D9E265DE9EB240F")); + + return new X9ECParameters(curve, G, n, h, S); + } + }; + + /* + * sect163k1 + */ + static X9ECParametersHolder sect163k1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + int m = 163; + int k1 = 3; + int k2 = 6; + int k3 = 7; + + BigInteger a = BigInteger.valueOf(1); + BigInteger b = BigInteger.valueOf(1); + byte[] S = null; + BigInteger n = fromHex("04000000000000000000020108A2E0CC0D99F8A5EF"); + BigInteger h = BigInteger.valueOf(2); + + ECCurve curve = new ECCurve.F2m(m, k1, k2, k3, a, b, n, h); + //ECPoint G = curve.decodePoint(Hex.decode("03" + //+ "02FE13C0537BBC11ACAA07D793DE4E6D5E5C94EEE8")); + ECPoint G = curve.decodePoint(Hex.decode("04" + + "02FE13C0537BBC11ACAA07D793DE4E6D5E5C94EEE8" + + "0289070FB05D38FF58321F2E800536D538CCDAA3D9")); + + return new X9ECParameters(curve, G, n, h, S); + } + }; + + /* + * sect163r1 + */ + static X9ECParametersHolder sect163r1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + int m = 163; + int k1 = 3; + int k2 = 6; + int k3 = 7; + + BigInteger a = fromHex("07B6882CAAEFA84F9554FF8428BD88E246D2782AE2"); + BigInteger b = fromHex("0713612DCDDCB40AAB946BDA29CA91F73AF958AFD9"); + byte[] S = Hex.decode("24B7B137C8A14D696E6768756151756FD0DA2E5C"); + BigInteger n = fromHex("03FFFFFFFFFFFFFFFFFFFF48AAB689C29CA710279B"); + BigInteger h = BigInteger.valueOf(2); + + ECCurve curve = new ECCurve.F2m(m, k1, k2, k3, a, b, n, h); + //ECPoint G = curve.decodePoint(Hex.decode("03" + //+ "0369979697AB43897789566789567F787A7876A654")); + ECPoint G = curve.decodePoint(Hex.decode("04" + + "0369979697AB43897789566789567F787A7876A654" + + "00435EDB42EFAFB2989D51FEFCE3C80988F41FF883")); + + return new X9ECParameters(curve, G, n, h, S); + } + }; + + /* + * sect163r2 + */ + static X9ECParametersHolder sect163r2 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + int m = 163; + int k1 = 3; + int k2 = 6; + int k3 = 7; + + BigInteger a = BigInteger.valueOf(1); + BigInteger b = fromHex("020A601907B8C953CA1481EB10512F78744A3205FD"); + byte[] S = Hex.decode("85E25BFE5C86226CDB12016F7553F9D0E693A268"); + BigInteger n = fromHex("040000000000000000000292FE77E70C12A4234C33"); + BigInteger h = BigInteger.valueOf(2); + + ECCurve curve = new ECCurve.F2m(m, k1, k2, k3, a, b, n, h); + //ECPoint G = curve.decodePoint(Hex.decode("03" + //+ "03F0EBA16286A2D57EA0991168D4994637E8343E36")); + ECPoint G = curve.decodePoint(Hex.decode("04" + + "03F0EBA16286A2D57EA0991168D4994637E8343E36" + + "00D51FBC6C71A0094FA2CDD545B11C5C0C797324F1")); + + return new X9ECParameters(curve, G, n, h, S); + } + }; + + /* + * sect193r1 + */ + static X9ECParametersHolder sect193r1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + int m = 193; + int k = 15; + + BigInteger a = fromHex("0017858FEB7A98975169E171F77B4087DE098AC8A911DF7B01"); + BigInteger b = fromHex("00FDFB49BFE6C3A89FACADAA7A1E5BBC7CC1C2E5D831478814"); + byte[] S = Hex.decode("103FAEC74D696E676875615175777FC5B191EF30"); + BigInteger n = fromHex("01000000000000000000000000C7F34A778F443ACC920EBA49"); + BigInteger h = BigInteger.valueOf(2); + + ECCurve curve = new ECCurve.F2m(m, k, a, b, n, h); + //ECPoint G = curve.decodePoint(Hex.decode("03" + //+ "01F481BC5F0FF84A74AD6CDF6FDEF4BF6179625372D8C0C5E1")); + ECPoint G = curve.decodePoint(Hex.decode("04" + + "01F481BC5F0FF84A74AD6CDF6FDEF4BF6179625372D8C0C5E1" + + "0025E399F2903712CCF3EA9E3A1AD17FB0B3201B6AF7CE1B05")); + + return new X9ECParameters(curve, G, n, h, S); + } + }; + + /* + * sect193r2 + */ + static X9ECParametersHolder sect193r2 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + int m = 193; + int k = 15; + + BigInteger a = fromHex("0163F35A5137C2CE3EA6ED8667190B0BC43ECD69977702709B"); + BigInteger b = fromHex("00C9BB9E8927D4D64C377E2AB2856A5B16E3EFB7F61D4316AE"); + byte[] S = Hex.decode("10B7B4D696E676875615175137C8A16FD0DA2211"); + BigInteger n = fromHex("010000000000000000000000015AAB561B005413CCD4EE99D5"); + BigInteger h = BigInteger.valueOf(2); + + ECCurve curve = new ECCurve.F2m(m, k, a, b, n, h); + //ECPoint G = curve.decodePoint(Hex.decode("03" + //+ "00D9B67D192E0367C803F39E1A7E82CA14A651350AAE617E8F")); + ECPoint G = curve.decodePoint(Hex.decode("04" + + "00D9B67D192E0367C803F39E1A7E82CA14A651350AAE617E8F" + + "01CE94335607C304AC29E7DEFBD9CA01F596F927224CDECF6C")); + + return new X9ECParameters(curve, G, n, h, S); + } + }; + + /* + * sect233k1 + */ + static X9ECParametersHolder sect233k1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + int m = 233; + int k = 74; + + BigInteger a = ECConstants.ZERO; + BigInteger b = BigInteger.valueOf(1); + byte[] S = null; + BigInteger n = fromHex("8000000000000000000000000000069D5BB915BCD46EFB1AD5F173ABDF"); + BigInteger h = BigInteger.valueOf(4); + + ECCurve curve = new ECCurve.F2m(m, k, a, b, n, h); + //ECPoint G = curve.decodePoint(Hex.decode("02" + //+ "017232BA853A7E731AF129F22FF4149563A419C26BF50A4C9D6EEFAD6126")); + ECPoint G = curve.decodePoint(Hex.decode("04" + + "017232BA853A7E731AF129F22FF4149563A419C26BF50A4C9D6EEFAD6126" + + "01DB537DECE819B7F70F555A67C427A8CD9BF18AEB9B56E0C11056FAE6A3")); + + return new X9ECParameters(curve, G, n, h, S); + } + }; + + /* + * sect233r1 + */ + static X9ECParametersHolder sect233r1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + int m = 233; + int k = 74; + + BigInteger a = BigInteger.valueOf(1); + BigInteger b = fromHex("0066647EDE6C332C7F8C0923BB58213B333B20E9CE4281FE115F7D8F90AD"); + byte[] S = Hex.decode("74D59FF07F6B413D0EA14B344B20A2DB049B50C3"); + BigInteger n = fromHex("01000000000000000000000000000013E974E72F8A6922031D2603CFE0D7"); + BigInteger h = BigInteger.valueOf(2); + + ECCurve curve = new ECCurve.F2m(m, k, a, b, n, h); + //ECPoint G = curve.decodePoint(Hex.decode("03" + //+ "00FAC9DFCBAC8313BB2139F1BB755FEF65BC391F8B36F8F8EB7371FD558B")); + ECPoint G = curve.decodePoint(Hex.decode("04" + + "00FAC9DFCBAC8313BB2139F1BB755FEF65BC391F8B36F8F8EB7371FD558B" + + "01006A08A41903350678E58528BEBF8A0BEFF867A7CA36716F7E01F81052")); + + return new X9ECParameters(curve, G, n, h, S); + } + }; + + /* + * sect239k1 + */ + static X9ECParametersHolder sect239k1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + int m = 239; + int k = 158; + + BigInteger a = ECConstants.ZERO; + BigInteger b = BigInteger.valueOf(1); + byte[] S = null; + BigInteger n = fromHex("2000000000000000000000000000005A79FEC67CB6E91F1C1DA800E478A5"); + BigInteger h = BigInteger.valueOf(4); + + ECCurve curve = new ECCurve.F2m(m, k, a, b, n, h); + //ECPoint G = curve.decodePoint(Hex.decode("03" + //+ "29A0B6A887A983E9730988A68727A8B2D126C44CC2CC7B2A6555193035DC")); + ECPoint G = curve.decodePoint(Hex.decode("04" + + "29A0B6A887A983E9730988A68727A8B2D126C44CC2CC7B2A6555193035DC" + + "76310804F12E549BDB011C103089E73510ACB275FC312A5DC6B76553F0CA")); + + return new X9ECParameters(curve, G, n, h, S); + } + }; + + /* + * sect283k1 + */ + static X9ECParametersHolder sect283k1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + int m = 283; + int k1 = 5; + int k2 = 7; + int k3 = 12; + + BigInteger a = ECConstants.ZERO; + BigInteger b = BigInteger.valueOf(1); + byte[] S = null; + BigInteger n = fromHex("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE9AE2ED07577265DFF7F94451E061E163C61"); + BigInteger h = BigInteger.valueOf(4); + + ECCurve curve = new ECCurve.F2m(m, k1, k2, k3, a, b, n, h); + //ECPoint G = curve.decodePoint(Hex.decode("02" + //+ "0503213F78CA44883F1A3B8162F188E553CD265F23C1567A16876913B0C2AC2458492836")); + ECPoint G = curve.decodePoint(Hex.decode("04" + + "0503213F78CA44883F1A3B8162F188E553CD265F23C1567A16876913B0C2AC2458492836" + + "01CCDA380F1C9E318D90F95D07E5426FE87E45C0E8184698E45962364E34116177DD2259")); + + return new X9ECParameters(curve, G, n, h, S); + } + }; + + /* + * sect283r1 + */ + static X9ECParametersHolder sect283r1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + int m = 283; + int k1 = 5; + int k2 = 7; + int k3 = 12; + + BigInteger a = BigInteger.valueOf(1); + BigInteger b = fromHex("027B680AC8B8596DA5A4AF8A19A0303FCA97FD7645309FA2A581485AF6263E313B79A2F5"); + byte[] S = Hex.decode("77E2B07370EB0F832A6DD5B62DFC88CD06BB84BE"); + BigInteger n = fromHex("03FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEF90399660FC938A90165B042A7CEFADB307"); + BigInteger h = BigInteger.valueOf(2); + + ECCurve curve = new ECCurve.F2m(m, k1, k2, k3, a, b, n, h); + //ECPoint G = curve.decodePoint(Hex.decode("03" + //+ "05F939258DB7DD90E1934F8C70B0DFEC2EED25B8557EAC9C80E2E198F8CDBECD86B12053")); + ECPoint G = curve.decodePoint(Hex.decode("04" + + "05F939258DB7DD90E1934F8C70B0DFEC2EED25B8557EAC9C80E2E198F8CDBECD86B12053" + + "03676854FE24141CB98FE6D4B20D02B4516FF702350EDDB0826779C813F0DF45BE8112F4")); + + return new X9ECParameters(curve, G, n, h, S); + } + }; + + /* + * sect409k1 + */ + static X9ECParametersHolder sect409k1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + int m = 409; + int k = 87; + + BigInteger a = ECConstants.ZERO; + BigInteger b = BigInteger.valueOf(1); + byte[] S = null; + BigInteger n = fromHex("7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE5F83B2D4EA20400EC4557D5ED3E3E7CA5B4B5C83B8E01E5FCF"); + BigInteger h = BigInteger.valueOf(4); + + ECCurve curve = new ECCurve.F2m(m, k, a, b, n, h); + //ECPoint G = curve.decodePoint(Hex.decode("03" + //+ "0060F05F658F49C1AD3AB1890F7184210EFD0987E307C84C27ACCFB8F9F67CC2C460189EB5AAAA62EE222EB1B35540CFE9023746")); + ECPoint G = curve.decodePoint(Hex.decode("04" + + "0060F05F658F49C1AD3AB1890F7184210EFD0987E307C84C27ACCFB8F9F67CC2C460189EB5AAAA62EE222EB1B35540CFE9023746" + + "01E369050B7C4E42ACBA1DACBF04299C3460782F918EA427E6325165E9EA10E3DA5F6C42E9C55215AA9CA27A5863EC48D8E0286B")); + + return new X9ECParameters(curve, G, n, h, S); + } + }; + + /* + * sect409r1 + */ + static X9ECParametersHolder sect409r1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + int m = 409; + int k = 87; + + BigInteger a = BigInteger.valueOf(1); + BigInteger b = fromHex("0021A5C2C8EE9FEB5C4B9A753B7B476B7FD6422EF1F3DD674761FA99D6AC27C8A9A197B272822F6CD57A55AA4F50AE317B13545F"); + byte[] S = Hex.decode("4099B5A457F9D69F79213D094C4BCD4D4262210B"); + BigInteger n = fromHex("010000000000000000000000000000000000000000000000000001E2AAD6A612F33307BE5FA47C3C9E052F838164CD37D9A21173"); + BigInteger h = BigInteger.valueOf(2); + + ECCurve curve = new ECCurve.F2m(m, k, a, b, n, h); + //ECPoint G = curve.decodePoint(Hex.decode("03" + //+ "015D4860D088DDB3496B0C6064756260441CDE4AF1771D4DB01FFE5B34E59703DC255A868A1180515603AEAB60794E54BB7996A7")); + ECPoint G = curve.decodePoint(Hex.decode("04" + + "015D4860D088DDB3496B0C6064756260441CDE4AF1771D4DB01FFE5B34E59703DC255A868A1180515603AEAB60794E54BB7996A7" + + "0061B1CFAB6BE5F32BBFA78324ED106A7636B9C5A7BD198D0158AA4F5488D08F38514F1FDF4B4F40D2181B3681C364BA0273C706")); + + return new X9ECParameters(curve, G, n, h, S); + } + }; + + /* + * sect571k1 + */ + static X9ECParametersHolder sect571k1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + int m = 571; + int k1 = 2; + int k2 = 5; + int k3 = 10; + + BigInteger a = ECConstants.ZERO; + BigInteger b = BigInteger.valueOf(1); + byte[] S = null; + BigInteger n = fromHex("020000000000000000000000000000000000000000000000000000000000000000000000131850E1F19A63E4B391A8DB917F4138B630D84BE5D639381E91DEB45CFE778F637C1001"); + BigInteger h = BigInteger.valueOf(4); + + ECCurve curve = new ECCurve.F2m(m, k1, k2, k3, a, b, n, h); + //ECPoint G = curve.decodePoint(Hex.decode("02" + //+ "026EB7A859923FBC82189631F8103FE4AC9CA2970012D5D46024804801841CA44370958493B205E647DA304DB4CEB08CBBD1BA39494776FB988B47174DCA88C7E2945283A01C8972")); + ECPoint G = curve.decodePoint(Hex.decode("04" + + "026EB7A859923FBC82189631F8103FE4AC9CA2970012D5D46024804801841CA44370958493B205E647DA304DB4CEB08CBBD1BA39494776FB988B47174DCA88C7E2945283A01C8972" + + "0349DC807F4FBF374F4AEADE3BCA95314DD58CEC9F307A54FFC61EFC006D8A2C9D4979C0AC44AEA74FBEBBB9F772AEDCB620B01A7BA7AF1B320430C8591984F601CD4C143EF1C7A3")); + + return new X9ECParameters(curve, G, n, h, S); + } + }; + + /* + * sect571r1 + */ + static X9ECParametersHolder sect571r1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + int m = 571; + int k1 = 2; + int k2 = 5; + int k3 = 10; + + BigInteger a = BigInteger.valueOf(1); + BigInteger b = fromHex("02F40E7E2221F295DE297117B7F3D62F5C6A97FFCB8CEFF1CD6BA8CE4A9A18AD84FFABBD8EFA59332BE7AD6756A66E294AFD185A78FF12AA520E4DE739BACA0C7FFEFF7F2955727A"); + byte[] S = Hex.decode("2AA058F73A0E33AB486B0F610410C53A7F132310"); + BigInteger n = fromHex("03FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE661CE18FF55987308059B186823851EC7DD9CA1161DE93D5174D66E8382E9BB2FE84E47"); + BigInteger h = BigInteger.valueOf(2); + + ECCurve curve = new ECCurve.F2m(m, k1, k2, k3, a, b, n, h); + //ECPoint G = curve.decodePoint(Hex.decode("03" + //+ "0303001D34B856296C16C0D40D3CD7750A93D1D2955FA80AA5F40FC8DB7B2ABDBDE53950F4C0D293CDD711A35B67FB1499AE60038614F1394ABFA3B4C850D927E1E7769C8EEC2D19")); + ECPoint G = curve.decodePoint(Hex.decode("04" + + "0303001D34B856296C16C0D40D3CD7750A93D1D2955FA80AA5F40FC8DB7B2ABDBDE53950F4C0D293CDD711A35B67FB1499AE60038614F1394ABFA3B4C850D927E1E7769C8EEC2D19" + + "037BF27342DA639B6DCCFFFEB73D69D78C6C27A6009CBBCA1980F8533921E8A684423E43BAB08A576291AF8F461BB2A8B3531D2F0485C19B16E2F1516E23DD3C1A4827AF1B8AC15B")); + + return new X9ECParameters(curve, G, n, h, S); + } + }; + + + static final Hashtable objIds = new Hashtable(); + static final Hashtable curves = new Hashtable(); + static final Hashtable names = new Hashtable(); + + static void defineCurve(String name, ASN1ObjectIdentifier oid, X9ECParametersHolder holder) + { + objIds.put(name, oid); + names.put(oid, name); + curves.put(oid, holder); + } + + static + { + defineCurve("secp112r1", SECObjectIdentifiers.secp112r1, secp112r1); + defineCurve("secp112r2", SECObjectIdentifiers.secp112r2, secp112r2); + defineCurve("secp128r1", SECObjectIdentifiers.secp128r1, secp128r1); + defineCurve("secp128r2", SECObjectIdentifiers.secp128r2, secp128r2); + defineCurve("secp160k1", SECObjectIdentifiers.secp160k1, secp160k1); + defineCurve("secp160r1", SECObjectIdentifiers.secp160r1, secp160r1); + defineCurve("secp160r2", SECObjectIdentifiers.secp160r2, secp160r2); + defineCurve("secp192k1", SECObjectIdentifiers.secp192k1, secp192k1); + defineCurve("secp192r1", SECObjectIdentifiers.secp192r1, secp192r1); + defineCurve("secp224k1", SECObjectIdentifiers.secp224k1, secp224k1); + defineCurve("secp224r1", SECObjectIdentifiers.secp224r1, secp224r1); + defineCurve("secp256k1", SECObjectIdentifiers.secp256k1, secp256k1); + defineCurve("secp256r1", SECObjectIdentifiers.secp256r1, secp256r1); + defineCurve("secp384r1", SECObjectIdentifiers.secp384r1, secp384r1); + defineCurve("secp521r1", SECObjectIdentifiers.secp521r1, secp521r1); + + defineCurve("sect113r1", SECObjectIdentifiers.sect113r1, sect113r1); + defineCurve("sect113r2", SECObjectIdentifiers.sect113r2, sect113r2); + defineCurve("sect131r1", SECObjectIdentifiers.sect131r1, sect131r1); + defineCurve("sect131r2", SECObjectIdentifiers.sect131r2, sect131r2); + defineCurve("sect163k1", SECObjectIdentifiers.sect163k1, sect163k1); + defineCurve("sect163r1", SECObjectIdentifiers.sect163r1, sect163r1); + defineCurve("sect163r2", SECObjectIdentifiers.sect163r2, sect163r2); + defineCurve("sect193r1", SECObjectIdentifiers.sect193r1, sect193r1); + defineCurve("sect193r2", SECObjectIdentifiers.sect193r2, sect193r2); + defineCurve("sect233k1", SECObjectIdentifiers.sect233k1, sect233k1); + defineCurve("sect233r1", SECObjectIdentifiers.sect233r1, sect233r1); + defineCurve("sect239k1", SECObjectIdentifiers.sect239k1, sect239k1); + defineCurve("sect283k1", SECObjectIdentifiers.sect283k1, sect283k1); + defineCurve("sect283r1", SECObjectIdentifiers.sect283r1, sect283r1); + defineCurve("sect409k1", SECObjectIdentifiers.sect409k1, sect409k1); + defineCurve("sect409r1", SECObjectIdentifiers.sect409r1, sect409r1); + defineCurve("sect571k1", SECObjectIdentifiers.sect571k1, sect571k1); + defineCurve("sect571r1", SECObjectIdentifiers.sect571r1, sect571r1); + } + + public static X9ECParameters getByName( + String name) + { + ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)objIds.get(Strings.toLowerCase(name)); + + if (oid != null) + { + return getByOID(oid); + } + + return null; + } + + /** + * return the X9ECParameters object for the named curve represented by + * the passed in object identifier. Null if the curve isn't present. + * + * @param oid an object identifier representing a named curve, if present. + */ + public static X9ECParameters getByOID( + ASN1ObjectIdentifier oid) + { + X9ECParametersHolder holder = (X9ECParametersHolder)curves.get(oid); + + if (holder != null) + { + return holder.getParameters(); + } + + return null; + } + + /** + * return the object identifier signified by the passed in name. Null + * if there is no object identifier associated with name. + * + * @return the object identifier associated with name, if present. + */ + public static ASN1ObjectIdentifier getOID( + String name) + { + return (ASN1ObjectIdentifier)objIds.get(Strings.toLowerCase(name)); + } + + /** + * return the named curve name represented by the given object identifier. + */ + public static String getName( + ASN1ObjectIdentifier oid) + { + return (String)names.get(oid); + } + + /** + * returns an enumeration containing the name strings for curves + * contained in this structure. + */ + public static Enumeration getNames() + { + return objIds.keys(); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/sec/SECObjectIdentifiers.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/sec/SECObjectIdentifiers.java new file mode 100644 index 0000000..a944787 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/sec/SECObjectIdentifiers.java @@ -0,0 +1,50 @@ +package org.bc.asn1.sec; + +import org.bc.asn1.ASN1ObjectIdentifier; +import org.bc.asn1.x9.X9ObjectIdentifiers; + +public interface SECObjectIdentifiers +{ + /** + * ellipticCurve OBJECT IDENTIFIER ::= { + * iso(1) identified-organization(3) certicom(132) curve(0) + * } + */ + static final ASN1ObjectIdentifier ellipticCurve = new ASN1ObjectIdentifier("1.3.132.0"); + + static final ASN1ObjectIdentifier sect163k1 = ellipticCurve.branch("1"); + static final ASN1ObjectIdentifier sect163r1 = ellipticCurve.branch("2"); + static final ASN1ObjectIdentifier sect239k1 = ellipticCurve.branch("3"); + static final ASN1ObjectIdentifier sect113r1 = ellipticCurve.branch("4"); + static final ASN1ObjectIdentifier sect113r2 = ellipticCurve.branch("5"); + static final ASN1ObjectIdentifier secp112r1 = ellipticCurve.branch("6"); + static final ASN1ObjectIdentifier secp112r2 = ellipticCurve.branch("7"); + static final ASN1ObjectIdentifier secp160r1 = ellipticCurve.branch("8"); + static final ASN1ObjectIdentifier secp160k1 = ellipticCurve.branch("9"); + static final ASN1ObjectIdentifier secp256k1 = ellipticCurve.branch("10"); + static final ASN1ObjectIdentifier sect163r2 = ellipticCurve.branch("15"); + static final ASN1ObjectIdentifier sect283k1 = ellipticCurve.branch("16"); + static final ASN1ObjectIdentifier sect283r1 = ellipticCurve.branch("17"); + static final ASN1ObjectIdentifier sect131r1 = ellipticCurve.branch("22"); + static final ASN1ObjectIdentifier sect131r2 = ellipticCurve.branch("23"); + static final ASN1ObjectIdentifier sect193r1 = ellipticCurve.branch("24"); + static final ASN1ObjectIdentifier sect193r2 = ellipticCurve.branch("25"); + static final ASN1ObjectIdentifier sect233k1 = ellipticCurve.branch("26"); + static final ASN1ObjectIdentifier sect233r1 = ellipticCurve.branch("27"); + static final ASN1ObjectIdentifier secp128r1 = ellipticCurve.branch("28"); + static final ASN1ObjectIdentifier secp128r2 = ellipticCurve.branch("29"); + static final ASN1ObjectIdentifier secp160r2 = ellipticCurve.branch("30"); + static final ASN1ObjectIdentifier secp192k1 = ellipticCurve.branch("31"); + static final ASN1ObjectIdentifier secp224k1 = ellipticCurve.branch("32"); + static final ASN1ObjectIdentifier secp224r1 = ellipticCurve.branch("33"); + static final ASN1ObjectIdentifier secp384r1 = ellipticCurve.branch("34"); + static final ASN1ObjectIdentifier secp521r1 = ellipticCurve.branch("35"); + static final ASN1ObjectIdentifier sect409k1 = ellipticCurve.branch("36"); + static final ASN1ObjectIdentifier sect409r1 = ellipticCurve.branch("37"); + static final ASN1ObjectIdentifier sect571k1 = ellipticCurve.branch("38"); + static final ASN1ObjectIdentifier sect571r1 = ellipticCurve.branch("39"); + + static final ASN1ObjectIdentifier secp192r1 = X9ObjectIdentifiers.prime192v1; + static final ASN1ObjectIdentifier secp256r1 = X9ObjectIdentifiers.prime256v1; + +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/smime/SMIMEAttributes.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/smime/SMIMEAttributes.java new file mode 100644 index 0000000..318c5c2 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/smime/SMIMEAttributes.java @@ -0,0 +1,10 @@ +package org.bc.asn1.smime; + +import org.bc.asn1.ASN1ObjectIdentifier; +import org.bc.asn1.pkcs.PKCSObjectIdentifiers; + +public interface SMIMEAttributes +{ + public static final ASN1ObjectIdentifier smimeCapabilities = PKCSObjectIdentifiers.pkcs_9_at_smimeCapabilities; + public static final ASN1ObjectIdentifier encrypKeyPref = PKCSObjectIdentifiers.id_aa_encrypKeyPref; +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/smime/SMIMECapabilities.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/smime/SMIMECapabilities.java new file mode 100644 index 0000000..80ff142 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/smime/SMIMECapabilities.java @@ -0,0 +1,115 @@ +package org.bc.asn1.smime; + +import java.util.Enumeration; +import java.util.Vector; + +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1ObjectIdentifier; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.cms.Attribute; +import org.bc.asn1.pkcs.PKCSObjectIdentifiers; + +/** + * Handler class for dealing with S/MIME Capabilities + */ +public class SMIMECapabilities + extends ASN1Object +{ + /** + * general preferences + */ + public static final ASN1ObjectIdentifier preferSignedData = PKCSObjectIdentifiers.preferSignedData; + public static final ASN1ObjectIdentifier canNotDecryptAny = PKCSObjectIdentifiers.canNotDecryptAny; + public static final ASN1ObjectIdentifier sMIMECapabilitesVersions = PKCSObjectIdentifiers.sMIMECapabilitiesVersions; + + /** + * encryption algorithms preferences + */ + public static final ASN1ObjectIdentifier dES_CBC = new ASN1ObjectIdentifier("1.3.14.3.2.7"); + public static final ASN1ObjectIdentifier dES_EDE3_CBC = PKCSObjectIdentifiers.des_EDE3_CBC; + public static final ASN1ObjectIdentifier rC2_CBC = PKCSObjectIdentifiers.RC2_CBC; + + private ASN1Sequence capabilities; + + /** + * return an Attribute object from the given object. + * + * @param o the object we want converted. + * @exception IllegalArgumentException if the object cannot be converted. + */ + public static SMIMECapabilities getInstance( + Object o) + { + if (o == null || o instanceof SMIMECapabilities) + { + return (SMIMECapabilities)o; + } + + if (o instanceof ASN1Sequence) + { + return new SMIMECapabilities((ASN1Sequence)o); + } + + if (o instanceof Attribute) + { + return new SMIMECapabilities( + (ASN1Sequence)(((Attribute)o).getAttrValues().getObjectAt(0))); + } + + throw new IllegalArgumentException("unknown object in factory: " + o.getClass().getName()); + } + + public SMIMECapabilities( + ASN1Sequence seq) + { + capabilities = seq; + } + + /** + * returns a vector with 0 or more objects of all the capabilities + * matching the passed in capability OID. If the OID passed is null the + * entire set is returned. + */ + public Vector getCapabilities( + ASN1ObjectIdentifier capability) + { + Enumeration e = capabilities.getObjects(); + Vector list = new Vector(); + + if (capability == null) + { + while (e.hasMoreElements()) + { + SMIMECapability cap = SMIMECapability.getInstance(e.nextElement()); + + list.addElement(cap); + } + } + else + { + while (e.hasMoreElements()) + { + SMIMECapability cap = SMIMECapability.getInstance(e.nextElement()); + + if (capability.equals(cap.getCapabilityID())) + { + list.addElement(cap); + } + } + } + + return list; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + *
+ * SMIMECapabilities ::= SEQUENCE OF SMIMECapability + *+ */ + public ASN1Primitive toASN1Primitive() + { + return capabilities; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/smime/SMIMECapabilitiesAttribute.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/smime/SMIMECapabilitiesAttribute.java new file mode 100644 index 0000000..905c626 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/smime/SMIMECapabilitiesAttribute.java @@ -0,0 +1,16 @@ +package org.bc.asn1.smime; + +import org.bc.asn1.DERSequence; +import org.bc.asn1.DERSet; +import org.bc.asn1.cms.Attribute; + +public class SMIMECapabilitiesAttribute + extends Attribute +{ + public SMIMECapabilitiesAttribute( + SMIMECapabilityVector capabilities) + { + super(SMIMEAttributes.smimeCapabilities, + new DERSet(new DERSequence(capabilities.toASN1EncodableVector()))); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/smime/SMIMECapability.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/smime/SMIMECapability.java new file mode 100644 index 0000000..7071b06 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/smime/SMIMECapability.java @@ -0,0 +1,103 @@ +package org.bc.asn1.smime; + +import org.bc.asn1.ASN1Encodable; +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1ObjectIdentifier; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DERSequence; +import org.bc.asn1.nist.NISTObjectIdentifiers; +import org.bc.asn1.pkcs.PKCSObjectIdentifiers; + +public class SMIMECapability + extends ASN1Object +{ + /** + * general preferences + */ + public static final ASN1ObjectIdentifier preferSignedData = PKCSObjectIdentifiers.preferSignedData; + public static final ASN1ObjectIdentifier canNotDecryptAny = PKCSObjectIdentifiers.canNotDecryptAny; + public static final ASN1ObjectIdentifier sMIMECapabilitiesVersions = PKCSObjectIdentifiers.sMIMECapabilitiesVersions; + + /** + * encryption algorithms preferences + */ + public static final ASN1ObjectIdentifier dES_CBC = new ASN1ObjectIdentifier("1.3.14.3.2.7"); + public static final ASN1ObjectIdentifier dES_EDE3_CBC = PKCSObjectIdentifiers.des_EDE3_CBC; + public static final ASN1ObjectIdentifier rC2_CBC = PKCSObjectIdentifiers.RC2_CBC; + public static final ASN1ObjectIdentifier aES128_CBC = NISTObjectIdentifiers.id_aes128_CBC; + public static final ASN1ObjectIdentifier aES192_CBC = NISTObjectIdentifiers.id_aes192_CBC; + public static final ASN1ObjectIdentifier aES256_CBC = NISTObjectIdentifiers.id_aes256_CBC; + + private ASN1ObjectIdentifier capabilityID; + private ASN1Encodable parameters; + + public SMIMECapability( + ASN1Sequence seq) + { + capabilityID = (ASN1ObjectIdentifier)seq.getObjectAt(0); + + if (seq.size() > 1) + { + parameters = (ASN1Primitive)seq.getObjectAt(1); + } + } + + public SMIMECapability( + ASN1ObjectIdentifier capabilityID, + ASN1Encodable parameters) + { + this.capabilityID = capabilityID; + this.parameters = parameters; + } + + public static SMIMECapability getInstance( + Object obj) + { + if (obj == null || obj instanceof SMIMECapability) + { + return (SMIMECapability)obj; + } + + if (obj instanceof ASN1Sequence) + { + return new SMIMECapability((ASN1Sequence)obj); + } + + throw new IllegalArgumentException("Invalid SMIMECapability"); + } + + public ASN1ObjectIdentifier getCapabilityID() + { + return capabilityID; + } + + public ASN1Encodable getParameters() + { + return parameters; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + *
+ * SMIMECapability ::= SEQUENCE { + * capabilityID OBJECT IDENTIFIER, + * parameters ANY DEFINED BY capabilityID OPTIONAL + * } + *+ */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(capabilityID); + + if (parameters != null) + { + v.add(parameters); + } + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/smime/SMIMECapabilityVector.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/smime/SMIMECapabilityVector.java new file mode 100644 index 0000000..9ec0f55 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/smime/SMIMECapabilityVector.java @@ -0,0 +1,50 @@ +package org.bc.asn1.smime; + +import org.bc.asn1.ASN1Encodable; +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1ObjectIdentifier; +import org.bc.asn1.DERSequence; + +/** + * Handler for creating a vector S/MIME Capabilities + */ +public class SMIMECapabilityVector +{ + private ASN1EncodableVector capabilities = new ASN1EncodableVector(); + + public void addCapability( + ASN1ObjectIdentifier capability) + { + capabilities.add(new DERSequence(capability)); + } + + public void addCapability( + ASN1ObjectIdentifier capability, + int value) + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(capability); + v.add(new ASN1Integer(value)); + + capabilities.add(new DERSequence(v)); + } + + public void addCapability( + ASN1ObjectIdentifier capability, + ASN1Encodable params) + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(capability); + v.add(params); + + capabilities.add(new DERSequence(v)); + } + + public ASN1EncodableVector toASN1EncodableVector() + { + return capabilities; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/smime/SMIMEEncryptionKeyPreferenceAttribute.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/smime/SMIMEEncryptionKeyPreferenceAttribute.java new file mode 100644 index 0000000..06db6e1 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/smime/SMIMEEncryptionKeyPreferenceAttribute.java @@ -0,0 +1,48 @@ +package org.bc.asn1.smime; + +import org.bc.asn1.ASN1OctetString; +import org.bc.asn1.DERSet; +import org.bc.asn1.DERTaggedObject; +import org.bc.asn1.cms.Attribute; +import org.bc.asn1.cms.IssuerAndSerialNumber; +import org.bc.asn1.cms.RecipientKeyIdentifier; + +/** + * The SMIMEEncryptionKeyPreference object. + *
+ * SMIMEEncryptionKeyPreference ::= CHOICE { + * issuerAndSerialNumber [0] IssuerAndSerialNumber, + * receipentKeyId [1] RecipientKeyIdentifier, + * subjectAltKeyIdentifier [2] SubjectKeyIdentifier + * } + *+ */ +public class SMIMEEncryptionKeyPreferenceAttribute + extends Attribute +{ + public SMIMEEncryptionKeyPreferenceAttribute( + IssuerAndSerialNumber issAndSer) + { + super(SMIMEAttributes.encrypKeyPref, + new DERSet(new DERTaggedObject(false, 0, issAndSer))); + } + + public SMIMEEncryptionKeyPreferenceAttribute( + RecipientKeyIdentifier rKeyId) + { + + super(SMIMEAttributes.encrypKeyPref, + new DERSet(new DERTaggedObject(false, 1, rKeyId))); + } + + /** + * @param sKeyId the subjectKeyIdentifier value (normally the X.509 one) + */ + public SMIMEEncryptionKeyPreferenceAttribute( + ASN1OctetString sKeyId) + { + + super(SMIMEAttributes.encrypKeyPref, + new DERSet(new DERTaggedObject(false, 2, sKeyId))); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/teletrust/TeleTrusTNamedCurves.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/teletrust/TeleTrusTNamedCurves.java new file mode 100644 index 0000000..801b1ba --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/teletrust/TeleTrusTNamedCurves.java @@ -0,0 +1,351 @@ +package org.bc.asn1.teletrust; + +import java.math.BigInteger; +import java.util.Enumeration; +import java.util.Hashtable; + +import org.bc.asn1.ASN1ObjectIdentifier; +import org.bc.asn1.x9.X9ECParameters; +import org.bc.asn1.x9.X9ECParametersHolder; +import org.bc.math.ec.ECCurve; +import org.bc.util.Strings; +import org.bc.util.encoders.Hex; + +/** + * elliptic curves defined in "ECC Brainpool Standard Curves and Curve Generation" + * http://www.ecc-brainpool.org/download/draft_pkix_additional_ecc_dp.txt + */ +public class TeleTrusTNamedCurves +{ + static X9ECParametersHolder brainpoolP160r1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + ECCurve curve = new ECCurve.Fp( + new BigInteger("E95E4A5F737059DC60DFC7AD95B3D8139515620F", 16), // q + new BigInteger("340E7BE2A280EB74E2BE61BADA745D97E8F7C300", 16), // a + new BigInteger("1E589A8595423412134FAA2DBDEC95C8D8675E58", 16)); // b + + return new X9ECParameters( + curve, + curve.decodePoint(Hex.decode("04BED5AF16EA3F6A4F62938C4631EB5AF7BDBCDBC31667CB477A1A8EC338F94741669C976316DA6321")), // G + new BigInteger("E95E4A5F737059DC60DF5991D45029409E60FC09", 16), //n + new BigInteger("01", 16)); // h + } + }; + + static X9ECParametersHolder brainpoolP160t1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + ECCurve curve = new ECCurve.Fp( + // new BigInteger("24DBFF5DEC9B986BBFE5295A29BFBAE45E0F5D0B", 16), // Z + new BigInteger("E95E4A5F737059DC60DFC7AD95B3D8139515620F", 16), // q + new BigInteger("E95E4A5F737059DC60DFC7AD95B3D8139515620C", 16), // a' + new BigInteger("7A556B6DAE535B7B51ED2C4D7DAA7A0B5C55F380", 16)); // b' + + return new X9ECParameters( + curve, + curve.decodePoint(Hex.decode("04B199B13B9B34EFC1397E64BAEB05ACC265FF2378ADD6718B7C7C1961F0991B842443772152C9E0AD")), // G + new BigInteger("E95E4A5F737059DC60DF5991D45029409E60FC09", 16), //n + new BigInteger("01", 16)); // h + } + }; + + static X9ECParametersHolder brainpoolP192r1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + ECCurve curve = new ECCurve.Fp( + new BigInteger("C302F41D932A36CDA7A3463093D18DB78FCE476DE1A86297", 16), // q + new BigInteger("6A91174076B1E0E19C39C031FE8685C1CAE040E5C69A28EF", 16), // a + new BigInteger("469A28EF7C28CCA3DC721D044F4496BCCA7EF4146FBF25C9", 16)); // b + + return new X9ECParameters( + curve, + curve.decodePoint(Hex.decode("04C0A0647EAAB6A48753B033C56CB0F0900A2F5C4853375FD614B690866ABD5BB88B5F4828C1490002E6773FA2FA299B8F")), // G + new BigInteger("C302F41D932A36CDA7A3462F9E9E916B5BE8F1029AC4ACC1", 16), //n + new BigInteger("01", 16)); // h + } + }; + + static X9ECParametersHolder brainpoolP192t1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + ECCurve curve = new ECCurve.Fp( + //new BigInteger("1B6F5CC8DB4DC7AF19458A9CB80DC2295E5EB9C3732104CB") //Z + new BigInteger("C302F41D932A36CDA7A3463093D18DB78FCE476DE1A86297", 16), // q + new BigInteger("C302F41D932A36CDA7A3463093D18DB78FCE476DE1A86294", 16), // a' + new BigInteger("13D56FFAEC78681E68F9DEB43B35BEC2FB68542E27897B79", 16)); // b' + + return new X9ECParameters( + curve, + curve.decodePoint(Hex.decode("043AE9E58C82F63C30282E1FE7BBF43FA72C446AF6F4618129097E2C5667C2223A902AB5CA449D0084B7E5B3DE7CCC01C9")), // G' + new BigInteger("C302F41D932A36CDA7A3462F9E9E916B5BE8F1029AC4ACC1", 16), //n + new BigInteger("01", 16)); // h + } + }; + + static X9ECParametersHolder brainpoolP224r1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + ECCurve curve = new ECCurve.Fp( + new BigInteger("D7C134AA264366862A18302575D1D787B09F075797DA89F57EC8C0FF", 16), // q + new BigInteger("68A5E62CA9CE6C1C299803A6C1530B514E182AD8B0042A59CAD29F43", 16), // a + new BigInteger("2580F63CCFE44138870713B1A92369E33E2135D266DBB372386C400B", 16)); // b + + return new X9ECParameters( + curve, + curve.decodePoint(Hex.decode("040D9029AD2C7E5CF4340823B2A87DC68C9E4CE3174C1E6EFDEE12C07D58AA56F772C0726F24C6B89E4ECDAC24354B9E99CAA3F6D3761402CD")), // G + new BigInteger("D7C134AA264366862A18302575D0FB98D116BC4B6DDEBCA3A5A7939F", 16), //n + new BigInteger("01", 16)); // n + } + }; + static X9ECParametersHolder brainpoolP224t1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + ECCurve curve = new ECCurve.Fp( + //new BigInteger("2DF271E14427A346910CF7A2E6CFA7B3F484E5C2CCE1C8B730E28B3F") //Z + new BigInteger("D7C134AA264366862A18302575D1D787B09F075797DA89F57EC8C0FF", 16), // q + new BigInteger("D7C134AA264366862A18302575D1D787B09F075797DA89F57EC8C0FC", 16), // a' + new BigInteger("4B337D934104CD7BEF271BF60CED1ED20DA14C08B3BB64F18A60888D", 16)); // b' + + return new X9ECParameters( + curve, + curve.decodePoint(Hex.decode("046AB1E344CE25FF3896424E7FFE14762ECB49F8928AC0C76029B4D5800374E9F5143E568CD23F3F4D7C0D4B1E41C8CC0D1C6ABD5F1A46DB4C")), // G' + new BigInteger("D7C134AA264366862A18302575D0FB98D116BC4B6DDEBCA3A5A7939F", 16), //n + new BigInteger("01", 16)); // h + } + }; + static X9ECParametersHolder brainpoolP256r1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + ECCurve curve = new ECCurve.Fp( + new BigInteger("A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E5377", 16), // q + new BigInteger("7D5A0975FC2C3057EEF67530417AFFE7FB8055C126DC5C6CE94A4B44F330B5D9", 16), // a + new BigInteger("26DC5C6CE94A4B44F330B5D9BBD77CBF958416295CF7E1CE6BCCDC18FF8C07B6", 16)); // b + + return new X9ECParameters( + curve, + curve.decodePoint(Hex.decode("048BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F046997")), // G + new BigInteger("A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A7", 16), //n + new BigInteger("01", 16)); // h + } + }; + static X9ECParametersHolder brainpoolP256t1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + ECCurve curve = new ECCurve.Fp( + //new BigInteger("3E2D4BD9597B58639AE7AA669CAB9837CF5CF20A2C852D10F655668DFC150EF0") //Z + new BigInteger("A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E5377", 16), // q + new BigInteger("A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E5374", 16), // a' + new BigInteger("662C61C430D84EA4FE66A7733D0B76B7BF93EBC4AF2F49256AE58101FEE92B04", 16)); // b' + + return new X9ECParameters( + curve, + curve.decodePoint(Hex.decode("04A3E8EB3CC1CFE7B7732213B23A656149AFA142C47AAFBC2B79A191562E1305F42D996C823439C56D7F7B22E14644417E69BCB6DE39D027001DABE8F35B25C9BE")), // G' + new BigInteger("A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A7", 16), //n + new BigInteger("01", 16)); // h + } + }; + static X9ECParametersHolder brainpoolP320r1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + ECCurve curve = new ECCurve.Fp( + new BigInteger("D35E472036BC4FB7E13C785ED201E065F98FCFA6F6F40DEF4F92B9EC7893EC28FCD412B1F1B32E27", 16), // q + new BigInteger("3EE30B568FBAB0F883CCEBD46D3F3BB8A2A73513F5EB79DA66190EB085FFA9F492F375A97D860EB4", 16), // a + new BigInteger("520883949DFDBC42D3AD198640688A6FE13F41349554B49ACC31DCCD884539816F5EB4AC8FB1F1A6", 16)); // b + + return new X9ECParameters( + curve, + curve.decodePoint(Hex.decode("0443BD7E9AFB53D8B85289BCC48EE5BFE6F20137D10A087EB6E7871E2A10A599C710AF8D0D39E2061114FDD05545EC1CC8AB4093247F77275E0743FFED117182EAA9C77877AAAC6AC7D35245D1692E8EE1")), // G + new BigInteger("D35E472036BC4FB7E13C785ED201E065F98FCFA5B68F12A32D482EC7EE8658E98691555B44C59311", 16), //n + new BigInteger("01", 16)); // h + } + }; + static X9ECParametersHolder brainpoolP320t1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + ECCurve curve = new ECCurve.Fp( + //new BigInteger("15F75CAF668077F7E85B42EB01F0A81FF56ECD6191D55CB82B7D861458A18FEFC3E5AB7496F3C7B1") //Z + new BigInteger("D35E472036BC4FB7E13C785ED201E065F98FCFA6F6F40DEF4F92B9EC7893EC28FCD412B1F1B32E27", 16), // q + new BigInteger("D35E472036BC4FB7E13C785ED201E065F98FCFA6F6F40DEF4F92B9EC7893EC28FCD412B1F1B32E24", 16), // a' + new BigInteger("A7F561E038EB1ED560B3D147DB782013064C19F27ED27C6780AAF77FB8A547CEB5B4FEF422340353", 16)); // b' + + return new X9ECParameters( + curve, + curve.decodePoint(Hex.decode("04925BE9FB01AFC6FB4D3E7D4990010F813408AB106C4F09CB7EE07868CC136FFF3357F624A21BED5263BA3A7A27483EBF6671DBEF7ABB30EBEE084E58A0B077AD42A5A0989D1EE71B1B9BC0455FB0D2C3")), // G' + new BigInteger("D35E472036BC4FB7E13C785ED201E065F98FCFA5B68F12A32D482EC7EE8658E98691555B44C59311", 16), //n + new BigInteger("01", 16)); // h + } + }; + static X9ECParametersHolder brainpoolP384r1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + ECCurve curve = new ECCurve.Fp( + new BigInteger("8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B412B1DA197FB71123ACD3A729901D1A71874700133107EC53", 16), // q + new BigInteger("7BC382C63D8C150C3C72080ACE05AFA0C2BEA28E4FB22787139165EFBA91F90F8AA5814A503AD4EB04A8C7DD22CE2826", 16), // a + new BigInteger("4A8C7DD22CE28268B39B55416F0447C2FB77DE107DCD2A62E880EA53EEB62D57CB4390295DBC9943AB78696FA504C11", 16)); // b + + return new X9ECParameters( + curve, + curve.decodePoint(Hex.decode("041D1C64F068CF45FFA2A63A81B7C13F6B8847A3E77EF14FE3DB7FCAFE0CBD10E8E826E03436D646AAEF87B2E247D4AF1E8ABE1D7520F9C2A45CB1EB8E95CFD55262B70B29FEEC5864E19C054FF99129280E4646217791811142820341263C5315")), // G + new BigInteger("8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B31F166E6CAC0425A7CF3AB6AF6B7FC3103B883202E9046565", 16), //n + new BigInteger("01", 16)); // h + } + }; + static X9ECParametersHolder brainpoolP384t1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + ECCurve curve = new ECCurve.Fp( + //new BigInteger("41DFE8DD399331F7166A66076734A89CD0D2BCDB7D068E44E1F378F41ECBAE97D2D63DBC87BCCDDCCC5DA39E8589291C") //Z + new BigInteger("8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B412B1DA197FB71123ACD3A729901D1A71874700133107EC53", 16), // q + new BigInteger("8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B412B1DA197FB71123ACD3A729901D1A71874700133107EC50", 16), // a' + new BigInteger("7F519EADA7BDA81BD826DBA647910F8C4B9346ED8CCDC64E4B1ABD11756DCE1D2074AA263B88805CED70355A33B471EE", 16)); // b' + + return new X9ECParameters( + curve, + curve.decodePoint(Hex.decode("0418DE98B02DB9A306F2AFCD7235F72A819B80AB12EBD653172476FECD462AABFFC4FF191B946A5F54D8D0AA2F418808CC25AB056962D30651A114AFD2755AD336747F93475B7A1FCA3B88F2B6A208CCFE469408584DC2B2912675BF5B9E582928")), // G' + new BigInteger("8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B31F166E6CAC0425A7CF3AB6AF6B7FC3103B883202E9046565", 16), //n + new BigInteger("01", 16)); // h + } + }; + static X9ECParametersHolder brainpoolP512r1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + ECCurve curve = new ECCurve.Fp( + new BigInteger("AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA703308717D4D9B009BC66842AECDA12AE6A380E62881FF2F2D82C68528AA6056583A48F3", 16), // q + new BigInteger("7830A3318B603B89E2327145AC234CC594CBDD8D3DF91610A83441CAEA9863BC2DED5D5AA8253AA10A2EF1C98B9AC8B57F1117A72BF2C7B9E7C1AC4D77FC94CA", 16), // a + new BigInteger("3DF91610A83441CAEA9863BC2DED5D5AA8253AA10A2EF1C98B9AC8B57F1117A72BF2C7B9E7C1AC4D77FC94CADC083E67984050B75EBAE5DD2809BD638016F723", 16)); // b + + return new X9ECParameters( + curve, + curve.decodePoint(Hex.decode("0481AEE4BDD82ED9645A21322E9C4C6A9385ED9F70B5D916C1B43B62EEF4D0098EFF3B1F78E2D0D48D50D1687B93B97D5F7C6D5047406A5E688B352209BCB9F8227DDE385D566332ECC0EABFA9CF7822FDF209F70024A57B1AA000C55B881F8111B2DCDE494A5F485E5BCA4BD88A2763AED1CA2B2FA8F0540678CD1E0F3AD80892")), // G + new BigInteger("AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA70330870553E5C414CA92619418661197FAC10471DB1D381085DDADDB58796829CA90069", 16), //n + new BigInteger("01", 16)); // h + } + }; + static X9ECParametersHolder brainpoolP512t1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + ECCurve curve = new ECCurve.Fp( + //new BigInteger("12EE58E6764838B69782136F0F2D3BA06E27695716054092E60A80BEDB212B64E585D90BCE13761F85C3F1D2A64E3BE8FEA2220F01EBA5EEB0F35DBD29D922AB") //Z + new BigInteger("AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA703308717D4D9B009BC66842AECDA12AE6A380E62881FF2F2D82C68528AA6056583A48F3", 16), // q + new BigInteger("AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA703308717D4D9B009BC66842AECDA12AE6A380E62881FF2F2D82C68528AA6056583A48F0", 16), // a' + new BigInteger("7CBBBCF9441CFAB76E1890E46884EAE321F70C0BCB4981527897504BEC3E36A62BCDFA2304976540F6450085F2DAE145C22553B465763689180EA2571867423E", 16)); // b' + + return new X9ECParameters( + curve, + curve.decodePoint(Hex.decode("04640ECE5C12788717B9C1BA06CBC2A6FEBA85842458C56DDE9DB1758D39C0313D82BA51735CDB3EA499AA77A7D6943A64F7A3F25FE26F06B51BAA2696FA9035DA5B534BD595F5AF0FA2C892376C84ACE1BB4E3019B71634C01131159CAE03CEE9D9932184BEEF216BD71DF2DADF86A627306ECFF96DBB8BACE198B61E00F8B332")), // G' + new BigInteger("AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA70330870553E5C414CA92619418661197FAC10471DB1D381085DDADDB58796829CA90069", 16), //n + new BigInteger("01", 16)); // h + } + }; + + static final Hashtable objIds = new Hashtable(); + static final Hashtable curves = new Hashtable(); + static final Hashtable names = new Hashtable(); + + static void defineCurve(String name, ASN1ObjectIdentifier oid, X9ECParametersHolder holder) + { + objIds.put(name, oid); + names.put(oid, name); + curves.put(oid, holder); + } + + static + { + defineCurve("brainpoolp160r1", TeleTrusTObjectIdentifiers.brainpoolP160r1, brainpoolP160r1); + defineCurve("brainpoolp160t1", TeleTrusTObjectIdentifiers.brainpoolP160t1, brainpoolP160t1); + defineCurve("brainpoolp192r1", TeleTrusTObjectIdentifiers.brainpoolP192r1, brainpoolP192r1); + defineCurve("brainpoolp192t1", TeleTrusTObjectIdentifiers.brainpoolP192t1, brainpoolP192t1); + defineCurve("brainpoolp224r1", TeleTrusTObjectIdentifiers.brainpoolP224r1, brainpoolP224r1); + defineCurve("brainpoolp224t1", TeleTrusTObjectIdentifiers.brainpoolP224t1, brainpoolP224t1); + defineCurve("brainpoolp256r1", TeleTrusTObjectIdentifiers.brainpoolP256r1, brainpoolP256r1); + defineCurve("brainpoolp256t1", TeleTrusTObjectIdentifiers.brainpoolP256t1, brainpoolP256t1); + defineCurve("brainpoolp320r1", TeleTrusTObjectIdentifiers.brainpoolP320r1, brainpoolP320r1); + defineCurve("brainpoolp320t1", TeleTrusTObjectIdentifiers.brainpoolP320t1, brainpoolP320t1); + defineCurve("brainpoolp384r1", TeleTrusTObjectIdentifiers.brainpoolP384r1, brainpoolP384r1); + defineCurve("brainpoolp384t1", TeleTrusTObjectIdentifiers.brainpoolP384t1, brainpoolP384t1); + defineCurve("brainpoolp512r1", TeleTrusTObjectIdentifiers.brainpoolP512r1, brainpoolP512r1); + defineCurve("brainpoolp512t1", TeleTrusTObjectIdentifiers.brainpoolP512t1, brainpoolP512t1); + } + + public static X9ECParameters getByName( + String name) + { + ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)objIds.get(Strings.toLowerCase(name)); + + if (oid != null) + { + return getByOID(oid); + } + + return null; + } + + /** + * return the X9ECParameters object for the named curve represented by + * the passed in object identifier. Null if the curve isn't present. + * + * @param oid an object identifier representing a named curve, if present. + */ + public static X9ECParameters getByOID( + ASN1ObjectIdentifier oid) + { + X9ECParametersHolder holder = (X9ECParametersHolder)curves.get(oid); + + if (holder != null) + { + return holder.getParameters(); + } + + return null; + } + + /** + * return the object identifier signified by the passed in name. Null + * if there is no object identifier associated with name. + * + * @return the object identifier associated with name, if present. + */ + public static ASN1ObjectIdentifier getOID( + String name) + { + return (ASN1ObjectIdentifier)objIds.get(Strings.toLowerCase(name)); + } + + /** + * return the named curve name represented by the given object identifier. + */ + public static String getName( + ASN1ObjectIdentifier oid) + { + return (String)names.get(oid); + } + + /** + * returns an enumeration containing the name strings for curves + * contained in this structure. + */ + public static Enumeration getNames() + { + return objIds.keys(); + } + + public static ASN1ObjectIdentifier getOID(short curvesize, boolean twisted) + { + return getOID("brainpoolP" + curvesize + (twisted ? "t" : "r") + "1"); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/teletrust/TeleTrusTObjectIdentifiers.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/teletrust/TeleTrusTObjectIdentifiers.java new file mode 100644 index 0000000..eb4b7f2 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/teletrust/TeleTrusTObjectIdentifiers.java @@ -0,0 +1,42 @@ +package org.bc.asn1.teletrust; + +import org.bc.asn1.ASN1ObjectIdentifier; + +public interface TeleTrusTObjectIdentifiers +{ + static final ASN1ObjectIdentifier teleTrusTAlgorithm = new ASN1ObjectIdentifier("1.3.36.3"); + + static final ASN1ObjectIdentifier ripemd160 = teleTrusTAlgorithm.branch("2.1"); + static final ASN1ObjectIdentifier ripemd128 = teleTrusTAlgorithm.branch("2.2"); + static final ASN1ObjectIdentifier ripemd256 = teleTrusTAlgorithm.branch("2.3"); + + static final ASN1ObjectIdentifier teleTrusTRSAsignatureAlgorithm = teleTrusTAlgorithm.branch("3.1"); + + static final ASN1ObjectIdentifier rsaSignatureWithripemd160 = teleTrusTRSAsignatureAlgorithm.branch("2"); + static final ASN1ObjectIdentifier rsaSignatureWithripemd128 = teleTrusTRSAsignatureAlgorithm.branch("3"); + static final ASN1ObjectIdentifier rsaSignatureWithripemd256 = teleTrusTRSAsignatureAlgorithm.branch("4"); + + static final ASN1ObjectIdentifier ecSign = teleTrusTAlgorithm.branch("3.2"); + + static final ASN1ObjectIdentifier ecSignWithSha1 = ecSign.branch("1"); + static final ASN1ObjectIdentifier ecSignWithRipemd160 = ecSign.branch("2"); + + static final ASN1ObjectIdentifier ecc_brainpool = teleTrusTAlgorithm.branch("3.2.8"); + static final ASN1ObjectIdentifier ellipticCurve = ecc_brainpool.branch("1"); + static final ASN1ObjectIdentifier versionOne = ellipticCurve.branch("1"); + + static final ASN1ObjectIdentifier brainpoolP160r1 = versionOne.branch("1"); + static final ASN1ObjectIdentifier brainpoolP160t1 = versionOne.branch("2"); + static final ASN1ObjectIdentifier brainpoolP192r1 = versionOne.branch("3"); + static final ASN1ObjectIdentifier brainpoolP192t1 = versionOne.branch("4"); + static final ASN1ObjectIdentifier brainpoolP224r1 = versionOne.branch("5"); + static final ASN1ObjectIdentifier brainpoolP224t1 = versionOne.branch("6"); + static final ASN1ObjectIdentifier brainpoolP256r1 = versionOne.branch("7"); + static final ASN1ObjectIdentifier brainpoolP256t1 = versionOne.branch("8"); + static final ASN1ObjectIdentifier brainpoolP320r1 = versionOne.branch("9"); + static final ASN1ObjectIdentifier brainpoolP320t1 = versionOne.branch("10"); + static final ASN1ObjectIdentifier brainpoolP384r1 = versionOne.branch("11"); + static final ASN1ObjectIdentifier brainpoolP384t1 = versionOne.branch("12"); + static final ASN1ObjectIdentifier brainpoolP512r1 = versionOne.branch("13"); + static final ASN1ObjectIdentifier brainpoolP512t1 = versionOne.branch("14"); +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/tsp/Accuracy.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/tsp/Accuracy.java new file mode 100644 index 0000000..e44b34f --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/tsp/Accuracy.java @@ -0,0 +1,173 @@ +package org.bc.asn1.tsp; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DERSequence; +import org.bc.asn1.DERTaggedObject; + + +public class Accuracy + extends ASN1Object +{ + ASN1Integer seconds; + + ASN1Integer millis; + + ASN1Integer micros; + + // constantes + protected static final int MIN_MILLIS = 1; + + protected static final int MAX_MILLIS = 999; + + protected static final int MIN_MICROS = 1; + + protected static final int MAX_MICROS = 999; + + protected Accuracy() + { + } + + public Accuracy( + ASN1Integer seconds, + ASN1Integer millis, + ASN1Integer micros) + { + this.seconds = seconds; + + //Verifications + if (millis != null + && (millis.getValue().intValue() < MIN_MILLIS || millis + .getValue().intValue() > MAX_MILLIS)) + { + throw new IllegalArgumentException( + "Invalid millis field : not in (1..999)"); + } + else + { + this.millis = millis; + } + + if (micros != null + && (micros.getValue().intValue() < MIN_MICROS || micros + .getValue().intValue() > MAX_MICROS)) + { + throw new IllegalArgumentException( + "Invalid micros field : not in (1..999)"); + } + else + { + this.micros = micros; + } + + } + + private Accuracy(ASN1Sequence seq) + { + seconds = null; + millis = null; + micros = null; + + for (int i = 0; i < seq.size(); i++) + { + // seconds + if (seq.getObjectAt(i) instanceof ASN1Integer) + { + seconds = (ASN1Integer) seq.getObjectAt(i); + } + else if (seq.getObjectAt(i) instanceof DERTaggedObject) + { + DERTaggedObject extra = (DERTaggedObject) seq.getObjectAt(i); + + switch (extra.getTagNo()) + { + case 0: + millis = ASN1Integer.getInstance(extra, false); + if (millis.getValue().intValue() < MIN_MILLIS + || millis.getValue().intValue() > MAX_MILLIS) + { + throw new IllegalArgumentException( + "Invalid millis field : not in (1..999)."); + } + break; + case 1: + micros = ASN1Integer.getInstance(extra, false); + if (micros.getValue().intValue() < MIN_MICROS + || micros.getValue().intValue() > MAX_MICROS) + { + throw new IllegalArgumentException( + "Invalid micros field : not in (1..999)."); + } + break; + default: + throw new IllegalArgumentException("Invalig tag number"); + } + } + } + } + + public static Accuracy getInstance(Object o) + { + if (o instanceof Accuracy) + { + return (Accuracy) o; + } + + if (o != null) + { + return new Accuracy(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public ASN1Integer getSeconds() + { + return seconds; + } + + public ASN1Integer getMillis() + { + return millis; + } + + public ASN1Integer getMicros() + { + return micros; + } + + /** + *
+ * Accuracy ::= SEQUENCE { + * seconds INTEGER OPTIONAL, + * millis [0] INTEGER (1..999) OPTIONAL, + * micros [1] INTEGER (1..999) OPTIONAL + * } + *+ */ + public ASN1Primitive toASN1Primitive() + { + + ASN1EncodableVector v = new ASN1EncodableVector(); + + if (seconds != null) + { + v.add(seconds); + } + + if (millis != null) + { + v.add(new DERTaggedObject(false, 0, millis)); + } + + if (micros != null) + { + v.add(new DERTaggedObject(false, 1, micros)); + } + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/tsp/MessageImprint.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/tsp/MessageImprint.java new file mode 100644 index 0000000..548a8bd --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/tsp/MessageImprint.java @@ -0,0 +1,78 @@ +package org.bc.asn1.tsp; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1OctetString; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DEROctetString; +import org.bc.asn1.DERSequence; +import org.bc.asn1.x509.AlgorithmIdentifier; + +public class MessageImprint + extends ASN1Object +{ + AlgorithmIdentifier hashAlgorithm; + byte[] hashedMessage; + + /** + * @param o + * @return a MessageImprint object. + */ + public static MessageImprint getInstance(Object o) + { + if (o instanceof MessageImprint) + { + return (MessageImprint)o; + } + + if (o != null) + { + return new MessageImprint(ASN1Sequence.getInstance(o)); + } + + return null; + } + + private MessageImprint( + ASN1Sequence seq) + { + this.hashAlgorithm = AlgorithmIdentifier.getInstance(seq.getObjectAt(0)); + this.hashedMessage = ASN1OctetString.getInstance(seq.getObjectAt(1)).getOctets(); + } + + public MessageImprint( + AlgorithmIdentifier hashAlgorithm, + byte[] hashedMessage) + { + this.hashAlgorithm = hashAlgorithm; + this.hashedMessage = hashedMessage; + } + + public AlgorithmIdentifier getHashAlgorithm() + { + return hashAlgorithm; + } + + public byte[] getHashedMessage() + { + return hashedMessage; + } + + /** + *
+ * MessageImprint ::= SEQUENCE { + * hashAlgorithm AlgorithmIdentifier, + * hashedMessage OCTET STRING } + *+ */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(hashAlgorithm); + v.add(new DEROctetString(hashedMessage)); + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/tsp/TSTInfo.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/tsp/TSTInfo.java new file mode 100644 index 0000000..d575412 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/tsp/TSTInfo.java @@ -0,0 +1,233 @@ +package org.bc.asn1.tsp; + +import java.util.Enumeration; + +import org.bc.asn1.ASN1Boolean; +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1GeneralizedTime; +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1ObjectIdentifier; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERSequence; +import org.bc.asn1.DERTaggedObject; +import org.bc.asn1.x509.Extensions; +import org.bc.asn1.x509.GeneralName; + +public class TSTInfo + extends ASN1Object +{ + private ASN1Integer version; + private ASN1ObjectIdentifier tsaPolicyId; + private MessageImprint messageImprint; + private ASN1Integer serialNumber; + private ASN1GeneralizedTime genTime; + private Accuracy accuracy; + private ASN1Boolean ordering; + private ASN1Integer nonce; + private GeneralName tsa; + private Extensions extensions; + + public static TSTInfo getInstance(Object o) + { + if (o instanceof TSTInfo) + { + return (TSTInfo)o; + } + else if (o != null) + { + return new TSTInfo(ASN1Sequence.getInstance(o)); + } + + return null; + } + + private TSTInfo(ASN1Sequence seq) + { + Enumeration e = seq.getObjects(); + + // version + version = ASN1Integer.getInstance(e.nextElement()); + + // tsaPolicy + tsaPolicyId = ASN1ObjectIdentifier.getInstance(e.nextElement()); + + // messageImprint + messageImprint = MessageImprint.getInstance(e.nextElement()); + + // serialNumber + serialNumber = ASN1Integer.getInstance(e.nextElement()); + + // genTime + genTime = ASN1GeneralizedTime.getInstance(e.nextElement()); + + // default for ordering + ordering = ASN1Boolean.getInstance(false); + + while (e.hasMoreElements()) + { + ASN1Object o = (ASN1Object) e.nextElement(); + + if (o instanceof ASN1TaggedObject) + { + DERTaggedObject tagged = (DERTaggedObject) o; + + switch (tagged.getTagNo()) + { + case 0: + tsa = GeneralName.getInstance(tagged, true); + break; + case 1: + extensions = Extensions.getInstance(tagged, false); + break; + default: + throw new IllegalArgumentException("Unknown tag value " + tagged.getTagNo()); + } + } + else if (o instanceof ASN1Sequence || o instanceof Accuracy) + { + accuracy = Accuracy.getInstance(o); + } + else if (o instanceof ASN1Boolean) + { + ordering = ASN1Boolean.getInstance(o); + } + else if (o instanceof ASN1Integer) + { + nonce = ASN1Integer.getInstance(o); + } + + } + } + + public TSTInfo(ASN1ObjectIdentifier tsaPolicyId, MessageImprint messageImprint, + ASN1Integer serialNumber, ASN1GeneralizedTime genTime, + Accuracy accuracy, ASN1Boolean ordering, ASN1Integer nonce, + GeneralName tsa, Extensions extensions) + { + version = new ASN1Integer(1); + this.tsaPolicyId = tsaPolicyId; + this.messageImprint = messageImprint; + this.serialNumber = serialNumber; + this.genTime = genTime; + + this.accuracy = accuracy; + this.ordering = ordering; + this.nonce = nonce; + this.tsa = tsa; + this.extensions = extensions; + } + + public ASN1Integer getVersion() + { + return version; + } + + public MessageImprint getMessageImprint() + { + return messageImprint; + } + + public ASN1ObjectIdentifier getPolicy() + { + return tsaPolicyId; + } + + public ASN1Integer getSerialNumber() + { + return serialNumber; + } + + public Accuracy getAccuracy() + { + return accuracy; + } + + public ASN1GeneralizedTime getGenTime() + { + return genTime; + } + + public ASN1Boolean getOrdering() + { + return ordering; + } + + public ASN1Integer getNonce() + { + return nonce; + } + + public GeneralName getTsa() + { + return tsa; + } + + public Extensions getExtensions() + { + return extensions; + } + + /** + *
+ * + * TSTInfo ::= SEQUENCE { + * version INTEGER { v1(1) }, + * policy TSAPolicyId, + * messageImprint MessageImprint, + * -- MUST have the same value as the similar field in + * -- TimeStampReq + * serialNumber INTEGER, + * -- Time-Stamping users MUST be ready to accommodate integers + * -- up to 160 bits. + * genTime GeneralizedTime, + * accuracy Accuracy OPTIONAL, + * ordering BOOLEAN DEFAULT FALSE, + * nonce INTEGER OPTIONAL, + * -- MUST be present if the similar field was present + * -- in TimeStampReq. In that case it MUST have the same value. + * tsa [0] GeneralName OPTIONAL, + * extensions [1] IMPLICIT Extensions OPTIONAL } + * + *+ */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector seq = new ASN1EncodableVector(); + seq.add(version); + + seq.add(tsaPolicyId); + seq.add(messageImprint); + seq.add(serialNumber); + seq.add(genTime); + + if (accuracy != null) + { + seq.add(accuracy); + } + + if (ordering != null && ordering.isTrue()) + { + seq.add(ordering); + } + + if (nonce != null) + { + seq.add(nonce); + } + + if (tsa != null) + { + seq.add(new DERTaggedObject(true, 0, tsa)); + } + + if (extensions != null) + { + seq.add(new DERTaggedObject(false, 1, extensions)); + } + + return new DERSequence(seq); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/tsp/TimeStampReq.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/tsp/TimeStampReq.java new file mode 100644 index 0000000..da46329 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/tsp/TimeStampReq.java @@ -0,0 +1,179 @@ +package org.bc.asn1.tsp; + +import org.bc.asn1.ASN1Boolean; +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1ObjectIdentifier; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERSequence; +import org.bc.asn1.DERTaggedObject; +import org.bc.asn1.x509.Extensions; + +public class TimeStampReq + extends ASN1Object +{ + ASN1Integer version; + + MessageImprint messageImprint; + + ASN1ObjectIdentifier tsaPolicy; + + ASN1Integer nonce; + + ASN1Boolean certReq; + + Extensions extensions; + + public static TimeStampReq getInstance(Object o) + { + if (o instanceof TimeStampReq) + { + return (TimeStampReq) o; + } + else if (o != null) + { + return new TimeStampReq(ASN1Sequence.getInstance(o)); + } + + return null; + } + + private TimeStampReq(ASN1Sequence seq) + { + int nbObjects = seq.size(); + + int seqStart = 0; + + // version + version = ASN1Integer.getInstance(seq.getObjectAt(seqStart)); + + seqStart++; + + // messageImprint + messageImprint = MessageImprint.getInstance(seq.getObjectAt(seqStart)); + + seqStart++; + + for (int opt = seqStart; opt < nbObjects; opt++) + { + // tsaPolicy + if (seq.getObjectAt(opt) instanceof ASN1ObjectIdentifier) + { + tsaPolicy = ASN1ObjectIdentifier.getInstance(seq.getObjectAt(opt)); + } + // nonce + else if (seq.getObjectAt(opt) instanceof ASN1Integer) + { + nonce = ASN1Integer.getInstance(seq.getObjectAt(opt)); + } + // certReq + else if (seq.getObjectAt(opt) instanceof ASN1Boolean) + { + certReq = ASN1Boolean.getInstance(seq.getObjectAt(opt)); + } + // extensions + else if (seq.getObjectAt(opt) instanceof ASN1TaggedObject) + { + ASN1TaggedObject tagged = (ASN1TaggedObject)seq.getObjectAt(opt); + if (tagged.getTagNo() == 0) + { + extensions = Extensions.getInstance(tagged, false); + } + } + } + } + + public TimeStampReq( + MessageImprint messageImprint, + ASN1ObjectIdentifier tsaPolicy, + ASN1Integer nonce, + ASN1Boolean certReq, + Extensions extensions) + { + // default + version = new ASN1Integer(1); + + this.messageImprint = messageImprint; + this.tsaPolicy = tsaPolicy; + this.nonce = nonce; + this.certReq = certReq; + this.extensions = extensions; + } + + public ASN1Integer getVersion() + { + return version; + } + + public MessageImprint getMessageImprint() + { + return messageImprint; + } + + public ASN1ObjectIdentifier getReqPolicy() + { + return tsaPolicy; + } + + public ASN1Integer getNonce() + { + return nonce; + } + + public ASN1Boolean getCertReq() + { + return certReq; + } + + public Extensions getExtensions() + { + return extensions; + } + + /** + *
+ * TimeStampReq ::= SEQUENCE { + * version INTEGER { v1(1) }, + * messageImprint MessageImprint, + * --a hash algorithm OID and the hash value of the data to be + * --time-stamped + * reqPolicy TSAPolicyId OPTIONAL, + * nonce INTEGER OPTIONAL, + * certReq BOOLEAN DEFAULT FALSE, + * extensions [0] IMPLICIT Extensions OPTIONAL + * } + *+ */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(version); + v.add(messageImprint); + + if (tsaPolicy != null) + { + v.add(tsaPolicy); + } + + if (nonce != null) + { + v.add(nonce); + } + + if (certReq != null && certReq.isTrue()) + { + v.add(certReq); + } + + if (extensions != null) + { + v.add(new DERTaggedObject(false, 0, extensions)); + } + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/tsp/TimeStampResp.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/tsp/TimeStampResp.java new file mode 100644 index 0000000..6b77fe0 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/tsp/TimeStampResp.java @@ -0,0 +1,84 @@ +package org.bc.asn1.tsp; + +import java.util.Enumeration; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DERSequence; +import org.bc.asn1.cmp.PKIStatusInfo; +import org.bc.asn1.cms.ContentInfo; + + +public class TimeStampResp + extends ASN1Object +{ + PKIStatusInfo pkiStatusInfo; + + ContentInfo timeStampToken; + + public static TimeStampResp getInstance(Object o) + { + if (o instanceof TimeStampResp) + { + return (TimeStampResp) o; + } + else if (o != null) + { + return new TimeStampResp(ASN1Sequence.getInstance(o)); + } + + return null; + } + + private TimeStampResp(ASN1Sequence seq) + { + + Enumeration e = seq.getObjects(); + + // status + pkiStatusInfo = PKIStatusInfo.getInstance(e.nextElement()); + + if (e.hasMoreElements()) + { + timeStampToken = ContentInfo.getInstance(e.nextElement()); + } + } + + public TimeStampResp(PKIStatusInfo pkiStatusInfo, ContentInfo timeStampToken) + { + this.pkiStatusInfo = pkiStatusInfo; + this.timeStampToken = timeStampToken; + } + + public PKIStatusInfo getStatus() + { + return pkiStatusInfo; + } + + public ContentInfo getTimeStampToken() + { + return timeStampToken; + } + + /** + *
+ * TimeStampResp ::= SEQUENCE { + * status PKIStatusInfo, + * timeStampToken TimeStampToken OPTIONAL } + *+ */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(pkiStatusInfo); + if (timeStampToken != null) + { + v.add(timeStampToken); + } + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ua/DSTU4145BinaryField.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ua/DSTU4145BinaryField.java new file mode 100644 index 0000000..bae61bf --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ua/DSTU4145BinaryField.java @@ -0,0 +1,119 @@ +package org.bc.asn1.ua; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DERSequence; + +public class DSTU4145BinaryField + extends ASN1Object +{ + + private int m, k, j, l; + + private DSTU4145BinaryField(ASN1Sequence seq) + { + m = ASN1Integer.getInstance(seq.getObjectAt(0)).getPositiveValue().intValue(); + + if (seq.getObjectAt(1) instanceof ASN1Integer) + { + k = ((ASN1Integer)seq.getObjectAt(1)).getPositiveValue().intValue(); + } + else if (seq.getObjectAt(1) instanceof ASN1Sequence) + { + ASN1Sequence coefs = ASN1Sequence.getInstance(seq.getObjectAt(1)); + + k = ASN1Integer.getInstance(coefs.getObjectAt(0)).getPositiveValue().intValue(); + j = ASN1Integer.getInstance(coefs.getObjectAt(1)).getPositiveValue().intValue(); + l = ASN1Integer.getInstance(coefs.getObjectAt(2)).getPositiveValue().intValue(); + } + else + { + throw new IllegalArgumentException("object parse error"); + } + } + + public static DSTU4145BinaryField getInstance(Object obj) + { + if (obj instanceof DSTU4145BinaryField) + { + return (DSTU4145BinaryField)obj; + } + + if (obj != null) + { + return new DSTU4145BinaryField(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public DSTU4145BinaryField(int m, int k1, int k2, int k3) + { + this.m = m; + this.k = k1; + this.j = k2; + this.l = k3; + } + + public int getM() + { + return m; + } + + public int getK1() + { + return k; + } + + public int getK2() + { + return j; + } + + public int getK3() + { + return l; + } + + public DSTU4145BinaryField(int m, int k) + { + this(m, k, 0, 0); + } + + /** + * BinaryField ::= SEQUENCE { + * M INTEGER, + * CHOICE {Trinomial, Pentanomial} + * Trinomial::= INTEGER + * Pentanomial::= SEQUENCE { + * k INTEGER, + * j INTEGER, + * l INTEGER} + */ + public ASN1Primitive toASN1Primitive() + { + + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(new ASN1Integer(m)); + if (j == 0) //Trinomial + { + v.add(new ASN1Integer(k)); + } + else + { + ASN1EncodableVector coefs = new ASN1EncodableVector(); + coefs.add(new ASN1Integer(k)); + coefs.add(new ASN1Integer(j)); + coefs.add(new ASN1Integer(l)); + + v.add(new DERSequence(coefs)); + } + + return new DERSequence(v); + } + +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ua/DSTU4145ECBinary.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ua/DSTU4145ECBinary.java new file mode 100644 index 0000000..e2df6a8 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ua/DSTU4145ECBinary.java @@ -0,0 +1,144 @@ +package org.bc.asn1.ua; + +import java.math.BigInteger; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1OctetString; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DEROctetString; +import org.bc.asn1.DERSequence; +import org.bc.asn1.DERTaggedObject; +import org.bc.asn1.x9.X9IntegerConverter; +import org.bc.crypto.params.ECDomainParameters; +import org.bc.math.ec.ECCurve; +import org.bc.util.Arrays; + +public class DSTU4145ECBinary + extends ASN1Object +{ + + BigInteger version = BigInteger.valueOf(0); + + DSTU4145BinaryField f; + ASN1Integer a; + ASN1OctetString b; + ASN1Integer n; + ASN1OctetString bp; + + public DSTU4145ECBinary(ECDomainParameters params) + { + if (!(params.getCurve() instanceof ECCurve.F2m)) + { + throw new IllegalArgumentException("only binary domain is possible"); + } + + // We always use big-endian in parameter encoding + ECCurve.F2m curve = (ECCurve.F2m)params.getCurve(); + f = new DSTU4145BinaryField(curve.getM(), curve.getK1(), curve.getK2(), curve.getK3()); + a = new ASN1Integer(curve.getA().toBigInteger()); + X9IntegerConverter converter = new X9IntegerConverter(); + b = new DEROctetString(converter.integerToBytes(curve.getB().toBigInteger(), converter.getByteLength(curve))); + n = new ASN1Integer(params.getN()); + bp = new DEROctetString(DSTU4145PointEncoder.encodePoint(params.getG())); + } + + private DSTU4145ECBinary(ASN1Sequence seq) + { + int index = 0; + + if (seq.getObjectAt(index) instanceof ASN1TaggedObject) + { + ASN1TaggedObject taggedVersion = (ASN1TaggedObject)seq.getObjectAt(index); + if (taggedVersion.isExplicit() && 0 == taggedVersion.getTagNo()) + { + version = ASN1Integer.getInstance(taggedVersion.getLoadedObject()).getValue(); + index++; + } + else + { + throw new IllegalArgumentException("object parse error"); + } + } + f = DSTU4145BinaryField.getInstance(seq.getObjectAt(index)); + index++; + a = ASN1Integer.getInstance(seq.getObjectAt(index)); + index++; + b = ASN1OctetString.getInstance(seq.getObjectAt(index)); + index++; + n = ASN1Integer.getInstance(seq.getObjectAt(index)); + index++; + bp = ASN1OctetString.getInstance(seq.getObjectAt(index)); + } + + public static DSTU4145ECBinary getInstance(Object obj) + { + if (obj instanceof DSTU4145ECBinary) + { + return (DSTU4145ECBinary)obj; + } + + if (obj != null) + { + return new DSTU4145ECBinary(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public DSTU4145BinaryField getField() + { + return f; + } + + public BigInteger getA() + { + return a.getValue(); + } + + public byte[] getB() + { + return Arrays.clone(b.getOctets()); + } + + public BigInteger getN() + { + return n.getValue(); + } + + public byte[] getG() + { + return Arrays.clone(bp.getOctets()); + } + + /** + * ECBinary ::= SEQUENCE { + * version [0] EXPLICIT INTEGER DEFAULT 0, + * f BinaryField, + * a INTEGER (0..1), + * b OCTET STRING, + * n INTEGER, + * bp OCTET STRING} + */ + public ASN1Primitive toASN1Primitive() + { + + ASN1EncodableVector v = new ASN1EncodableVector(); + + if (0 != version.compareTo(BigInteger.valueOf(0))) + { + v.add(new DERTaggedObject(true, 0, new ASN1Integer(version))); + } + v.add(f); + v.add(a); + v.add(b); + v.add(n); + v.add(bp); + + return new DERSequence(v); + } + +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ua/DSTU4145NamedCurves.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ua/DSTU4145NamedCurves.java new file mode 100644 index 0000000..7145672 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ua/DSTU4145NamedCurves.java @@ -0,0 +1,94 @@ +package org.bc.asn1.ua; + +import java.math.BigInteger; + +import org.bc.asn1.ASN1ObjectIdentifier; +import org.bc.crypto.params.ECDomainParameters; +import org.bc.math.ec.ECCurve; +import org.bc.math.ec.ECPoint; + +public class DSTU4145NamedCurves +{ + private static final BigInteger ZERO = BigInteger.valueOf(0); + private static final BigInteger ONE = BigInteger.valueOf(1); + + public static final ECDomainParameters[] params = new ECDomainParameters[10]; + static final ASN1ObjectIdentifier[] oids = new ASN1ObjectIdentifier[10]; + + //All named curves have the following oid format: 1.2.804.2.1.1.1.1.3.1.1.2.X + //where X is the curve number 0-9 + static final String oidBase = UAObjectIdentifiers.dstu4145le.getId() + ".2."; + + static + { + ECCurve.F2m[] curves = new ECCurve.F2m[10]; + curves[0] = new ECCurve.F2m(163, 3, 6, 7, ONE, new BigInteger("5FF6108462A2DC8210AB403925E638A19C1455D21", 16)); + curves[1] = new ECCurve.F2m(167, 6, ONE, new BigInteger("6EE3CEEB230811759F20518A0930F1A4315A827DAC", 16)); + curves[2] = new ECCurve.F2m(173, 1, 2, 10, ZERO, new BigInteger("108576C80499DB2FC16EDDF6853BBB278F6B6FB437D9", 16)); + curves[3] = new ECCurve.F2m(179, 1, 2, 4, ONE, new BigInteger("4A6E0856526436F2F88DD07A341E32D04184572BEB710", 16)); + curves[4] = new ECCurve.F2m(191, 9, ONE, new BigInteger("7BC86E2102902EC4D5890E8B6B4981ff27E0482750FEFC03", 16)); + curves[5] = new ECCurve.F2m(233, 1, 4, 9, ONE, new BigInteger("06973B15095675534C7CF7E64A21BD54EF5DD3B8A0326AA936ECE454D2C", 16)); + curves[6] = new ECCurve.F2m(257, 12, ZERO, new BigInteger("1CEF494720115657E18F938D7A7942394FF9425C1458C57861F9EEA6ADBE3BE10", 16)); + curves[7] = new ECCurve.F2m(307, 2, 4, 8, ONE, new BigInteger("393C7F7D53666B5054B5E6C6D3DE94F4296C0C599E2E2E241050DF18B6090BDC90186904968BB", 16)); + curves[8] = new ECCurve.F2m(367, 21, ONE, new BigInteger("43FC8AD242B0B7A6F3D1627AD5654447556B47BF6AA4A64B0C2AFE42CADAB8F93D92394C79A79755437B56995136", 16)); + curves[9] = new ECCurve.F2m(431, 1, 3, 5, ONE, new BigInteger("03CE10490F6A708FC26DFE8C3D27C4F94E690134D5BFF988D8D28AAEAEDE975936C66BAC536B18AE2DC312CA493117DAA469C640CAF3", 16)); + + ECPoint[] points = new ECPoint[10]; + points[0] = curves[0].createPoint(new BigInteger("2E2F85F5DD74CE983A5C4237229DAF8A3F35823BE", 16), new BigInteger("3826F008A8C51D7B95284D9D03FF0E00CE2CD723A", 16), false); + points[1] = curves[1].createPoint(new BigInteger("7A1F6653786A68192803910A3D30B2A2018B21CD54", 16), new BigInteger("5F49EB26781C0EC6B8909156D98ED435E45FD59918", 16), false); + points[2] = curves[2].createPoint(new BigInteger("4D41A619BCC6EADF0448FA22FAD567A9181D37389CA", 16), new BigInteger("10B51CC12849B234C75E6DD2028BF7FF5C1CE0D991A1", 16), false); + points[3] = curves[3].createPoint(new BigInteger("6BA06FE51464B2BD26DC57F48819BA9954667022C7D03", 16), new BigInteger("25FBC363582DCEC065080CA8287AAFF09788A66DC3A9E", 16), false); + points[4] = curves[4].createPoint(new BigInteger("714114B762F2FF4A7912A6D2AC58B9B5C2FCFE76DAEB7129", 16), new BigInteger("29C41E568B77C617EFE5902F11DB96FA9613CD8D03DB08DA", 16), false); + points[5] = curves[5].createPoint(new BigInteger("3FCDA526B6CDF83BA1118DF35B3C31761D3545F32728D003EEB25EFE96", 16), new BigInteger("9CA8B57A934C54DEEDA9E54A7BBAD95E3B2E91C54D32BE0B9DF96D8D35", 16), false); + points[6] = curves[6].createPoint(new BigInteger("02A29EF207D0E9B6C55CD260B306C7E007AC491CA1B10C62334A9E8DCD8D20FB7", 16), new BigInteger("10686D41FF744D4449FCCF6D8EEA03102E6812C93A9D60B978B702CF156D814EF", 16), false); + points[7] = curves[7].createPoint(new BigInteger("216EE8B189D291A0224984C1E92F1D16BF75CCD825A087A239B276D3167743C52C02D6E7232AA", 16), new BigInteger("5D9306BACD22B7FAEB09D2E049C6E2866C5D1677762A8F2F2DC9A11C7F7BE8340AB2237C7F2A0", 16), false); + points[8] = curves[8].createPoint(new BigInteger("324A6EDDD512F08C49A99AE0D3F961197A76413E7BE81A400CA681E09639B5FE12E59A109F78BF4A373541B3B9A1", 16), new BigInteger("1AB597A5B4477F59E39539007C7F977D1A567B92B043A49C6B61984C3FE3481AAF454CD41BA1F051626442B3C10", 16), false); + points[9] = curves[9].createPoint(new BigInteger("1A62BA79D98133A16BBAE7ED9A8E03C32E0824D57AEF72F88986874E5AAE49C27BED49A2A95058068426C2171E99FD3B43C5947C857D", 16), new BigInteger("70B5E1E14031C1F70BBEFE96BDDE66F451754B4CA5F48DA241F331AA396B8D1839A855C1769B1EA14BA53308B5E2723724E090E02DB9", 16), false); + + BigInteger[] n_s = new BigInteger[10]; + n_s[0] = new BigInteger("400000000000000000002BEC12BE2262D39BCF14D", 16); + n_s[1] = new BigInteger("3FFFFFFFFFFFFFFFFFFFFFB12EBCC7D7F29FF7701F", 16); + n_s[2] = new BigInteger("800000000000000000000189B4E67606E3825BB2831", 16); + n_s[3] = new BigInteger("3FFFFFFFFFFFFFFFFFFFFFFB981960435FE5AB64236EF", 16); + n_s[4] = new BigInteger("40000000000000000000000069A779CAC1DABC6788F7474F", 16); + n_s[5] = new BigInteger("1000000000000000000000000000013E974E72F8A6922031D2603CFE0D7", 16); + n_s[6] = new BigInteger("800000000000000000000000000000006759213AF182E987D3E17714907D470D", 16); + n_s[7] = new BigInteger("3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC079C2F3825DA70D390FBBA588D4604022B7B7", 16); + n_s[8] = new BigInteger("40000000000000000000000000000000000000000000009C300B75A3FA824F22428FD28CE8812245EF44049B2D49", 16); + n_s[9] = new BigInteger("3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBA3175458009A8C0A724F02F81AA8A1FCBAF80D90C7A95110504CF", 16); + + for (int i = 0; i < params.length; i++) + { + params[i] = new ECDomainParameters(curves[i], points[i], n_s[i]); + } + + for (int i = 0; i < oids.length; i++) + { + oids[i] = new ASN1ObjectIdentifier(oidBase + i); + } + } + + /** + * All named curves have the following oid format: 1.2.804.2.1.1.1.1.3.1.1.2.X + * where X is the curve number 0-9 + */ + public static ASN1ObjectIdentifier[] getOIDs() + { + return oids; + } + + /** + * All named curves have the following oid format: 1.2.804.2.1.1.1.1.3.1.1.2.X + * where X is the curve number 0-9 + */ + public static ECDomainParameters getByOID(ASN1ObjectIdentifier oid) + { + String oidStr = oid.getId(); + if (oidStr.startsWith(oidBase)) + { + int index = Integer.parseInt(oidStr.substring(oidStr.length() - 1)); + return params[index]; + } + return null; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ua/DSTU4145Params.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ua/DSTU4145Params.java new file mode 100644 index 0000000..54387dd --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ua/DSTU4145Params.java @@ -0,0 +1,114 @@ +package org.bc.asn1.ua; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1ObjectIdentifier; +import org.bc.asn1.ASN1OctetString; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DEROctetString; +import org.bc.asn1.DERSequence; + +public class DSTU4145Params extends ASN1Object +{ + private static final byte DEFAULT_DKE[]={ + (byte) 0xa9, (byte) 0xd6, (byte) 0xeb, 0x45, (byte) 0xf1, 0x3c, 0x70, (byte) 0x82, + (byte) 0x80, (byte) 0xc4, (byte) 0x96, 0x7b, 0x23, 0x1f, 0x5e, (byte) 0xad, + (byte) 0xf6, 0x58, (byte) 0xeb, (byte) 0xa4, (byte) 0xc0, 0x37, 0x29, 0x1d, + 0x38, (byte) 0xd9, 0x6b, (byte) 0xf0, 0x25, (byte) 0xca, 0x4e, 0x17, + (byte) 0xf8, (byte) 0xe9, 0x72, 0x0d, (byte) 0xc6, 0x15, (byte) 0xb4, 0x3a, + 0x28, (byte) 0x97, 0x5f, 0x0b, (byte) 0xc1, (byte) 0xde, (byte) 0xa3, 0x64, + 0x38, (byte) 0xb5, 0x64, (byte) 0xea, 0x2c, 0x17, (byte) 0x9f, (byte) 0xd0, + 0x12, 0x3e, 0x6d, (byte) 0xb8, (byte) 0xfa, (byte) 0xc5, 0x79, 0x04}; + + + private ASN1ObjectIdentifier namedCurve; + private DSTU4145ECBinary ecbinary; + private byte[] dke=DEFAULT_DKE; + + public DSTU4145Params(ASN1ObjectIdentifier namedCurve) + { + this.namedCurve=namedCurve; + } + + public DSTU4145Params(DSTU4145ECBinary ecbinary) + { + this.ecbinary=ecbinary; + } + + public boolean isNamedCurve() + { + return namedCurve != null; + } + + public DSTU4145ECBinary getECBinary() + { + return ecbinary; + } + + public byte[] getDKE() + { + return dke; + } + + public static byte[] getDefaultDKE() + { + return DEFAULT_DKE; + } + + public ASN1ObjectIdentifier getNamedCurve() + { + return namedCurve; + } + + public static DSTU4145Params getInstance(Object obj) + { + if (obj instanceof DSTU4145Params) + { + return (DSTU4145Params)obj; + } + + if (obj != null) + { + ASN1Sequence seq=ASN1Sequence.getInstance(obj); + DSTU4145Params params; + + if (seq.getObjectAt(0) instanceof ASN1ObjectIdentifier) + params=new DSTU4145Params(ASN1ObjectIdentifier.getInstance(seq.getObjectAt(0))); + else + params=new DSTU4145Params(DSTU4145ECBinary.getInstance(seq.getObjectAt(0))); + + if (seq.size()==2) + { + params.dke = ASN1OctetString.getInstance(seq.getObjectAt(1)).getOctets(); + if (params.dke.length!=DSTU4145Params.DEFAULT_DKE.length) + throw new IllegalArgumentException("object parse error"); + } + + return params; + } + + throw new IllegalArgumentException("object parse error"); + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v=new ASN1EncodableVector(); + + if (namedCurve!=null) + { + v.add(namedCurve); + } + else + { + v.add(ecbinary); + } + + if (!org.bc.util.Arrays.areEqual(dke, DEFAULT_DKE)) + { + v.add(new DEROctetString(dke)); + } + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ua/DSTU4145PointEncoder.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ua/DSTU4145PointEncoder.java new file mode 100644 index 0000000..ca655f5 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ua/DSTU4145PointEncoder.java @@ -0,0 +1,162 @@ +package org.bc.asn1.ua; + +import java.math.BigInteger; +import java.util.Random; + +import org.bc.asn1.x9.X9IntegerConverter; +import org.bc.math.ec.ECConstants; +import org.bc.math.ec.ECCurve; +import org.bc.math.ec.ECFieldElement; +import org.bc.math.ec.ECPoint; +import org.bc.util.Arrays; + +/** + * DSTU4145 encodes points somewhat differently than X9.62 + * It compresses the point to the size of the field element + */ + +public abstract class DSTU4145PointEncoder +{ + + private static X9IntegerConverter converter = new X9IntegerConverter(); + + private static BigInteger trace(ECFieldElement fe) + { + ECFieldElement t = fe; + for (int i = 0; i < fe.getFieldSize() - 1; i++) + { + t = t.square().add(fe); + } + return t.toBigInteger(); + } + + /** + * Solves a quadratic equation
z2 + z = beta
(X9.62
+ * D.1.6) The other solution is z + 1
.
+ *
+ * @param beta The value to solve the qradratic equation for.
+ * @return the solution for z2 + z = beta
or
+ * null
if no solution exists.
+ */
+ private static ECFieldElement solveQuadradicEquation(ECFieldElement beta)
+ {
+ ECFieldElement.F2m b = (ECFieldElement.F2m)beta;
+ ECFieldElement zeroElement = new ECFieldElement.F2m(
+ b.getM(), b.getK1(), b.getK2(), b.getK3(), ECConstants.ZERO);
+
+ if (beta.toBigInteger().equals(ECConstants.ZERO))
+ {
+ return zeroElement;
+ }
+
+ ECFieldElement z = null;
+ ECFieldElement gamma = zeroElement;
+
+ Random rand = new Random();
+ int m = b.getM();
+ do
+ {
+ ECFieldElement t = new ECFieldElement.F2m(b.getM(), b.getK1(),
+ b.getK2(), b.getK3(), new BigInteger(m, rand));
+ z = zeroElement;
+ ECFieldElement w = beta;
+ for (int i = 1; i <= m - 1; i++)
+ {
+ ECFieldElement w2 = w.square();
+ z = z.square().add(w2.multiply(t));
+ w = w2.add(beta);
+ }
+ if (!w.toBigInteger().equals(ECConstants.ZERO))
+ {
+ return null;
+ }
+ gamma = z.square().add(z);
+ }
+ while (gamma.toBigInteger().equals(ECConstants.ZERO));
+
+ return z;
+ }
+
+ public static byte[] encodePoint(ECPoint Q)
+ {
+ /*if (!Q.isCompressed())
+ Q=new ECPoint.F2m(Q.getCurve(),Q.getX(),Q.getY(),true);
+
+ byte[] bytes=Q.getEncoded();
+
+ if (bytes[0]==0x02)
+ bytes[bytes.length-1]&=0xFE;
+ else if (bytes[0]==0x02)
+ bytes[bytes.length-1]|=0x01;
+
+ return Arrays.copyOfRange(bytes, 1, bytes.length);*/
+
+ int byteCount = converter.getByteLength(Q.getX());
+ byte[] bytes = converter.integerToBytes(Q.getX().toBigInteger(), byteCount);
+
+ if (!(Q.getX().toBigInteger().equals(ECConstants.ZERO)))
+ {
+ ECFieldElement y = Q.getY().multiply(Q.getX().invert());
+ if (trace(y).equals(ECConstants.ONE))
+ {
+ bytes[bytes.length - 1] |= 0x01;
+ }
+ else
+ {
+ bytes[bytes.length - 1] &= 0xFE;
+ }
+ }
+
+ return bytes;
+ }
+
+ public static ECPoint decodePoint(ECCurve curve, byte[] bytes)
+ {
+ /*byte[] bp_enc=new byte[bytes.length+1];
+ if (0==(bytes[bytes.length-1]&0x1))
+ bp_enc[0]=0x02;
+ else
+ bp_enc[0]=0x03;
+ System.arraycopy(bytes, 0, bp_enc, 1, bytes.length);
+ if (!trace(curve.fromBigInteger(new BigInteger(1, bytes))).equals(curve.getA().toBigInteger()))
+ bp_enc[bp_enc.length-1]^=0x01;
+
+ return curve.decodePoint(bp_enc);*/
+
+ BigInteger k = BigInteger.valueOf(bytes[bytes.length - 1] & 0x1);
+ if (!trace(curve.fromBigInteger(new BigInteger(1, bytes))).equals(curve.getA().toBigInteger()))
+ {
+ bytes = Arrays.clone(bytes);
+ bytes[bytes.length - 1] ^= 0x01;
+ }
+ ECCurve.F2m c = (ECCurve.F2m)curve;
+ ECFieldElement xp = curve.fromBigInteger(new BigInteger(1, bytes));
+ ECFieldElement yp = null;
+ if (xp.toBigInteger().equals(ECConstants.ZERO))
+ {
+ yp = (ECFieldElement.F2m)curve.getB();
+ for (int i = 0; i < c.getM() - 1; i++)
+ {
+ yp = yp.square();
+ }
+ }
+ else
+ {
+ ECFieldElement beta = xp.add(curve.getA()).add(
+ curve.getB().multiply(xp.square().invert()));
+ ECFieldElement z = solveQuadradicEquation(beta);
+ if (z == null)
+ {
+ throw new RuntimeException("Invalid point compression");
+ }
+ if (!trace(z).equals(k))
+ {
+ z = z.add(curve.fromBigInteger(ECConstants.ONE));
+ }
+ yp = xp.multiply(z);
+ }
+
+ return new ECPoint.F2m(curve, xp, yp);
+ }
+
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ua/DSTU4145PublicKey.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ua/DSTU4145PublicKey.java
new file mode 100644
index 0000000..15d18cf
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ua/DSTU4145PublicKey.java
@@ -0,0 +1,46 @@
+package org.bc.asn1.ua;
+
+import org.bc.asn1.ASN1Object;
+import org.bc.asn1.ASN1OctetString;
+import org.bc.asn1.ASN1Primitive;
+import org.bc.asn1.DEROctetString;
+import org.bc.math.ec.ECPoint;
+
+public class DSTU4145PublicKey
+ extends ASN1Object
+{
+
+ private ASN1OctetString pubKey;
+
+ public DSTU4145PublicKey(ECPoint pubKey)
+ {
+ // We always use big-endian in parameter encoding
+ this.pubKey = new DEROctetString(DSTU4145PointEncoder.encodePoint(pubKey));
+ }
+
+ private DSTU4145PublicKey(ASN1OctetString ocStr)
+ {
+ pubKey = ocStr;
+ }
+
+ public static DSTU4145PublicKey getInstance(Object obj)
+ {
+ if (obj instanceof DSTU4145PublicKey)
+ {
+ return (DSTU4145PublicKey)obj;
+ }
+
+ if (obj != null)
+ {
+ return new DSTU4145PublicKey(ASN1OctetString.getInstance(obj));
+ }
+
+ return null;
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+ return pubKey;
+ }
+
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ua/UAObjectIdentifiers.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ua/UAObjectIdentifiers.java
new file mode 100644
index 0000000..4d00337
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/ua/UAObjectIdentifiers.java
@@ -0,0 +1,16 @@
+package org.bc.asn1.ua;
+
+import org.bc.asn1.ASN1ObjectIdentifier;
+
+public interface UAObjectIdentifiers
+{
+ // Ukrainian object identifiers
+ // {iso(1) member-body(2) Ukraine(804 ) root(2) security(1) cryptography(1) pki(1)}
+
+ static final ASN1ObjectIdentifier UaOid = new ASN1ObjectIdentifier("1.2.804.2.1.1.1");
+
+ // {pki-alg(1) pki-alg-�sym(3) Dstu4145WithGost34311(1) PB(1)}
+ // DSTU4145 in polynomial basis has 2 oids, one for little-endian representation and one for big-endian
+ static final ASN1ObjectIdentifier dstu4145le = UaOid.branch("1.3.1.1");
+ static final ASN1ObjectIdentifier dstu4145be = UaOid.branch("1.3.1.1.1.1");
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/util/ASN1Dump.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/util/ASN1Dump.java
new file mode 100644
index 0000000..54d8709
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/util/ASN1Dump.java
@@ -0,0 +1,402 @@
+package org.bc.asn1.util;
+
+import java.io.IOException;
+import java.util.Enumeration;
+
+import org.bc.asn1.ASN1Encodable;
+import org.bc.asn1.ASN1Integer;
+import org.bc.asn1.ASN1ObjectIdentifier;
+import org.bc.asn1.ASN1OctetString;
+import org.bc.asn1.ASN1Primitive;
+import org.bc.asn1.ASN1Sequence;
+import org.bc.asn1.ASN1Set;
+import org.bc.asn1.ASN1TaggedObject;
+import org.bc.asn1.BERApplicationSpecific;
+import org.bc.asn1.BERConstructedOctetString;
+import org.bc.asn1.BEROctetString;
+import org.bc.asn1.BERSequence;
+import org.bc.asn1.BERSet;
+import org.bc.asn1.BERTaggedObject;
+import org.bc.asn1.BERTags;
+import org.bc.asn1.DERApplicationSpecific;
+import org.bc.asn1.DERBMPString;
+import org.bc.asn1.DERBitString;
+import org.bc.asn1.DERBoolean;
+import org.bc.asn1.DEREnumerated;
+import org.bc.asn1.DERExternal;
+import org.bc.asn1.DERGeneralizedTime;
+import org.bc.asn1.DERIA5String;
+import org.bc.asn1.DERNull;
+import org.bc.asn1.DERPrintableString;
+import org.bc.asn1.DERSequence;
+import org.bc.asn1.DERT61String;
+import org.bc.asn1.DERUTCTime;
+import org.bc.asn1.DERUTF8String;
+import org.bc.asn1.DERVisibleString;
+import org.bc.util.encoders.Hex;
+
+public class ASN1Dump
+{
+ private static final String TAB = " ";
+ private static final int SAMPLE_SIZE = 32;
+
+ /**
+ * dump a DER object as a formatted string with indentation
+ *
+ * @param obj the ASN1Primitive to be dumped out.
+ */
+ static void _dumpAsString(
+ String indent,
+ boolean verbose,
+ ASN1Primitive obj,
+ StringBuffer buf)
+ {
+ String nl = System.getProperty("line.separator");
+ if (obj instanceof ASN1Sequence)
+ {
+ Enumeration e = ((ASN1Sequence)obj).getObjects();
+ String tab = indent + TAB;
+
+ buf.append(indent);
+ if (obj instanceof BERSequence)
+ {
+ buf.append("BER Sequence");
+ }
+ else if (obj instanceof DERSequence)
+ {
+ buf.append("DER Sequence");
+ }
+ else
+ {
+ buf.append("Sequence");
+ }
+
+ buf.append(nl);
+
+ while (e.hasMoreElements())
+ {
+ Object o = e.nextElement();
+
+ if (o == null || o.equals(DERNull.INSTANCE))
+ {
+ buf.append(tab);
+ buf.append("NULL");
+ buf.append(nl);
+ }
+ else if (o instanceof ASN1Primitive)
+ {
+ _dumpAsString(tab, verbose, (ASN1Primitive)o, buf);
+ }
+ else
+ {
+ _dumpAsString(tab, verbose, ((ASN1Encodable)o).toASN1Primitive(), buf);
+ }
+ }
+ }
+ else if (obj instanceof ASN1TaggedObject)
+ {
+ String tab = indent + TAB;
+
+ buf.append(indent);
+ if (obj instanceof BERTaggedObject)
+ {
+ buf.append("BER Tagged [");
+ }
+ else
+ {
+ buf.append("Tagged [");
+ }
+
+ ASN1TaggedObject o = (ASN1TaggedObject)obj;
+
+ buf.append(Integer.toString(o.getTagNo()));
+ buf.append(']');
+
+ if (!o.isExplicit())
+ {
+ buf.append(" IMPLICIT ");
+ }
+
+ buf.append(nl);
+
+ if (o.isEmpty())
+ {
+ buf.append(tab);
+ buf.append("EMPTY");
+ buf.append(nl);
+ }
+ else
+ {
+ _dumpAsString(tab, verbose, o.getObject(), buf);
+ }
+ }
+ else if (obj instanceof ASN1Set)
+ {
+ Enumeration e = ((ASN1Set)obj).getObjects();
+ String tab = indent + TAB;
+
+ buf.append(indent);
+
+ if (obj instanceof BERSet)
+ {
+ buf.append("BER Set");
+ }
+ else
+ {
+ buf.append("DER Set");
+ }
+
+ buf.append(nl);
+
+ while (e.hasMoreElements())
+ {
+ Object o = e.nextElement();
+
+ if (o == null)
+ {
+ buf.append(tab);
+ buf.append("NULL");
+ buf.append(nl);
+ }
+ else if (o instanceof ASN1Primitive)
+ {
+ _dumpAsString(tab, verbose, (ASN1Primitive)o, buf);
+ }
+ else
+ {
+ _dumpAsString(tab, verbose, ((ASN1Encodable)o).toASN1Primitive(), buf);
+ }
+ }
+ }
+ else if (obj instanceof ASN1OctetString)
+ {
+ ASN1OctetString oct = (ASN1OctetString)obj;
+
+ if (obj instanceof BEROctetString || obj instanceof BERConstructedOctetString)
+ {
+ buf.append(indent + "BER Constructed Octet String" + "[" + oct.getOctets().length + "] ");
+ }
+ else
+ {
+ buf.append(indent + "DER Octet String" + "[" + oct.getOctets().length + "] ");
+ }
+ if (verbose)
+ {
+ buf.append(dumpBinaryDataAsString(indent, oct.getOctets()));
+ }
+ else{
+ buf.append(nl);
+ }
+ }
+ else if (obj instanceof ASN1ObjectIdentifier)
+ {
+ buf.append(indent + "ObjectIdentifier(" + ((ASN1ObjectIdentifier)obj).getId() + ")" + nl);
+ }
+ else if (obj instanceof DERBoolean)
+ {
+ buf.append(indent + "Boolean(" + ((DERBoolean)obj).isTrue() + ")" + nl);
+ }
+ else if (obj instanceof ASN1Integer)
+ {
+ buf.append(indent + "Integer(" + ((ASN1Integer)obj).getValue() + ")" + nl);
+ }
+ else if (obj instanceof DERBitString)
+ {
+ DERBitString bt = (DERBitString)obj;
+ buf.append(indent + "DER Bit String" + "[" + bt.getBytes().length + ", " + bt.getPadBits() + "] ");
+ if (verbose)
+ {
+ buf.append(dumpBinaryDataAsString(indent, bt.getBytes()));
+ }
+ else{
+ buf.append(nl);
+ }
+ }
+ else if (obj instanceof DERIA5String)
+ {
+ buf.append(indent + "IA5String(" + ((DERIA5String)obj).getString() + ") " + nl);
+ }
+ else if (obj instanceof DERUTF8String)
+ {
+ buf.append(indent + "UTF8String(" + ((DERUTF8String)obj).getString() + ") " + nl);
+ }
+ else if (obj instanceof DERPrintableString)
+ {
+ buf.append(indent + "PrintableString(" + ((DERPrintableString)obj).getString() + ") " + nl);
+ }
+ else if (obj instanceof DERVisibleString)
+ {
+ buf.append(indent + "VisibleString(" + ((DERVisibleString)obj).getString() + ") " + nl);
+ }
+ else if (obj instanceof DERBMPString)
+ {
+ buf.append(indent + "BMPString(" + ((DERBMPString)obj).getString() + ") " + nl);
+ }
+ else if (obj instanceof DERT61String)
+ {
+ buf.append(indent + "T61String(" + ((DERT61String)obj).getString() + ") " + nl);
+ }
+ else if (obj instanceof DERUTCTime)
+ {
+ buf.append(indent + "UTCTime(" + ((DERUTCTime)obj).getTime() + ") " + nl);
+ }
+ else if (obj instanceof DERGeneralizedTime)
+ {
+ buf.append(indent + "GeneralizedTime(" + ((DERGeneralizedTime)obj).getTime() + ") " + nl);
+ }
+ else if (obj instanceof BERApplicationSpecific)
+ {
+ buf.append(outputApplicationSpecific("BER", indent, verbose, obj, nl));
+ }
+ else if (obj instanceof DERApplicationSpecific)
+ {
+ buf.append(outputApplicationSpecific("DER", indent, verbose, obj, nl));
+ }
+ else if (obj instanceof DEREnumerated)
+ {
+ DEREnumerated en = (DEREnumerated) obj;
+ buf.append(indent + "DER Enumerated(" + en.getValue() + ")" + nl);
+ }
+ else if (obj instanceof DERExternal)
+ {
+ DERExternal ext = (DERExternal) obj;
+ buf.append(indent + "External " + nl);
+ String tab = indent + TAB;
+ if (ext.getDirectReference() != null)
+ {
+ buf.append(tab + "Direct Reference: " + ext.getDirectReference().getId() + nl);
+ }
+ if (ext.getIndirectReference() != null)
+ {
+ buf.append(tab + "Indirect Reference: " + ext.getIndirectReference().toString() + nl);
+ }
+ if (ext.getDataValueDescriptor() != null)
+ {
+ _dumpAsString(tab, verbose, ext.getDataValueDescriptor(), buf);
+ }
+ buf.append(tab + "Encoding: " + ext.getEncoding() + nl);
+ _dumpAsString(tab, verbose, ext.getExternalContent(), buf);
+ }
+ else
+ {
+ buf.append(indent + obj.toString() + nl);
+ }
+ }
+
+ private static String outputApplicationSpecific(String type, String indent, boolean verbose, ASN1Primitive obj, String nl)
+ {
+ DERApplicationSpecific app = (DERApplicationSpecific)obj;
+ StringBuffer buf = new StringBuffer();
+
+ if (app.isConstructed())
+ {
+ try
+ {
+ ASN1Sequence s = ASN1Sequence.getInstance(app.getObject(BERTags.SEQUENCE));
+ buf.append(indent + type + " ApplicationSpecific[" + app.getApplicationTag() + "]" + nl);
+ for (Enumeration e = s.getObjects(); e.hasMoreElements();)
+ {
+ _dumpAsString(indent + TAB, verbose, (ASN1Primitive)e.nextElement(), buf);
+ }
+ }
+ catch (IOException e)
+ {
+ buf.append(e);
+ }
+ return buf.toString();
+ }
+
+ return indent + type + " ApplicationSpecific[" + app.getApplicationTag() + "] (" + new String(Hex.encode(app.getContents())) + ")" + nl;
+ }
+
+ /**
+ * dump out a DER object as a formatted string, in non-verbose mode.
+ *
+ * @param obj the ASN1Primitive to be dumped out.
+ * @return the resulting string.
+ */
+ public static String dumpAsString(
+ Object obj)
+ {
+ return dumpAsString(obj, false);
+ }
+
+ /**
+ * Dump out the object as a string.
+ *
+ * @param obj the object to be dumped
+ * @param verbose if true, dump out the contents of octet and bit strings.
+ * @return the resulting string.
+ */
+ public static String dumpAsString(
+ Object obj,
+ boolean verbose)
+ {
+ StringBuffer buf = new StringBuffer();
+
+ if (obj instanceof ASN1Primitive)
+ {
+ _dumpAsString("", verbose, (ASN1Primitive)obj, buf);
+ }
+ else if (obj instanceof ASN1Encodable)
+ {
+ _dumpAsString("", verbose, ((ASN1Encodable)obj).toASN1Primitive(), buf);
+ }
+ else
+ {
+ return "unknown object type " + obj.toString();
+ }
+
+ return buf.toString();
+ }
+
+ private static String dumpBinaryDataAsString(String indent, byte[] bytes)
+ {
+ String nl = System.getProperty("line.separator");
+ StringBuffer buf = new StringBuffer();
+
+ indent += TAB;
+
+ buf.append(nl);
+ for (int i = 0; i < bytes.length; i += SAMPLE_SIZE)
+ {
+ if (bytes.length - i > SAMPLE_SIZE)
+ {
+ buf.append(indent);
+ buf.append(new String(Hex.encode(bytes, i, SAMPLE_SIZE)));
+ buf.append(TAB);
+ buf.append(calculateAscString(bytes, i, SAMPLE_SIZE));
+ buf.append(nl);
+ }
+ else
+ {
+ buf.append(indent);
+ buf.append(new String(Hex.encode(bytes, i, bytes.length - i)));
+ for (int j = bytes.length - i; j != SAMPLE_SIZE; j++)
+ {
+ buf.append(" ");
+ }
+ buf.append(TAB);
+ buf.append(calculateAscString(bytes, i, bytes.length - i));
+ buf.append(nl);
+ }
+ }
+
+ return buf.toString();
+ }
+
+ private static String calculateAscString(byte[] bytes, int off, int len)
+ {
+ StringBuffer buf = new StringBuffer();
+
+ for (int i = off; i != off + len; i++)
+ {
+ if (bytes[i] >= ' ' && bytes[i] <= '~')
+ {
+ buf.append((char)bytes[i]);
+ }
+ }
+
+ return buf.toString();
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/util/DERDump.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/util/DERDump.java
new file mode 100644
index 0000000..ca036e1
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/util/DERDump.java
@@ -0,0 +1,41 @@
+package org.bc.asn1.util;
+
+import org.bc.asn1.ASN1Encodable;
+import org.bc.asn1.ASN1Primitive;
+
+/**
+ * @deprecated use ASN1Dump.
+ */
+public class DERDump
+ extends ASN1Dump
+{
+ /**
+ * dump out a DER object as a formatted string
+ *
+ * @param obj the ASN1Primitive to be dumped out.
+ */
+ public static String dumpAsString(
+ ASN1Primitive obj)
+ {
+ StringBuffer buf = new StringBuffer();
+
+ _dumpAsString("", false, obj, buf);
+
+ return buf.toString();
+ }
+
+ /**
+ * dump out a DER object as a formatted string
+ *
+ * @param obj the ASN1Primitive to be dumped out.
+ */
+ public static String dumpAsString(
+ ASN1Encodable obj)
+ {
+ StringBuffer buf = new StringBuffer();
+
+ _dumpAsString("", false, obj.toASN1Primitive(), buf);
+
+ return buf.toString();
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/util/Dump.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/util/Dump.java
new file mode 100644
index 0000000..913c339
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/util/Dump.java
@@ -0,0 +1,22 @@
+package org.bc.asn1.util;
+
+import java.io.FileInputStream;
+
+import org.bc.asn1.ASN1InputStream;
+
+public class Dump
+{
+ public static void main(
+ String args[])
+ throws Exception
+ {
+ FileInputStream fIn = new FileInputStream(args[0]);
+ ASN1InputStream bIn = new ASN1InputStream(fIn);
+ Object obj = null;
+
+ while ((obj = bIn.readObject()) != null)
+ {
+ System.out.println(ASN1Dump.dumpAsString(obj));
+ }
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x500/AttributeTypeAndValue.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x500/AttributeTypeAndValue.java
new file mode 100644
index 0000000..e0c043d
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x500/AttributeTypeAndValue.java
@@ -0,0 +1,72 @@
+package org.bc.asn1.x500;
+
+import org.bc.asn1.ASN1Encodable;
+import org.bc.asn1.ASN1EncodableVector;
+import org.bc.asn1.ASN1Object;
+import org.bc.asn1.ASN1ObjectIdentifier;
+import org.bc.asn1.ASN1Primitive;
+import org.bc.asn1.ASN1Sequence;
+import org.bc.asn1.DERSequence;
+
+public class AttributeTypeAndValue
+ extends ASN1Object
+{
+ private ASN1ObjectIdentifier type;
+ private ASN1Encodable value;
+
+ private AttributeTypeAndValue(ASN1Sequence seq)
+ {
+ type = (ASN1ObjectIdentifier)seq.getObjectAt(0);
+ value = (ASN1Encodable)seq.getObjectAt(1);
+ }
+
+ public static AttributeTypeAndValue getInstance(Object o)
+ {
+ if (o instanceof AttributeTypeAndValue)
+ {
+ return (AttributeTypeAndValue)o;
+ }
+ else if (o != null)
+ {
+ return new AttributeTypeAndValue(ASN1Sequence.getInstance(o));
+ }
+
+ throw new IllegalArgumentException("null value in getInstance()");
+ }
+
+ public AttributeTypeAndValue(
+ ASN1ObjectIdentifier type,
+ ASN1Encodable value)
+ {
+ this.type = type;
+ this.value = value;
+ }
+
+ public ASN1ObjectIdentifier getType()
+ {
+ return type;
+ }
+
+ public ASN1Encodable getValue()
+ {
+ return value;
+ }
+
+ /**
+ * + * AttributeTypeAndValue ::= SEQUENCE { + * type OBJECT IDENTIFIER, + * value ANY DEFINED BY type } + *+ * @return a basic ASN.1 object representation. + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(type); + v.add(value); + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x500/DirectoryString.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x500/DirectoryString.java new file mode 100644 index 0000000..7a21e0b --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x500/DirectoryString.java @@ -0,0 +1,125 @@ +package org.bc.asn1.x500; + +import org.bc.asn1.ASN1Choice; +import org.bc.asn1.ASN1Encodable; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1String; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERBMPString; +import org.bc.asn1.DERPrintableString; +import org.bc.asn1.DERT61String; +import org.bc.asn1.DERUTF8String; +import org.bc.asn1.DERUniversalString; + +public class DirectoryString + extends ASN1Object + implements ASN1Choice, ASN1String +{ + private ASN1String string; + + public static DirectoryString getInstance(Object o) + { + if (o == null || o instanceof DirectoryString) + { + return (DirectoryString)o; + } + + if (o instanceof DERT61String) + { + return new DirectoryString((DERT61String)o); + } + + if (o instanceof DERPrintableString) + { + return new DirectoryString((DERPrintableString)o); + } + + if (o instanceof DERUniversalString) + { + return new DirectoryString((DERUniversalString)o); + } + + if (o instanceof DERUTF8String) + { + return new DirectoryString((DERUTF8String)o); + } + + if (o instanceof DERBMPString) + { + return new DirectoryString((DERBMPString)o); + } + + throw new IllegalArgumentException("illegal object in getInstance: " + o.getClass().getName()); + } + + public static DirectoryString getInstance(ASN1TaggedObject o, boolean explicit) + { + if (!explicit) + { + throw new IllegalArgumentException("choice item must be explicitly tagged"); + } + + return getInstance(o.getObject()); + } + + private DirectoryString( + DERT61String string) + { + this.string = string; + } + + private DirectoryString( + DERPrintableString string) + { + this.string = string; + } + + private DirectoryString( + DERUniversalString string) + { + this.string = string; + } + + private DirectoryString( + DERUTF8String string) + { + this.string = string; + } + + private DirectoryString( + DERBMPString string) + { + this.string = string; + } + + public DirectoryString(String string) + { + this.string = new DERUTF8String(string); + } + + public String getString() + { + return string.getString(); + } + + public String toString() + { + return string.getString(); + } + + /** + *
+ * DirectoryString ::= CHOICE { + * teletexString TeletexString (SIZE (1..MAX)), + * printableString PrintableString (SIZE (1..MAX)), + * universalString UniversalString (SIZE (1..MAX)), + * utf8String UTF8String (SIZE (1..MAX)), + * bmpString BMPString (SIZE (1..MAX)) } + *+ */ + public ASN1Primitive toASN1Primitive() + { + return ((ASN1Encodable)string).toASN1Primitive(); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x500/RDN.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x500/RDN.java new file mode 100644 index 0000000..d81b023 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x500/RDN.java @@ -0,0 +1,119 @@ +package org.bc.asn1.x500; + +import org.bc.asn1.ASN1Encodable; +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1ObjectIdentifier; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Set; +import org.bc.asn1.DERSequence; +import org.bc.asn1.DERSet; + +public class RDN + extends ASN1Object +{ + private ASN1Set values; + + private RDN(ASN1Set values) + { + this.values = values; + } + + public static RDN getInstance(Object obj) + { + if (obj instanceof RDN) + { + return (RDN)obj; + } + else if (obj != null) + { + return new RDN(ASN1Set.getInstance(obj)); + } + + return null; + } + + /** + * Create a single valued RDN. + * + * @param oid RDN type. + * @param value RDN value. + */ + public RDN(ASN1ObjectIdentifier oid, ASN1Encodable value) + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(oid); + v.add(value); + + this.values = new DERSet(new DERSequence(v)); + } + + public RDN(AttributeTypeAndValue attrTAndV) + { + this.values = new DERSet(attrTAndV); + } + + /** + * Create a multi-valued RDN. + * + * @param aAndVs attribute type/value pairs making up the RDN + */ + public RDN(AttributeTypeAndValue[] aAndVs) + { + this.values = new DERSet(aAndVs); + } + + public boolean isMultiValued() + { + return this.values.size() > 1; + } + + /** + * Return the number of AttributeTypeAndValue objects in this RDN, + * + * @return size of RDN, greater than 1 if multi-valued. + */ + public int size() + { + return this.values.size(); + } + + public AttributeTypeAndValue getFirst() + { + if (this.values.size() == 0) + { + return null; + } + + return AttributeTypeAndValue.getInstance(this.values.getObjectAt(0)); + } + + public AttributeTypeAndValue[] getTypesAndValues() + { + AttributeTypeAndValue[] tmp = new AttributeTypeAndValue[values.size()]; + + for (int i = 0; i != tmp.length; i++) + { + tmp[i] = AttributeTypeAndValue.getInstance(values.getObjectAt(i)); + } + + return tmp; + } + + /** + *
+ * RelativeDistinguishedName ::= + * SET OF AttributeTypeAndValue + + * AttributeTypeAndValue ::= SEQUENCE { + * type AttributeType, + * value AttributeValue } + *+ * @return this object as an ASN1Primitive type + */ + public ASN1Primitive toASN1Primitive() + { + return values; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x500/X500Name.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x500/X500Name.java new file mode 100644 index 0000000..c7ffc13 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x500/X500Name.java @@ -0,0 +1,326 @@ +package org.bc.asn1.x500; + +import java.util.Enumeration; + +import org.bc.asn1.ASN1Choice; +import org.bc.asn1.ASN1Encodable; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1ObjectIdentifier; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERSequence; +import org.bc.asn1.x500.style.BCStyle; + +/** + *
+ * Name ::= CHOICE { + * RDNSequence } + * + * RDNSequence ::= SEQUENCE OF RelativeDistinguishedName + * + * RelativeDistinguishedName ::= SET SIZE (1..MAX) OF AttributeTypeAndValue + * + * AttributeTypeAndValue ::= SEQUENCE { + * type OBJECT IDENTIFIER, + * value ANY } + *+ */ +public class X500Name + extends ASN1Object + implements ASN1Choice +{ + private static X500NameStyle defaultStyle = BCStyle.INSTANCE; + + private boolean isHashCodeCalculated; + private int hashCodeValue; + + private X500NameStyle style; + private RDN[] rdns; + + public X500Name(X500NameStyle style, X500Name name) + { + this.rdns = name.rdns; + this.style = style; + } + + /** + * Return a X500Name based on the passed in tagged object. + * + * @param obj tag object holding name. + * @param explicit true if explicitly tagged false otherwise. + * @return the X500Name + */ + public static X500Name getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + // must be true as choice item + return getInstance(ASN1Sequence.getInstance(obj, true)); + } + + public static X500Name getInstance( + Object obj) + { + if (obj instanceof X500Name) + { + return (X500Name)obj; + } + else if (obj != null) + { + return new X500Name(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public static X500Name getInstance( + X500NameStyle style, + Object obj) + { + if (obj instanceof X500Name) + { + return getInstance(style, ((X500Name)obj).toASN1Primitive()); + } + else if (obj != null) + { + return new X500Name(style, ASN1Sequence.getInstance(obj)); + } + + return null; + } + + /** + * Constructor from ASN1Sequence + * + * the principal will be a list of constructed sets, each containing an (OID, String) pair. + */ + private X500Name( + ASN1Sequence seq) + { + this(defaultStyle, seq); + } + + private X500Name( + X500NameStyle style, + ASN1Sequence seq) + { + this.style = style; + this.rdns = new RDN[seq.size()]; + + int index = 0; + + for (Enumeration e = seq.getObjects(); e.hasMoreElements();) + { + rdns[index++] = RDN.getInstance(e.nextElement()); + } + } + + public X500Name( + RDN[] rDNs) + { + this(defaultStyle, rDNs); + } + + public X500Name( + X500NameStyle style, + RDN[] rDNs) + { + this.rdns = rDNs; + this.style = style; + } + + public X500Name( + String dirName) + { + this(defaultStyle, dirName); + } + + public X500Name( + X500NameStyle style, + String dirName) + { + this(style.fromString(dirName)); + + this.style = style; + } + + /** + * return an array of RDNs in structure order. + * + * @return an array of RDN objects. + */ + public RDN[] getRDNs() + { + RDN[] tmp = new RDN[this.rdns.length]; + + System.arraycopy(rdns, 0, tmp, 0, tmp.length); + + return tmp; + } + + /** + * return an array of OIDs contained in the attribute type of each RDN in structure order. + * + * @return an array, possibly zero length, of ASN1ObjectIdentifiers objects. + */ + public ASN1ObjectIdentifier[] getAttributeTypes() + { + int count = 0; + + for (int i = 0; i != rdns.length; i++) + { + RDN rdn = rdns[i]; + + count += rdn.size(); + } + + ASN1ObjectIdentifier[] res = new ASN1ObjectIdentifier[count]; + + count = 0; + + for (int i = 0; i != rdns.length; i++) + { + RDN rdn = rdns[i]; + + if (rdn.isMultiValued()) + { + AttributeTypeAndValue[] attr = rdn.getTypesAndValues(); + for (int j = 0; j != attr.length; j++) + { + res[count++] = attr[j].getType(); + } + } + else if (rdn.size() != 0) + { + res[count++] = rdn.getFirst().getType(); + } + } + + return res; + } + + /** + * return an array of RDNs containing the attribute type given by OID in structure order. + * + * @param attributeType the type OID we are looking for. + * @return an array, possibly zero length, of RDN objects. + */ + public RDN[] getRDNs(ASN1ObjectIdentifier attributeType) + { + RDN[] res = new RDN[rdns.length]; + int count = 0; + + for (int i = 0; i != rdns.length; i++) + { + RDN rdn = rdns[i]; + + if (rdn.isMultiValued()) + { + AttributeTypeAndValue[] attr = rdn.getTypesAndValues(); + for (int j = 0; j != attr.length; j++) + { + if (attr[j].getType().equals(attributeType)) + { + res[count++] = rdn; + break; + } + } + } + else + { + if (rdn.getFirst().getType().equals(attributeType)) + { + res[count++] = rdn; + } + } + } + + RDN[] tmp = new RDN[count]; + + System.arraycopy(res, 0, tmp, 0, tmp.length); + + return tmp; + } + + public ASN1Primitive toASN1Primitive() + { + return new DERSequence(rdns); + } + + public int hashCode() + { + if (isHashCodeCalculated) + { + return hashCodeValue; + } + + isHashCodeCalculated = true; + + hashCodeValue = style.calculateHashCode(this); + + return hashCodeValue; + } + + /** + * test for equality - note: case is ignored. + */ + public boolean equals(Object obj) + { + if (obj == this) + { + return true; + } + + if (!(obj instanceof X500Name || obj instanceof ASN1Sequence)) + { + return false; + } + + ASN1Primitive derO = ((ASN1Encodable)obj).toASN1Primitive(); + + if (this.toASN1Primitive().equals(derO)) + { + return true; + } + + try + { + return style.areEqual(this, new X500Name(ASN1Sequence.getInstance(((ASN1Encodable)obj).toASN1Primitive()))); + } + catch (Exception e) + { + return false; + } + } + + public String toString() + { + return style.toString(this); + } + + /** + * Set the default style for X500Name construction. + * + * @param style an X500NameStyle + */ + public static void setDefaultStyle(X500NameStyle style) + { + if (style == null) + { + throw new NullPointerException("cannot set style to null"); + } + + defaultStyle = style; + } + + /** + * Return the current default style. + * + * @return default style for X500Name construction. + */ + public static X500NameStyle getDefaultStyle() + { + return defaultStyle; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x500/X500NameBuilder.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x500/X500NameBuilder.java new file mode 100644 index 0000000..4616cb7 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x500/X500NameBuilder.java @@ -0,0 +1,87 @@ +package org.bc.asn1.x500; + +import java.util.Vector; + +import org.bc.asn1.ASN1Encodable; +import org.bc.asn1.ASN1ObjectIdentifier; +import org.bc.asn1.x500.style.BCStyle; + +public class X500NameBuilder +{ + private X500NameStyle template; + private Vector rdns = new Vector(); + + public X500NameBuilder() + { + this(BCStyle.INSTANCE); + } + + public X500NameBuilder(X500NameStyle template) + { + this.template = template; + } + + public X500NameBuilder addRDN(ASN1ObjectIdentifier oid, String value) + { + this.addRDN(oid, template.stringToValue(oid, value)); + + return this; + } + + public X500NameBuilder addRDN(ASN1ObjectIdentifier oid, ASN1Encodable value) + { + rdns.addElement(new RDN(oid, value)); + + return this; + } + + public X500NameBuilder addRDN(AttributeTypeAndValue attrTAndV) + { + rdns.addElement(new RDN(attrTAndV)); + + return this; + } + + public X500NameBuilder addMultiValuedRDN(ASN1ObjectIdentifier[] oids, String[] values) + { + ASN1Encodable[] vals = new ASN1Encodable[values.length]; + + for (int i = 0; i != vals.length; i++) + { + vals[i] = template.stringToValue(oids[i], values[i]); + } + + return addMultiValuedRDN(oids, vals); + } + + public X500NameBuilder addMultiValuedRDN(ASN1ObjectIdentifier[] oids, ASN1Encodable[] values) + { + AttributeTypeAndValue[] avs = new AttributeTypeAndValue[oids.length]; + + for (int i = 0; i != oids.length; i++) + { + avs[i] = new AttributeTypeAndValue(oids[i], values[i]); + } + + return addMultiValuedRDN(avs); + } + + public X500NameBuilder addMultiValuedRDN(AttributeTypeAndValue[] attrTAndVs) + { + rdns.addElement(new RDN(attrTAndVs)); + + return this; + } + + public X500Name build() + { + RDN[] vals = new RDN[rdns.size()]; + + for (int i = 0; i != vals.length; i++) + { + vals[i] = (RDN)rdns.elementAt(i); + } + + return new X500Name(template, vals); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x500/X500NameStyle.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x500/X500NameStyle.java new file mode 100644 index 0000000..22b89af --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x500/X500NameStyle.java @@ -0,0 +1,34 @@ +package org.bc.asn1.x500; + +import org.bc.asn1.ASN1Encodable; +import org.bc.asn1.ASN1ObjectIdentifier; + +/** + * It turns out that the number of standard ways the fields in a DN should be + * encoded into their ASN.1 counterparts is rapidly approaching the + * number of machines on the internet. By default the X500Name class + * will produce UTF8Strings in line with the current recommendations (RFC 3280). + *
+ */ +public interface X500NameStyle +{ + /** + * Convert the passed in String value into the appropriate ASN.1 + * encoded object. + * + * @param oid the oid associated with the value in the DN. + * @param value the value of the particular DN component. + * @return the ASN.1 equivalent for the value. + */ + ASN1Encodable stringToValue(ASN1ObjectIdentifier oid, String value); + + ASN1ObjectIdentifier attrNameToOID(String attrName); + + boolean areEqual(X500Name name1, X500Name name2); + + RDN[] fromString(String dirName); + + int calculateHashCode(X500Name name); + + String toString(X500Name name); +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x500/style/BCStrictStyle.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x500/style/BCStrictStyle.java new file mode 100644 index 0000000..d5a13cc --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x500/style/BCStrictStyle.java @@ -0,0 +1,36 @@ +package org.bc.asn1.x500.style; + +import org.bc.asn1.x500.RDN; +import org.bc.asn1.x500.X500Name; +import org.bc.asn1.x500.X500NameStyle; + +/** + * Variation of BCStyle that insists on strict ordering for equality + * and hashCode comparisons + */ +public class BCStrictStyle + extends BCStyle +{ + public static final X500NameStyle INSTANCE = new BCStrictStyle(); + + public boolean areEqual(X500Name name1, X500Name name2) + { + RDN[] rdns1 = name1.getRDNs(); + RDN[] rdns2 = name2.getRDNs(); + + if (rdns1.length != rdns2.length) + { + return false; + } + + for (int i = 0; i != rdns1.length; i++) + { + if (!rdnAreEqual(rdns1[i], rdns2[i])) + { + return false; + } + } + + return true; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x500/style/BCStyle.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x500/style/BCStyle.java new file mode 100644 index 0000000..599b755 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x500/style/BCStyle.java @@ -0,0 +1,449 @@ +package org.bc.asn1.x500.style; + +import java.io.IOException; +import java.util.Hashtable; + +import org.bc.asn1.ASN1Encodable; +import org.bc.asn1.ASN1GeneralizedTime; +import org.bc.asn1.ASN1ObjectIdentifier; +import org.bc.asn1.DERIA5String; +import org.bc.asn1.DERPrintableString; +import org.bc.asn1.DERUTF8String; +import org.bc.asn1.pkcs.PKCSObjectIdentifiers; +import org.bc.asn1.x500.AttributeTypeAndValue; +import org.bc.asn1.x500.RDN; +import org.bc.asn1.x500.X500Name; +import org.bc.asn1.x500.X500NameStyle; +import org.bc.asn1.x509.X509ObjectIdentifiers; + +public class BCStyle + implements X500NameStyle +{ + public static final X500NameStyle INSTANCE = new BCStyle(); + + /** + * country code - StringType(SIZE(2)) + */ + public static final ASN1ObjectIdentifier C = new ASN1ObjectIdentifier("2.5.4.6"); + + /** + * organization - StringType(SIZE(1..64)) + */ + public static final ASN1ObjectIdentifier O = new ASN1ObjectIdentifier("2.5.4.10"); + + /** + * organizational unit name - StringType(SIZE(1..64)) + */ + public static final ASN1ObjectIdentifier OU = new ASN1ObjectIdentifier("2.5.4.11"); + + /** + * Title + */ + public static final ASN1ObjectIdentifier T = new ASN1ObjectIdentifier("2.5.4.12"); + + /** + * common name - StringType(SIZE(1..64)) + */ + public static final ASN1ObjectIdentifier CN = new ASN1ObjectIdentifier("2.5.4.3"); + + /** + * device serial number name - StringType(SIZE(1..64)) + */ + public static final ASN1ObjectIdentifier SN = new ASN1ObjectIdentifier("2.5.4.5"); + + /** + * street - StringType(SIZE(1..64)) + */ + public static final ASN1ObjectIdentifier STREET = new ASN1ObjectIdentifier("2.5.4.9"); + + /** + * device serial number name - StringType(SIZE(1..64)) + */ + public static final ASN1ObjectIdentifier SERIALNUMBER = SN; + + /** + * locality name - StringType(SIZE(1..64)) + */ + public static final ASN1ObjectIdentifier L = new ASN1ObjectIdentifier("2.5.4.7"); + + /** + * state, or province name - StringType(SIZE(1..64)) + */ + public static final ASN1ObjectIdentifier ST = new ASN1ObjectIdentifier("2.5.4.8"); + + /** + * Naming attributes of type X520name + */ + public static final ASN1ObjectIdentifier SURNAME = new ASN1ObjectIdentifier("2.5.4.4"); + public static final ASN1ObjectIdentifier GIVENNAME = new ASN1ObjectIdentifier("2.5.4.42"); + public static final ASN1ObjectIdentifier INITIALS = new ASN1ObjectIdentifier("2.5.4.43"); + public static final ASN1ObjectIdentifier GENERATION = new ASN1ObjectIdentifier("2.5.4.44"); + public static final ASN1ObjectIdentifier UNIQUE_IDENTIFIER = new ASN1ObjectIdentifier("2.5.4.45"); + + /** + * businessCategory - DirectoryString(SIZE(1..128) + */ + public static final ASN1ObjectIdentifier BUSINESS_CATEGORY = new ASN1ObjectIdentifier( + "2.5.4.15"); + + /** + * postalCode - DirectoryString(SIZE(1..40) + */ + public static final ASN1ObjectIdentifier POSTAL_CODE = new ASN1ObjectIdentifier( + "2.5.4.17"); + + /** + * dnQualifier - DirectoryString(SIZE(1..64) + */ + public static final ASN1ObjectIdentifier DN_QUALIFIER = new ASN1ObjectIdentifier( + "2.5.4.46"); + + /** + * RFC 3039 Pseudonym - DirectoryString(SIZE(1..64) + */ + public static final ASN1ObjectIdentifier PSEUDONYM = new ASN1ObjectIdentifier( + "2.5.4.65"); + + + /** + * RFC 3039 DateOfBirth - GeneralizedTime - YYYYMMDD000000Z + */ + public static final ASN1ObjectIdentifier DATE_OF_BIRTH = new ASN1ObjectIdentifier( + "1.3.6.1.5.5.7.9.1"); + + /** + * RFC 3039 PlaceOfBirth - DirectoryString(SIZE(1..128) + */ + public static final ASN1ObjectIdentifier PLACE_OF_BIRTH = new ASN1ObjectIdentifier( + "1.3.6.1.5.5.7.9.2"); + + /** + * RFC 3039 Gender - PrintableString (SIZE(1)) -- "M", "F", "m" or "f" + */ + public static final ASN1ObjectIdentifier GENDER = new ASN1ObjectIdentifier( + "1.3.6.1.5.5.7.9.3"); + + /** + * RFC 3039 CountryOfCitizenship - PrintableString (SIZE (2)) -- ISO 3166 + * codes only + */ + public static final ASN1ObjectIdentifier COUNTRY_OF_CITIZENSHIP = new ASN1ObjectIdentifier( + "1.3.6.1.5.5.7.9.4"); + + /** + * RFC 3039 CountryOfResidence - PrintableString (SIZE (2)) -- ISO 3166 + * codes only + */ + public static final ASN1ObjectIdentifier COUNTRY_OF_RESIDENCE = new ASN1ObjectIdentifier( + "1.3.6.1.5.5.7.9.5"); + + + /** + * ISIS-MTT NameAtBirth - DirectoryString(SIZE(1..64) + */ + public static final ASN1ObjectIdentifier NAME_AT_BIRTH = new ASN1ObjectIdentifier("1.3.36.8.3.14"); + + /** + * RFC 3039 PostalAddress - SEQUENCE SIZE (1..6) OF + * DirectoryString(SIZE(1..30)) + */ + public static final ASN1ObjectIdentifier POSTAL_ADDRESS = new ASN1ObjectIdentifier("2.5.4.16"); + + /** + * RFC 2256 dmdName + */ + public static final ASN1ObjectIdentifier DMD_NAME = new ASN1ObjectIdentifier("2.5.4.54"); + + /** + * id-at-telephoneNumber + */ + public static final ASN1ObjectIdentifier TELEPHONE_NUMBER = X509ObjectIdentifiers.id_at_telephoneNumber; + + /** + * id-at-name + */ + public static final ASN1ObjectIdentifier NAME = X509ObjectIdentifiers.id_at_name; + + /** + * Email address (RSA PKCS#9 extension) - IA5String. + *
Note: if you're trying to be ultra orthodox, don't use this! It shouldn't be in here. + */ + public static final ASN1ObjectIdentifier EmailAddress = PKCSObjectIdentifiers.pkcs_9_at_emailAddress; + + /** + * more from PKCS#9 + */ + public static final ASN1ObjectIdentifier UnstructuredName = PKCSObjectIdentifiers.pkcs_9_at_unstructuredName; + public static final ASN1ObjectIdentifier UnstructuredAddress = PKCSObjectIdentifiers.pkcs_9_at_unstructuredAddress; + + /** + * email address in Verisign certificates + */ + public static final ASN1ObjectIdentifier E = EmailAddress; + + /* + * others... + */ + public static final ASN1ObjectIdentifier DC = new ASN1ObjectIdentifier("0.9.2342.19200300.100.1.25"); + + /** + * LDAP User id. + */ + public static final ASN1ObjectIdentifier UID = new ASN1ObjectIdentifier("0.9.2342.19200300.100.1.1"); + + /** + * default look up table translating OID values into their common symbols following + * the convention in RFC 2253 with a few extras + */ + private static final Hashtable DefaultSymbols = new Hashtable(); + + /** + * look up table translating common symbols into their OIDS. + */ + private static final Hashtable DefaultLookUp = new Hashtable(); + + static + { + DefaultSymbols.put(C, "C"); + DefaultSymbols.put(O, "O"); + DefaultSymbols.put(T, "T"); + DefaultSymbols.put(OU, "OU"); + DefaultSymbols.put(CN, "CN"); + DefaultSymbols.put(L, "L"); + DefaultSymbols.put(ST, "ST"); + DefaultSymbols.put(SN, "SERIALNUMBER"); + DefaultSymbols.put(EmailAddress, "E"); + DefaultSymbols.put(DC, "DC"); + DefaultSymbols.put(UID, "UID"); + DefaultSymbols.put(STREET, "STREET"); + DefaultSymbols.put(SURNAME, "SURNAME"); + DefaultSymbols.put(GIVENNAME, "GIVENNAME"); + DefaultSymbols.put(INITIALS, "INITIALS"); + DefaultSymbols.put(GENERATION, "GENERATION"); + DefaultSymbols.put(UnstructuredAddress, "unstructuredAddress"); + DefaultSymbols.put(UnstructuredName, "unstructuredName"); + DefaultSymbols.put(UNIQUE_IDENTIFIER, "UniqueIdentifier"); + DefaultSymbols.put(DN_QUALIFIER, "DN"); + DefaultSymbols.put(PSEUDONYM, "Pseudonym"); + DefaultSymbols.put(POSTAL_ADDRESS, "PostalAddress"); + DefaultSymbols.put(NAME_AT_BIRTH, "NameAtBirth"); + DefaultSymbols.put(COUNTRY_OF_CITIZENSHIP, "CountryOfCitizenship"); + DefaultSymbols.put(COUNTRY_OF_RESIDENCE, "CountryOfResidence"); + DefaultSymbols.put(GENDER, "Gender"); + DefaultSymbols.put(PLACE_OF_BIRTH, "PlaceOfBirth"); + DefaultSymbols.put(DATE_OF_BIRTH, "DateOfBirth"); + DefaultSymbols.put(POSTAL_CODE, "PostalCode"); + DefaultSymbols.put(BUSINESS_CATEGORY, "BusinessCategory"); + DefaultSymbols.put(TELEPHONE_NUMBER, "TelephoneNumber"); + DefaultSymbols.put(NAME, "Name"); + + DefaultLookUp.put("c", C); + DefaultLookUp.put("o", O); + DefaultLookUp.put("t", T); + DefaultLookUp.put("ou", OU); + DefaultLookUp.put("cn", CN); + DefaultLookUp.put("l", L); + DefaultLookUp.put("st", ST); + DefaultLookUp.put("sn", SN); + DefaultLookUp.put("serialnumber", SN); + DefaultLookUp.put("street", STREET); + DefaultLookUp.put("emailaddress", E); + DefaultLookUp.put("dc", DC); + DefaultLookUp.put("e", E); + DefaultLookUp.put("uid", UID); + DefaultLookUp.put("surname", SURNAME); + DefaultLookUp.put("givenname", GIVENNAME); + DefaultLookUp.put("initials", INITIALS); + DefaultLookUp.put("generation", GENERATION); + DefaultLookUp.put("unstructuredaddress", UnstructuredAddress); + DefaultLookUp.put("unstructuredname", UnstructuredName); + DefaultLookUp.put("uniqueidentifier", UNIQUE_IDENTIFIER); + DefaultLookUp.put("dn", DN_QUALIFIER); + DefaultLookUp.put("pseudonym", PSEUDONYM); + DefaultLookUp.put("postaladdress", POSTAL_ADDRESS); + DefaultLookUp.put("nameofbirth", NAME_AT_BIRTH); + DefaultLookUp.put("countryofcitizenship", COUNTRY_OF_CITIZENSHIP); + DefaultLookUp.put("countryofresidence", COUNTRY_OF_RESIDENCE); + DefaultLookUp.put("gender", GENDER); + DefaultLookUp.put("placeofbirth", PLACE_OF_BIRTH); + DefaultLookUp.put("dateofbirth", DATE_OF_BIRTH); + DefaultLookUp.put("postalcode", POSTAL_CODE); + DefaultLookUp.put("businesscategory", BUSINESS_CATEGORY); + DefaultLookUp.put("telephonenumber", TELEPHONE_NUMBER); + DefaultLookUp.put("name", NAME); + } + + protected BCStyle() + { + + } + + public ASN1Encodable stringToValue(ASN1ObjectIdentifier oid, String value) + { + if (value.length() != 0 && value.charAt(0) == '#') + { + try + { + return IETFUtils.valueFromHexString(value, 1); + } + catch (IOException e) + { + throw new RuntimeException("can't recode value for oid " + oid.getId()); + } + } + else + { + if (value.length() != 0 && value.charAt(0) == '\\') + { + value = value.substring(1); + } + if (oid.equals(EmailAddress) || oid.equals(DC)) + { + return new DERIA5String(value); + } + else if (oid.equals(DATE_OF_BIRTH)) // accept time string as well as # (for compatibility) + { + return new ASN1GeneralizedTime(value); + } + else if (oid.equals(C) || oid.equals(SN) || oid.equals(DN_QUALIFIER) + || oid.equals(TELEPHONE_NUMBER)) + { + return new DERPrintableString(value); + } + } + + return new DERUTF8String(value); + } + + public ASN1ObjectIdentifier attrNameToOID(String attrName) + { + return IETFUtils.decodeAttrName(attrName, DefaultLookUp); + } + + public boolean areEqual(X500Name name1, X500Name name2) + { + RDN[] rdns1 = name1.getRDNs(); + RDN[] rdns2 = name2.getRDNs(); + + if (rdns1.length != rdns2.length) + { + return false; + } + + boolean reverse = false; + + if (rdns1[0].getFirst() != null && rdns2[0].getFirst() != null) + { + reverse = !rdns1[0].getFirst().getType().equals(rdns2[0].getFirst().getType()); // guess forward + } + + for (int i = 0; i != rdns1.length; i++) + { + if (!foundMatch(reverse, rdns1[i], rdns2)) + { + return false; + } + } + + return true; + } + + private boolean foundMatch(boolean reverse, RDN rdn, RDN[] possRDNs) + { + if (reverse) + { + for (int i = possRDNs.length - 1; i >= 0; i--) + { + if (possRDNs[i] != null && rdnAreEqual(rdn, possRDNs[i])) + { + possRDNs[i] = null; + return true; + } + } + } + else + { + for (int i = 0; i != possRDNs.length; i++) + { + if (possRDNs[i] != null && rdnAreEqual(rdn, possRDNs[i])) + { + possRDNs[i] = null; + return true; + } + } + } + + return false; + } + + protected boolean rdnAreEqual(RDN rdn1, RDN rdn2) + { + return IETFUtils.rDNAreEqual(rdn1, rdn2); + } + + public RDN[] fromString(String dirName) + { + return IETFUtils.rDNsFromString(dirName, this); + } + + public int calculateHashCode(X500Name name) + { + int hashCodeValue = 0; + RDN[] rdns = name.getRDNs(); + + // this needs to be order independent, like equals + for (int i = 0; i != rdns.length; i++) + { + if (rdns[i].isMultiValued()) + { + AttributeTypeAndValue[] atv = rdns[i].getTypesAndValues(); + + for (int j = 0; j != atv.length; j++) + { + hashCodeValue ^= atv[j].getType().hashCode(); + hashCodeValue ^= calcHashCode(atv[j].getValue()); + } + } + else + { + hashCodeValue ^= rdns[i].getFirst().getType().hashCode(); + hashCodeValue ^= calcHashCode(rdns[i].getFirst().getValue()); + } + } + + return hashCodeValue; + } + + private int calcHashCode(ASN1Encodable enc) + { + String value = IETFUtils.valueToString(enc); + + value = IETFUtils.canonicalize(value); + + return value.hashCode(); + } + + public String toString(X500Name name) + { + StringBuffer buf = new StringBuffer(); + boolean first = true; + + RDN[] rdns = name.getRDNs(); + + for (int i = 0; i < rdns.length; i++) + { + if (first) + { + first = false; + } + else + { + buf.append(','); + } + + IETFUtils.appendRDN(buf, rdns[i], DefaultSymbols); + } + + return buf.toString(); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x500/style/IETFUtils.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x500/style/IETFUtils.java new file mode 100644 index 0000000..bcd1828 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x500/style/IETFUtils.java @@ -0,0 +1,409 @@ +package org.bc.asn1.x500.style; + +import java.io.IOException; +import java.util.Hashtable; +import java.util.Vector; + +import org.bc.asn1.ASN1Encodable; +import org.bc.asn1.ASN1Encoding; +import org.bc.asn1.ASN1ObjectIdentifier; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1String; +import org.bc.asn1.DERUniversalString; +import org.bc.asn1.x500.AttributeTypeAndValue; +import org.bc.asn1.x500.RDN; +import org.bc.asn1.x500.X500NameBuilder; +import org.bc.asn1.x500.X500NameStyle; +import org.bc.util.Strings; +import org.bc.util.encoders.Hex; + +public class IETFUtils +{ + public static RDN[] rDNsFromString(String name, X500NameStyle x500Style) + { + X500NameTokenizer nTok = new X500NameTokenizer(name); + X500NameBuilder builder = new X500NameBuilder(x500Style); + + while (nTok.hasMoreTokens()) + { + String token = nTok.nextToken(); + int index = token.indexOf('='); + + if (index == -1) + { + throw new IllegalArgumentException("badly formated directory string"); + } + + String attr = token.substring(0, index); + String value = token.substring(index + 1); + ASN1ObjectIdentifier oid = x500Style.attrNameToOID(attr); + + if (value.indexOf('+') > 0) + { + X500NameTokenizer vTok = new X500NameTokenizer(value, '+'); + String v = vTok.nextToken(); + + Vector oids = new Vector(); + Vector values = new Vector(); + + oids.addElement(oid); + values.addElement(v); + + while (vTok.hasMoreTokens()) + { + String sv = vTok.nextToken(); + int ndx = sv.indexOf('='); + + String nm = sv.substring(0, ndx); + String vl = sv.substring(ndx + 1); + + oids.addElement(x500Style.attrNameToOID(nm)); + values.addElement(vl); + } + + builder.addMultiValuedRDN(toOIDArray(oids), toValueArray(values)); + } + else + { + builder.addRDN(oid, value); + } + } + + return builder.build().getRDNs(); + } + + private static String[] toValueArray(Vector values) + { + String[] tmp = new String[values.size()]; + + for (int i = 0; i != tmp.length; i++) + { + tmp[i] = (String)values.elementAt(i); + } + + return tmp; + } + + private static ASN1ObjectIdentifier[] toOIDArray(Vector oids) + { + ASN1ObjectIdentifier[] tmp = new ASN1ObjectIdentifier[oids.size()]; + + for (int i = 0; i != tmp.length; i++) + { + tmp[i] = (ASN1ObjectIdentifier)oids.elementAt(i); + } + + return tmp; + } + + public static ASN1ObjectIdentifier decodeAttrName( + String name, + Hashtable lookUp) + { + if (Strings.toUpperCase(name).startsWith("OID.")) + { + return new ASN1ObjectIdentifier(name.substring(4)); + } + else if (name.charAt(0) >= '0' && name.charAt(0) <= '9') + { + return new ASN1ObjectIdentifier(name); + } + + ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)lookUp.get(Strings.toLowerCase(name)); + if (oid == null) + { + throw new IllegalArgumentException("Unknown object id - " + name + " - passed to distinguished name"); + } + + return oid; + } + + public static ASN1Encodable valueFromHexString( + String str, + int off) + throws IOException + { + str = Strings.toLowerCase(str); + byte[] data = new byte[(str.length() - off) / 2]; + for (int index = 0; index != data.length; index++) + { + char left = str.charAt((index * 2) + off); + char right = str.charAt((index * 2) + off + 1); + + if (left < 'a') + { + data[index] = (byte)((left - '0') << 4); + } + else + { + data[index] = (byte)((left - 'a' + 10) << 4); + } + if (right < 'a') + { + data[index] |= (byte)(right - '0'); + } + else + { + data[index] |= (byte)(right - 'a' + 10); + } + } + + return ASN1Primitive.fromByteArray(data); + } + + public static void appendRDN( + StringBuffer buf, + RDN rdn, + Hashtable oidSymbols) + { + if (rdn.isMultiValued()) + { + AttributeTypeAndValue[] atv = rdn.getTypesAndValues(); + boolean firstAtv = true; + + for (int j = 0; j != atv.length; j++) + { + if (firstAtv) + { + firstAtv = false; + } + else + { + buf.append('+'); + } + + IETFUtils.appendTypeAndValue(buf, atv[j], oidSymbols); + } + } + else + { + IETFUtils.appendTypeAndValue(buf, rdn.getFirst(), oidSymbols); + } + } + + public static void appendTypeAndValue( + StringBuffer buf, + AttributeTypeAndValue typeAndValue, + Hashtable oidSymbols) + { + String sym = (String)oidSymbols.get(typeAndValue.getType()); + + if (sym != null) + { + buf.append(sym); + } + else + { + buf.append(typeAndValue.getType().getId()); + } + + buf.append('='); + + buf.append(valueToString(typeAndValue.getValue())); + } + + public static String valueToString(ASN1Encodable value) + { + StringBuffer vBuf = new StringBuffer(); + + if (value instanceof ASN1String && !(value instanceof DERUniversalString)) + { + String v = ((ASN1String)value).getString(); + if (v.length() > 0 && v.charAt(0) == '#') + { + vBuf.append("\\" + v); + } + else + { + vBuf.append(v); + } + } + else + { + try + { + vBuf.append("#" + bytesToString(Hex.encode(value.toASN1Primitive().getEncoded(ASN1Encoding.DER)))); + } + catch (IOException e) + { + throw new IllegalArgumentException("Other value has no encoded form"); + } + } + + int end = vBuf.length(); + int index = 0; + + if (vBuf.length() >= 2 && vBuf.charAt(0) == '\\' && vBuf.charAt(1) == '#') + { + index += 2; + } + + while (index != end) + { + if ((vBuf.charAt(index) == ',') + || (vBuf.charAt(index) == '"') + || (vBuf.charAt(index) == '\\') + || (vBuf.charAt(index) == '+') + || (vBuf.charAt(index) == '=') + || (vBuf.charAt(index) == '<') + || (vBuf.charAt(index) == '>') + || (vBuf.charAt(index) == ';')) + { + vBuf.insert(index, "\\"); + index++; + end++; + } + + index++; + } + + return vBuf.toString(); + } + + private static String bytesToString( + byte[] data) + { + char[] cs = new char[data.length]; + + for (int i = 0; i != cs.length; i++) + { + cs[i] = (char)(data[i] & 0xff); + } + + return new String(cs); + } + + public static String canonicalize(String s) + { + String value = Strings.toLowerCase(s.trim()); + + if (value.length() > 0 && value.charAt(0) == '#') + { + ASN1Primitive obj = decodeObject(value); + + if (obj instanceof ASN1String) + { + value = Strings.toLowerCase(((ASN1String)obj).getString().trim()); + } + } + + value = stripInternalSpaces(value); + + return value; + } + + private static ASN1Primitive decodeObject(String oValue) + { + try + { + return ASN1Primitive.fromByteArray(Hex.decode(oValue.substring(1))); + } + catch (IOException e) + { + throw new IllegalStateException("unknown encoding in name: " + e); + } + } + + public static String stripInternalSpaces( + String str) + { + StringBuffer res = new StringBuffer(); + + if (str.length() != 0) + { + char c1 = str.charAt(0); + + res.append(c1); + + for (int k = 1; k < str.length(); k++) + { + char c2 = str.charAt(k); + if (!(c1 == ' ' && c2 == ' ')) + { + res.append(c2); + } + c1 = c2; + } + } + + return res.toString(); + } + + public static boolean rDNAreEqual(RDN rdn1, RDN rdn2) + { + if (rdn1.isMultiValued()) + { + if (rdn2.isMultiValued()) + { + AttributeTypeAndValue[] atvs1 = rdn1.getTypesAndValues(); + AttributeTypeAndValue[] atvs2 = rdn2.getTypesAndValues(); + + if (atvs1.length != atvs2.length) + { + return false; + } + + for (int i = 0; i != atvs1.length; i++) + { + if (!atvAreEqual(atvs1[i], atvs2[i])) + { + return false; + } + } + } + else + { + return false; + } + } + else + { + if (!rdn2.isMultiValued()) + { + return atvAreEqual(rdn1.getFirst(), rdn2.getFirst()); + } + else + { + return false; + } + } + + return true; + } + + private static boolean atvAreEqual(AttributeTypeAndValue atv1, AttributeTypeAndValue atv2) + { + if (atv1 == atv2) + { + return true; + } + + if (atv1 == null) + { + return false; + } + + if (atv2 == null) + { + return false; + } + + ASN1ObjectIdentifier o1 = atv1.getType(); + ASN1ObjectIdentifier o2 = atv2.getType(); + + if (!o1.equals(o2)) + { + return false; + } + + String v1 = IETFUtils.canonicalize(IETFUtils.valueToString(atv1.getValue())); + String v2 = IETFUtils.canonicalize(IETFUtils.valueToString(atv2.getValue())); + + if (!v1.equals(v2)) + { + return false; + } + + return true; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x500/style/RFC4519Style.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x500/style/RFC4519Style.java new file mode 100644 index 0000000..c40b869 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x500/style/RFC4519Style.java @@ -0,0 +1,348 @@ +package org.bc.asn1.x500.style; + +import java.io.IOException; +import java.util.Hashtable; + +import org.bc.asn1.ASN1Encodable; +import org.bc.asn1.ASN1ObjectIdentifier; +import org.bc.asn1.DERIA5String; +import org.bc.asn1.DERPrintableString; +import org.bc.asn1.DERUTF8String; +import org.bc.asn1.x500.AttributeTypeAndValue; +import org.bc.asn1.x500.RDN; +import org.bc.asn1.x500.X500Name; +import org.bc.asn1.x500.X500NameStyle; + +public class RFC4519Style + implements X500NameStyle +{ + public static final X500NameStyle INSTANCE = new RFC4519Style(); + + public static final ASN1ObjectIdentifier businessCategory = new ASN1ObjectIdentifier("2.5.4.15"); + public static final ASN1ObjectIdentifier c = new ASN1ObjectIdentifier("2.5.4.6"); + public static final ASN1ObjectIdentifier cn = new ASN1ObjectIdentifier("2.5.4.3"); + public static final ASN1ObjectIdentifier dc = new ASN1ObjectIdentifier("0.9.2342.19200300.100.1.25"); + public static final ASN1ObjectIdentifier description = new ASN1ObjectIdentifier("2.5.4.13"); + public static final ASN1ObjectIdentifier destinationIndicator = new ASN1ObjectIdentifier("2.5.4.27"); + public static final ASN1ObjectIdentifier distinguishedName = new ASN1ObjectIdentifier("2.5.4.49"); + public static final ASN1ObjectIdentifier dnQualifier = new ASN1ObjectIdentifier("2.5.4.46"); + public static final ASN1ObjectIdentifier enhancedSearchGuide = new ASN1ObjectIdentifier("2.5.4.47"); + public static final ASN1ObjectIdentifier facsimileTelephoneNumber = new ASN1ObjectIdentifier("2.5.4.23"); + public static final ASN1ObjectIdentifier generationQualifier = new ASN1ObjectIdentifier("2.5.4.44"); + public static final ASN1ObjectIdentifier givenName = new ASN1ObjectIdentifier("2.5.4.42"); + public static final ASN1ObjectIdentifier houseIdentifier = new ASN1ObjectIdentifier("2.5.4.51"); + public static final ASN1ObjectIdentifier initials = new ASN1ObjectIdentifier("2.5.4.43"); + public static final ASN1ObjectIdentifier internationalISDNNumber = new ASN1ObjectIdentifier("2.5.4.25"); + public static final ASN1ObjectIdentifier l = new ASN1ObjectIdentifier("2.5.4.7"); + public static final ASN1ObjectIdentifier member = new ASN1ObjectIdentifier("2.5.4.31"); + public static final ASN1ObjectIdentifier name = new ASN1ObjectIdentifier("2.5.4.41"); + public static final ASN1ObjectIdentifier o = new ASN1ObjectIdentifier("2.5.4.10"); + public static final ASN1ObjectIdentifier ou = new ASN1ObjectIdentifier("2.5.4.11"); + public static final ASN1ObjectIdentifier owner = new ASN1ObjectIdentifier("2.5.4.32"); + public static final ASN1ObjectIdentifier physicalDeliveryOfficeName = new ASN1ObjectIdentifier("2.5.4.19"); + public static final ASN1ObjectIdentifier postalAddress = new ASN1ObjectIdentifier("2.5.4.16"); + public static final ASN1ObjectIdentifier postalCode = new ASN1ObjectIdentifier("2.5.4.17"); + public static final ASN1ObjectIdentifier postOfficeBox = new ASN1ObjectIdentifier("2.5.4.18"); + public static final ASN1ObjectIdentifier preferredDeliveryMethod = new ASN1ObjectIdentifier("2.5.4.28"); + public static final ASN1ObjectIdentifier registeredAddress = new ASN1ObjectIdentifier("2.5.4.26"); + public static final ASN1ObjectIdentifier roleOccupant = new ASN1ObjectIdentifier("2.5.4.33"); + public static final ASN1ObjectIdentifier searchGuide = new ASN1ObjectIdentifier("2.5.4.14"); + public static final ASN1ObjectIdentifier seeAlso = new ASN1ObjectIdentifier("2.5.4.34"); + public static final ASN1ObjectIdentifier serialNumber = new ASN1ObjectIdentifier("2.5.4.5"); + public static final ASN1ObjectIdentifier sn = new ASN1ObjectIdentifier("2.5.4.4"); + public static final ASN1ObjectIdentifier st = new ASN1ObjectIdentifier("2.5.4.8"); + public static final ASN1ObjectIdentifier street = new ASN1ObjectIdentifier("2.5.4.9"); + public static final ASN1ObjectIdentifier telephoneNumber = new ASN1ObjectIdentifier("2.5.4.20"); + public static final ASN1ObjectIdentifier teletexTerminalIdentifier = new ASN1ObjectIdentifier("2.5.4.22"); + public static final ASN1ObjectIdentifier telexNumber = new ASN1ObjectIdentifier("2.5.4.21"); + public static final ASN1ObjectIdentifier title = new ASN1ObjectIdentifier("2.5.4.12"); + public static final ASN1ObjectIdentifier uid = new ASN1ObjectIdentifier("0.9.2342.19200300.100.1.1"); + public static final ASN1ObjectIdentifier uniqueMember = new ASN1ObjectIdentifier("2.5.4.50"); + public static final ASN1ObjectIdentifier userPassword = new ASN1ObjectIdentifier("2.5.4.35"); + public static final ASN1ObjectIdentifier x121Address = new ASN1ObjectIdentifier("2.5.4.24"); + public static final ASN1ObjectIdentifier x500UniqueIdentifier = new ASN1ObjectIdentifier("2.5.4.45"); + + /** + * default look up table translating OID values into their common symbols following + * the convention in RFC 2253 with a few extras + */ + private static final Hashtable DefaultSymbols = new Hashtable(); + + /** + * look up table translating common symbols into their OIDS. + */ + private static final Hashtable DefaultLookUp = new Hashtable(); + + static + { + DefaultSymbols.put(businessCategory, "businessCategory"); + DefaultSymbols.put(c, "c"); + DefaultSymbols.put(cn, "cn"); + DefaultSymbols.put(dc, "dc"); + DefaultSymbols.put(description, "description"); + DefaultSymbols.put(destinationIndicator, "destinationIndicator"); + DefaultSymbols.put(distinguishedName, "distinguishedName"); + DefaultSymbols.put(dnQualifier, "dnQualifier"); + DefaultSymbols.put(enhancedSearchGuide, "enhancedSearchGuide"); + DefaultSymbols.put(facsimileTelephoneNumber, "facsimileTelephoneNumber"); + DefaultSymbols.put(generationQualifier, "generationQualifier"); + DefaultSymbols.put(givenName, "givenName"); + DefaultSymbols.put(houseIdentifier, "houseIdentifier"); + DefaultSymbols.put(initials, "initials"); + DefaultSymbols.put(internationalISDNNumber, "internationalISDNNumber"); + DefaultSymbols.put(l, "l"); + DefaultSymbols.put(member, "member"); + DefaultSymbols.put(name, "name"); + DefaultSymbols.put(o, "o"); + DefaultSymbols.put(ou, "ou"); + DefaultSymbols.put(owner, "owner"); + DefaultSymbols.put(physicalDeliveryOfficeName, "physicalDeliveryOfficeName"); + DefaultSymbols.put(postalAddress, "postalAddress"); + DefaultSymbols.put(postalCode, "postalCode"); + DefaultSymbols.put(postOfficeBox, "postOfficeBox"); + DefaultSymbols.put(preferredDeliveryMethod, "preferredDeliveryMethod"); + DefaultSymbols.put(registeredAddress, "registeredAddress"); + DefaultSymbols.put(roleOccupant, "roleOccupant"); + DefaultSymbols.put(searchGuide, "searchGuide"); + DefaultSymbols.put(seeAlso, "seeAlso"); + DefaultSymbols.put(serialNumber, "serialNumber"); + DefaultSymbols.put(sn, "sn"); + DefaultSymbols.put(st, "st"); + DefaultSymbols.put(street, "street"); + DefaultSymbols.put(telephoneNumber, "telephoneNumber"); + DefaultSymbols.put(teletexTerminalIdentifier, "teletexTerminalIdentifier"); + DefaultSymbols.put(telexNumber, "telexNumber"); + DefaultSymbols.put(title, "title"); + DefaultSymbols.put(uid, "uid"); + DefaultSymbols.put(uniqueMember, "uniqueMember"); + DefaultSymbols.put(userPassword, "userPassword"); + DefaultSymbols.put(x121Address, "x121Address"); + DefaultSymbols.put(x500UniqueIdentifier, "x500UniqueIdentifier"); + + DefaultLookUp.put("businesscategory", businessCategory); + DefaultLookUp.put("c", c); + DefaultLookUp.put("cn", cn); + DefaultLookUp.put("dc", dc); + DefaultLookUp.put("description", description); + DefaultLookUp.put("destinationindicator", destinationIndicator); + DefaultLookUp.put("distinguishedname", distinguishedName); + DefaultLookUp.put("dnqualifier", dnQualifier); + DefaultLookUp.put("enhancedsearchguide", enhancedSearchGuide); + DefaultLookUp.put("facsimiletelephonenumber", facsimileTelephoneNumber); + DefaultLookUp.put("generationqualifier", generationQualifier); + DefaultLookUp.put("givenname", givenName); + DefaultLookUp.put("houseidentifier", houseIdentifier); + DefaultLookUp.put("initials", initials); + DefaultLookUp.put("internationalisdnnumber", internationalISDNNumber); + DefaultLookUp.put("l", l); + DefaultLookUp.put("member", member); + DefaultLookUp.put("name", name); + DefaultLookUp.put("o", o); + DefaultLookUp.put("ou", ou); + DefaultLookUp.put("owner", owner); + DefaultLookUp.put("physicaldeliveryofficename", physicalDeliveryOfficeName); + DefaultLookUp.put("postaladdress", postalAddress); + DefaultLookUp.put("postalcode", postalCode); + DefaultLookUp.put("postofficebox", postOfficeBox); + DefaultLookUp.put("preferreddeliverymethod", preferredDeliveryMethod); + DefaultLookUp.put("registeredaddress", registeredAddress); + DefaultLookUp.put("roleoccupant", roleOccupant); + DefaultLookUp.put("searchguide", searchGuide); + DefaultLookUp.put("seealso", seeAlso); + DefaultLookUp.put("serialnumber", serialNumber); + DefaultLookUp.put("sn", sn); + DefaultLookUp.put("st", st); + DefaultLookUp.put("street", street); + DefaultLookUp.put("telephonenumber", telephoneNumber); + DefaultLookUp.put("teletexterminalidentifier", teletexTerminalIdentifier); + DefaultLookUp.put("telexnumber", telexNumber); + DefaultLookUp.put("title", title); + DefaultLookUp.put("uid", uid); + DefaultLookUp.put("uniquemember", uniqueMember); + DefaultLookUp.put("userpassword", userPassword); + DefaultLookUp.put("x121address", x121Address); + DefaultLookUp.put("x500uniqueidentifier", x500UniqueIdentifier); + + // TODO: need to add correct matching for equality comparisons. + } + + protected RFC4519Style() + { + + } + + public ASN1Encodable stringToValue(ASN1ObjectIdentifier oid, String value) + { + if (value.length() != 0 && value.charAt(0) == '#') + { + try + { + return IETFUtils.valueFromHexString(value, 1); + } + catch (IOException e) + { + throw new RuntimeException("can't recode value for oid " + oid.getId()); + } + } + else + { + if (value.length() != 0 && value.charAt(0) == '\\') + { + value = value.substring(1); + } + if (oid.equals(dc)) + { + return new DERIA5String(value); + } + else if (oid.equals(c) || oid.equals(serialNumber) || oid.equals(dnQualifier) + || oid.equals(telephoneNumber)) + { + return new DERPrintableString(value); + } + } + + return new DERUTF8String(value); + } + + public ASN1ObjectIdentifier attrNameToOID(String attrName) + { + return IETFUtils.decodeAttrName(attrName, DefaultLookUp); + } + + public boolean areEqual(X500Name name1, X500Name name2) + { + RDN[] rdns1 = name1.getRDNs(); + RDN[] rdns2 = name2.getRDNs(); + + if (rdns1.length != rdns2.length) + { + return false; + } + + boolean reverse = false; + + if (rdns1[0].getFirst() != null && rdns2[0].getFirst() != null) + { + reverse = !rdns1[0].getFirst().getType().equals(rdns2[0].getFirst().getType()); // guess forward + } + + for (int i = 0; i != rdns1.length; i++) + { + if (!foundMatch(reverse, rdns1[i], rdns2)) + { + return false; + } + } + + return true; + } + + private boolean foundMatch(boolean reverse, RDN rdn, RDN[] possRDNs) + { + if (reverse) + { + for (int i = possRDNs.length - 1; i >= 0; i--) + { + if (possRDNs[i] != null && rdnAreEqual(rdn, possRDNs[i])) + { + possRDNs[i] = null; + return true; + } + } + } + else + { + for (int i = 0; i != possRDNs.length; i++) + { + if (possRDNs[i] != null && rdnAreEqual(rdn, possRDNs[i])) + { + possRDNs[i] = null; + return true; + } + } + } + + return false; + } + + protected boolean rdnAreEqual(RDN rdn1, RDN rdn2) + { + return IETFUtils.rDNAreEqual(rdn1, rdn2); + } + + // parse backwards + public RDN[] fromString(String dirName) + { + RDN[] tmp = IETFUtils.rDNsFromString(dirName, this); + RDN[] res = new RDN[tmp.length]; + + for (int i = 0; i != tmp.length; i++) + { + res[res.length - i - 1] = tmp[i]; + } + + return res; + } + + public int calculateHashCode(X500Name name) + { + int hashCodeValue = 0; + RDN[] rdns = name.getRDNs(); + + // this needs to be order independent, like equals + for (int i = 0; i != rdns.length; i++) + { + if (rdns[i].isMultiValued()) + { + AttributeTypeAndValue[] atv = rdns[i].getTypesAndValues(); + + for (int j = 0; j != atv.length; j++) + { + hashCodeValue ^= atv[j].getType().hashCode(); + hashCodeValue ^= calcHashCode(atv[j].getValue()); + } + } + else + { + hashCodeValue ^= rdns[i].getFirst().getType().hashCode(); + hashCodeValue ^= calcHashCode(rdns[i].getFirst().getValue()); + } + } + + return hashCodeValue; + } + + private int calcHashCode(ASN1Encodable enc) + { + String value = IETFUtils.valueToString(enc); + + value = IETFUtils.canonicalize(value); + + return value.hashCode(); + } + + // convert in reverse + public String toString(X500Name name) + { + StringBuffer buf = new StringBuffer(); + boolean first = true; + + RDN[] rdns = name.getRDNs(); + + for (int i = rdns.length - 1; i >= 0; i--) + { + if (first) + { + first = false; + } + else + { + buf.append(','); + } + + IETFUtils.appendRDN(buf, rdns[i], DefaultSymbols); + } + + return buf.toString(); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x500/style/X500NameTokenizer.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x500/style/X500NameTokenizer.java new file mode 100644 index 0000000..2760ca5 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x500/style/X500NameTokenizer.java @@ -0,0 +1,107 @@ +package org.bc.asn1.x500.style; + +/** + * class for breaking up an X500 Name into it's component tokens, ala + * java.util.StringTokenizer. We need this class as some of the + * lightweight Java environment don't support classes like + * StringTokenizer. + */ +class X500NameTokenizer +{ + private String value; + private int index; + private char separator; + private StringBuffer buf = new StringBuffer(); + + public X500NameTokenizer( + String oid) + { + this(oid, ','); + } + + public X500NameTokenizer( + String oid, + char separator) + { + this.value = oid; + this.index = -1; + this.separator = separator; + } + + public boolean hasMoreTokens() + { + return (index != value.length()); + } + + public String nextToken() + { + if (index == value.length()) + { + return null; + } + + int end = index + 1; + boolean quoted = false; + boolean escaped = false; + + buf.setLength(0); + + while (end != value.length()) + { + char c = value.charAt(end); + + if (c == '"') + { + if (!escaped) + { + quoted = !quoted; + } + else + { + if (c == '#' && buf.charAt(buf.length() - 1) == '=') + { + buf.append('\\'); + } + else if (c == '+' && separator != '+') + { + buf.append('\\'); + } + buf.append(c); + } + escaped = false; + } + else + { + if (escaped || quoted) + { + if (c == '#' && buf.charAt(buf.length() - 1) == '=') + { + buf.append('\\'); + } + else if (c == '+' && separator != '+') + { + buf.append('\\'); + } + buf.append(c); + escaped = false; + } + else if (c == '\\') + { + escaped = true; + } + else if (c == separator) + { + break; + } + else + { + buf.append(c); + } + } + end++; + } + + index = end; + return buf.toString().trim(); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/AccessDescription.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/AccessDescription.java new file mode 100644 index 0000000..072d497 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/AccessDescription.java @@ -0,0 +1,98 @@ +package org.bc.asn1.x509; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1ObjectIdentifier; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DERSequence; + +/** + * The AccessDescription object. + *
+ * AccessDescription ::= SEQUENCE { + * accessMethod OBJECT IDENTIFIER, + * accessLocation GeneralName } + *+ */ +public class AccessDescription + extends ASN1Object +{ + public final static ASN1ObjectIdentifier id_ad_caIssuers = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.48.2"); + + public final static ASN1ObjectIdentifier id_ad_ocsp = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.48.1"); + + ASN1ObjectIdentifier accessMethod = null; + GeneralName accessLocation = null; + + public static AccessDescription getInstance( + Object obj) + { + if (obj instanceof AccessDescription) + { + return (AccessDescription)obj; + } + else if (obj != null) + { + return new AccessDescription(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + private AccessDescription( + ASN1Sequence seq) + { + if (seq.size() != 2) + { + throw new IllegalArgumentException("wrong number of elements in sequence"); + } + + accessMethod = ASN1ObjectIdentifier.getInstance(seq.getObjectAt(0)); + accessLocation = GeneralName.getInstance(seq.getObjectAt(1)); + } + + /** + * create an AccessDescription with the oid and location provided. + */ + public AccessDescription( + ASN1ObjectIdentifier oid, + GeneralName location) + { + accessMethod = oid; + accessLocation = location; + } + + /** + * + * @return the access method. + */ + public ASN1ObjectIdentifier getAccessMethod() + { + return accessMethod; + } + + /** + * + * @return the access location + */ + public GeneralName getAccessLocation() + { + return accessLocation; + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector accessDescription = new ASN1EncodableVector(); + + accessDescription.add(accessMethod); + accessDescription.add(accessLocation); + + return new DERSequence(accessDescription); + } + + public String toString() + { + return ("AccessDescription: Oid(" + this.accessMethod.getId() + ")"); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/AlgorithmIdentifier.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/AlgorithmIdentifier.java new file mode 100644 index 0000000..bbfd26f --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/AlgorithmIdentifier.java @@ -0,0 +1,173 @@ +package org.bc.asn1.x509; + +import org.bc.asn1.ASN1Encodable; +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1ObjectIdentifier; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1SequenceParser; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERNull; +import org.bc.asn1.DERObjectIdentifier; +import org.bc.asn1.DERSequence; + +public class AlgorithmIdentifier + extends ASN1Object +{ + private ASN1ObjectIdentifier objectId; + private ASN1Encodable parameters; + private boolean parametersDefined = false; + + public static AlgorithmIdentifier getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static AlgorithmIdentifier getInstance( + Object obj) + { + if (obj== null || obj instanceof AlgorithmIdentifier) + { + return (AlgorithmIdentifier)obj; + } + + if (obj instanceof ASN1ObjectIdentifier) + { + return new AlgorithmIdentifier((ASN1ObjectIdentifier)obj); + } + + if (obj instanceof String) + { + return new AlgorithmIdentifier((String)obj); + } + + if (obj instanceof ASN1Sequence || obj instanceof ASN1SequenceParser) + { + return new AlgorithmIdentifier(ASN1Sequence.getInstance(obj)); + } + + throw new IllegalArgumentException("unknown object in factory: " + obj.getClass().getName()); + } + + public AlgorithmIdentifier( + ASN1ObjectIdentifier objectId) + { + this.objectId = objectId; + } + + /** + * @deprecated use ASN1ObjectIdentifier + * @param objectId + */ + public AlgorithmIdentifier( + String objectId) + { + this.objectId = new ASN1ObjectIdentifier(objectId); + } + + /** + * @deprecated use ASN1ObjectIdentifier + * @param objectId + */ + public AlgorithmIdentifier( + DERObjectIdentifier objectId) + { + this.objectId = new ASN1ObjectIdentifier(objectId.getId()); + } + + /** + * @deprecated use ASN1ObjectIdentifier + * @param objectId + * @param parameters + */ + public AlgorithmIdentifier( + DERObjectIdentifier objectId, + ASN1Encodable parameters) + { + parametersDefined = true; + this.objectId = new ASN1ObjectIdentifier(objectId.getId()); + this.parameters = parameters; + } + + public AlgorithmIdentifier( + ASN1ObjectIdentifier objectId, + ASN1Encodable parameters) + { + parametersDefined = true; + this.objectId = objectId; + this.parameters = parameters; + } + + public AlgorithmIdentifier( + ASN1Sequence seq) + { + if (seq.size() < 1 || seq.size() > 2) + { + throw new IllegalArgumentException("Bad sequence size: " + + seq.size()); + } + + objectId = ASN1ObjectIdentifier.getInstance(seq.getObjectAt(0)); + + if (seq.size() == 2) + { + parametersDefined = true; + parameters = seq.getObjectAt(1); + } + else + { + parameters = null; + } + } + + public ASN1ObjectIdentifier getAlgorithm() + { + return new ASN1ObjectIdentifier(objectId.getId()); + } + + /** + * @deprecated use getAlgorithm + * @return + */ + public ASN1ObjectIdentifier getObjectId() + { + return objectId; + } + + public ASN1Encodable getParameters() + { + return parameters; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + *
+ * AlgorithmIdentifier ::= SEQUENCE { + * algorithm OBJECT IDENTIFIER, + * parameters ANY DEFINED BY algorithm OPTIONAL } + *+ */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(objectId); + + if (parametersDefined) + { + if (parameters != null) + { + v.add(parameters); + } + else + { + v.add(DERNull.INSTANCE); + } + } + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/AttCertIssuer.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/AttCertIssuer.java new file mode 100644 index 0000000..35a0bd5 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/AttCertIssuer.java @@ -0,0 +1,91 @@ +package org.bc.asn1.x509; + +import org.bc.asn1.ASN1Choice; +import org.bc.asn1.ASN1Encodable; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERTaggedObject; + +public class AttCertIssuer + extends ASN1Object + implements ASN1Choice +{ + ASN1Encodable obj; + ASN1Primitive choiceObj; + + public static AttCertIssuer getInstance( + Object obj) + { + if (obj == null || obj instanceof AttCertIssuer) + { + return (AttCertIssuer)obj; + } + else if (obj instanceof V2Form) + { + return new AttCertIssuer(V2Form.getInstance(obj)); + } + else if (obj instanceof GeneralNames) + { + return new AttCertIssuer((GeneralNames)obj); + } + else if (obj instanceof ASN1TaggedObject) + { + return new AttCertIssuer(V2Form.getInstance((ASN1TaggedObject)obj, false)); + } + else if (obj instanceof ASN1Sequence) + { + return new AttCertIssuer(GeneralNames.getInstance(obj)); + } + + throw new IllegalArgumentException("unknown object in factory: " + obj.getClass().getName()); + } + + public static AttCertIssuer getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(obj.getObject()); // must be explicitly tagged + } + + /** + * Don't use this one if you are trying to be RFC 3281 compliant. + * Use it for v1 attribute certificates only. + * + * @param names our GeneralNames structure + */ + public AttCertIssuer( + GeneralNames names) + { + obj = names; + choiceObj = obj.toASN1Primitive(); + } + + public AttCertIssuer( + V2Form v2Form) + { + obj = v2Form; + choiceObj = new DERTaggedObject(false, 0, obj); + } + + public ASN1Encodable getIssuer() + { + return obj; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + *
+ * AttCertIssuer ::= CHOICE { + * v1Form GeneralNames, -- MUST NOT be used in this + * -- profile + * v2Form [0] V2Form -- v2 only + * } + *+ */ + public ASN1Primitive toASN1Primitive() + { + return choiceObj; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/AttCertValidityPeriod.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/AttCertValidityPeriod.java new file mode 100644 index 0000000..bc12929 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/AttCertValidityPeriod.java @@ -0,0 +1,84 @@ +package org.bc.asn1.x509; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1GeneralizedTime; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DERSequence; + +public class AttCertValidityPeriod + extends ASN1Object +{ + ASN1GeneralizedTime notBeforeTime; + ASN1GeneralizedTime notAfterTime; + + public static AttCertValidityPeriod getInstance( + Object obj) + { + if (obj instanceof AttCertValidityPeriod) + { + return (AttCertValidityPeriod)obj; + } + else if (obj != null) + { + return new AttCertValidityPeriod(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + private AttCertValidityPeriod( + ASN1Sequence seq) + { + if (seq.size() != 2) + { + throw new IllegalArgumentException("Bad sequence size: " + + seq.size()); + } + + notBeforeTime = ASN1GeneralizedTime.getInstance(seq.getObjectAt(0)); + notAfterTime = ASN1GeneralizedTime.getInstance(seq.getObjectAt(1)); + } + + /** + * @param notBeforeTime + * @param notAfterTime + */ + public AttCertValidityPeriod( + ASN1GeneralizedTime notBeforeTime, + ASN1GeneralizedTime notAfterTime) + { + this.notBeforeTime = notBeforeTime; + this.notAfterTime = notAfterTime; + } + + public ASN1GeneralizedTime getNotBeforeTime() + { + return notBeforeTime; + } + + public ASN1GeneralizedTime getNotAfterTime() + { + return notAfterTime; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + *
+ * AttCertValidityPeriod ::= SEQUENCE { + * notBeforeTime GeneralizedTime, + * notAfterTime GeneralizedTime + * } + *+ */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(notBeforeTime); + v.add(notAfterTime); + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/Attribute.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/Attribute.java new file mode 100644 index 0000000..ca622b6 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/Attribute.java @@ -0,0 +1,93 @@ +package org.bc.asn1.x509; + +import org.bc.asn1.ASN1Encodable; +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1ObjectIdentifier; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1Set; +import org.bc.asn1.DERSequence; + +public class Attribute + extends ASN1Object +{ + private ASN1ObjectIdentifier attrType; + private ASN1Set attrValues; + + /** + * return an Attribute object from the given object. + * + * @param o the object we want converted. + * @exception IllegalArgumentException if the object cannot be converted. + */ + public static Attribute getInstance( + Object o) + { + if (o instanceof Attribute) + { + return (Attribute)o; + } + + if (o != null) + { + return new Attribute(ASN1Sequence.getInstance(o)); + } + + return null; + } + + private Attribute( + ASN1Sequence seq) + { + if (seq.size() != 2) + { + throw new IllegalArgumentException("Bad sequence size: " + seq.size()); + } + + attrType = ASN1ObjectIdentifier.getInstance(seq.getObjectAt(0)); + attrValues = ASN1Set.getInstance(seq.getObjectAt(1)); + } + + public Attribute( + ASN1ObjectIdentifier attrType, + ASN1Set attrValues) + { + this.attrType = attrType; + this.attrValues = attrValues; + } + + public ASN1ObjectIdentifier getAttrType() + { + return new ASN1ObjectIdentifier(attrType.getId()); + } + + public ASN1Encodable[] getAttributeValues() + { + return attrValues.toArray(); + } + + public ASN1Set getAttrValues() + { + return attrValues; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + *
+ * Attribute ::= SEQUENCE { + * attrType OBJECT IDENTIFIER, + * attrValues SET OF AttributeValue + * } + *+ */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(attrType); + v.add(attrValues); + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/AttributeCertificate.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/AttributeCertificate.java new file mode 100644 index 0000000..f3c75bf --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/AttributeCertificate.java @@ -0,0 +1,94 @@ +package org.bc.asn1.x509; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DERBitString; +import org.bc.asn1.DERSequence; + +public class AttributeCertificate + extends ASN1Object +{ + AttributeCertificateInfo acinfo; + AlgorithmIdentifier signatureAlgorithm; + DERBitString signatureValue; + + /** + * @param obj + * @return an AttributeCertificate object + */ + public static AttributeCertificate getInstance(Object obj) + { + if (obj instanceof AttributeCertificate) + { + return (AttributeCertificate)obj; + } + else if (obj != null) + { + return new AttributeCertificate(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public AttributeCertificate( + AttributeCertificateInfo acinfo, + AlgorithmIdentifier signatureAlgorithm, + DERBitString signatureValue) + { + this.acinfo = acinfo; + this.signatureAlgorithm = signatureAlgorithm; + this.signatureValue = signatureValue; + } + + public AttributeCertificate( + ASN1Sequence seq) + { + if (seq.size() != 3) + { + throw new IllegalArgumentException("Bad sequence size: " + + seq.size()); + } + + this.acinfo = AttributeCertificateInfo.getInstance(seq.getObjectAt(0)); + this.signatureAlgorithm = AlgorithmIdentifier.getInstance(seq.getObjectAt(1)); + this.signatureValue = DERBitString.getInstance(seq.getObjectAt(2)); + } + + public AttributeCertificateInfo getAcinfo() + { + return acinfo; + } + + public AlgorithmIdentifier getSignatureAlgorithm() + { + return signatureAlgorithm; + } + + public DERBitString getSignatureValue() + { + return signatureValue; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + *
+ * AttributeCertificate ::= SEQUENCE { + * acinfo AttributeCertificateInfo, + * signatureAlgorithm AlgorithmIdentifier, + * signatureValue BIT STRING + * } + *+ */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(acinfo); + v.add(signatureAlgorithm); + v.add(signatureValue); + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/AttributeCertificateInfo.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/AttributeCertificateInfo.java new file mode 100644 index 0000000..9b09414 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/AttributeCertificateInfo.java @@ -0,0 +1,166 @@ +package org.bc.asn1.x509; + +import org.bc.asn1.ASN1Encodable; +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERBitString; +import org.bc.asn1.DERSequence; + +public class AttributeCertificateInfo + extends ASN1Object +{ + private ASN1Integer version; + private Holder holder; + private AttCertIssuer issuer; + private AlgorithmIdentifier signature; + private ASN1Integer serialNumber; + private AttCertValidityPeriod attrCertValidityPeriod; + private ASN1Sequence attributes; + private DERBitString issuerUniqueID; + private Extensions extensions; + + public static AttributeCertificateInfo getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static AttributeCertificateInfo getInstance( + Object obj) + { + if (obj instanceof AttributeCertificateInfo) + { + return (AttributeCertificateInfo)obj; + } + else if (obj != null) + { + return new AttributeCertificateInfo(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + private AttributeCertificateInfo( + ASN1Sequence seq) + { + if (seq.size() < 7 || seq.size() > 9) + { + throw new IllegalArgumentException("Bad sequence size: " + seq.size()); + } + + this.version = ASN1Integer.getInstance(seq.getObjectAt(0)); + this.holder = Holder.getInstance(seq.getObjectAt(1)); + this.issuer = AttCertIssuer.getInstance(seq.getObjectAt(2)); + this.signature = AlgorithmIdentifier.getInstance(seq.getObjectAt(3)); + this.serialNumber = ASN1Integer.getInstance(seq.getObjectAt(4)); + this.attrCertValidityPeriod = AttCertValidityPeriod.getInstance(seq.getObjectAt(5)); + this.attributes = ASN1Sequence.getInstance(seq.getObjectAt(6)); + + for (int i = 7; i < seq.size(); i++) + { + ASN1Encodable obj = (ASN1Encodable)seq.getObjectAt(i); + + if (obj instanceof DERBitString) + { + this.issuerUniqueID = DERBitString.getInstance(seq.getObjectAt(i)); + } + else if (obj instanceof ASN1Sequence || obj instanceof Extensions) + { + this.extensions = Extensions.getInstance(seq.getObjectAt(i)); + } + } + } + + public ASN1Integer getVersion() + { + return version; + } + + public Holder getHolder() + { + return holder; + } + + public AttCertIssuer getIssuer() + { + return issuer; + } + + public AlgorithmIdentifier getSignature() + { + return signature; + } + + public ASN1Integer getSerialNumber() + { + return serialNumber; + } + + public AttCertValidityPeriod getAttrCertValidityPeriod() + { + return attrCertValidityPeriod; + } + + public ASN1Sequence getAttributes() + { + return attributes; + } + + public DERBitString getIssuerUniqueID() + { + return issuerUniqueID; + } + + public Extensions getExtensions() + { + return extensions; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + *
+ * AttributeCertificateInfo ::= SEQUENCE { + * version AttCertVersion -- version is v2, + * holder Holder, + * issuer AttCertIssuer, + * signature AlgorithmIdentifier, + * serialNumber CertificateSerialNumber, + * attrCertValidityPeriod AttCertValidityPeriod, + * attributes SEQUENCE OF Attribute, + * issuerUniqueID UniqueIdentifier OPTIONAL, + * extensions Extensions OPTIONAL + * } + * + * AttCertVersion ::= INTEGER { v2(1) } + *+ */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(version); + v.add(holder); + v.add(issuer); + v.add(signature); + v.add(serialNumber); + v.add(attrCertValidityPeriod); + v.add(attributes); + + if (issuerUniqueID != null) + { + v.add(issuerUniqueID); + } + + if (extensions != null) + { + v.add(extensions); + } + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/AuthorityInformationAccess.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/AuthorityInformationAccess.java new file mode 100644 index 0000000..e82bfb9 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/AuthorityInformationAccess.java @@ -0,0 +1,101 @@ +package org.bc.asn1.x509; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1ObjectIdentifier; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DERSequence; + +/** + * The AuthorityInformationAccess object. + *
+ * id-pe-authorityInfoAccess OBJECT IDENTIFIER ::= { id-pe 1 } + * + * AuthorityInfoAccessSyntax ::= + * SEQUENCE SIZE (1..MAX) OF AccessDescription + * AccessDescription ::= SEQUENCE { + * accessMethod OBJECT IDENTIFIER, + * accessLocation GeneralName } + * + * id-ad OBJECT IDENTIFIER ::= { id-pkix 48 } + * id-ad-caIssuers OBJECT IDENTIFIER ::= { id-ad 2 } + * id-ad-ocsp OBJECT IDENTIFIER ::= { id-ad 1 } + *+ */ +public class AuthorityInformationAccess + extends ASN1Object +{ + private AccessDescription[] descriptions; + + public static AuthorityInformationAccess getInstance( + Object obj) + { + if (obj instanceof AuthorityInformationAccess) + { + return (AuthorityInformationAccess)obj; + } + + if (obj != null) + { + return new AuthorityInformationAccess(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + private AuthorityInformationAccess( + ASN1Sequence seq) + { + if (seq.size() < 1) + { + throw new IllegalArgumentException("sequence may not be empty"); + } + + descriptions = new AccessDescription[seq.size()]; + + for (int i = 0; i != seq.size(); i++) + { + descriptions[i] = AccessDescription.getInstance(seq.getObjectAt(i)); + } + } + + /** + * create an AuthorityInformationAccess with the oid and location provided. + */ + public AuthorityInformationAccess( + ASN1ObjectIdentifier oid, + GeneralName location) + { + descriptions = new AccessDescription[1]; + + descriptions[0] = new AccessDescription(oid, location); + } + + + /** + * + * @return the access descriptions contained in this object. + */ + public AccessDescription[] getAccessDescriptions() + { + return descriptions; + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector vec = new ASN1EncodableVector(); + + for (int i = 0; i != descriptions.length; i++) + { + vec.add(descriptions[i]); + } + + return new DERSequence(vec); + } + + public String toString() + { + return ("AuthorityInformationAccess: Oid(" + this.descriptions[0].getAccessMethod().getId() + ")"); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/AuthorityKeyIdentifier.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/AuthorityKeyIdentifier.java new file mode 100644 index 0000000..182c6ae --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/AuthorityKeyIdentifier.java @@ -0,0 +1,232 @@ +package org.bc.asn1.x509; + +import java.math.BigInteger; +import java.util.Enumeration; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1OctetString; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DEROctetString; +import org.bc.asn1.DERSequence; +import org.bc.asn1.DERTaggedObject; +import org.bc.crypto.Digest; +import org.bc.crypto.digests.SHA1Digest; + +/** + * The AuthorityKeyIdentifier object. + *
+ * id-ce-authorityKeyIdentifier OBJECT IDENTIFIER ::= { id-ce 35 } + * + * AuthorityKeyIdentifier ::= SEQUENCE { + * keyIdentifier [0] IMPLICIT KeyIdentifier OPTIONAL, + * authorityCertIssuer [1] IMPLICIT GeneralNames OPTIONAL, + * authorityCertSerialNumber [2] IMPLICIT CertificateSerialNumber OPTIONAL } + * + * KeyIdentifier ::= OCTET STRING + *+ * + */ +public class AuthorityKeyIdentifier + extends ASN1Object +{ + ASN1OctetString keyidentifier=null; + GeneralNames certissuer=null; + ASN1Integer certserno=null; + + public static AuthorityKeyIdentifier getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static AuthorityKeyIdentifier getInstance( + Object obj) + { + if (obj instanceof AuthorityKeyIdentifier) + { + return (AuthorityKeyIdentifier)obj; + } + if (obj != null) + { + return new AuthorityKeyIdentifier(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public static AuthorityKeyIdentifier fromExtensions(Extensions extensions) + { + return AuthorityKeyIdentifier.getInstance(extensions.getExtensionParsedValue(Extension.authorityKeyIdentifier)); + } + + protected AuthorityKeyIdentifier( + ASN1Sequence seq) + { + Enumeration e = seq.getObjects(); + + while (e.hasMoreElements()) + { + ASN1TaggedObject o = DERTaggedObject.getInstance(e.nextElement()); + + switch (o.getTagNo()) + { + case 0: + this.keyidentifier = ASN1OctetString.getInstance(o, false); + break; + case 1: + this.certissuer = GeneralNames.getInstance(o, false); + break; + case 2: + this.certserno = ASN1Integer.getInstance(o, false); + break; + default: + throw new IllegalArgumentException("illegal tag"); + } + } + } + + /** + * + * Calulates the keyidentifier using a SHA1 hash over the BIT STRING + * from SubjectPublicKeyInfo as defined in RFC2459. + * + * Example of making a AuthorityKeyIdentifier: + *
+ * SubjectPublicKeyInfo apki = new SubjectPublicKeyInfo((ASN1Sequence)new ASN1InputStream( + * publicKey.getEncoded()).readObject()); + * AuthorityKeyIdentifier aki = new AuthorityKeyIdentifier(apki); + *+ * + **/ + public AuthorityKeyIdentifier( + SubjectPublicKeyInfo spki) + { + Digest digest = new SHA1Digest(); + byte[] resBuf = new byte[digest.getDigestSize()]; + + byte[] bytes = spki.getPublicKeyData().getBytes(); + digest.update(bytes, 0, bytes.length); + digest.doFinal(resBuf, 0); + this.keyidentifier = new DEROctetString(resBuf); + } + + /** + * create an AuthorityKeyIdentifier with the GeneralNames tag and + * the serial number provided as well. + */ + public AuthorityKeyIdentifier( + SubjectPublicKeyInfo spki, + GeneralNames name, + BigInteger serialNumber) + { + Digest digest = new SHA1Digest(); + byte[] resBuf = new byte[digest.getDigestSize()]; + + byte[] bytes = spki.getPublicKeyData().getBytes(); + digest.update(bytes, 0, bytes.length); + digest.doFinal(resBuf, 0); + + this.keyidentifier = new DEROctetString(resBuf); + this.certissuer = GeneralNames.getInstance(name.toASN1Primitive()); + this.certserno = new ASN1Integer(serialNumber); + } + + /** + * create an AuthorityKeyIdentifier with the GeneralNames tag and + * the serial number provided. + */ + public AuthorityKeyIdentifier( + GeneralNames name, + BigInteger serialNumber) + { + this.keyidentifier = null; + this.certissuer = GeneralNames.getInstance(name.toASN1Primitive()); + this.certserno = new ASN1Integer(serialNumber); + } + + /** + * create an AuthorityKeyIdentifier with a precomupted key identifier + */ + public AuthorityKeyIdentifier( + byte[] keyIdentifier) + { + this.keyidentifier = new DEROctetString(keyIdentifier); + this.certissuer = null; + this.certserno = null; + } + + /** + * create an AuthorityKeyIdentifier with a precomupted key identifier + * and the GeneralNames tag and the serial number provided as well. + */ + public AuthorityKeyIdentifier( + byte[] keyIdentifier, + GeneralNames name, + BigInteger serialNumber) + { + this.keyidentifier = new DEROctetString(keyIdentifier); + this.certissuer = GeneralNames.getInstance(name.toASN1Primitive()); + this.certserno = new ASN1Integer(serialNumber); + } + + public byte[] getKeyIdentifier() + { + if (keyidentifier != null) + { + return keyidentifier.getOctets(); + } + + return null; + } + + public GeneralNames getAuthorityCertIssuer() + { + return certissuer; + } + + public BigInteger getAuthorityCertSerialNumber() + { + if (certserno != null) + { + return certserno.getValue(); + } + + return null; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + if (keyidentifier != null) + { + v.add(new DERTaggedObject(false, 0, keyidentifier)); + } + + if (certissuer != null) + { + v.add(new DERTaggedObject(false, 1, certissuer)); + } + + if (certserno != null) + { + v.add(new DERTaggedObject(false, 2, certserno)); + } + + + return new DERSequence(v); + } + + public String toString() + { + return ("AuthorityKeyIdentifier: KeyID(" + this.keyidentifier.getOctets() + ")"); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/BasicConstraints.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/BasicConstraints.java new file mode 100644 index 0000000..74630a5 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/BasicConstraints.java @@ -0,0 +1,164 @@ +package org.bc.asn1.x509; + +import java.math.BigInteger; + +import org.bc.asn1.ASN1Boolean; +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERBoolean; +import org.bc.asn1.DERSequence; + +public class BasicConstraints + extends ASN1Object +{ + ASN1Boolean cA = ASN1Boolean.getInstance(false); + ASN1Integer pathLenConstraint = null; + + public static BasicConstraints getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static BasicConstraints getInstance( + Object obj) + { + if (obj instanceof BasicConstraints) + { + return (BasicConstraints)obj; + } + if (obj instanceof X509Extension) + { + return getInstance(X509Extension.convertValueToObject((X509Extension)obj)); + } + if (obj != null) + { + return new BasicConstraints(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public static BasicConstraints fromExtensions(Extensions extensions) + { + return BasicConstraints.getInstance(extensions.getExtensionParsedValue(Extension.basicConstraints)); + } + + private BasicConstraints( + ASN1Sequence seq) + { + if (seq.size() == 0) + { + this.cA = null; + this.pathLenConstraint = null; + } + else + { + if (seq.getObjectAt(0) instanceof DERBoolean) + { + this.cA = DERBoolean.getInstance(seq.getObjectAt(0)); + } + else + { + this.cA = null; + this.pathLenConstraint = ASN1Integer.getInstance(seq.getObjectAt(0)); + } + if (seq.size() > 1) + { + if (this.cA != null) + { + this.pathLenConstraint = ASN1Integer.getInstance(seq.getObjectAt(1)); + } + else + { + throw new IllegalArgumentException("wrong sequence in constructor"); + } + } + } + } + + public BasicConstraints( + boolean cA) + { + if (cA) + { + this.cA = ASN1Boolean.getInstance(true); + } + else + { + this.cA = null; + } + this.pathLenConstraint = null; + } + + /** + * create a cA=true object for the given path length constraint. + * + * @param pathLenConstraint + */ + public BasicConstraints( + int pathLenConstraint) + { + this.cA = ASN1Boolean.getInstance(true); + this.pathLenConstraint = new ASN1Integer(pathLenConstraint); + } + + public boolean isCA() + { + return (cA != null) && cA.isTrue(); + } + + public BigInteger getPathLenConstraint() + { + if (pathLenConstraint != null) + { + return pathLenConstraint.getValue(); + } + + return null; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + *
+ * BasicConstraints := SEQUENCE { + * cA BOOLEAN DEFAULT FALSE, + * pathLenConstraint INTEGER (0..MAX) OPTIONAL + * } + *+ */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + if (cA != null) + { + v.add(cA); + } + + if (pathLenConstraint != null) // yes some people actually do this when cA is false... + { + v.add(pathLenConstraint); + } + + return new DERSequence(v); + } + + public String toString() + { + if (pathLenConstraint == null) + { + if (cA == null) + { + return "BasicConstraints: isCa(false)"; + } + return "BasicConstraints: isCa(" + this.isCA() + ")"; + } + return "BasicConstraints: isCa(" + this.isCA() + "), pathLenConstraint = " + pathLenConstraint.getValue(); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/CRLDistPoint.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/CRLDistPoint.java new file mode 100644 index 0000000..9aa4cff --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/CRLDistPoint.java @@ -0,0 +1,100 @@ +package org.bc.asn1.x509; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERSequence; + +public class CRLDistPoint + extends ASN1Object +{ + ASN1Sequence seq = null; + + public static CRLDistPoint getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static CRLDistPoint getInstance( + Object obj) + { + if (obj instanceof CRLDistPoint) + { + return (CRLDistPoint)obj; + } + else if (obj != null) + { + return new CRLDistPoint(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + private CRLDistPoint( + ASN1Sequence seq) + { + this.seq = seq; + } + + public CRLDistPoint( + DistributionPoint[] points) + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + for (int i = 0; i != points.length; i++) + { + v.add(points[i]); + } + + seq = new DERSequence(v); + } + + /** + * Return the distribution points making up the sequence. + * + * @return DistributionPoint[] + */ + public DistributionPoint[] getDistributionPoints() + { + DistributionPoint[] dp = new DistributionPoint[seq.size()]; + + for (int i = 0; i != seq.size(); i++) + { + dp[i] = DistributionPoint.getInstance(seq.getObjectAt(i)); + } + + return dp; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + *
+ * CRLDistPoint ::= SEQUENCE SIZE {1..MAX} OF DistributionPoint + *+ */ + public ASN1Primitive toASN1Primitive() + { + return seq; + } + + public String toString() + { + StringBuffer buf = new StringBuffer(); + String sep = System.getProperty("line.separator"); + + buf.append("CRLDistPoint:"); + buf.append(sep); + DistributionPoint dp[] = getDistributionPoints(); + for (int i = 0; i != dp.length; i++) + { + buf.append(" "); + buf.append(dp[i]); + buf.append(sep); + } + return buf.toString(); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/CRLNumber.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/CRLNumber.java new file mode 100644 index 0000000..b1e7b06 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/CRLNumber.java @@ -0,0 +1,54 @@ +package org.bc.asn1.x509; + +import java.math.BigInteger; + +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; + +/** + * The CRLNumber object. + *
+ * CRLNumber::= INTEGER(0..MAX) + *+ */ +public class CRLNumber + extends ASN1Object +{ + private BigInteger number; + + public CRLNumber( + BigInteger number) + { + this.number = number; + } + + public BigInteger getCRLNumber() + { + return number; + } + + public String toString() + { + return "CRLNumber: " + getCRLNumber(); + } + + public ASN1Primitive toASN1Primitive() + { + return new ASN1Integer(number); + } + + public static CRLNumber getInstance(Object o) + { + if (o instanceof CRLNumber) + { + return (CRLNumber)o; + } + else if (o != null) + { + return new CRLNumber(ASN1Integer.getInstance(o).getValue()); + } + + return null; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/CRLReason.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/CRLReason.java new file mode 100644 index 0000000..6e2e8e1 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/CRLReason.java @@ -0,0 +1,151 @@ +package org.bc.asn1.x509; + +import java.math.BigInteger; +import java.util.Hashtable; + +import org.bc.asn1.ASN1Enumerated; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.util.Integers; + +/** + * The CRLReason enumeration. + *
+ * CRLReason ::= ENUMERATED { + * unspecified (0), + * keyCompromise (1), + * cACompromise (2), + * affiliationChanged (3), + * superseded (4), + * cessationOfOperation (5), + * certificateHold (6), + * removeFromCRL (8), + * privilegeWithdrawn (9), + * aACompromise (10) + * } + *+ */ +public class CRLReason + extends ASN1Object +{ + /** + * @deprecated use lower case version + */ + public static final int UNSPECIFIED = 0; + /** + * @deprecated use lower case version + */ + public static final int KEY_COMPROMISE = 1; + /** + * @deprecated use lower case version + */ + public static final int CA_COMPROMISE = 2; + /** + * @deprecated use lower case version + */ + public static final int AFFILIATION_CHANGED = 3; + /** + * @deprecated use lower case version + */ + public static final int SUPERSEDED = 4; + /** + * @deprecated use lower case version + */ + public static final int CESSATION_OF_OPERATION = 5; + /** + * @deprecated use lower case version + */ + public static final int CERTIFICATE_HOLD = 6; + /** + * @deprecated use lower case version + */ + public static final int REMOVE_FROM_CRL = 8; + /** + * @deprecated use lower case version + */ + public static final int PRIVILEGE_WITHDRAWN = 9; + /** + * @deprecated use lower case version + */ + public static final int AA_COMPROMISE = 10; + + public static final int unspecified = 0; + public static final int keyCompromise = 1; + public static final int cACompromise = 2; + public static final int affiliationChanged = 3; + public static final int superseded = 4; + public static final int cessationOfOperation = 5; + public static final int certificateHold = 6; + // 7 -> unknown + public static final int removeFromCRL = 8; + public static final int privilegeWithdrawn = 9; + public static final int aACompromise = 10; + + private static final String[] reasonString = + { + "unspecified", "keyCompromise", "cACompromise", "affiliationChanged", + "superseded", "cessationOfOperation", "certificateHold", "unknown", + "removeFromCRL", "privilegeWithdrawn", "aACompromise" + }; + + private static final Hashtable table = new Hashtable(); + + private ASN1Enumerated value; + + public static CRLReason getInstance(Object o) + { + if (o instanceof CRLReason) + { + return (CRLReason)o; + } + else if (o != null) + { + return lookup(ASN1Enumerated.getInstance(o).getValue().intValue()); + } + + return null; + } + + private CRLReason( + int reason) + { + value = new ASN1Enumerated(reason); + } + + public String toString() + { + String str; + int reason = getValue().intValue(); + if (reason < 0 || reason > 10) + { + str = "invalid"; + } + else + { + str = reasonString[reason]; + } + return "CRLReason: " + str; + } + + public BigInteger getValue() + { + return value.getValue(); + } + + public ASN1Primitive toASN1Primitive() + { + return value; + } + + public static CRLReason lookup(int value) + { + Integer idx = Integers.valueOf(value); + + if (!table.containsKey(idx)) + { + table.put(idx, new CRLReason(value)); + } + + return (CRLReason)table.get(idx); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/CertPolicyId.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/CertPolicyId.java new file mode 100644 index 0000000..aba2ee0 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/CertPolicyId.java @@ -0,0 +1,57 @@ +package org.bc.asn1.x509; + +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1ObjectIdentifier; +import org.bc.asn1.ASN1Primitive; + + +/** + * CertPolicyId, used in the CertificatePolicies and PolicyMappings + * X509V3 Extensions. + * + *
+ * CertPolicyId ::= OBJECT IDENTIFIER + *+ */ +/** + * CertPolicyId, used in the CertificatePolicies and PolicyMappings + * X509V3 Extensions. + * + *
+ * CertPolicyId ::= OBJECT IDENTIFIER + *+ */ +public class CertPolicyId + extends ASN1Object +{ + private ASN1ObjectIdentifier id; + + private CertPolicyId(ASN1ObjectIdentifier id) + { + this.id = id; + } + + public static CertPolicyId getInstance(Object o) + { + if (o instanceof CertPolicyId) + { + return (CertPolicyId)o; + } + else if (o != null) + { + return new CertPolicyId(ASN1ObjectIdentifier.getInstance(o)); + } + + return null; + } + + public String getId() + { + return id.getId(); + } + + public ASN1Primitive toASN1Primitive() + { + return id; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/Certificate.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/Certificate.java new file mode 100644 index 0000000..f065e36 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/Certificate.java @@ -0,0 +1,131 @@ +package org.bc.asn1.x509; + +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERBitString; +import org.bc.asn1.x500.X500Name; + +/** + * an X509Certificate structure. + *
+ * Certificate ::= SEQUENCE { + * tbsCertificate TBSCertificate, + * signatureAlgorithm AlgorithmIdentifier, + * signature BIT STRING + * } + *+ */ +public class Certificate + extends ASN1Object +{ + ASN1Sequence seq; + TBSCertificate tbsCert; + AlgorithmIdentifier sigAlgId; + DERBitString sig; + + public static Certificate getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static Certificate getInstance( + Object obj) + { + if (obj instanceof Certificate) + { + return (Certificate)obj; + } + else if (obj != null) + { + return new Certificate(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + private Certificate( + ASN1Sequence seq) + { + this.seq = seq; + + // + // correct x509 certficate + // + if (seq.size() == 3) + { + tbsCert = TBSCertificate.getInstance(seq.getObjectAt(0)); + sigAlgId = AlgorithmIdentifier.getInstance(seq.getObjectAt(1)); + + sig = DERBitString.getInstance(seq.getObjectAt(2)); + } + else + { + throw new IllegalArgumentException("sequence wrong size for a certificate"); + } + } + + public TBSCertificate getTBSCertificate() + { + return tbsCert; + } + + public ASN1Integer getVersion() + { + return tbsCert.getVersion(); + } + + public int getVersionNumber() + { + return tbsCert.getVersionNumber(); + } + + public ASN1Integer getSerialNumber() + { + return tbsCert.getSerialNumber(); + } + + public X500Name getIssuer() + { + return tbsCert.getIssuer(); + } + + public Time getStartDate() + { + return tbsCert.getStartDate(); + } + + public Time getEndDate() + { + return tbsCert.getEndDate(); + } + + public X500Name getSubject() + { + return tbsCert.getSubject(); + } + + public SubjectPublicKeyInfo getSubjectPublicKeyInfo() + { + return tbsCert.getSubjectPublicKeyInfo(); + } + + public AlgorithmIdentifier getSignatureAlgorithm() + { + return sigAlgId; + } + + public DERBitString getSignature() + { + return sig; + } + + public ASN1Primitive toASN1Primitive() + { + return seq; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/CertificateList.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/CertificateList.java new file mode 100644 index 0000000..a78d72f --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/CertificateList.java @@ -0,0 +1,127 @@ + +package org.bc.asn1.x509; + +import java.util.Enumeration; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERBitString; +import org.bc.asn1.DERSequence; +import org.bc.asn1.x500.X500Name; + +/** + * PKIX RFC-2459 + * + * The X.509 v2 CRL syntax is as follows. For signature calculation, + * the data that is to be signed is ASN.1 DER encoded. + * + *
+ * CertificateList ::= SEQUENCE { + * tbsCertList TBSCertList, + * signatureAlgorithm AlgorithmIdentifier, + * signatureValue BIT STRING } + *+ */ +public class CertificateList + extends ASN1Object +{ + TBSCertList tbsCertList; + AlgorithmIdentifier sigAlgId; + DERBitString sig; + + public static CertificateList getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static CertificateList getInstance( + Object obj) + { + if (obj instanceof CertificateList) + { + return (CertificateList)obj; + } + else if (obj != null) + { + return new CertificateList(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public CertificateList( + ASN1Sequence seq) + { + if (seq.size() == 3) + { + tbsCertList = TBSCertList.getInstance(seq.getObjectAt(0)); + sigAlgId = AlgorithmIdentifier.getInstance(seq.getObjectAt(1)); + sig = DERBitString.getInstance(seq.getObjectAt(2)); + } + else + { + throw new IllegalArgumentException("sequence wrong size for CertificateList"); + } + } + + public TBSCertList getTBSCertList() + { + return tbsCertList; + } + + public TBSCertList.CRLEntry[] getRevokedCertificates() + { + return tbsCertList.getRevokedCertificates(); + } + + public Enumeration getRevokedCertificateEnumeration() + { + return tbsCertList.getRevokedCertificateEnumeration(); + } + + public AlgorithmIdentifier getSignatureAlgorithm() + { + return sigAlgId; + } + + public DERBitString getSignature() + { + return sig; + } + + public int getVersionNumber() + { + return tbsCertList.getVersionNumber(); + } + + public X500Name getIssuer() + { + return tbsCertList.getIssuer(); + } + + public Time getThisUpdate() + { + return tbsCertList.getThisUpdate(); + } + + public Time getNextUpdate() + { + return tbsCertList.getNextUpdate(); + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(tbsCertList); + v.add(sigAlgId); + v.add(sig); + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/CertificatePair.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/CertificatePair.java new file mode 100644 index 0000000..df7d3b5 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/CertificatePair.java @@ -0,0 +1,169 @@ +package org.bc.asn1.x509; + +import java.util.Enumeration; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERSequence; +import org.bc.asn1.DERTaggedObject; + +/** + * This class helps to support crossCerfificatePairs in a LDAP directory + * according RFC 2587 + * + *
+ * crossCertificatePairATTRIBUTE::={ + * WITH SYNTAX CertificatePair + * EQUALITY MATCHING RULE certificatePairExactMatch + * ID joint-iso-ccitt(2) ds(5) attributeType(4) crossCertificatePair(40)} + *+ * + *
The forward elements of the crossCertificatePair attribute of a + * CA's directory entry shall be used to store all, except self-issued + * certificates issued to this CA. Optionally, the reverse elements of the + * crossCertificatePair attribute, of a CA's directory entry may contain a + * subset of certificates issued by this CA to other CAs. When both the forward + * and the reverse elements are present in a single attribute value, issuer name + * in one certificate shall match the subject name in the other and vice versa, + * and the subject public key in one certificate shall be capable of verifying + * the digital signature on the other certificate and vice versa. + * + * When a reverse element is present, the forward element value and the reverse + * element value need not be stored in the same attribute value; in other words, + * they can be stored in either a single attribute value or two attribute + * values.+ * + *
+ * CertificatePair ::= SEQUENCE { + * forward [0] Certificate OPTIONAL, + * reverse [1] Certificate OPTIONAL, + * -- at least one of the pair shall be present -- } + *+ */ +public class CertificatePair + extends ASN1Object +{ + private Certificate forward; + + private Certificate reverse; + + public static CertificatePair getInstance(Object obj) + { + if (obj == null || obj instanceof CertificatePair) + { + return (CertificatePair)obj; + } + + if (obj instanceof ASN1Sequence) + { + return new CertificatePair((ASN1Sequence)obj); + } + + throw new IllegalArgumentException("illegal object in getInstance: " + + obj.getClass().getName()); + } + + /** + * Constructor from ASN1Sequence. + * + * The sequence is of type CertificatePair: + * + *
+ * CertificatePair ::= SEQUENCE { + * forward [0] Certificate OPTIONAL, + * reverse [1] Certificate OPTIONAL, + * -- at least one of the pair shall be present -- } + *+ * + * @param seq The ASN.1 sequence. + */ + private CertificatePair(ASN1Sequence seq) + { + if (seq.size() != 1 && seq.size() != 2) + { + throw new IllegalArgumentException("Bad sequence size: " + + seq.size()); + } + + Enumeration e = seq.getObjects(); + + while (e.hasMoreElements()) + { + ASN1TaggedObject o = ASN1TaggedObject.getInstance(e.nextElement()); + if (o.getTagNo() == 0) + { + forward = Certificate.getInstance(o, true); + } + else if (o.getTagNo() == 1) + { + reverse = Certificate.getInstance(o, true); + } + else + { + throw new IllegalArgumentException("Bad tag number: " + + o.getTagNo()); + } + } + } + + /** + * Constructor from a given details. + * + * @param forward Certificates issued to this CA. + * @param reverse Certificates issued by this CA to other CAs. + */ + public CertificatePair(Certificate forward, Certificate reverse) + { + this.forward = forward; + this.reverse = reverse; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * + * Returns: + * + *
+ * CertificatePair ::= SEQUENCE { + * forward [0] Certificate OPTIONAL, + * reverse [1] Certificate OPTIONAL, + * -- at least one of the pair shall be present -- } + *+ * + * @return a ASN1Primitive + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector vec = new ASN1EncodableVector(); + + if (forward != null) + { + vec.add(new DERTaggedObject(0, forward)); + } + if (reverse != null) + { + vec.add(new DERTaggedObject(1, reverse)); + } + + return new DERSequence(vec); + } + + /** + * @return Returns the forward. + */ + public Certificate getForward() + { + return forward; + } + + /** + * @return Returns the reverse. + */ + public Certificate getReverse() + { + return reverse; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/CertificatePolicies.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/CertificatePolicies.java new file mode 100644 index 0000000..5d22cf8 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/CertificatePolicies.java @@ -0,0 +1,99 @@ +package org.bc.asn1.x509; + +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERSequence; + +public class CertificatePolicies + extends ASN1Object +{ + private final PolicyInformation[] policyInformation; + + public static CertificatePolicies getInstance( + Object obj) + { + if (obj instanceof CertificatePolicies) + { + return (CertificatePolicies)obj; + } + + if (obj != null) + { + return new CertificatePolicies(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public static CertificatePolicies getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + /** + * Construct a CertificatePolicies object containing one PolicyInformation. + * + * @param name the name to be contained. + */ + public CertificatePolicies( + PolicyInformation name) + { + this.policyInformation = new PolicyInformation[] { name }; + } + + public CertificatePolicies( + PolicyInformation[] policyInformation) + { + this.policyInformation = policyInformation; + } + + private CertificatePolicies( + ASN1Sequence seq) + { + this.policyInformation = new PolicyInformation[seq.size()]; + + for (int i = 0; i != seq.size(); i++) + { + policyInformation[i] = PolicyInformation.getInstance(seq.getObjectAt(i)); + } + } + + public PolicyInformation[] getPolicyInformation() + { + PolicyInformation[] tmp = new PolicyInformation[policyInformation.length]; + + System.arraycopy(policyInformation, 0, tmp, 0, policyInformation.length); + + return tmp; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + *
+ * CertificatePolicies ::= SEQUENCE SIZE {1..MAX} OF PolicyInformation + *+ */ + public ASN1Primitive toASN1Primitive() + { + return new DERSequence(policyInformation); + } + + public String toString() + { + String p = null; + for (int i = 0; i < policyInformation.length; i++) + { + if (p != null) + { + p += ", "; + } + p += policyInformation[i]; + } + + return "CertificatePolicies: " + p; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/DSAParameter.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/DSAParameter.java new file mode 100644 index 0000000..0b04edd --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/DSAParameter.java @@ -0,0 +1,92 @@ +package org.bc.asn1.x509; + +import java.math.BigInteger; +import java.util.Enumeration; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERSequence; + +public class DSAParameter + extends ASN1Object +{ + ASN1Integer p, q, g; + + public static DSAParameter getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static DSAParameter getInstance( + Object obj) + { + if (obj instanceof DSAParameter) + { + return (DSAParameter)obj; + } + + if(obj != null) + { + return new DSAParameter(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public DSAParameter( + BigInteger p, + BigInteger q, + BigInteger g) + { + this.p = new ASN1Integer(p); + this.q = new ASN1Integer(q); + this.g = new ASN1Integer(g); + } + + private DSAParameter( + ASN1Sequence seq) + { + if (seq.size() != 3) + { + throw new IllegalArgumentException("Bad sequence size: " + seq.size()); + } + + Enumeration e = seq.getObjects(); + + p = ASN1Integer.getInstance(e.nextElement()); + q = ASN1Integer.getInstance(e.nextElement()); + g = ASN1Integer.getInstance(e.nextElement()); + } + + public BigInteger getP() + { + return p.getPositiveValue(); + } + + public BigInteger getQ() + { + return q.getPositiveValue(); + } + + public BigInteger getG() + { + return g.getPositiveValue(); + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(p); + v.add(q); + v.add(g); + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/DigestInfo.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/DigestInfo.java new file mode 100644 index 0000000..13bb5f5 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/DigestInfo.java @@ -0,0 +1,86 @@ +package org.bc.asn1.x509; + +import java.util.Enumeration; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1OctetString; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DEROctetString; +import org.bc.asn1.DERSequence; + +/** + * The DigestInfo object. + *
+ * DigestInfo::=SEQUENCE{ + * digestAlgorithm AlgorithmIdentifier, + * digest OCTET STRING } + *+ */ +public class DigestInfo + extends ASN1Object +{ + private byte[] digest; + private AlgorithmIdentifier algId; + + public static DigestInfo getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static DigestInfo getInstance( + Object obj) + { + if (obj instanceof DigestInfo) + { + return (DigestInfo)obj; + } + else if (obj != null) + { + return new DigestInfo(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public DigestInfo( + AlgorithmIdentifier algId, + byte[] digest) + { + this.digest = digest; + this.algId = algId; + } + + public DigestInfo( + ASN1Sequence obj) + { + Enumeration e = obj.getObjects(); + + algId = AlgorithmIdentifier.getInstance(e.nextElement()); + digest = ASN1OctetString.getInstance(e.nextElement()).getOctets(); + } + + public AlgorithmIdentifier getAlgorithmId() + { + return algId; + } + + public byte[] getDigest() + { + return digest; + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(algId); + v.add(new DEROctetString(digest)); + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/DisplayText.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/DisplayText.java new file mode 100644 index 0000000..1f6dda0 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/DisplayText.java @@ -0,0 +1,165 @@ + +package org.bc.asn1.x509; + +import org.bc.asn1.ASN1Choice; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1String; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERBMPString; +import org.bc.asn1.DERIA5String; +import org.bc.asn1.DERUTF8String; +import org.bc.asn1.DERVisibleString; + +/** + *
DisplayText
class, used in
+ * CertificatePolicies
X509 V3 extensions (in policy qualifiers).
+ *
+ * It stores a string in a chosen encoding. + *
+ * DisplayText ::= CHOICE { + * ia5String IA5String (SIZE (1..200)), + * visibleString VisibleString (SIZE (1..200)), + * bmpString BMPString (SIZE (1..200)), + * utf8String UTF8String (SIZE (1..200)) } + *+ * @see PolicyQualifierInfo + * @see PolicyInformation + */ +public class DisplayText + extends ASN1Object + implements ASN1Choice +{ + /** + * Constant corresponding to ia5String encoding. + * + */ + public static final int CONTENT_TYPE_IA5STRING = 0; + /** + * Constant corresponding to bmpString encoding. + * + */ + public static final int CONTENT_TYPE_BMPSTRING = 1; + /** + * Constant corresponding to utf8String encoding. + * + */ + public static final int CONTENT_TYPE_UTF8STRING = 2; + /** + * Constant corresponding to visibleString encoding. + * + */ + public static final int CONTENT_TYPE_VISIBLESTRING = 3; + + /** + * Describe constant
DISPLAY_TEXT_MAXIMUM_SIZE
here.
+ *
+ */
+ public static final int DISPLAY_TEXT_MAXIMUM_SIZE = 200;
+
+ int contentType;
+ ASN1String contents;
+
+ /**
+ * Creates a new DisplayText
instance.
+ *
+ * @param type the desired encoding type for the text.
+ * @param text the text to store. Strings longer than 200
+ * characters are truncated.
+ */
+ public DisplayText(int type, String text)
+ {
+ if (text.length() > DISPLAY_TEXT_MAXIMUM_SIZE)
+ {
+ // RFC3280 limits these strings to 200 chars
+ // truncate the string
+ text = text.substring (0, DISPLAY_TEXT_MAXIMUM_SIZE);
+ }
+
+ contentType = type;
+ switch (type)
+ {
+ case CONTENT_TYPE_IA5STRING:
+ contents = new DERIA5String(text);
+ break;
+ case CONTENT_TYPE_UTF8STRING:
+ contents = new DERUTF8String(text);
+ break;
+ case CONTENT_TYPE_VISIBLESTRING:
+ contents = new DERVisibleString(text);
+ break;
+ case CONTENT_TYPE_BMPSTRING:
+ contents = new DERBMPString(text);
+ break;
+ default:
+ contents = new DERUTF8String(text);
+ break;
+ }
+ }
+
+ /**
+ * Creates a new DisplayText
instance.
+ *
+ * @param text the text to encapsulate. Strings longer than 200
+ * characters are truncated.
+ */
+ public DisplayText(String text)
+ {
+ // by default use UTF8String
+ if (text.length() > DISPLAY_TEXT_MAXIMUM_SIZE)
+ {
+ text = text.substring(0, DISPLAY_TEXT_MAXIMUM_SIZE);
+ }
+
+ contentType = CONTENT_TYPE_UTF8STRING;
+ contents = new DERUTF8String(text);
+ }
+
+ /**
+ * Creates a new DisplayText
instance.
+ * Useful when reading back a DisplayText
class
+ * from it's ASN1Encodable/DEREncodable form.
+ *
+ * @param de a DEREncodable
instance.
+ */
+ private DisplayText(ASN1String de)
+ {
+ contents = de;
+ }
+
+ public static DisplayText getInstance(Object obj)
+ {
+ if (obj instanceof ASN1String)
+ {
+ return new DisplayText((ASN1String)obj);
+ }
+ else if (obj == null || obj instanceof DisplayText)
+ {
+ return (DisplayText)obj;
+ }
+
+ throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
+ }
+
+ public static DisplayText getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit)
+ {
+ return getInstance(obj.getObject()); // must be explicitly tagged
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+ return (ASN1Primitive)contents;
+ }
+
+ /**
+ * Returns the stored String
object.
+ *
+ * @return the stored text as a String
.
+ */
+ public String getString()
+ {
+ return contents.getString();
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/DistributionPoint.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/DistributionPoint.java
new file mode 100644
index 0000000..4baf52d
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/DistributionPoint.java
@@ -0,0 +1,158 @@
+package org.bc.asn1.x509;
+
+import org.bc.asn1.ASN1EncodableVector;
+import org.bc.asn1.ASN1Object;
+import org.bc.asn1.ASN1Primitive;
+import org.bc.asn1.ASN1Sequence;
+import org.bc.asn1.ASN1TaggedObject;
+import org.bc.asn1.DERBitString;
+import org.bc.asn1.DERSequence;
+import org.bc.asn1.DERTaggedObject;
+
+/**
+ * The DistributionPoint object.
+ *
+ * DistributionPoint ::= SEQUENCE { + * distributionPoint [0] DistributionPointName OPTIONAL, + * reasons [1] ReasonFlags OPTIONAL, + * cRLIssuer [2] GeneralNames OPTIONAL + * } + *+ */ +public class DistributionPoint + extends ASN1Object +{ + DistributionPointName distributionPoint; + ReasonFlags reasons; + GeneralNames cRLIssuer; + + public static DistributionPoint getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static DistributionPoint getInstance( + Object obj) + { + if(obj == null || obj instanceof DistributionPoint) + { + return (DistributionPoint)obj; + } + + if(obj instanceof ASN1Sequence) + { + return new DistributionPoint((ASN1Sequence)obj); + } + + throw new IllegalArgumentException("Invalid DistributionPoint: " + obj.getClass().getName()); + } + + public DistributionPoint( + ASN1Sequence seq) + { + for (int i = 0; i != seq.size(); i++) + { + ASN1TaggedObject t = ASN1TaggedObject.getInstance(seq.getObjectAt(i)); + switch (t.getTagNo()) + { + case 0: + distributionPoint = DistributionPointName.getInstance(t, true); + break; + case 1: + reasons = new ReasonFlags(DERBitString.getInstance(t, false)); + break; + case 2: + cRLIssuer = GeneralNames.getInstance(t, false); + } + } + } + + public DistributionPoint( + DistributionPointName distributionPoint, + ReasonFlags reasons, + GeneralNames cRLIssuer) + { + this.distributionPoint = distributionPoint; + this.reasons = reasons; + this.cRLIssuer = cRLIssuer; + } + + public DistributionPointName getDistributionPoint() + { + return distributionPoint; + } + + public ReasonFlags getReasons() + { + return reasons; + } + + public GeneralNames getCRLIssuer() + { + return cRLIssuer; + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + if (distributionPoint != null) + { + // + // as this is a CHOICE it must be explicitly tagged + // + v.add(new DERTaggedObject(0, distributionPoint)); + } + + if (reasons != null) + { + v.add(new DERTaggedObject(false, 1, reasons)); + } + + if (cRLIssuer != null) + { + v.add(new DERTaggedObject(false, 2, cRLIssuer)); + } + + return new DERSequence(v); + } + + public String toString() + { + String sep = System.getProperty("line.separator"); + StringBuffer buf = new StringBuffer(); + buf.append("DistributionPoint: ["); + buf.append(sep); + if (distributionPoint != null) + { + appendObject(buf, sep, "distributionPoint", distributionPoint.toString()); + } + if (reasons != null) + { + appendObject(buf, sep, "reasons", reasons.toString()); + } + if (cRLIssuer != null) + { + appendObject(buf, sep, "cRLIssuer", cRLIssuer.toString()); + } + buf.append("]"); + buf.append(sep); + return buf.toString(); + } + + private void appendObject(StringBuffer buf, String sep, String name, String value) + { + String indent = " "; + + buf.append(indent); + buf.append(name); + buf.append(":"); + buf.append(sep); + buf.append(indent); + buf.append(indent); + buf.append(value); + buf.append(sep); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/DistributionPointName.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/DistributionPointName.java new file mode 100644 index 0000000..be852cd --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/DistributionPointName.java @@ -0,0 +1,138 @@ +package org.bc.asn1.x509; + +import org.bc.asn1.ASN1Choice; +import org.bc.asn1.ASN1Encodable; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Set; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERTaggedObject; + +/** + * The DistributionPointName object. + *
+ * DistributionPointName ::= CHOICE { + * fullName [0] GeneralNames, + * nameRelativeToCRLIssuer [1] RDN + * } + *+ */ +public class DistributionPointName + extends ASN1Object + implements ASN1Choice +{ + ASN1Encodable name; + int type; + + public static final int FULL_NAME = 0; + public static final int NAME_RELATIVE_TO_CRL_ISSUER = 1; + + public static DistributionPointName getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1TaggedObject.getInstance(obj, true)); + } + + public static DistributionPointName getInstance( + Object obj) + { + if (obj == null || obj instanceof DistributionPointName) + { + return (DistributionPointName)obj; + } + else if (obj instanceof ASN1TaggedObject) + { + return new DistributionPointName((ASN1TaggedObject)obj); + } + + throw new IllegalArgumentException("unknown object in factory: " + obj.getClass().getName()); + } + + public DistributionPointName( + int type, + ASN1Encodable name) + { + this.type = type; + this.name = name; + } + + public DistributionPointName( + GeneralNames name) + { + this(FULL_NAME, name); + } + + /** + * Return the tag number applying to the underlying choice. + * + * @return the tag number for this point name. + */ + public int getType() + { + return this.type; + } + + /** + * Return the tagged object inside the distribution point name. + * + * @return the underlying choice item. + */ + public ASN1Encodable getName() + { + return (ASN1Encodable)name; + } + + public DistributionPointName( + ASN1TaggedObject obj) + { + this.type = obj.getTagNo(); + + if (type == 0) + { + this.name = GeneralNames.getInstance(obj, false); + } + else + { + this.name = ASN1Set.getInstance(obj, false); + } + } + + public ASN1Primitive toASN1Primitive() + { + return new DERTaggedObject(false, type, name); + } + + public String toString() + { + String sep = System.getProperty("line.separator"); + StringBuffer buf = new StringBuffer(); + buf.append("DistributionPointName: ["); + buf.append(sep); + if (type == FULL_NAME) + { + appendObject(buf, sep, "fullName", name.toString()); + } + else + { + appendObject(buf, sep, "nameRelativeToCRLIssuer", name.toString()); + } + buf.append("]"); + buf.append(sep); + return buf.toString(); + } + + private void appendObject(StringBuffer buf, String sep, String name, String value) + { + String indent = " "; + + buf.append(indent); + buf.append(name); + buf.append(":"); + buf.append(sep); + buf.append(indent); + buf.append(indent); + buf.append(value); + buf.append(sep); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/ExtendedKeyUsage.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/ExtendedKeyUsage.java new file mode 100644 index 0000000..a9f9d08 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/ExtendedKeyUsage.java @@ -0,0 +1,147 @@ +package org.bc.asn1.x509; + +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Vector; + +import org.bc.asn1.ASN1Encodable; +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1ObjectIdentifier; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERSequence; + +/** + * The extendedKeyUsage object. + *
+ * extendedKeyUsage ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId + *+ */ +public class ExtendedKeyUsage + extends ASN1Object +{ + Hashtable usageTable = new Hashtable(); + ASN1Sequence seq; + + public static ExtendedKeyUsage getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static ExtendedKeyUsage getInstance( + Object obj) + { + if (obj instanceof ExtendedKeyUsage) + { + return (ExtendedKeyUsage)obj; + } + else if (obj != null) + { + return new ExtendedKeyUsage(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public static ExtendedKeyUsage fromExtensions(Extensions extensions) + { + return ExtendedKeyUsage.getInstance(extensions.getExtensionParsedValue(Extension.extendedKeyUsage)); + } + + public ExtendedKeyUsage( + KeyPurposeId usage) + { + this.seq = new DERSequence(usage); + + this.usageTable.put(usage, usage); + } + + private ExtendedKeyUsage( + ASN1Sequence seq) + { + this.seq = seq; + + Enumeration e = seq.getObjects(); + + while (e.hasMoreElements()) + { + ASN1Encodable o = (ASN1Encodable)e.nextElement(); + if (!(o.toASN1Primitive() instanceof ASN1ObjectIdentifier)) + { + throw new IllegalArgumentException("Only ASN1ObjectIdentifiers allowed in ExtendedKeyUsage."); + } + this.usageTable.put(o, o); + } + } + + public ExtendedKeyUsage( + KeyPurposeId[] usages) + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + for (int i = 0; i != usages.length; i++) + { + v.add(usages[i]); + this.usageTable.put(usages[i], usages[i]); + } + + this.seq = new DERSequence(v); + } + + /** + * @deprecated use KeyPurposeId[] constructor. + */ + public ExtendedKeyUsage( + Vector usages) + { + ASN1EncodableVector v = new ASN1EncodableVector(); + Enumeration e = usages.elements(); + + while (e.hasMoreElements()) + { + ASN1Primitive o = (ASN1Primitive)e.nextElement(); + + v.add(o); + this.usageTable.put(o, o); + } + + this.seq = new DERSequence(v); + } + + public boolean hasKeyPurposeId( + KeyPurposeId keyPurposeId) + { + return (usageTable.get(keyPurposeId) != null); + } + + /** + * Returns all extended key usages. + * The returned vector contains DERObjectIdentifiers. + * @return An array with all key purposes. + */ + public KeyPurposeId[] getUsages() + { + KeyPurposeId[] temp = new KeyPurposeId[seq.size()]; + + int i = 0; + for (Enumeration it = seq.getObjects(); it.hasMoreElements();) + { + temp[i++] = KeyPurposeId.getInstance(it.nextElement()); + } + return temp; + } + + public int size() + { + return usageTable.size(); + } + + public ASN1Primitive toASN1Primitive() + { + return seq; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/Extension.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/Extension.java new file mode 100644 index 0000000..9ceebac --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/Extension.java @@ -0,0 +1,266 @@ +package org.bc.asn1.x509; + +import java.io.IOException; + +import org.bc.asn1.ASN1Boolean; +import org.bc.asn1.ASN1Encodable; +import org.bc.asn1.ASN1ObjectIdentifier; +import org.bc.asn1.ASN1OctetString; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.DEROctetString; + +/** + * an object for the elements in the X.509 V3 extension block. + */ +public class Extension +{ + /** + * Subject Directory Attributes + */ + public static final ASN1ObjectIdentifier subjectDirectoryAttributes = new ASN1ObjectIdentifier("2.5.29.9"); + + /** + * Subject Key Identifier + */ + public static final ASN1ObjectIdentifier subjectKeyIdentifier = new ASN1ObjectIdentifier("2.5.29.14"); + + /** + * Key Usage + */ + public static final ASN1ObjectIdentifier keyUsage = new ASN1ObjectIdentifier("2.5.29.15"); + + /** + * Private Key Usage Period + */ + public static final ASN1ObjectIdentifier privateKeyUsagePeriod = new ASN1ObjectIdentifier("2.5.29.16"); + + /** + * Subject Alternative Name + */ + public static final ASN1ObjectIdentifier subjectAlternativeName = new ASN1ObjectIdentifier("2.5.29.17"); + + /** + * Issuer Alternative Name + */ + public static final ASN1ObjectIdentifier issuerAlternativeName = new ASN1ObjectIdentifier("2.5.29.18"); + + /** + * Basic Constraints + */ + public static final ASN1ObjectIdentifier basicConstraints = new ASN1ObjectIdentifier("2.5.29.19"); + + /** + * CRL Number + */ + public static final ASN1ObjectIdentifier cRLNumber = new ASN1ObjectIdentifier("2.5.29.20"); + + /** + * Reason code + */ + public static final ASN1ObjectIdentifier reasonCode = new ASN1ObjectIdentifier("2.5.29.21"); + + /** + * Hold Instruction Code + */ + public static final ASN1ObjectIdentifier instructionCode = new ASN1ObjectIdentifier("2.5.29.23"); + + /** + * Invalidity Date + */ + public static final ASN1ObjectIdentifier invalidityDate = new ASN1ObjectIdentifier("2.5.29.24"); + + /** + * Delta CRL indicator + */ + public static final ASN1ObjectIdentifier deltaCRLIndicator = new ASN1ObjectIdentifier("2.5.29.27"); + + /** + * Issuing Distribution Point + */ + public static final ASN1ObjectIdentifier issuingDistributionPoint = new ASN1ObjectIdentifier("2.5.29.28"); + + /** + * Certificate Issuer + */ + public static final ASN1ObjectIdentifier certificateIssuer = new ASN1ObjectIdentifier("2.5.29.29"); + + /** + * Name Constraints + */ + public static final ASN1ObjectIdentifier nameConstraints = new ASN1ObjectIdentifier("2.5.29.30"); + + /** + * CRL Distribution Points + */ + public static final ASN1ObjectIdentifier cRLDistributionPoints = new ASN1ObjectIdentifier("2.5.29.31"); + + /** + * Certificate Policies + */ + public static final ASN1ObjectIdentifier certificatePolicies = new ASN1ObjectIdentifier("2.5.29.32"); + + /** + * Policy Mappings + */ + public static final ASN1ObjectIdentifier policyMappings = new ASN1ObjectIdentifier("2.5.29.33"); + + /** + * Authority Key Identifier + */ + public static final ASN1ObjectIdentifier authorityKeyIdentifier = new ASN1ObjectIdentifier("2.5.29.35"); + + /** + * Policy Constraints + */ + public static final ASN1ObjectIdentifier policyConstraints = new ASN1ObjectIdentifier("2.5.29.36"); + + /** + * Extended Key Usage + */ + public static final ASN1ObjectIdentifier extendedKeyUsage = new ASN1ObjectIdentifier("2.5.29.37"); + + /** + * Freshest CRL + */ + public static final ASN1ObjectIdentifier freshestCRL = new ASN1ObjectIdentifier("2.5.29.46"); + + /** + * Inhibit Any Policy + */ + public static final ASN1ObjectIdentifier inhibitAnyPolicy = new ASN1ObjectIdentifier("2.5.29.54"); + + /** + * Authority Info Access + */ + public static final ASN1ObjectIdentifier authorityInfoAccess = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.1"); + + /** + * Subject Info Access + */ + public static final ASN1ObjectIdentifier subjectInfoAccess = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.11"); + + /** + * Logo Type + */ + public static final ASN1ObjectIdentifier logoType = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.12"); + + /** + * BiometricInfo + */ + public static final ASN1ObjectIdentifier biometricInfo = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.2"); + + /** + * QCStatements + */ + public static final ASN1ObjectIdentifier qCStatements = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.3"); + + /** + * Audit identity extension in attribute certificates. + */ + public static final ASN1ObjectIdentifier auditIdentity = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.4"); + + /** + * NoRevAvail extension in attribute certificates. + */ + public static final ASN1ObjectIdentifier noRevAvail = new ASN1ObjectIdentifier("2.5.29.56"); + + /** + * TargetInformation extension in attribute certificates. + */ + public static final ASN1ObjectIdentifier targetInformation = new ASN1ObjectIdentifier("2.5.29.55"); + + private ASN1ObjectIdentifier extnId; + + boolean critical; + ASN1OctetString value; + + public Extension( + ASN1ObjectIdentifier extnId, + ASN1Boolean critical, + ASN1OctetString value) + { + this(extnId, critical.isTrue(), value); + } + + public Extension( + ASN1ObjectIdentifier extnId, + boolean critical, + byte[] value) + { + this(extnId, critical, new DEROctetString(value)); + } + + public Extension( + ASN1ObjectIdentifier extnId, + boolean critical, + ASN1OctetString value) + { + this.extnId = extnId; + this.critical = critical; + this.value = value; + } + + public ASN1ObjectIdentifier getExtnId() + { + return extnId; + } + + public boolean isCritical() + { + return critical; + } + + public ASN1OctetString getExtnValue() + { + return value; + } + + public ASN1Encodable getParsedValue() + { + return convertValueToObject(this); + } + + public int hashCode() + { + if (this.isCritical()) + { + return this.getExtnValue().hashCode(); + } + + return ~this.getExtnValue().hashCode(); + } + + public boolean equals( + Object o) + { + if (!(o instanceof Extension)) + { + return false; + } + + Extension other = (Extension)o; + + return other.getExtnValue().equals(this.getExtnValue()) + && (other.isCritical() == this.isCritical()); + } + + /** + * Convert the value of the passed in extension to an object + * @param ext the extension to parse + * @return the object the value string contains + * @exception IllegalArgumentException if conversion is not possible + */ + private static ASN1Primitive convertValueToObject( + Extension ext) + throws IllegalArgumentException + { + try + { + return ASN1Primitive.fromByteArray(ext.getExtnValue().getOctets()); + } + catch (IOException e) + { + throw new IllegalArgumentException("can't convert extension: " + e); + } + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/Extensions.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/Extensions.java new file mode 100644 index 0000000..840e9a3 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/Extensions.java @@ -0,0 +1,245 @@ +package org.bc.asn1.x509; + +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Vector; + +import org.bc.asn1.ASN1Boolean; +import org.bc.asn1.ASN1Encodable; +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1ObjectIdentifier; +import org.bc.asn1.ASN1OctetString; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERSequence; + +public class Extensions + extends ASN1Object +{ + private Hashtable extensions = new Hashtable(); + private Vector ordering = new Vector(); + + public static Extensions getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static Extensions getInstance( + Object obj) + { + if (obj instanceof Extensions) + { + return (Extensions)obj; + } + else if (obj != null) + { + return new Extensions(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + /** + * Constructor from ASN1Sequence. + * + * the extensions are a list of constructed sequences, either with (OID, OctetString) or (OID, Boolean, OctetString) + */ + private Extensions( + ASN1Sequence seq) + { + Enumeration e = seq.getObjects(); + + while (e.hasMoreElements()) + { + ASN1Sequence s = ASN1Sequence.getInstance(e.nextElement()); + + if (s.size() == 3) + { + extensions.put(s.getObjectAt(0), new Extension(ASN1ObjectIdentifier.getInstance(s.getObjectAt(0)), ASN1Boolean.getInstance(s.getObjectAt(1)), ASN1OctetString.getInstance(s.getObjectAt(2)))); + } + else if (s.size() == 2) + { + extensions.put(s.getObjectAt(0), new Extension(ASN1ObjectIdentifier.getInstance(s.getObjectAt(0)), false, ASN1OctetString.getInstance(s.getObjectAt(1)))); + } + else + { + throw new IllegalArgumentException("Bad sequence size: " + s.size()); + } + + ordering.addElement(s.getObjectAt(0)); + } + } + + /** + * Base Constructor + * + * @param extension a single extension. + */ + public Extensions( + Extension extension) + { + this.ordering.addElement(extension.getExtnId()); + this.extensions.put(extension.getExtnId(), extension); + } + + /** + * Base Constructor + * + * @param extensions an array of extensions. + */ + public Extensions( + Extension[] extensions) + { + for (int i = 0; i != extensions.length; i++) + { + Extension ext = extensions[i]; + + this.ordering.addElement(ext.getExtnId()); + this.extensions.put(ext.getExtnId(), ext); + } + } + + /** + * return an Enumeration of the extension field's object ids. + */ + public Enumeration oids() + { + return ordering.elements(); + } + + /** + * return the extension represented by the object identifier + * passed in. + * + * @return the extension if it's present, null otherwise. + */ + public Extension getExtension( + ASN1ObjectIdentifier oid) + { + return (Extension)extensions.get(oid); + } + + /** + * return the parsed value of the extension represented by the object identifier + * passed in. + * + * @return the parsed value of the extension if it's present, null otherwise. + */ + public ASN1Encodable getExtensionParsedValue(ASN1ObjectIdentifier oid) + { + Extension ext = this.getExtension(oid); + + if (ext != null) + { + return ext.getParsedValue(); + } + + return null; + } + + /** + *
+ * Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension + * + * Extension ::= SEQUENCE { + * extnId EXTENSION.&id ({ExtensionSet}), + * critical BOOLEAN DEFAULT FALSE, + * extnValue OCTET STRING } + *+ */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector vec = new ASN1EncodableVector(); + Enumeration e = ordering.elements(); + + while (e.hasMoreElements()) + { + ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement(); + Extension ext = (Extension)extensions.get(oid); + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(oid); + + if (ext.isCritical()) + { + v.add(ASN1Boolean.getInstance(true)); + } + + v.add(ext.getExtnValue()); + + vec.add(new DERSequence(v)); + } + + return new DERSequence(vec); + } + + public boolean equivalent( + Extensions other) + { + if (extensions.size() != other.extensions.size()) + { + return false; + } + + Enumeration e1 = extensions.keys(); + + while (e1.hasMoreElements()) + { + Object key = e1.nextElement(); + + if (!extensions.get(key).equals(other.extensions.get(key))) + { + return false; + } + } + + return true; + } + + public ASN1ObjectIdentifier[] getExtensionOIDs() + { + return toOidArray(ordering); + } + + public ASN1ObjectIdentifier[] getNonCriticalExtensionOIDs() + { + return getExtensionOIDs(false); + } + + public ASN1ObjectIdentifier[] getCriticalExtensionOIDs() + { + return getExtensionOIDs(true); + } + + private ASN1ObjectIdentifier[] getExtensionOIDs(boolean isCritical) + { + Vector oidVec = new Vector(); + + for (int i = 0; i != ordering.size(); i++) + { + Object oid = ordering.elementAt(i); + + if (((Extension)extensions.get(oid)).isCritical() == isCritical) + { + oidVec.addElement(oid); + } + } + + return toOidArray(oidVec); + } + + private ASN1ObjectIdentifier[] toOidArray(Vector oidVec) + { + ASN1ObjectIdentifier[] oids = new ASN1ObjectIdentifier[oidVec.size()]; + + for (int i = 0; i != oids.length; i++) + { + oids[i] = (ASN1ObjectIdentifier)oidVec.elementAt(i); + } + return oids; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/ExtensionsGenerator.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/ExtensionsGenerator.java new file mode 100644 index 0000000..0537f66 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/ExtensionsGenerator.java @@ -0,0 +1,94 @@ +package org.bc.asn1.x509; + +import java.io.IOException; +import java.util.Hashtable; +import java.util.Vector; + +import org.bc.asn1.ASN1Encodable; +import org.bc.asn1.ASN1Encoding; +import org.bc.asn1.ASN1ObjectIdentifier; +import org.bc.asn1.DEROctetString; + +/** + * Generator for X.509 extensions + */ +public class ExtensionsGenerator +{ + private Hashtable extensions = new Hashtable(); + private Vector extOrdering = new Vector(); + + /** + * Reset the generator + */ + public void reset() + { + extensions = new Hashtable(); + extOrdering = new Vector(); + } + + /** + * Add an extension with the given oid and the passed in value to be included + * in the OCTET STRING associated with the extension. + * + * @param oid OID for the extension. + * @param critical true if critical, false otherwise. + * @param value the ASN.1 object to be included in the extension. + */ + public void addExtension( + ASN1ObjectIdentifier oid, + boolean critical, + ASN1Encodable value) + throws IOException + { + this.addExtension(oid, critical, value.toASN1Primitive().getEncoded(ASN1Encoding.DER)); + } + + /** + * Add an extension with the given oid and the passed in byte array to be wrapped in the + * OCTET STRING associated with the extension. + * + * @param oid OID for the extension. + * @param critical true if critical, false otherwise. + * @param value the byte array to be wrapped. + */ + public void addExtension( + ASN1ObjectIdentifier oid, + boolean critical, + byte[] value) + { + if (extensions.containsKey(oid)) + { + throw new IllegalArgumentException("extension " + oid + " already added"); + } + + extOrdering.addElement(oid); + extensions.put(oid, new Extension(oid, critical, new DEROctetString(value))); + } + + /** + * Return true if there are no extension present in this generator. + * + * @return true if empty, false otherwise + */ + public boolean isEmpty() + { + return extOrdering.isEmpty(); + } + + /** + * Generate an Extensions object based on the current state of the generator. + * + * @return an X09Extensions object. + */ + public Extensions generate() + { + Extension[] exts = new Extension[extOrdering.size()]; + + for (int i = 0; i != extOrdering.size(); i++) + { + exts[i] = (Extension)extensions.get(extOrdering.elementAt(i)); + } + + return new Extensions(exts); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/GeneralName.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/GeneralName.java new file mode 100644 index 0000000..85098ae --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/GeneralName.java @@ -0,0 +1,439 @@ +package org.bc.asn1.x509; + +import java.io.IOException; +import java.util.StringTokenizer; + +import org.bc.asn1.ASN1Choice; +import org.bc.asn1.ASN1Encodable; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1ObjectIdentifier; +import org.bc.asn1.ASN1OctetString; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERIA5String; +import org.bc.asn1.DEROctetString; +import org.bc.asn1.DERTaggedObject; +import org.bc.asn1.x500.X500Name; +import org.bc.util.IPAddress; + +/** + * The GeneralName object. + *
+ * GeneralName ::= CHOICE { + * otherName [0] OtherName, + * rfc822Name [1] IA5String, + * dNSName [2] IA5String, + * x400Address [3] ORAddress, + * directoryName [4] Name, + * ediPartyName [5] EDIPartyName, + * uniformResourceIdentifier [6] IA5String, + * iPAddress [7] OCTET STRING, + * registeredID [8] OBJECT IDENTIFIER} + * + * OtherName ::= SEQUENCE { + * type-id OBJECT IDENTIFIER, + * value [0] EXPLICIT ANY DEFINED BY type-id } + * + * EDIPartyName ::= SEQUENCE { + * nameAssigner [0] DirectoryString OPTIONAL, + * partyName [1] DirectoryString } + * + * Name ::= CHOICE { RDNSequence } + *+ */ +public class GeneralName + extends ASN1Object + implements ASN1Choice +{ + public static final int otherName = 0; + public static final int rfc822Name = 1; + public static final int dNSName = 2; + public static final int x400Address = 3; + public static final int directoryName = 4; + public static final int ediPartyName = 5; + public static final int uniformResourceIdentifier = 6; + public static final int iPAddress = 7; + public static final int registeredID = 8; + + private ASN1Encodable obj; + private int tag; + + /** + * @deprecated use X500Name constructor. + * @param dirName + */ + public GeneralName( + X509Name dirName) + { + this.obj = X500Name.getInstance(dirName); + this.tag = 4; + } + + public GeneralName( + X500Name dirName) + { + this.obj = dirName; + this.tag = 4; + } + + /** + * When the subjectAltName extension contains an Internet mail address, + * the address MUST be included as an rfc822Name. The format of an + * rfc822Name is an "addr-spec" as defined in RFC 822 [RFC 822]. + * + * When the subjectAltName extension contains a domain name service + * label, the domain name MUST be stored in the dNSName (an IA5String). + * The name MUST be in the "preferred name syntax," as specified by RFC + * 1034 [RFC 1034]. + * + * When the subjectAltName extension contains a URI, the name MUST be + * stored in the uniformResourceIdentifier (an IA5String). The name MUST + * be a non-relative URL, and MUST follow the URL syntax and encoding + * rules specified in [RFC 1738]. The name must include both a scheme + * (e.g., "http" or "ftp") and a scheme-specific-part. The scheme- + * specific-part must include a fully qualified domain name or IP + * address as the host. + * + * When the subjectAltName extension contains a iPAddress, the address + * MUST be stored in the octet string in "network byte order," as + * specified in RFC 791 [RFC 791]. The least significant bit (LSB) of + * each octet is the LSB of the corresponding byte in the network + * address. For IP Version 4, as specified in RFC 791, the octet string + * MUST contain exactly four octets. For IP Version 6, as specified in + * RFC 1883, the octet string MUST contain exactly sixteen octets [RFC + * 1883]. + */ + public GeneralName( + int tag, + ASN1Encodable name) + { + this.obj = name; + this.tag = tag; + } + + /** + * Create a GeneralName for the given tag from the passed in String. + *
+ * This constructor can handle: + *
+ * Note: A directory name can be encoded in different ways into a byte + * representation. Be aware of this if the byte representation is used for + * comparing results. + * + * @param tag tag number + * @param name string representation of name + * @throws IllegalArgumentException if the string encoding is not correct or * not supported. + */ + public GeneralName( + int tag, + String name) + { + this.tag = tag; + + if (tag == rfc822Name || tag == dNSName || tag == uniformResourceIdentifier) + { + this.obj = new DERIA5String(name); + } + else if (tag == registeredID) + { + this.obj = new ASN1ObjectIdentifier(name); + } + else if (tag == directoryName) + { + this.obj = new X500Name(name); + } + else if (tag == iPAddress) + { + byte[] enc = toGeneralNameEncoding(name); + if (enc != null) + { + this.obj = new DEROctetString(enc); + } + else + { + throw new IllegalArgumentException("IP Address is invalid"); + } + } + else + { + throw new IllegalArgumentException("can't process String for tag: " + tag); + } + } + + public static GeneralName getInstance( + Object obj) + { + if (obj == null || obj instanceof GeneralName) + { + return (GeneralName)obj; + } + + if (obj instanceof ASN1TaggedObject) + { + ASN1TaggedObject tagObj = (ASN1TaggedObject)obj; + int tag = tagObj.getTagNo(); + + switch (tag) + { + case otherName: + return new GeneralName(tag, ASN1Sequence.getInstance(tagObj, false)); + case rfc822Name: + return new GeneralName(tag, DERIA5String.getInstance(tagObj, false)); + case dNSName: + return new GeneralName(tag, DERIA5String.getInstance(tagObj, false)); + case x400Address: + throw new IllegalArgumentException("unknown tag: " + tag); + case directoryName: + return new GeneralName(tag, X500Name.getInstance(tagObj, true)); + case ediPartyName: + return new GeneralName(tag, ASN1Sequence.getInstance(tagObj, false)); + case uniformResourceIdentifier: + return new GeneralName(tag, DERIA5String.getInstance(tagObj, false)); + case iPAddress: + return new GeneralName(tag, ASN1OctetString.getInstance(tagObj, false)); + case registeredID: + return new GeneralName(tag, ASN1ObjectIdentifier.getInstance(tagObj, false)); + } + } + + if (obj instanceof byte[]) + { + try + { + return getInstance(ASN1Primitive.fromByteArray((byte[])obj)); + } + catch (IOException e) + { + throw new IllegalArgumentException("unable to parse encoded general name"); + } + } + + throw new IllegalArgumentException("unknown object in getInstance: " + obj.getClass().getName()); + } + + public static GeneralName getInstance( + ASN1TaggedObject tagObj, + boolean explicit) + { + return GeneralName.getInstance(ASN1TaggedObject.getInstance(tagObj, true)); + } + + public int getTagNo() + { + return tag; + } + + public ASN1Encodable getName() + { + return obj; + } + + public String toString() + { + StringBuffer buf = new StringBuffer(); + + buf.append(tag); + buf.append(": "); + switch (tag) + { + case rfc822Name: + case dNSName: + case uniformResourceIdentifier: + buf.append(DERIA5String.getInstance(obj).getString()); + break; + case directoryName: + buf.append(X500Name.getInstance(obj).toString()); + break; + default: + buf.append(obj.toString()); + } + return buf.toString(); + } + + private byte[] toGeneralNameEncoding(String ip) + { + if (IPAddress.isValidIPv6WithNetmask(ip) || IPAddress.isValidIPv6(ip)) + { + int slashIndex = ip.indexOf('/'); + + if (slashIndex < 0) + { + byte[] addr = new byte[16]; + int[] parsedIp = parseIPv6(ip); + copyInts(parsedIp, addr, 0); + + return addr; + } + else + { + byte[] addr = new byte[32]; + int[] parsedIp = parseIPv6(ip.substring(0, slashIndex)); + copyInts(parsedIp, addr, 0); + String mask = ip.substring(slashIndex + 1); + if (mask.indexOf(':') > 0) + { + parsedIp = parseIPv6(mask); + } + else + { + parsedIp = parseMask(mask); + } + copyInts(parsedIp, addr, 16); + + return addr; + } + } + else if (IPAddress.isValidIPv4WithNetmask(ip) || IPAddress.isValidIPv4(ip)) + { + int slashIndex = ip.indexOf('/'); + + if (slashIndex < 0) + { + byte[] addr = new byte[4]; + + parseIPv4(ip, addr, 0); + + return addr; + } + else + { + byte[] addr = new byte[8]; + + parseIPv4(ip.substring(0, slashIndex), addr, 0); + + String mask = ip.substring(slashIndex + 1); + if (mask.indexOf('.') > 0) + { + parseIPv4(mask, addr, 4); + } + else + { + parseIPv4Mask(mask, addr, 4); + } + + return addr; + } + } + + return null; + } + + private void parseIPv4Mask(String mask, byte[] addr, int offset) + { + int maskVal = Integer.parseInt(mask); + + for (int i = 0; i != maskVal; i++) + { + addr[(i / 8) + offset] |= 1 << (7 - (i % 8)); + } + } + + private void parseIPv4(String ip, byte[] addr, int offset) + { + StringTokenizer sTok = new StringTokenizer(ip, "./"); + int index = 0; + + while (sTok.hasMoreTokens()) + { + addr[offset + index++] = (byte)Integer.parseInt(sTok.nextToken()); + } + } + + private int[] parseMask(String mask) + { + int[] res = new int[8]; + int maskVal = Integer.parseInt(mask); + + for (int i = 0; i != maskVal; i++) + { + res[i / 16] |= 1 << (15 - (i % 16)); + } + return res; + } + + private void copyInts(int[] parsedIp, byte[] addr, int offSet) + { + for (int i = 0; i != parsedIp.length; i++) + { + addr[(i * 2) + offSet] = (byte)(parsedIp[i] >> 8); + addr[(i * 2 + 1) + offSet] = (byte)parsedIp[i]; + } + } + + private int[] parseIPv6(String ip) + { + StringTokenizer sTok = new StringTokenizer(ip, ":", true); + int index = 0; + int[] val = new int[8]; + + if (ip.charAt(0) == ':' && ip.charAt(1) == ':') + { + sTok.nextToken(); // skip the first one + } + + int doubleColon = -1; + + while (sTok.hasMoreTokens()) + { + String e = sTok.nextToken(); + + if (e.equals(":")) + { + doubleColon = index; + val[index++] = 0; + } + else + { + if (e.indexOf('.') < 0) + { + val[index++] = Integer.parseInt(e, 16); + if (sTok.hasMoreTokens()) + { + sTok.nextToken(); + } + } + else + { + StringTokenizer eTok = new StringTokenizer(e, "."); + + val[index++] = (Integer.parseInt(eTok.nextToken()) << 8) | Integer.parseInt(eTok.nextToken()); + val[index++] = (Integer.parseInt(eTok.nextToken()) << 8) | Integer.parseInt(eTok.nextToken()); + } + } + } + + if (index != val.length) + { + System.arraycopy(val, doubleColon, val, val.length - (index - doubleColon), index - doubleColon); + for (int i = doubleColon; i != val.length - (index - doubleColon); i++) + { + val[i] = 0; + } + } + + return val; + } + + public ASN1Primitive toASN1Primitive() + { + if (tag == directoryName) // directoryName is explicitly tagged as it is a CHOICE + { + return new DERTaggedObject(true, tag, obj); + } + else + { + return new DERTaggedObject(false, tag, obj); + } + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/GeneralNames.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/GeneralNames.java new file mode 100644 index 0000000..c4befa4 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/GeneralNames.java @@ -0,0 +1,108 @@ +package org.bc.asn1.x509; + +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1ObjectIdentifier; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERSequence; + +public class GeneralNames + extends ASN1Object +{ + private final GeneralName[] names; + + public static GeneralNames getInstance( + Object obj) + { + if (obj instanceof GeneralNames) + { + return (GeneralNames)obj; + } + + if (obj != null) + { + return new GeneralNames(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public static GeneralNames getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static GeneralNames fromExtensions(Extensions extensions, ASN1ObjectIdentifier extOID) + { + return GeneralNames.getInstance(extensions.getExtensionParsedValue(extOID)); + } + + /** + * Construct a GeneralNames object containing one GeneralName. + * + * @param name the name to be contained. + */ + public GeneralNames( + GeneralName name) + { + this.names = new GeneralName[] { name }; + } + + + public GeneralNames( + GeneralName[] names) + { + this.names = names; + } + + private GeneralNames( + ASN1Sequence seq) + { + this.names = new GeneralName[seq.size()]; + + for (int i = 0; i != seq.size(); i++) + { + names[i] = GeneralName.getInstance(seq.getObjectAt(i)); + } + } + + public GeneralName[] getNames() + { + GeneralName[] tmp = new GeneralName[names.length]; + + System.arraycopy(names, 0, tmp, 0, names.length); + + return tmp; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + *
+ * GeneralNames ::= SEQUENCE SIZE {1..MAX} OF GeneralName + *+ */ + public ASN1Primitive toASN1Primitive() + { + return new DERSequence(names); + } + + public String toString() + { + StringBuffer buf = new StringBuffer(); + String sep = System.getProperty("line.separator"); + + buf.append("GeneralNames:"); + buf.append(sep); + + for (int i = 0; i != names.length; i++) + { + buf.append(" "); + buf.append(names[i]); + buf.append(sep); + } + return buf.toString(); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/GeneralSubtree.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/GeneralSubtree.java new file mode 100644 index 0000000..af805ad --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/GeneralSubtree.java @@ -0,0 +1,218 @@ +package org.bc.asn1.x509; + +import java.math.BigInteger; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERSequence; +import org.bc.asn1.DERTaggedObject; + +/** + * Class for containing a restriction object subtrees in NameConstraints. See + * RFC 3280. + * + *
+ * + * GeneralSubtree ::= SEQUENCE + * { + * base GeneralName, + * minimum [0] BaseDistance DEFAULT 0, + * maximum [1] BaseDistance OPTIONAL + * } + *+ * + * @see org.bc.asn1.x509.NameConstraints + * + */ +public class GeneralSubtree + extends ASN1Object +{ + private static final BigInteger ZERO = BigInteger.valueOf(0); + + private GeneralName base; + + private ASN1Integer minimum; + + private ASN1Integer maximum; + + private GeneralSubtree( + ASN1Sequence seq) + { + base = GeneralName.getInstance(seq.getObjectAt(0)); + + switch (seq.size()) + { + case 1: + break; + case 2: + ASN1TaggedObject o = ASN1TaggedObject.getInstance(seq.getObjectAt(1)); + switch (o.getTagNo()) + { + case 0: + minimum = ASN1Integer.getInstance(o, false); + break; + case 1: + maximum = ASN1Integer.getInstance(o, false); + break; + default: + throw new IllegalArgumentException("Bad tag number: " + + o.getTagNo()); + } + break; + case 3: + { + { + ASN1TaggedObject oMin = ASN1TaggedObject.getInstance(seq.getObjectAt(1)); + if (oMin.getTagNo() != 0) + { + throw new IllegalArgumentException("Bad tag number for 'minimum': " + oMin.getTagNo()); + } + minimum = ASN1Integer.getInstance(oMin, false); + } + + { + ASN1TaggedObject oMax = ASN1TaggedObject.getInstance(seq.getObjectAt(2)); + if (oMax.getTagNo() != 1) + { + throw new IllegalArgumentException("Bad tag number for 'maximum': " + oMax.getTagNo()); + } + maximum = ASN1Integer.getInstance(oMax, false); + } + + break; + } + default: + throw new IllegalArgumentException("Bad sequence size: " + + seq.size()); + } + } + + /** + * Constructor from a given details. + * + * According RFC 3280, the minimum and maximum fields are not used with any + * name forms, thus minimum MUST be zero, and maximum MUST be absent. + *
+ * If minimum is null
, zero is assumed, if
+ * maximum is null
, maximum is absent.
+ *
+ * @param base
+ * A restriction.
+ * @param minimum
+ * Minimum
+ *
+ * @param maximum
+ * Maximum
+ */
+ public GeneralSubtree(
+ GeneralName base,
+ BigInteger minimum,
+ BigInteger maximum)
+ {
+ this.base = base;
+ if (maximum != null)
+ {
+ this.maximum = new ASN1Integer(maximum);
+ }
+ if (minimum == null)
+ {
+ this.minimum = null;
+ }
+ else
+ {
+ this.minimum = new ASN1Integer(minimum);
+ }
+ }
+
+ public GeneralSubtree(GeneralName base)
+ {
+ this(base, null, null);
+ }
+
+ public static GeneralSubtree getInstance(
+ ASN1TaggedObject o,
+ boolean explicit)
+ {
+ return new GeneralSubtree(ASN1Sequence.getInstance(o, explicit));
+ }
+
+ public static GeneralSubtree getInstance(
+ Object obj)
+ {
+ if (obj == null)
+ {
+ return null;
+ }
+
+ if (obj instanceof GeneralSubtree)
+ {
+ return (GeneralSubtree) obj;
+ }
+
+ return new GeneralSubtree(ASN1Sequence.getInstance(obj));
+ }
+
+ public GeneralName getBase()
+ {
+ return base;
+ }
+
+ public BigInteger getMinimum()
+ {
+ if (minimum == null)
+ {
+ return ZERO;
+ }
+
+ return minimum.getValue();
+ }
+
+ public BigInteger getMaximum()
+ {
+ if (maximum == null)
+ {
+ return null;
+ }
+
+ return maximum.getValue();
+ }
+
+ /**
+ * Produce an object suitable for an ASN1OutputStream.
+ *
+ * Returns:
+ *
+ *
+ * GeneralSubtree ::= SEQUENCE + * { + * base GeneralName, + * minimum [0] BaseDistance DEFAULT 0, + * maximum [1] BaseDistance OPTIONAL + * } + *+ * + * @return a ASN1Primitive + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(base); + + if (minimum != null && !minimum.getValue().equals(ZERO)) + { + v.add(new DERTaggedObject(false, 0, minimum)); + } + + if (maximum != null) + { + v.add(new DERTaggedObject(false, 1, maximum)); + } + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/Holder.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/Holder.java new file mode 100644 index 0000000..a375726 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/Holder.java @@ -0,0 +1,245 @@ +package org.bc.asn1.x509; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERSequence; +import org.bc.asn1.DERTaggedObject; + +/** + * The Holder object. + *
+ * For an v2 attribute certificate this is: + * + *
+ * Holder ::= SEQUENCE { + * baseCertificateID [0] IssuerSerial OPTIONAL, + * -- the issuer and serial number of + * -- the holder's Public Key Certificate + * entityName [1] GeneralNames OPTIONAL, + * -- the name of the claimant or role + * objectDigestInfo [2] ObjectDigestInfo OPTIONAL + * -- used to directly authenticate the holder, + * -- for example, an executable + * } + *+ * + *
+ * For an v1 attribute certificate this is: + * + *
+ * subject CHOICE { + * baseCertificateID [0] IssuerSerial, + * -- associated with a Public Key Certificate + * subjectName [1] GeneralNames }, + * -- associated with a name + *+ */ +public class Holder + extends ASN1Object +{ + public static final int V1_CERTIFICATE_HOLDER = 0; + public static final int V2_CERTIFICATE_HOLDER = 1; + + IssuerSerial baseCertificateID; + + GeneralNames entityName; + + ObjectDigestInfo objectDigestInfo; + + private int version = V2_CERTIFICATE_HOLDER; + + public static Holder getInstance(Object obj) + { + if (obj instanceof Holder) + { + return (Holder)obj; + } + else if (obj instanceof ASN1TaggedObject) + { + return new Holder(ASN1TaggedObject.getInstance(obj)); + } + else if (obj != null) + { + return new Holder(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + /** + * Constructor for a holder for an V1 attribute certificate. + * + * @param tagObj The ASN.1 tagged holder object. + */ + private Holder(ASN1TaggedObject tagObj) + { + switch (tagObj.getTagNo()) + { + case 0: + baseCertificateID = IssuerSerial.getInstance(tagObj, false); + break; + case 1: + entityName = GeneralNames.getInstance(tagObj, false); + break; + default: + throw new IllegalArgumentException("unknown tag in Holder"); + } + version = 0; + } + + /** + * Constructor for a holder for an V2 attribute certificate. + * + * @param seq The ASN.1 sequence. + */ + private Holder(ASN1Sequence seq) + { + if (seq.size() > 3) + { + throw new IllegalArgumentException("Bad sequence size: " + + seq.size()); + } + + for (int i = 0; i != seq.size(); i++) + { + ASN1TaggedObject tObj = ASN1TaggedObject.getInstance(seq + .getObjectAt(i)); + + switch (tObj.getTagNo()) + { + case 0: + baseCertificateID = IssuerSerial.getInstance(tObj, false); + break; + case 1: + entityName = GeneralNames.getInstance(tObj, false); + break; + case 2: + objectDigestInfo = ObjectDigestInfo.getInstance(tObj, false); + break; + default: + throw new IllegalArgumentException("unknown tag in Holder"); + } + } + version = 1; + } + + public Holder(IssuerSerial baseCertificateID) + { + this(baseCertificateID, V2_CERTIFICATE_HOLDER); + } + + /** + * Constructs a holder from a IssuerSerial for a V1 or V2 certificate. + * . + * @param baseCertificateID The IssuerSerial. + * @param version The version of the attribute certificate. + */ + public Holder(IssuerSerial baseCertificateID, int version) + { + this.baseCertificateID = baseCertificateID; + this.version = version; + } + + /** + * Returns 1 for V2 attribute certificates or 0 for V1 attribute + * certificates. + * @return The version of the attribute certificate. + */ + public int getVersion() + { + return version; + } + + /** + * Constructs a holder with an entityName for V2 attribute certificates. + * + * @param entityName The entity or subject name. + */ + public Holder(GeneralNames entityName) + { + this(entityName, V2_CERTIFICATE_HOLDER); + } + + /** + * Constructs a holder with an entityName for V2 attribute certificates or + * with a subjectName for V1 attribute certificates. + * + * @param entityName The entity or subject name. + * @param version The version of the attribute certificate. + */ + public Holder(GeneralNames entityName, int version) + { + this.entityName = entityName; + this.version = version; + } + + /** + * Constructs a holder from an object digest info. + * + * @param objectDigestInfo The object digest info object. + */ + public Holder(ObjectDigestInfo objectDigestInfo) + { + this.objectDigestInfo = objectDigestInfo; + } + + public IssuerSerial getBaseCertificateID() + { + return baseCertificateID; + } + + /** + * Returns the entityName for an V2 attribute certificate or the subjectName + * for an V1 attribute certificate. + * + * @return The entityname or subjectname. + */ + public GeneralNames getEntityName() + { + return entityName; + } + + public ObjectDigestInfo getObjectDigestInfo() + { + return objectDigestInfo; + } + + public ASN1Primitive toASN1Primitive() + { + if (version == 1) + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + if (baseCertificateID != null) + { + v.add(new DERTaggedObject(false, 0, baseCertificateID)); + } + + if (entityName != null) + { + v.add(new DERTaggedObject(false, 1, entityName)); + } + + if (objectDigestInfo != null) + { + v.add(new DERTaggedObject(false, 2, objectDigestInfo)); + } + + return new DERSequence(v); + } + else + { + if (entityName != null) + { + return new DERTaggedObject(false, 1, entityName); + } + else + { + return new DERTaggedObject(false, 0, baseCertificateID); + } + } + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/IetfAttrSyntax.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/IetfAttrSyntax.java new file mode 100644 index 0000000..2e5afb2 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/IetfAttrSyntax.java @@ -0,0 +1,189 @@ +package org.bc.asn1.x509; + +import java.util.Enumeration; +import java.util.Vector; + +import org.bc.asn1.ASN1Encodable; +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1ObjectIdentifier; +import org.bc.asn1.ASN1OctetString; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DEROctetString; +import org.bc.asn1.DERSequence; +import org.bc.asn1.DERTaggedObject; +import org.bc.asn1.DERUTF8String; + +/** + * Implementation of
IetfAttrSyntax
as specified by RFC3281.
+ */
+public class IetfAttrSyntax
+ extends ASN1Object
+{
+ public static final int VALUE_OCTETS = 1;
+ public static final int VALUE_OID = 2;
+ public static final int VALUE_UTF8 = 3;
+ GeneralNames policyAuthority = null;
+ Vector values = new Vector();
+ int valueChoice = -1;
+
+ public static IetfAttrSyntax getInstance(Object obj)
+ {
+ if (obj instanceof IetfAttrSyntax)
+ {
+ return (IetfAttrSyntax)obj;
+ }
+ if (obj != null)
+ {
+ return new IetfAttrSyntax(ASN1Sequence.getInstance(obj));
+ }
+
+ return null;
+ }
+
+ /**
+ *
+ */
+ private IetfAttrSyntax(ASN1Sequence seq)
+ {
+ int i = 0;
+
+ if (seq.getObjectAt(0) instanceof ASN1TaggedObject)
+ {
+ policyAuthority = GeneralNames.getInstance(((ASN1TaggedObject)seq.getObjectAt(0)), false);
+ i++;
+ }
+ else if (seq.size() == 2)
+ { // VOMS fix
+ policyAuthority = GeneralNames.getInstance(seq.getObjectAt(0));
+ i++;
+ }
+
+ if (!(seq.getObjectAt(i) instanceof ASN1Sequence))
+ {
+ throw new IllegalArgumentException("Non-IetfAttrSyntax encoding");
+ }
+
+ seq = (ASN1Sequence)seq.getObjectAt(i);
+
+ for (Enumeration e = seq.getObjects(); e.hasMoreElements();)
+ {
+ ASN1Primitive obj = (ASN1Primitive)e.nextElement();
+ int type;
+
+ if (obj instanceof ASN1ObjectIdentifier)
+ {
+ type = VALUE_OID;
+ }
+ else if (obj instanceof DERUTF8String)
+ {
+ type = VALUE_UTF8;
+ }
+ else if (obj instanceof DEROctetString)
+ {
+ type = VALUE_OCTETS;
+ }
+ else
+ {
+ throw new IllegalArgumentException("Bad value type encoding IetfAttrSyntax");
+ }
+
+ if (valueChoice < 0)
+ {
+ valueChoice = type;
+ }
+
+ if (type != valueChoice)
+ {
+ throw new IllegalArgumentException("Mix of value types in IetfAttrSyntax");
+ }
+
+ values.addElement(obj);
+ }
+ }
+
+ public GeneralNames getPolicyAuthority()
+ {
+ return policyAuthority;
+ }
+
+ public int getValueType()
+ {
+ return valueChoice;
+ }
+
+ public Object[] getValues()
+ {
+ if (this.getValueType() == VALUE_OCTETS)
+ {
+ ASN1OctetString[] tmp = new ASN1OctetString[values.size()];
+
+ for (int i = 0; i != tmp.length; i++)
+ {
+ tmp[i] = (ASN1OctetString)values.elementAt(i);
+ }
+
+ return tmp;
+ }
+ else if (this.getValueType() == VALUE_OID)
+ {
+ ASN1ObjectIdentifier[] tmp = new ASN1ObjectIdentifier[values.size()];
+
+ for (int i = 0; i != tmp.length; i++)
+ {
+ tmp[i] = (ASN1ObjectIdentifier)values.elementAt(i);
+ }
+
+ return tmp;
+ }
+ else
+ {
+ DERUTF8String[] tmp = new DERUTF8String[values.size()];
+
+ for (int i = 0; i != tmp.length; i++)
+ {
+ tmp[i] = (DERUTF8String)values.elementAt(i);
+ }
+
+ return tmp;
+ }
+ }
+
+ /**
+ *
+ * + * + * IetfAttrSyntax ::= SEQUENCE { + * policyAuthority [0] GeneralNames OPTIONAL, + * values SEQUENCE OF CHOICE { + * octets OCTET STRING, + * oid OBJECT IDENTIFIER, + * string UTF8String + * } + * } + * + *+ */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + if (policyAuthority != null) + { + v.add(new DERTaggedObject(0, policyAuthority)); + } + + ASN1EncodableVector v2 = new ASN1EncodableVector(); + + for (Enumeration i = values.elements(); i.hasMoreElements();) + { + v2.add((ASN1Encodable)i.nextElement()); + } + + v.add(new DERSequence(v2)); + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/IssuerSerial.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/IssuerSerial.java new file mode 100644 index 0000000..01ea871 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/IssuerSerial.java @@ -0,0 +1,115 @@ +package org.bc.asn1.x509; + +import java.math.BigInteger; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERBitString; +import org.bc.asn1.DERSequence; + +public class IssuerSerial + extends ASN1Object +{ + GeneralNames issuer; + ASN1Integer serial; + DERBitString issuerUID; + + public static IssuerSerial getInstance( + Object obj) + { + if (obj instanceof IssuerSerial) + { + return (IssuerSerial)obj; + } + + if (obj != null) + { + return new IssuerSerial(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public static IssuerSerial getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + private IssuerSerial( + ASN1Sequence seq) + { + if (seq.size() != 2 && seq.size() != 3) + { + throw new IllegalArgumentException("Bad sequence size: " + seq.size()); + } + + issuer = GeneralNames.getInstance(seq.getObjectAt(0)); + serial = ASN1Integer.getInstance(seq.getObjectAt(1)); + + if (seq.size() == 3) + { + issuerUID = DERBitString.getInstance(seq.getObjectAt(2)); + } + } + + public IssuerSerial( + GeneralNames issuer, + BigInteger serial) + { + this(issuer, new ASN1Integer(serial)); + } + + public IssuerSerial( + GeneralNames issuer, + ASN1Integer serial) + { + this.issuer = issuer; + this.serial = serial; + } + + public GeneralNames getIssuer() + { + return issuer; + } + + public ASN1Integer getSerial() + { + return serial; + } + + public DERBitString getIssuerUID() + { + return issuerUID; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + *
+ * IssuerSerial ::= SEQUENCE { + * issuer GeneralNames, + * serial CertificateSerialNumber, + * issuerUID UniqueIdentifier OPTIONAL + * } + *+ */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(issuer); + v.add(serial); + + if (issuerUID != null) + { + v.add(issuerUID); + } + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/IssuingDistributionPoint.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/IssuingDistributionPoint.java new file mode 100644 index 0000000..fe268ec --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/IssuingDistributionPoint.java @@ -0,0 +1,274 @@ +package org.bc.asn1.x509; + +import org.bc.asn1.ASN1Boolean; +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERSequence; +import org.bc.asn1.DERTaggedObject; + +/** + *
+ * IssuingDistributionPoint ::= SEQUENCE { + * distributionPoint [0] DistributionPointName OPTIONAL, + * onlyContainsUserCerts [1] BOOLEAN DEFAULT FALSE, + * onlyContainsCACerts [2] BOOLEAN DEFAULT FALSE, + * onlySomeReasons [3] ReasonFlags OPTIONAL, + * indirectCRL [4] BOOLEAN DEFAULT FALSE, + * onlyContainsAttributeCerts [5] BOOLEAN DEFAULT FALSE } + *+ */ +public class IssuingDistributionPoint + extends ASN1Object +{ + private DistributionPointName distributionPoint; + + private boolean onlyContainsUserCerts; + + private boolean onlyContainsCACerts; + + private ReasonFlags onlySomeReasons; + + private boolean indirectCRL; + + private boolean onlyContainsAttributeCerts; + + private ASN1Sequence seq; + + public static IssuingDistributionPoint getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static IssuingDistributionPoint getInstance( + Object obj) + { + if (obj instanceof IssuingDistributionPoint) + { + return (IssuingDistributionPoint)obj; + } + else if (obj != null) + { + return new IssuingDistributionPoint(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + /** + * Constructor from given details. + * + * @param distributionPoint + * May contain an URI as pointer to most current CRL. + * @param onlyContainsUserCerts Covers revocation information for end certificates. + * @param onlyContainsCACerts Covers revocation information for CA certificates. + * + * @param onlySomeReasons + * Which revocation reasons does this point cover. + * @param indirectCRL + * If
true
then the CRL contains revocation
+ * information about certificates ssued by other CAs.
+ * @param onlyContainsAttributeCerts Covers revocation information for attribute certificates.
+ */
+ public IssuingDistributionPoint(
+ DistributionPointName distributionPoint,
+ boolean onlyContainsUserCerts,
+ boolean onlyContainsCACerts,
+ ReasonFlags onlySomeReasons,
+ boolean indirectCRL,
+ boolean onlyContainsAttributeCerts)
+ {
+ this.distributionPoint = distributionPoint;
+ this.indirectCRL = indirectCRL;
+ this.onlyContainsAttributeCerts = onlyContainsAttributeCerts;
+ this.onlyContainsCACerts = onlyContainsCACerts;
+ this.onlyContainsUserCerts = onlyContainsUserCerts;
+ this.onlySomeReasons = onlySomeReasons;
+
+ ASN1EncodableVector vec = new ASN1EncodableVector();
+ if (distributionPoint != null)
+ { // CHOICE item so explicitly tagged
+ vec.add(new DERTaggedObject(true, 0, distributionPoint));
+ }
+ if (onlyContainsUserCerts)
+ {
+ vec.add(new DERTaggedObject(false, 1, ASN1Boolean.getInstance(true)));
+ }
+ if (onlyContainsCACerts)
+ {
+ vec.add(new DERTaggedObject(false, 2, ASN1Boolean.getInstance(true)));
+ }
+ if (onlySomeReasons != null)
+ {
+ vec.add(new DERTaggedObject(false, 3, onlySomeReasons));
+ }
+ if (indirectCRL)
+ {
+ vec.add(new DERTaggedObject(false, 4, ASN1Boolean.getInstance(true)));
+ }
+ if (onlyContainsAttributeCerts)
+ {
+ vec.add(new DERTaggedObject(false, 5, ASN1Boolean.getInstance(true)));
+ }
+
+ seq = new DERSequence(vec);
+ }
+
+ /**
+ * Shorthand Constructor from given details.
+ *
+ * @param distributionPoint
+ * May contain an URI as pointer to most current CRL.
+ * @param indirectCRL
+ * If true
then the CRL contains revocation
+ * information about certificates ssued by other CAs.
+ * @param onlyContainsAttributeCerts Covers revocation information for attribute certificates.
+ */
+ public IssuingDistributionPoint(
+ DistributionPointName distributionPoint,
+ boolean indirectCRL,
+ boolean onlyContainsAttributeCerts)
+ {
+ this(distributionPoint, false, false, null, indirectCRL, onlyContainsAttributeCerts);
+ }
+
+ /**
+ * Constructor from ASN1Sequence
+ */
+ private IssuingDistributionPoint(
+ ASN1Sequence seq)
+ {
+ this.seq = seq;
+
+ for (int i = 0; i != seq.size(); i++)
+ {
+ ASN1TaggedObject o = ASN1TaggedObject.getInstance(seq.getObjectAt(i));
+
+ switch (o.getTagNo())
+ {
+ case 0:
+ // CHOICE so explicit
+ distributionPoint = DistributionPointName.getInstance(o, true);
+ break;
+ case 1:
+ onlyContainsUserCerts = ASN1Boolean.getInstance(o, false).isTrue();
+ break;
+ case 2:
+ onlyContainsCACerts = ASN1Boolean.getInstance(o, false).isTrue();
+ break;
+ case 3:
+ onlySomeReasons = new ReasonFlags(ReasonFlags.getInstance(o, false));
+ break;
+ case 4:
+ indirectCRL = ASN1Boolean.getInstance(o, false).isTrue();
+ break;
+ case 5:
+ onlyContainsAttributeCerts = ASN1Boolean.getInstance(o, false).isTrue();
+ break;
+ default:
+ throw new IllegalArgumentException(
+ "unknown tag in IssuingDistributionPoint");
+ }
+ }
+ }
+
+ public boolean onlyContainsUserCerts()
+ {
+ return onlyContainsUserCerts;
+ }
+
+ public boolean onlyContainsCACerts()
+ {
+ return onlyContainsCACerts;
+ }
+
+ public boolean isIndirectCRL()
+ {
+ return indirectCRL;
+ }
+
+ public boolean onlyContainsAttributeCerts()
+ {
+ return onlyContainsAttributeCerts;
+ }
+
+ /**
+ * @return Returns the distributionPoint.
+ */
+ public DistributionPointName getDistributionPoint()
+ {
+ return distributionPoint;
+ }
+
+ /**
+ * @return Returns the onlySomeReasons.
+ */
+ public ReasonFlags getOnlySomeReasons()
+ {
+ return onlySomeReasons;
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+ return seq;
+ }
+
+ public String toString()
+ {
+ String sep = System.getProperty("line.separator");
+ StringBuffer buf = new StringBuffer();
+
+ buf.append("IssuingDistributionPoint: [");
+ buf.append(sep);
+ if (distributionPoint != null)
+ {
+ appendObject(buf, sep, "distributionPoint", distributionPoint.toString());
+ }
+ if (onlyContainsUserCerts)
+ {
+ appendObject(buf, sep, "onlyContainsUserCerts", booleanToString(onlyContainsUserCerts));
+ }
+ if (onlyContainsCACerts)
+ {
+ appendObject(buf, sep, "onlyContainsCACerts", booleanToString(onlyContainsCACerts));
+ }
+ if (onlySomeReasons != null)
+ {
+ appendObject(buf, sep, "onlySomeReasons", onlySomeReasons.toString());
+ }
+ if (onlyContainsAttributeCerts)
+ {
+ appendObject(buf, sep, "onlyContainsAttributeCerts", booleanToString(onlyContainsAttributeCerts));
+ }
+ if (indirectCRL)
+ {
+ appendObject(buf, sep, "indirectCRL", booleanToString(indirectCRL));
+ }
+ buf.append("]");
+ buf.append(sep);
+ return buf.toString();
+ }
+
+ private void appendObject(StringBuffer buf, String sep, String name, String value)
+ {
+ String indent = " ";
+
+ buf.append(indent);
+ buf.append(name);
+ buf.append(":");
+ buf.append(sep);
+ buf.append(indent);
+ buf.append(indent);
+ buf.append(value);
+ buf.append(sep);
+ }
+
+ private String booleanToString(boolean value)
+ {
+ return value ? "true" : "false";
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/KeyPurposeId.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/KeyPurposeId.java
new file mode 100644
index 0000000..2bb0897
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/KeyPurposeId.java
@@ -0,0 +1,151 @@
+package org.bc.asn1.x509;
+
+import org.bc.asn1.ASN1Object;
+import org.bc.asn1.ASN1ObjectIdentifier;
+import org.bc.asn1.ASN1Primitive;
+
+/**
+ * The KeyPurposeId object.
+ * + * KeyPurposeId ::= OBJECT IDENTIFIER + * + * id-kp ::= OBJECT IDENTIFIER { iso(1) identified-organization(3) + * dod(6) internet(1) security(5) mechanisms(5) pkix(7) 3} + * + *+ */ +public class KeyPurposeId + extends ASN1Object +{ + private static final ASN1ObjectIdentifier id_kp = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.3"); + + /** + * { 2 5 29 37 0 } + */ + public static final KeyPurposeId anyExtendedKeyUsage = new KeyPurposeId(Extension.extendedKeyUsage.branch("0")); + + /** + * { id-kp 1 } + */ + public static final KeyPurposeId id_kp_serverAuth = new KeyPurposeId(id_kp.branch("1")); + /** + * { id-kp 2 } + */ + public static final KeyPurposeId id_kp_clientAuth = new KeyPurposeId(id_kp.branch("2")); + /** + * { id-kp 3 } + */ + public static final KeyPurposeId id_kp_codeSigning = new KeyPurposeId(id_kp.branch("3")); + /** + * { id-kp 4 } + */ + public static final KeyPurposeId id_kp_emailProtection = new KeyPurposeId(id_kp.branch("4")); + /** + * Usage deprecated by RFC4945 - was { id-kp 5 } + */ + public static final KeyPurposeId id_kp_ipsecEndSystem = new KeyPurposeId(id_kp.branch("5")); + /** + * Usage deprecated by RFC4945 - was { id-kp 6 } + */ + public static final KeyPurposeId id_kp_ipsecTunnel = new KeyPurposeId(id_kp.branch("6")); + /** + * Usage deprecated by RFC4945 - was { idkp 7 } + */ + public static final KeyPurposeId id_kp_ipsecUser = new KeyPurposeId(id_kp.branch("7")); + /** + * { id-kp 8 } + */ + public static final KeyPurposeId id_kp_timeStamping = new KeyPurposeId(id_kp.branch("8")); + /** + * { id-kp 9 } + */ + public static final KeyPurposeId id_kp_OCSPSigning = new KeyPurposeId(id_kp.branch("9")); + /** + * { id-kp 10 } + */ + public static final KeyPurposeId id_kp_dvcs = new KeyPurposeId(id_kp.branch("10")); + /** + * { id-kp 11 } + */ + public static final KeyPurposeId id_kp_sbgpCertAAServerAuth = new KeyPurposeId(id_kp.branch("11")); + /** + * { id-kp 12 } + */ + public static final KeyPurposeId id_kp_scvp_responder = new KeyPurposeId(id_kp.branch("12")); + /** + * { id-kp 13 } + */ + public static final KeyPurposeId id_kp_eapOverPPP = new KeyPurposeId(id_kp.branch("13")); + /** + * { id-kp 14 } + */ + public static final KeyPurposeId id_kp_eapOverLAN = new KeyPurposeId(id_kp.branch("14")); + /** + * { id-kp 15 } + */ + public static final KeyPurposeId id_kp_scvpServer = new KeyPurposeId(id_kp.branch("15")); + /** + * { id-kp 16 } + */ + public static final KeyPurposeId id_kp_scvpClient = new KeyPurposeId(id_kp.branch("16")); + /** + * { id-kp 17 } + */ + public static final KeyPurposeId id_kp_ipsecIKE = new KeyPurposeId(id_kp.branch("17")); + /** + * { id-kp 18 } + */ + public static final KeyPurposeId id_kp_capwapAC = new KeyPurposeId(id_kp.branch("18")); + /** + * { id-kp 19 } + */ + public static final KeyPurposeId id_kp_capwapWTP = new KeyPurposeId(id_kp.branch("19")); + + // + // microsoft key purpose ids + // + /** + * { 1 3 6 1 4 1 311 20 2 2 } + */ + public static final KeyPurposeId id_kp_smartcardlogon = new KeyPurposeId(new ASN1ObjectIdentifier("1.3.6.1.4.1.311.20.2.2")); + + private ASN1ObjectIdentifier id; + + private KeyPurposeId(ASN1ObjectIdentifier id) + { + this.id = id; + } + + /** + * @deprecated use getInstance and an OID or one of the constants above. + * @param id string representation of an OID. + */ + public KeyPurposeId(String id) + { + this(new ASN1ObjectIdentifier(id)); + } + + public static KeyPurposeId getInstance(Object o) + { + if (o instanceof KeyPurposeId) + { + return (KeyPurposeId)o; + } + else if (o != null) + { + return new KeyPurposeId(ASN1ObjectIdentifier.getInstance(o)); + } + + return null; + } + + public ASN1Primitive toASN1Primitive() + { + return id; + } + + public String getId() + { + return id.getId(); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/KeyUsage.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/KeyUsage.java new file mode 100644 index 0000000..ce5720b --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/KeyUsage.java @@ -0,0 +1,102 @@ +package org.bc.asn1.x509; + +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.DERBitString; + +/** + * The KeyUsage object. + *
+ * id-ce-keyUsage OBJECT IDENTIFIER ::= { id-ce 15 } + * + * KeyUsage ::= BIT STRING { + * digitalSignature (0), + * nonRepudiation (1), + * keyEncipherment (2), + * dataEncipherment (3), + * keyAgreement (4), + * keyCertSign (5), + * cRLSign (6), + * encipherOnly (7), + * decipherOnly (8) } + *+ */ +public class KeyUsage + extends ASN1Object +{ + public static final int digitalSignature = (1 << 7); + public static final int nonRepudiation = (1 << 6); + public static final int keyEncipherment = (1 << 5); + public static final int dataEncipherment = (1 << 4); + public static final int keyAgreement = (1 << 3); + public static final int keyCertSign = (1 << 2); + public static final int cRLSign = (1 << 1); + public static final int encipherOnly = (1 << 0); + public static final int decipherOnly = (1 << 15); + + private DERBitString bitString; + + public static KeyUsage getInstance(Object obj) // needs to be DERBitString for other VMs + { + if (obj instanceof KeyUsage) + { + return (KeyUsage)obj; + } + else if (obj != null) + { + return new KeyUsage(DERBitString.getInstance(obj)); + } + + return null; + } + + public static KeyUsage fromExtensions(Extensions extensions) + { + return KeyUsage.getInstance(extensions.getExtensionParsedValue(Extension.keyUsage)); + } + + /** + * Basic constructor. + * + * @param usage - the bitwise OR of the Key Usage flags giving the + * allowed uses for the key. + * e.g. (KeyUsage.keyEncipherment | KeyUsage.dataEncipherment) + */ + public KeyUsage( + int usage) + { + this.bitString = new DERBitString(usage); + } + + private KeyUsage( + DERBitString bitString) + { + this.bitString = bitString; + } + + public byte[] getBytes() + { + return bitString.getBytes(); + } + + public int getPadBits() + { + return bitString.getPadBits(); + } + + public String toString() + { + byte[] data = bitString.getBytes(); + + if (data.length == 1) + { + return "KeyUsage: 0x" + Integer.toHexString(data[0] & 0xff); + } + return "KeyUsage: 0x" + Integer.toHexString((data[1] & 0xff) << 8 | (data[0] & 0xff)); + } + + public ASN1Primitive toASN1Primitive() + { + return bitString; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/NameConstraints.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/NameConstraints.java new file mode 100644 index 0000000..5081162 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/NameConstraints.java @@ -0,0 +1,118 @@ +package org.bc.asn1.x509; + +import java.util.Enumeration; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERSequence; +import org.bc.asn1.DERTaggedObject; + +public class NameConstraints + extends ASN1Object +{ + private GeneralSubtree[] permitted, excluded; + + public static NameConstraints getInstance(Object obj) + { + if (obj instanceof NameConstraints) + { + return (NameConstraints)obj; + } + if (obj != null) + { + return new NameConstraints(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + private NameConstraints(ASN1Sequence seq) + { + Enumeration e = seq.getObjects(); + while (e.hasMoreElements()) + { + ASN1TaggedObject o = ASN1TaggedObject.getInstance(e.nextElement()); + switch (o.getTagNo()) + { + case 0: + permitted = createArray(ASN1Sequence.getInstance(o, false)); + break; + case 1: + excluded = createArray(ASN1Sequence.getInstance(o, false)); + break; + } + } + } + + /** + * Constructor from a given details. + * + *
+ * permitted and excluded are arrays of GeneralSubtree objects.
+ *
+ * @param permitted
+ * Permitted subtrees
+ * @param excluded
+ * Excludes subtrees
+ */
+ public NameConstraints(
+ GeneralSubtree[] permitted,
+ GeneralSubtree[] excluded)
+ {
+ if (permitted != null)
+ {
+ this.permitted = permitted;
+ }
+
+ if (excluded != null)
+ {
+ this.excluded = excluded;
+ }
+ }
+
+ private GeneralSubtree[] createArray(ASN1Sequence subtree)
+ {
+ GeneralSubtree[] ar = new GeneralSubtree[subtree.size()];
+
+ for (int i = 0; i != ar.length; i++)
+ {
+ ar[i] = GeneralSubtree.getInstance(subtree.getObjectAt(i));
+ }
+
+ return ar;
+ }
+
+ public GeneralSubtree[] getPermittedSubtrees()
+ {
+ return permitted;
+ }
+
+ public GeneralSubtree[] getExcludedSubtrees()
+ {
+ return excluded;
+ }
+
+ /*
+ * NameConstraints ::= SEQUENCE { permittedSubtrees [0] GeneralSubtrees
+ * OPTIONAL, excludedSubtrees [1] GeneralSubtrees OPTIONAL }
+ */
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ if (permitted != null)
+ {
+ v.add(new DERTaggedObject(false, 0, new DERSequence(permitted)));
+ }
+
+ if (excluded != null)
+ {
+ v.add(new DERTaggedObject(false, 1, new DERSequence(excluded)));
+ }
+
+ return new DERSequence(v);
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/NoticeReference.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/NoticeReference.java
new file mode 100644
index 0000000..7bc1b43
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/NoticeReference.java
@@ -0,0 +1,170 @@
+package org.bc.asn1.x509;
+
+import java.math.BigInteger;
+import java.util.Enumeration;
+import java.util.Vector;
+
+import org.bc.asn1.ASN1EncodableVector;
+import org.bc.asn1.ASN1Integer;
+import org.bc.asn1.ASN1Object;
+import org.bc.asn1.ASN1Primitive;
+import org.bc.asn1.ASN1Sequence;
+import org.bc.asn1.DERSequence;
+
+/**
+ * NoticeReference
class, used in
+ * CertificatePolicies
X509 V3 extensions
+ * (in policy qualifiers).
+ *
+ *
+ * NoticeReference ::= SEQUENCE { + * organization DisplayText, + * noticeNumbers SEQUENCE OF INTEGER } + * + *+ * + * @see PolicyQualifierInfo + * @see PolicyInformation + */ +public class NoticeReference + extends ASN1Object +{ + private DisplayText organization; + private ASN1Sequence noticeNumbers; + + private static ASN1EncodableVector convertVector(Vector numbers) + { + ASN1EncodableVector av = new ASN1EncodableVector(); + + Enumeration it = numbers.elements(); + + while (it.hasMoreElements()) + { + Object o = it.nextElement(); + ASN1Integer di; + + if (o instanceof BigInteger) + { + di = new ASN1Integer((BigInteger)o); + } + else if (o instanceof Integer) + { + di = new ASN1Integer(((Integer)o).intValue()); + } + else + { + throw new IllegalArgumentException(); + } + + av.add(di); + } + return av; + } + + /** + * Creates a new
NoticeReference
instance.
+ *
+ * @param organization a String
value
+ * @param numbers a Vector
value
+ */
+ public NoticeReference(
+ String organization,
+ Vector numbers)
+ {
+ this(organization, convertVector(numbers));
+ }
+
+ /**
+ * Creates a new NoticeReference
instance.
+ *
+ * @param organization a String
value
+ * @param noticeNumbers an ASN1EncodableVector
value
+ */
+ public NoticeReference(
+ String organization,
+ ASN1EncodableVector noticeNumbers)
+ {
+ this(new DisplayText(organization), noticeNumbers);
+ }
+
+ /**
+ * Creates a new NoticeReference
instance.
+ *
+ * @param organization displayText
+ * @param noticeNumbers an ASN1EncodableVector
value
+ */
+ public NoticeReference(
+ DisplayText organization,
+ ASN1EncodableVector noticeNumbers)
+ {
+ this.organization = organization;
+ this.noticeNumbers = new DERSequence(noticeNumbers);
+ }
+
+ /**
+ * Creates a new NoticeReference
instance.
+ * Useful for reconstructing a NoticeReference
+ * instance from its encodable/encoded form.
+ *
+ * @param as an ASN1Sequence
value obtained from either
+ * calling @{link toASN1Primitive()} for a NoticeReference
+ * instance or from parsing it from a DER-encoded stream.
+ */
+ private NoticeReference(
+ ASN1Sequence as)
+ {
+ if (as.size() != 2)
+ {
+ throw new IllegalArgumentException("Bad sequence size: "
+ + as.size());
+ }
+
+ organization = DisplayText.getInstance(as.getObjectAt(0));
+ noticeNumbers = ASN1Sequence.getInstance(as.getObjectAt(1));
+ }
+
+ public static NoticeReference getInstance(
+ Object as)
+ {
+ if (as instanceof NoticeReference)
+ {
+ return (NoticeReference)as;
+ }
+ else if (as != null)
+ {
+ return new NoticeReference(ASN1Sequence.getInstance(as));
+ }
+
+ return null;
+ }
+
+ public DisplayText getOrganization()
+ {
+ return organization;
+ }
+
+ public ASN1Integer[] getNoticeNumbers()
+ {
+ ASN1Integer[] tmp = new ASN1Integer[noticeNumbers.size()];
+
+ for (int i = 0; i != noticeNumbers.size(); i++)
+ {
+ tmp[i] = ASN1Integer.getInstance(noticeNumbers.getObjectAt(i));
+ }
+
+ return tmp;
+ }
+
+ /**
+ * Describe toASN1Object
method here.
+ *
+ * @return a ASN1Primitive
value
+ */
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector av = new ASN1EncodableVector();
+ av.add (organization);
+ av.add (noticeNumbers);
+ return new DERSequence (av);
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/ObjectDigestInfo.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/ObjectDigestInfo.java
new file mode 100644
index 0000000..6dc0fb8
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/ObjectDigestInfo.java
@@ -0,0 +1,190 @@
+package org.bc.asn1.x509;
+
+import org.bc.asn1.ASN1EncodableVector;
+import org.bc.asn1.ASN1Enumerated;
+import org.bc.asn1.ASN1Object;
+import org.bc.asn1.ASN1ObjectIdentifier;
+import org.bc.asn1.ASN1Primitive;
+import org.bc.asn1.ASN1Sequence;
+import org.bc.asn1.ASN1TaggedObject;
+import org.bc.asn1.DERBitString;
+import org.bc.asn1.DERSequence;
+
+/**
+ * ObjectDigestInfo ASN.1 structure used in v2 attribute certificates.
+ *
+ *
+ * + * ObjectDigestInfo ::= SEQUENCE { + * digestedObjectType ENUMERATED { + * publicKey (0), + * publicKeyCert (1), + * otherObjectTypes (2) }, + * -- otherObjectTypes MUST NOT + * -- be used in this profile + * otherObjectTypeID OBJECT IDENTIFIER OPTIONAL, + * digestAlgorithm AlgorithmIdentifier, + * objectDigest BIT STRING + * } + * + *+ * + */ +public class ObjectDigestInfo + extends ASN1Object +{ + /** + * The public key is hashed. + */ + public final static int publicKey = 0; + + /** + * The public key certificate is hashed. + */ + public final static int publicKeyCert = 1; + + /** + * An other object is hashed. + */ + public final static int otherObjectDigest = 2; + + ASN1Enumerated digestedObjectType; + + ASN1ObjectIdentifier otherObjectTypeID; + + AlgorithmIdentifier digestAlgorithm; + + DERBitString objectDigest; + + public static ObjectDigestInfo getInstance( + Object obj) + { + if (obj instanceof ObjectDigestInfo) + { + return (ObjectDigestInfo)obj; + } + + if (obj != null) + { + return new ObjectDigestInfo(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public static ObjectDigestInfo getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + /** + * Constructor from given details. + *
+ * If digestedObjectType
is not {@link #publicKeyCert} or
+ * {@link #publicKey} otherObjectTypeID
must be given,
+ * otherwise it is ignored.
+ *
+ * @param digestedObjectType The digest object type.
+ * @param otherObjectTypeID The object type ID for
+ * otherObjectDigest
.
+ * @param digestAlgorithm The algorithm identifier for the hash.
+ * @param objectDigest The hash value.
+ */
+ public ObjectDigestInfo(
+ int digestedObjectType,
+ ASN1ObjectIdentifier otherObjectTypeID,
+ AlgorithmIdentifier digestAlgorithm,
+ byte[] objectDigest)
+ {
+ this.digestedObjectType = new ASN1Enumerated(digestedObjectType);
+ if (digestedObjectType == otherObjectDigest)
+ {
+ this.otherObjectTypeID = otherObjectTypeID;
+ }
+
+ this.digestAlgorithm = digestAlgorithm;
+ this.objectDigest = new DERBitString(objectDigest);
+ }
+
+ private ObjectDigestInfo(
+ ASN1Sequence seq)
+ {
+ if (seq.size() > 4 || seq.size() < 3)
+ {
+ throw new IllegalArgumentException("Bad sequence size: "
+ + seq.size());
+ }
+
+ digestedObjectType = ASN1Enumerated.getInstance(seq.getObjectAt(0));
+
+ int offset = 0;
+
+ if (seq.size() == 4)
+ {
+ otherObjectTypeID = ASN1ObjectIdentifier.getInstance(seq.getObjectAt(1));
+ offset++;
+ }
+
+ digestAlgorithm = AlgorithmIdentifier.getInstance(seq.getObjectAt(1 + offset));
+
+ objectDigest = DERBitString.getInstance(seq.getObjectAt(2 + offset));
+ }
+
+ public ASN1Enumerated getDigestedObjectType()
+ {
+ return digestedObjectType;
+ }
+
+ public ASN1ObjectIdentifier getOtherObjectTypeID()
+ {
+ return otherObjectTypeID;
+ }
+
+ public AlgorithmIdentifier getDigestAlgorithm()
+ {
+ return digestAlgorithm;
+ }
+
+ public DERBitString getObjectDigest()
+ {
+ return objectDigest;
+ }
+
+ /**
+ * Produce an object suitable for an ASN1OutputStream.
+ *
+ *
+ * + * ObjectDigestInfo ::= SEQUENCE { + * digestedObjectType ENUMERATED { + * publicKey (0), + * publicKeyCert (1), + * otherObjectTypes (2) }, + * -- otherObjectTypes MUST NOT + * -- be used in this profile + * otherObjectTypeID OBJECT IDENTIFIER OPTIONAL, + * digestAlgorithm AlgorithmIdentifier, + * objectDigest BIT STRING + * } + * + *+ */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(digestedObjectType); + + if (otherObjectTypeID != null) + { + v.add(otherObjectTypeID); + } + + v.add(digestAlgorithm); + v.add(objectDigest); + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/PolicyInformation.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/PolicyInformation.java new file mode 100644 index 0000000..af724e2 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/PolicyInformation.java @@ -0,0 +1,87 @@ +package org.bc.asn1.x509; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1ObjectIdentifier; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DERSequence; + +public class PolicyInformation + extends ASN1Object +{ + private ASN1ObjectIdentifier policyIdentifier; + private ASN1Sequence policyQualifiers; + + private PolicyInformation( + ASN1Sequence seq) + { + if (seq.size() < 1 || seq.size() > 2) + { + throw new IllegalArgumentException("Bad sequence size: " + + seq.size()); + } + + policyIdentifier = ASN1ObjectIdentifier.getInstance(seq.getObjectAt(0)); + + if (seq.size() > 1) + { + policyQualifiers = ASN1Sequence.getInstance(seq.getObjectAt(1)); + } + } + + public PolicyInformation( + ASN1ObjectIdentifier policyIdentifier) + { + this.policyIdentifier = policyIdentifier; + } + + public PolicyInformation( + ASN1ObjectIdentifier policyIdentifier, + ASN1Sequence policyQualifiers) + { + this.policyIdentifier = policyIdentifier; + this.policyQualifiers = policyQualifiers; + } + + public static PolicyInformation getInstance( + Object obj) + { + if (obj == null || obj instanceof PolicyInformation) + { + return (PolicyInformation)obj; + } + + return new PolicyInformation(ASN1Sequence.getInstance(obj)); + } + + public ASN1ObjectIdentifier getPolicyIdentifier() + { + return policyIdentifier; + } + + public ASN1Sequence getPolicyQualifiers() + { + return policyQualifiers; + } + + /* + * PolicyInformation ::= SEQUENCE { + * policyIdentifier CertPolicyId, + * policyQualifiers SEQUENCE SIZE (1..MAX) OF + * PolicyQualifierInfo OPTIONAL } + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(policyIdentifier); + + if (policyQualifiers != null) + { + v.add(policyQualifiers); + } + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/PolicyMappings.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/PolicyMappings.java new file mode 100644 index 0000000..ac3fdc7 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/PolicyMappings.java @@ -0,0 +1,107 @@ +package org.bc.asn1.x509; + +import java.util.Enumeration; +import java.util.Hashtable; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1ObjectIdentifier; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DERSequence; + +/** + * PolicyMappings V3 extension, described in RFC3280. + *
+ * PolicyMappings ::= SEQUENCE SIZE (1..MAX) OF SEQUENCE { + * issuerDomainPolicy CertPolicyId, + * subjectDomainPolicy CertPolicyId } + *+ * + * @see RFC 3280, section 4.2.1.6 + */ +public class PolicyMappings + extends ASN1Object +{ + ASN1Sequence seq = null; + + public static PolicyMappings getInstance(Object obj) + { + if (obj instanceof PolicyMappings) + { + return (PolicyMappings)obj; + } + if (obj != null) + { + return new PolicyMappings(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + /** + * Creates a new
PolicyMappings
instance.
+ *
+ * @param seq an ASN1Sequence
constructed as specified
+ * in RFC 3280
+ */
+ private PolicyMappings(ASN1Sequence seq)
+ {
+ this.seq = seq;
+ }
+
+ /**
+ * Creates a new PolicyMappings
instance.
+ *
+ * @param mappings a HashMap
value that maps
+ * String
oids
+ * to other String
oids.
+ * @deprecated use CertPolicyId constructors.
+ */
+ public PolicyMappings(Hashtable mappings)
+ {
+ ASN1EncodableVector dev = new ASN1EncodableVector();
+ Enumeration it = mappings.keys();
+
+ while (it.hasMoreElements())
+ {
+ String idp = (String)it.nextElement();
+ String sdp = (String)mappings.get(idp);
+ ASN1EncodableVector dv = new ASN1EncodableVector();
+ dv.add(new ASN1ObjectIdentifier(idp));
+ dv.add(new ASN1ObjectIdentifier(sdp));
+ dev.add(new DERSequence(dv));
+ }
+
+ seq = new DERSequence(dev);
+ }
+
+ public PolicyMappings(CertPolicyId issuerDomainPolicy, CertPolicyId subjectDomainPolicy)
+ {
+ ASN1EncodableVector dv = new ASN1EncodableVector();
+ dv.add(issuerDomainPolicy);
+ dv.add(subjectDomainPolicy);
+
+ seq = new DERSequence(new DERSequence(dv));
+ }
+
+ public PolicyMappings(CertPolicyId[] issuerDomainPolicy, CertPolicyId[] subjectDomainPolicy)
+ {
+ ASN1EncodableVector dev = new ASN1EncodableVector();
+
+ for (int i = 0; i != issuerDomainPolicy.length; i++)
+ {
+ ASN1EncodableVector dv = new ASN1EncodableVector();
+ dv.add(issuerDomainPolicy[i]);
+ dv.add(subjectDomainPolicy[i]);
+ dev.add(new DERSequence(dv));
+ }
+
+ seq = new DERSequence(dev);
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+ return seq;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/PolicyQualifierId.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/PolicyQualifierId.java
new file mode 100644
index 0000000..323f0ef
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/PolicyQualifierId.java
@@ -0,0 +1,31 @@
+
+package org.bc.asn1.x509;
+
+import org.bc.asn1.ASN1ObjectIdentifier;
+
+/**
+ * PolicyQualifierId, used in the CertificatePolicies
+ * X509V3 extension.
+ *
+ * + * id-qt OBJECT IDENTIFIER ::= { id-pkix 2 } + * id-qt-cps OBJECT IDENTIFIER ::= { id-qt 1 } + * id-qt-unotice OBJECT IDENTIFIER ::= { id-qt 2 } + * PolicyQualifierId ::= + * OBJECT IDENTIFIER (id-qt-cps | id-qt-unotice) + *+ */ +public class PolicyQualifierId extends ASN1ObjectIdentifier +{ + private static final String id_qt = "1.3.6.1.5.5.7.2"; + + private PolicyQualifierId(String id) + { + super(id); + } + + public static final PolicyQualifierId id_qt_cps = + new PolicyQualifierId(id_qt + ".1"); + public static final PolicyQualifierId id_qt_unotice = + new PolicyQualifierId(id_qt + ".2"); +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/PolicyQualifierInfo.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/PolicyQualifierInfo.java new file mode 100644 index 0000000..25aa42a --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/PolicyQualifierInfo.java @@ -0,0 +1,114 @@ +package org.bc.asn1.x509; + +import org.bc.asn1.ASN1Encodable; +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1ObjectIdentifier; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DERIA5String; +import org.bc.asn1.DERSequence; + +/** + * Policy qualifiers, used in the X509V3 CertificatePolicies + * extension. + * + *
+ * PolicyQualifierInfo ::= SEQUENCE { + * policyQualifierId PolicyQualifierId, + * qualifier ANY DEFINED BY policyQualifierId } + *+ */ +public class PolicyQualifierInfo + extends ASN1Object +{ + private ASN1ObjectIdentifier policyQualifierId; + private ASN1Encodable qualifier; + + /** + * Creates a new
PolicyQualifierInfo
instance.
+ *
+ * @param policyQualifierId a PolicyQualifierId
value
+ * @param qualifier the qualifier, defined by the above field.
+ */
+ public PolicyQualifierInfo(
+ ASN1ObjectIdentifier policyQualifierId,
+ ASN1Encodable qualifier)
+ {
+ this.policyQualifierId = policyQualifierId;
+ this.qualifier = qualifier;
+ }
+
+ /**
+ * Creates a new PolicyQualifierInfo
containing a
+ * cPSuri qualifier.
+ *
+ * @param cps the CPS (certification practice statement) uri as a
+ * String
.
+ */
+ public PolicyQualifierInfo(
+ String cps)
+ {
+ policyQualifierId = PolicyQualifierId.id_qt_cps;
+ qualifier = new DERIA5String (cps);
+ }
+
+ /**
+ * Creates a new PolicyQualifierInfo
instance.
+ *
+ * @param as PolicyQualifierInfo
X509 structure
+ * encoded as an ASN1Sequence.
+ */
+ public PolicyQualifierInfo(
+ ASN1Sequence as)
+ {
+ if (as.size() != 2)
+ {
+ throw new IllegalArgumentException("Bad sequence size: "
+ + as.size());
+ }
+
+ policyQualifierId = ASN1ObjectIdentifier.getInstance(as.getObjectAt(0));
+ qualifier = as.getObjectAt(1);
+ }
+
+ public static PolicyQualifierInfo getInstance(
+ Object obj)
+ {
+ if (obj instanceof PolicyQualifierInfo)
+ {
+ return (PolicyQualifierInfo)obj;
+ }
+ else if (obj != null)
+ {
+ return new PolicyQualifierInfo(ASN1Sequence.getInstance(obj));
+ }
+
+ return null;
+ }
+
+
+ public ASN1ObjectIdentifier getPolicyQualifierId()
+ {
+ return policyQualifierId;
+ }
+
+ public ASN1Encodable getQualifier()
+ {
+ return qualifier;
+ }
+
+ /**
+ * Returns a DER-encodable representation of this instance.
+ *
+ * @return a ASN1Primitive
value
+ */
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector dev = new ASN1EncodableVector();
+ dev.add(policyQualifierId);
+ dev.add(qualifier);
+
+ return new DERSequence(dev);
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/PrivateKeyUsagePeriod.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/PrivateKeyUsagePeriod.java
new file mode 100644
index 0000000..66511f7
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/PrivateKeyUsagePeriod.java
@@ -0,0 +1,84 @@
+package org.bc.asn1.x509;
+
+import java.util.Enumeration;
+
+import org.bc.asn1.ASN1EncodableVector;
+import org.bc.asn1.ASN1Object;
+import org.bc.asn1.ASN1Primitive;
+import org.bc.asn1.ASN1Sequence;
+import org.bc.asn1.ASN1TaggedObject;
+import org.bc.asn1.DERGeneralizedTime;
+import org.bc.asn1.DERSequence;
+import org.bc.asn1.DERTaggedObject;
+
+/**
+ * + * PrivateKeyUsagePeriod ::= SEQUENCE { + * notBefore [0] GeneralizedTime OPTIONAL, + * notAfter [1] GeneralizedTime OPTIONAL } + *+ */ +public class PrivateKeyUsagePeriod + extends ASN1Object +{ + public static PrivateKeyUsagePeriod getInstance(Object obj) + { + if (obj instanceof PrivateKeyUsagePeriod) + { + return (PrivateKeyUsagePeriod)obj; + } + + if (obj != null) + { + return new PrivateKeyUsagePeriod(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + private DERGeneralizedTime _notBefore, _notAfter; + + private PrivateKeyUsagePeriod(ASN1Sequence seq) + { + Enumeration en = seq.getObjects(); + while (en.hasMoreElements()) + { + ASN1TaggedObject tObj = (ASN1TaggedObject)en.nextElement(); + + if (tObj.getTagNo() == 0) + { + _notBefore = DERGeneralizedTime.getInstance(tObj, false); + } + else if (tObj.getTagNo() == 1) + { + _notAfter = DERGeneralizedTime.getInstance(tObj, false); + } + } + } + + public DERGeneralizedTime getNotBefore() + { + return _notBefore; + } + + public DERGeneralizedTime getNotAfter() + { + return _notAfter; + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + if (_notBefore != null) + { + v.add(new DERTaggedObject(false, 0, _notBefore)); + } + if (_notAfter != null) + { + v.add(new DERTaggedObject(false, 1, _notAfter)); + } + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/RSAPublicKeyStructure.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/RSAPublicKeyStructure.java new file mode 100644 index 0000000..488dad7 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/RSAPublicKeyStructure.java @@ -0,0 +1,98 @@ +package org.bc.asn1.x509; + +import java.math.BigInteger; +import java.util.Enumeration; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERSequence; + +/** + * @deprecated use org.bouncycastle.asn1.pkcs.RSAPublicKey + */ +public class RSAPublicKeyStructure + extends ASN1Object +{ + private BigInteger modulus; + private BigInteger publicExponent; + + public static RSAPublicKeyStructure getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static RSAPublicKeyStructure getInstance( + Object obj) + { + if(obj == null || obj instanceof RSAPublicKeyStructure) + { + return (RSAPublicKeyStructure)obj; + } + + if(obj instanceof ASN1Sequence) + { + return new RSAPublicKeyStructure((ASN1Sequence)obj); + } + + throw new IllegalArgumentException("Invalid RSAPublicKeyStructure: " + obj.getClass().getName()); + } + + public RSAPublicKeyStructure( + BigInteger modulus, + BigInteger publicExponent) + { + this.modulus = modulus; + this.publicExponent = publicExponent; + } + + public RSAPublicKeyStructure( + ASN1Sequence seq) + { + if (seq.size() != 2) + { + throw new IllegalArgumentException("Bad sequence size: " + + seq.size()); + } + + Enumeration e = seq.getObjects(); + + modulus = ASN1Integer.getInstance(e.nextElement()).getPositiveValue(); + publicExponent = ASN1Integer.getInstance(e.nextElement()).getPositiveValue(); + } + + public BigInteger getModulus() + { + return modulus; + } + + public BigInteger getPublicExponent() + { + return publicExponent; + } + + /** + * This outputs the key in PKCS1v2 format. + *
+ * RSAPublicKey ::= SEQUENCE { + * modulus INTEGER, -- n + * publicExponent INTEGER, -- e + * } + *+ *
+ */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(new ASN1Integer(getModulus())); + v.add(new ASN1Integer(getPublicExponent())); + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/ReasonFlags.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/ReasonFlags.java new file mode 100644 index 0000000..36bdc0b --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/ReasonFlags.java @@ -0,0 +1,85 @@ +package org.bc.asn1.x509; + +import org.bc.asn1.DERBitString; + +/** + * The ReasonFlags object. + *
+ * ReasonFlags ::= BIT STRING { + * unused (0), + * keyCompromise (1), + * cACompromise (2), + * affiliationChanged (3), + * superseded (4), + * cessationOfOperation (5), + * certificateHold (6), + * privilegeWithdrawn (7), + * aACompromise (8) } + *+ */ +public class ReasonFlags + extends DERBitString +{ + /** + * @deprecated use lower case version + */ + public static final int UNUSED = (1 << 7); + /** + * @deprecated use lower case version + */ + public static final int KEY_COMPROMISE = (1 << 6); + /** + * @deprecated use lower case version + */ + public static final int CA_COMPROMISE = (1 << 5); + /** + * @deprecated use lower case version + */ + public static final int AFFILIATION_CHANGED = (1 << 4); + /** + * @deprecated use lower case version + */ + public static final int SUPERSEDED = (1 << 3); + /** + * @deprecated use lower case version + */ + public static final int CESSATION_OF_OPERATION = (1 << 2); + /** + * @deprecated use lower case version + */ + public static final int CERTIFICATE_HOLD = (1 << 1); + /** + * @deprecated use lower case version + */ + public static final int PRIVILEGE_WITHDRAWN = (1 << 0); + /** + * @deprecated use lower case version + */ + public static final int AA_COMPROMISE = (1 << 15); + + public static final int unused = (1 << 7); + public static final int keyCompromise = (1 << 6); + public static final int cACompromise = (1 << 5); + public static final int affiliationChanged = (1 << 4); + public static final int superseded = (1 << 3); + public static final int cessationOfOperation = (1 << 2); + public static final int certificateHold = (1 << 1); + public static final int privilegeWithdrawn = (1 << 0); + public static final int aACompromise = (1 << 15); + + /** + * @param reasons - the bitwise OR of the Key Reason flags giving the + * allowed uses for the key. + */ + public ReasonFlags( + int reasons) + { + super(getBytes(reasons), getPadBits(reasons)); + } + + public ReasonFlags( + DERBitString reasons) + { + super(reasons.getBytes(), reasons.getPadBits()); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/RoleSyntax.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/RoleSyntax.java new file mode 100644 index 0000000..71c1202 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/RoleSyntax.java @@ -0,0 +1,237 @@ +package org.bc.asn1.x509; + +import org.bc.asn1.ASN1Encodable; +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1String; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERSequence; +import org.bc.asn1.DERTaggedObject; + +/** + * Implementation of the RoleSyntax object as specified by the RFC3281. + * + *
+ * RoleSyntax ::= SEQUENCE { + * roleAuthority [0] GeneralNames OPTIONAL, + * roleName [1] GeneralName + * } + *+ */ +public class RoleSyntax + extends ASN1Object +{ + private GeneralNames roleAuthority; + private GeneralName roleName; + + /** + * RoleSyntax factory method. + * @param obj the object used to construct an instance of
+ * RoleSyntax
. It must be an instance of RoleSyntax
+ *
or ASN1Sequence
.
+ * @return the instance of RoleSyntax
built from the
+ * supplied object.
+ * @throws java.lang.IllegalArgumentException if the object passed
+ * to the factory is not an instance of RoleSyntax
or
+ * ASN1Sequence
.
+ */
+ public static RoleSyntax getInstance(
+ Object obj)
+ {
+
+ if (obj instanceof RoleSyntax)
+ {
+ return (RoleSyntax)obj;
+ }
+ else if (obj != null)
+ {
+ return new RoleSyntax(ASN1Sequence.getInstance(obj));
+ }
+
+ return null;
+ }
+
+ /**
+ * Constructor.
+ * @param roleAuthority the role authority of this RoleSyntax.
+ * @param roleName the role name of this RoleSyntax.
+ */
+ public RoleSyntax(
+ GeneralNames roleAuthority,
+ GeneralName roleName)
+ {
+ if(roleName == null ||
+ roleName.getTagNo() != GeneralName.uniformResourceIdentifier ||
+ ((ASN1String)roleName.getName()).getString().equals(""))
+ {
+ throw new IllegalArgumentException("the role name MUST be non empty and MUST " +
+ "use the URI option of GeneralName");
+ }
+ this.roleAuthority = roleAuthority;
+ this.roleName = roleName;
+ }
+
+ /**
+ * Constructor. Invoking this constructor is the same as invoking
+ * new RoleSyntax(null, roleName)
.
+ * @param roleName the role name of this RoleSyntax.
+ */
+ public RoleSyntax(
+ GeneralName roleName)
+ {
+ this(null, roleName);
+ }
+
+ /**
+ * Utility constructor. Takes a String
argument representing
+ * the role name, builds a GeneralName
to hold the role name
+ * and calls the constructor that takes a GeneralName
.
+ * @param roleName
+ */
+ public RoleSyntax(
+ String roleName)
+ {
+ this(new GeneralName(GeneralName.uniformResourceIdentifier,
+ (roleName == null)? "": roleName));
+ }
+
+ /**
+ * Constructor that builds an instance of RoleSyntax
by
+ * extracting the encoded elements from the ASN1Sequence
+ * object supplied.
+ * @param seq an instance of ASN1Sequence
that holds
+ * the encoded elements used to build this RoleSyntax
.
+ */
+ private RoleSyntax(
+ ASN1Sequence seq)
+ {
+ if (seq.size() < 1 || seq.size() > 2)
+ {
+ throw new IllegalArgumentException("Bad sequence size: "
+ + seq.size());
+ }
+
+ for (int i = 0; i != seq.size(); i++)
+ {
+ ASN1TaggedObject taggedObject = ASN1TaggedObject.getInstance(seq.getObjectAt(i));
+ switch (taggedObject.getTagNo())
+ {
+ case 0:
+ roleAuthority = GeneralNames.getInstance(taggedObject, false);
+ break;
+ case 1:
+ roleName = GeneralName.getInstance(taggedObject, true);
+ break;
+ default:
+ throw new IllegalArgumentException("Unknown tag in RoleSyntax");
+ }
+ }
+ }
+
+ /**
+ * Gets the role authority of this RoleSyntax.
+ * @return an instance of GeneralNames
holding the
+ * role authority of this RoleSyntax.
+ */
+ public GeneralNames getRoleAuthority()
+ {
+ return this.roleAuthority;
+ }
+
+ /**
+ * Gets the role name of this RoleSyntax.
+ * @return an instance of GeneralName
holding the
+ * role name of this RoleSyntax.
+ */
+ public GeneralName getRoleName()
+ {
+ return this.roleName;
+ }
+
+ /**
+ * Gets the role name as a java.lang.String
object.
+ * @return the role name of this RoleSyntax represented as a
+ * java.lang.String
object.
+ */
+ public String getRoleNameAsString()
+ {
+ ASN1String str = (ASN1String)this.roleName.getName();
+
+ return str.getString();
+ }
+
+ /**
+ * Gets the role authority as a String[]
object.
+ * @return the role authority of this RoleSyntax represented as a
+ * String[]
array.
+ */
+ public String[] getRoleAuthorityAsString()
+ {
+ if(roleAuthority == null)
+ {
+ return new String[0];
+ }
+
+ GeneralName[] names = roleAuthority.getNames();
+ String[] namesString = new String[names.length];
+ for(int i = 0; i < names.length; i++)
+ {
+ ASN1Encodable value = names[i].getName();
+ if(value instanceof ASN1String)
+ {
+ namesString[i] = ((ASN1String)value).getString();
+ }
+ else
+ {
+ namesString[i] = value.toString();
+ }
+ }
+ return namesString;
+ }
+
+ /**
+ * Implementation of the method toASN1Object
as
+ * required by the superclass ASN1Encodable
.
+ *
+ * + * RoleSyntax ::= SEQUENCE { + * roleAuthority [0] GeneralNames OPTIONAL, + * roleName [1] GeneralName + * } + *+ */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + if(this.roleAuthority != null) + { + v.add(new DERTaggedObject(false, 0, roleAuthority)); + } + v.add(new DERTaggedObject(true, 1, roleName)); + + return new DERSequence(v); + } + + public String toString() + { + StringBuffer buff = new StringBuffer("Name: " + this.getRoleNameAsString() + + " - Auth: "); + if(this.roleAuthority == null || roleAuthority.getNames().length == 0) + { + buff.append("N/A"); + } + else + { + String[] names = this.getRoleAuthorityAsString(); + buff.append('[').append(names[0]); + for(int i = 1; i < names.length; i++) + { + buff.append(", ").append(names[i]); + } + buff.append(']'); + } + return buff.toString(); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/SubjectDirectoryAttributes.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/SubjectDirectoryAttributes.java new file mode 100644 index 0000000..2fe1bb4 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/SubjectDirectoryAttributes.java @@ -0,0 +1,144 @@ +package org.bc.asn1.x509; + +import java.util.Enumeration; +import java.util.Vector; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DERSequence; + +/** + * This extension may contain further X.500 attributes of the subject. See also + * RFC 3039. + * + *
+ * SubjectDirectoryAttributes ::= Attributes + * Attributes ::= SEQUENCE SIZE (1..MAX) OF Attribute + * Attribute ::= SEQUENCE + * { + * type AttributeType + * values SET OF AttributeValue + * } + * + * AttributeType ::= OBJECT IDENTIFIER + * AttributeValue ::= ANY DEFINED BY AttributeType + *+ * + * @see org.bc.asn1.x500.style.BCStyle for AttributeType ObjectIdentifiers. + */ +public class SubjectDirectoryAttributes + extends ASN1Object +{ + private Vector attributes = new Vector(); + + public static SubjectDirectoryAttributes getInstance( + Object obj) + { + if (obj instanceof SubjectDirectoryAttributes) + { + return (SubjectDirectoryAttributes)obj; + } + + if (obj != null) + { + return new SubjectDirectoryAttributes(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + /** + * Constructor from ASN1Sequence. + * + * The sequence is of type SubjectDirectoryAttributes: + * + *
+ * SubjectDirectoryAttributes ::= Attributes + * Attributes ::= SEQUENCE SIZE (1..MAX) OF Attribute + * Attribute ::= SEQUENCE + * { + * type AttributeType + * values SET OF AttributeValue + * } + * + * AttributeType ::= OBJECT IDENTIFIER + * AttributeValue ::= ANY DEFINED BY AttributeType + *+ * + * @param seq + * The ASN.1 sequence. + */ + private SubjectDirectoryAttributes(ASN1Sequence seq) + { + Enumeration e = seq.getObjects(); + + while (e.hasMoreElements()) + { + ASN1Sequence s = ASN1Sequence.getInstance(e.nextElement()); + attributes.addElement(Attribute.getInstance(s)); + } + } + + /** + * Constructor from a vector of attributes. + * + * The vector consists of attributes of type {@link Attribute Attribute} + * + * @param attributes + * The attributes. + * + */ + public SubjectDirectoryAttributes(Vector attributes) + { + Enumeration e = attributes.elements(); + + while (e.hasMoreElements()) + { + this.attributes.addElement(e.nextElement()); + } + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * + * Returns: + * + *
+ * SubjectDirectoryAttributes ::= Attributes + * Attributes ::= SEQUENCE SIZE (1..MAX) OF Attribute + * Attribute ::= SEQUENCE + * { + * type AttributeType + * values SET OF AttributeValue + * } + * + * AttributeType ::= OBJECT IDENTIFIER + * AttributeValue ::= ANY DEFINED BY AttributeType + *+ * + * @return a ASN1Primitive + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector vec = new ASN1EncodableVector(); + Enumeration e = attributes.elements(); + + while (e.hasMoreElements()) + { + + vec.add((Attribute)e.nextElement()); + } + + return new DERSequence(vec); + } + + /** + * @return Returns the attributes. + */ + public Vector getAttributes() + { + return attributes; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/SubjectKeyIdentifier.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/SubjectKeyIdentifier.java new file mode 100644 index 0000000..19d3676 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/SubjectKeyIdentifier.java @@ -0,0 +1,135 @@ +package org.bc.asn1.x509; + +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1OctetString; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DEROctetString; +import org.bc.crypto.Digest; +import org.bc.crypto.digests.SHA1Digest; + +/** + * The SubjectKeyIdentifier object. + *
+ * SubjectKeyIdentifier::= OCTET STRING + *+ */ +public class SubjectKeyIdentifier + extends ASN1Object +{ + private byte[] keyidentifier; + + public static SubjectKeyIdentifier getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1OctetString.getInstance(obj, explicit)); + } + + public static SubjectKeyIdentifier getInstance( + Object obj) + { + if (obj instanceof SubjectKeyIdentifier) + { + return (SubjectKeyIdentifier)obj; + } + else if (obj != null) + { + return new SubjectKeyIdentifier(ASN1OctetString.getInstance(obj)); + } + + return null; + } + + public static SubjectKeyIdentifier fromExtensions(Extensions extensions) + { + return SubjectKeyIdentifier.getInstance(extensions.getExtensionParsedValue(Extension.subjectKeyIdentifier)); + } + + public SubjectKeyIdentifier( + byte[] keyid) + { + this.keyidentifier = keyid; + } + + protected SubjectKeyIdentifier( + ASN1OctetString keyid) + { + this.keyidentifier = keyid.getOctets(); + } + + public byte[] getKeyIdentifier() + { + return keyidentifier; + } + + public ASN1Primitive toASN1Primitive() + { + return new DEROctetString(keyidentifier); + } + + + /** + * Calculates the keyidentifier using a SHA1 hash over the BIT STRING + * from SubjectPublicKeyInfo as defined in RFC3280. + * + * @param spki the subject public key info. + * @deprecated + */ + public SubjectKeyIdentifier( + SubjectPublicKeyInfo spki) + { + this.keyidentifier = getDigest(spki); + } + + /** + * Return a RFC 3280 type 1 key identifier. As in: + *
+ * (1) The keyIdentifier is composed of the 160-bit SHA-1 hash of the + * value of the BIT STRING subjectPublicKey (excluding the tag, + * length, and number of unused bits). + *+ * @param keyInfo the key info object containing the subjectPublicKey field. + * @return the key identifier. + * @deprecated use org.bouncycastle.cert.X509ExtensionUtils.createSubjectKeyIdentifier + */ + public static SubjectKeyIdentifier createSHA1KeyIdentifier(SubjectPublicKeyInfo keyInfo) + { + return new SubjectKeyIdentifier(keyInfo); + } + + /** + * Return a RFC 3280 type 2 key identifier. As in: + *
+ * (2) The keyIdentifier is composed of a four bit type field with + * the value 0100 followed by the least significant 60 bits of the + * SHA-1 hash of the value of the BIT STRING subjectPublicKey. + *+ * @param keyInfo the key info object containing the subjectPublicKey field. + * @return the key identifier. + * @deprecated use org.bouncycastle.cert.X509ExtensionUtils.createTruncatedSubjectKeyIdentifier + */ + public static SubjectKeyIdentifier createTruncatedSHA1KeyIdentifier(SubjectPublicKeyInfo keyInfo) + { + byte[] dig = getDigest(keyInfo); + byte[] id = new byte[8]; + + System.arraycopy(dig, dig.length - 8, id, 0, id.length); + + id[0] &= 0x0f; + id[0] |= 0x40; + + return new SubjectKeyIdentifier(id); + } + + private static byte[] getDigest(SubjectPublicKeyInfo spki) + { + Digest digest = new SHA1Digest(); + byte[] resBuf = new byte[digest.getDigestSize()]; + + byte[] bytes = spki.getPublicKeyData().getBytes(); + digest.update(bytes, 0, bytes.length); + digest.doFinal(resBuf, 0); + return resBuf; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/SubjectPublicKeyInfo.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/SubjectPublicKeyInfo.java new file mode 100644 index 0000000..98ed68a --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/SubjectPublicKeyInfo.java @@ -0,0 +1,156 @@ +package org.bc.asn1.x509; + +import java.io.IOException; +import java.util.Enumeration; + +import org.bc.asn1.ASN1Encodable; +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1InputStream; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERBitString; +import org.bc.asn1.DERSequence; + +/** + * The object that contains the public key stored in a certficate. + *
+ * The getEncoded() method in the public keys in the JCE produces a DER + * encoded one of these. + */ +public class SubjectPublicKeyInfo + extends ASN1Object +{ + private AlgorithmIdentifier algId; + private DERBitString keyData; + + public static SubjectPublicKeyInfo getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static SubjectPublicKeyInfo getInstance( + Object obj) + { + if (obj instanceof SubjectPublicKeyInfo) + { + return (SubjectPublicKeyInfo)obj; + } + else if (obj != null) + { + return new SubjectPublicKeyInfo(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public SubjectPublicKeyInfo( + AlgorithmIdentifier algId, + ASN1Encodable publicKey) + throws IOException + { + this.keyData = new DERBitString(publicKey); + this.algId = algId; + } + + public SubjectPublicKeyInfo( + AlgorithmIdentifier algId, + byte[] publicKey) + { + this.keyData = new DERBitString(publicKey); + this.algId = algId; + } + + public SubjectPublicKeyInfo( + ASN1Sequence seq) + { + if (seq.size() != 2) + { + throw new IllegalArgumentException("Bad sequence size: " + + seq.size()); + } + + Enumeration e = seq.getObjects(); + + this.algId = AlgorithmIdentifier.getInstance(e.nextElement()); + this.keyData = DERBitString.getInstance(e.nextElement()); + } + + public AlgorithmIdentifier getAlgorithm() + { + return algId; + } + + /** + * @deprecated use getAlgorithm() + * @return alg ID. + */ + public AlgorithmIdentifier getAlgorithmId() + { + return algId; + } + + /** + * for when the public key is an encoded object - if the bitstring + * can't be decoded this routine throws an IOException. + * + * @exception IOException - if the bit string doesn't represent a DER + * encoded object. + * @return the public key as an ASN.1 primitive. + */ + public ASN1Primitive parsePublicKey() + throws IOException + { + ASN1InputStream aIn = new ASN1InputStream(keyData.getBytes()); + + return aIn.readObject(); + } + + /** + * for when the public key is an encoded object - if the bitstring + * can't be decoded this routine throws an IOException. + * + * @exception IOException - if the bit string doesn't represent a DER + * encoded object. + * @deprecated use parsePublicKey + * @return the public key as an ASN.1 primitive. + */ + public ASN1Primitive getPublicKey() + throws IOException + { + ASN1InputStream aIn = new ASN1InputStream(keyData.getBytes()); + + return aIn.readObject(); + } + + /** + * for when the public key is raw bits. + * + * @return the public key as the raw bit string... + */ + public DERBitString getPublicKeyData() + { + return keyData; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + *
+ * SubjectPublicKeyInfo ::= SEQUENCE { + * algorithm AlgorithmIdentifier, + * publicKey BIT STRING } + *+ */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(algId); + v.add(keyData); + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/TBSCertList.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/TBSCertList.java new file mode 100644 index 0000000..d6dffa0 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/TBSCertList.java @@ -0,0 +1,309 @@ +package org.bc.asn1.x509; + +import java.util.Enumeration; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERGeneralizedTime; +import org.bc.asn1.DERSequence; +import org.bc.asn1.DERTaggedObject; +import org.bc.asn1.DERUTCTime; +import org.bc.asn1.x500.X500Name; + +/** + * PKIX RFC-2459 - TBSCertList object. + *
+ * TBSCertList ::= SEQUENCE { + * version Version OPTIONAL, + * -- if present, shall be v2 + * signature AlgorithmIdentifier, + * issuer Name, + * thisUpdate Time, + * nextUpdate Time OPTIONAL, + * revokedCertificates SEQUENCE OF SEQUENCE { + * userCertificate CertificateSerialNumber, + * revocationDate Time, + * crlEntryExtensions Extensions OPTIONAL + * -- if present, shall be v2 + * } OPTIONAL, + * crlExtensions [0] EXPLICIT Extensions OPTIONAL + * -- if present, shall be v2 + * } + *+ */ +public class TBSCertList + extends ASN1Object +{ + public static class CRLEntry + extends ASN1Object + { + ASN1Sequence seq; + + Extensions crlEntryExtensions; + + private CRLEntry( + ASN1Sequence seq) + { + if (seq.size() < 2 || seq.size() > 3) + { + throw new IllegalArgumentException("Bad sequence size: " + seq.size()); + } + + this.seq = seq; + } + + public static CRLEntry getInstance(Object o) + { + if (o instanceof CRLEntry) + { + return ((CRLEntry)o); + } + else if (o != null) + { + return new CRLEntry(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public ASN1Integer getUserCertificate() + { + return ASN1Integer.getInstance(seq.getObjectAt(0)); + } + + public Time getRevocationDate() + { + return Time.getInstance(seq.getObjectAt(1)); + } + + public Extensions getExtensions() + { + if (crlEntryExtensions == null && seq.size() == 3) + { + crlEntryExtensions = Extensions.getInstance(seq.getObjectAt(2)); + } + + return crlEntryExtensions; + } + + public ASN1Primitive toASN1Primitive() + { + return seq; + } + + public boolean hasExtensions() + { + return seq.size() == 3; + } + } + + private class RevokedCertificatesEnumeration + implements Enumeration + { + private final Enumeration en; + + RevokedCertificatesEnumeration(Enumeration en) + { + this.en = en; + } + + public boolean hasMoreElements() + { + return en.hasMoreElements(); + } + + public Object nextElement() + { + return CRLEntry.getInstance(en.nextElement()); + } + } + + private class EmptyEnumeration + implements Enumeration + { + public boolean hasMoreElements() + { + return false; + } + + public Object nextElement() + { + return null; // TODO: check exception handling + } + } + + ASN1Integer version; + AlgorithmIdentifier signature; + X500Name issuer; + Time thisUpdate; + Time nextUpdate; + ASN1Sequence revokedCertificates; + Extensions crlExtensions; + + public static TBSCertList getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static TBSCertList getInstance( + Object obj) + { + if (obj instanceof TBSCertList) + { + return (TBSCertList)obj; + } + else if (obj != null) + { + return new TBSCertList(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public TBSCertList( + ASN1Sequence seq) + { + if (seq.size() < 3 || seq.size() > 7) + { + throw new IllegalArgumentException("Bad sequence size: " + seq.size()); + } + + int seqPos = 0; + + if (seq.getObjectAt(seqPos) instanceof ASN1Integer) + { + version = ASN1Integer.getInstance(seq.getObjectAt(seqPos++)); + } + else + { + version = null; // version is optional + } + + signature = AlgorithmIdentifier.getInstance(seq.getObjectAt(seqPos++)); + issuer = X500Name.getInstance(seq.getObjectAt(seqPos++)); + thisUpdate = Time.getInstance(seq.getObjectAt(seqPos++)); + + if (seqPos < seq.size() + && (seq.getObjectAt(seqPos) instanceof DERUTCTime + || seq.getObjectAt(seqPos) instanceof DERGeneralizedTime + || seq.getObjectAt(seqPos) instanceof Time)) + { + nextUpdate = Time.getInstance(seq.getObjectAt(seqPos++)); + } + + if (seqPos < seq.size() + && !(seq.getObjectAt(seqPos) instanceof DERTaggedObject)) + { + revokedCertificates = ASN1Sequence.getInstance(seq.getObjectAt(seqPos++)); + } + + if (seqPos < seq.size() + && seq.getObjectAt(seqPos) instanceof DERTaggedObject) + { + crlExtensions = Extensions.getInstance(ASN1Sequence.getInstance((ASN1TaggedObject)seq.getObjectAt(seqPos), true)); + } + } + + public int getVersionNumber() + { + if (version == null) + { + return 1; + } + return version.getValue().intValue() + 1; + } + + public ASN1Integer getVersion() + { + return version; + } + + public AlgorithmIdentifier getSignature() + { + return signature; + } + + public X500Name getIssuer() + { + return issuer; + } + + public Time getThisUpdate() + { + return thisUpdate; + } + + public Time getNextUpdate() + { + return nextUpdate; + } + + public CRLEntry[] getRevokedCertificates() + { + if (revokedCertificates == null) + { + return new CRLEntry[0]; + } + + CRLEntry[] entries = new CRLEntry[revokedCertificates.size()]; + + for (int i = 0; i < entries.length; i++) + { + entries[i] = CRLEntry.getInstance(revokedCertificates.getObjectAt(i)); + } + + return entries; + } + + public Enumeration getRevokedCertificateEnumeration() + { + if (revokedCertificates == null) + { + return new EmptyEnumeration(); + } + + return new RevokedCertificatesEnumeration(revokedCertificates.getObjects()); + } + + public Extensions getExtensions() + { + return crlExtensions; + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + if (version != null) + { + v.add(version); + } + v.add(signature); + v.add(issuer); + + v.add(thisUpdate); + if (nextUpdate != null) + { + v.add(nextUpdate); + } + + // Add CRLEntries if they exist + if (revokedCertificates != null) + { + v.add(revokedCertificates); + } + + if (crlExtensions != null) + { + v.add(new DERTaggedObject(0, crlExtensions)); + } + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/TBSCertificate.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/TBSCertificate.java new file mode 100644 index 0000000..3d09fdc --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/TBSCertificate.java @@ -0,0 +1,192 @@ +package org.bc.asn1.x509; + +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERBitString; +import org.bc.asn1.DERTaggedObject; +import org.bc.asn1.x500.X500Name; + +/** + * The TBSCertificate object. + *
+ * TBSCertificate ::= SEQUENCE { + * version [ 0 ] Version DEFAULT v1(0), + * serialNumber CertificateSerialNumber, + * signature AlgorithmIdentifier, + * issuer Name, + * validity Validity, + * subject Name, + * subjectPublicKeyInfo SubjectPublicKeyInfo, + * issuerUniqueID [ 1 ] IMPLICIT UniqueIdentifier OPTIONAL, + * subjectUniqueID [ 2 ] IMPLICIT UniqueIdentifier OPTIONAL, + * extensions [ 3 ] Extensions OPTIONAL + * } + *+ *
+ * Note: issuerUniqueID and subjectUniqueID are both deprecated by the IETF. This class + * will parse them, but you really shouldn't be creating new ones. + */ +public class TBSCertificate + extends ASN1Object +{ + ASN1Sequence seq; + + ASN1Integer version; + ASN1Integer serialNumber; + AlgorithmIdentifier signature; + X500Name issuer; + Time startDate, endDate; + X500Name subject; + SubjectPublicKeyInfo subjectPublicKeyInfo; + DERBitString issuerUniqueId; + DERBitString subjectUniqueId; + Extensions extensions; + + public static TBSCertificate getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static TBSCertificate getInstance( + Object obj) + { + if (obj instanceof TBSCertificate) + { + return (TBSCertificate)obj; + } + else if (obj != null) + { + return new TBSCertificate(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + private TBSCertificate( + ASN1Sequence seq) + { + int seqStart = 0; + + this.seq = seq; + + // + // some certficates don't include a version number - we assume v1 + // + if (seq.getObjectAt(0) instanceof DERTaggedObject) + { + version = ASN1Integer.getInstance((ASN1TaggedObject)seq.getObjectAt(0), true); + } + else + { + seqStart = -1; // field 0 is missing! + version = new ASN1Integer(0); + } + + serialNumber = ASN1Integer.getInstance(seq.getObjectAt(seqStart + 1)); + + signature = AlgorithmIdentifier.getInstance(seq.getObjectAt(seqStart + 2)); + issuer = X500Name.getInstance(seq.getObjectAt(seqStart + 3)); + + // + // before and after dates + // + ASN1Sequence dates = (ASN1Sequence)seq.getObjectAt(seqStart + 4); + + startDate = Time.getInstance(dates.getObjectAt(0)); + endDate = Time.getInstance(dates.getObjectAt(1)); + + subject = X500Name.getInstance(seq.getObjectAt(seqStart + 5)); + + // + // public key info. + // + subjectPublicKeyInfo = SubjectPublicKeyInfo.getInstance(seq.getObjectAt(seqStart + 6)); + + for (int extras = seq.size() - (seqStart + 6) - 1; extras > 0; extras--) + { + DERTaggedObject extra = (DERTaggedObject)seq.getObjectAt(seqStart + 6 + extras); + + switch (extra.getTagNo()) + { + case 1: + issuerUniqueId = DERBitString.getInstance(extra, false); + break; + case 2: + subjectUniqueId = DERBitString.getInstance(extra, false); + break; + case 3: + extensions = Extensions.getInstance(ASN1Sequence.getInstance(extra, true)); + } + } + } + + public int getVersionNumber() + { + return version.getValue().intValue() + 1; + } + + public ASN1Integer getVersion() + { + return version; + } + + public ASN1Integer getSerialNumber() + { + return serialNumber; + } + + public AlgorithmIdentifier getSignature() + { + return signature; + } + + public X500Name getIssuer() + { + return issuer; + } + + public Time getStartDate() + { + return startDate; + } + + public Time getEndDate() + { + return endDate; + } + + public X500Name getSubject() + { + return subject; + } + + public SubjectPublicKeyInfo getSubjectPublicKeyInfo() + { + return subjectPublicKeyInfo; + } + + public DERBitString getIssuerUniqueId() + { + return issuerUniqueId; + } + + public DERBitString getSubjectUniqueId() + { + return subjectUniqueId; + } + + public Extensions getExtensions() + { + return extensions; + } + + public ASN1Primitive toASN1Primitive() + { + return seq; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/TBSCertificateStructure.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/TBSCertificateStructure.java new file mode 100644 index 0000000..50cfec3 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/TBSCertificateStructure.java @@ -0,0 +1,194 @@ +package org.bc.asn1.x509; + +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERBitString; +import org.bc.asn1.DERTaggedObject; +import org.bc.asn1.pkcs.PKCSObjectIdentifiers; +import org.bc.asn1.x500.X500Name; + +/** + * The TBSCertificate object. + *
+ * TBSCertificate ::= SEQUENCE { + * version [ 0 ] Version DEFAULT v1(0), + * serialNumber CertificateSerialNumber, + * signature AlgorithmIdentifier, + * issuer Name, + * validity Validity, + * subject Name, + * subjectPublicKeyInfo SubjectPublicKeyInfo, + * issuerUniqueID [ 1 ] IMPLICIT UniqueIdentifier OPTIONAL, + * subjectUniqueID [ 2 ] IMPLICIT UniqueIdentifier OPTIONAL, + * extensions [ 3 ] Extensions OPTIONAL + * } + *+ *
+ * Note: issuerUniqueID and subjectUniqueID are both deprecated by the IETF. This class + * will parse them, but you really shouldn't be creating new ones. + */ +public class TBSCertificateStructure + extends ASN1Object + implements X509ObjectIdentifiers, PKCSObjectIdentifiers +{ + ASN1Sequence seq; + + ASN1Integer version; + ASN1Integer serialNumber; + AlgorithmIdentifier signature; + X500Name issuer; + Time startDate, endDate; + X500Name subject; + SubjectPublicKeyInfo subjectPublicKeyInfo; + DERBitString issuerUniqueId; + DERBitString subjectUniqueId; + X509Extensions extensions; + + public static TBSCertificateStructure getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static TBSCertificateStructure getInstance( + Object obj) + { + if (obj instanceof TBSCertificateStructure) + { + return (TBSCertificateStructure)obj; + } + else if (obj != null) + { + return new TBSCertificateStructure(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public TBSCertificateStructure( + ASN1Sequence seq) + { + int seqStart = 0; + + this.seq = seq; + + // + // some certficates don't include a version number - we assume v1 + // + if (seq.getObjectAt(0) instanceof DERTaggedObject) + { + version = ASN1Integer.getInstance((ASN1TaggedObject)seq.getObjectAt(0), true); + } + else + { + seqStart = -1; // field 0 is missing! + version = new ASN1Integer(0); + } + + serialNumber = ASN1Integer.getInstance(seq.getObjectAt(seqStart + 1)); + + signature = AlgorithmIdentifier.getInstance(seq.getObjectAt(seqStart + 2)); + issuer = X500Name.getInstance(seq.getObjectAt(seqStart + 3)); + + // + // before and after dates + // + ASN1Sequence dates = (ASN1Sequence)seq.getObjectAt(seqStart + 4); + + startDate = Time.getInstance(dates.getObjectAt(0)); + endDate = Time.getInstance(dates.getObjectAt(1)); + + subject = X500Name.getInstance(seq.getObjectAt(seqStart + 5)); + + // + // public key info. + // + subjectPublicKeyInfo = SubjectPublicKeyInfo.getInstance(seq.getObjectAt(seqStart + 6)); + + for (int extras = seq.size() - (seqStart + 6) - 1; extras > 0; extras--) + { + DERTaggedObject extra = (DERTaggedObject)seq.getObjectAt(seqStart + 6 + extras); + + switch (extra.getTagNo()) + { + case 1: + issuerUniqueId = DERBitString.getInstance(extra, false); + break; + case 2: + subjectUniqueId = DERBitString.getInstance(extra, false); + break; + case 3: + extensions = X509Extensions.getInstance(extra); + } + } + } + + public int getVersion() + { + return version.getValue().intValue() + 1; + } + + public ASN1Integer getVersionNumber() + { + return version; + } + + public ASN1Integer getSerialNumber() + { + return serialNumber; + } + + public AlgorithmIdentifier getSignature() + { + return signature; + } + + public X500Name getIssuer() + { + return issuer; + } + + public Time getStartDate() + { + return startDate; + } + + public Time getEndDate() + { + return endDate; + } + + public X500Name getSubject() + { + return subject; + } + + public SubjectPublicKeyInfo getSubjectPublicKeyInfo() + { + return subjectPublicKeyInfo; + } + + public DERBitString getIssuerUniqueId() + { + return issuerUniqueId; + } + + public DERBitString getSubjectUniqueId() + { + return subjectUniqueId; + } + + public X509Extensions getExtensions() + { + return extensions; + } + + public ASN1Primitive toASN1Primitive() + { + return seq; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/Target.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/Target.java new file mode 100644 index 0000000..4e09ca8 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/Target.java @@ -0,0 +1,138 @@ +package org.bc.asn1.x509; + +import org.bc.asn1.ASN1Choice; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERTaggedObject; + +/** + * Target structure used in target information extension for attribute + * certificates from RFC 3281. + * + *
+ * Target ::= CHOICE { + * targetName [0] GeneralName, + * targetGroup [1] GeneralName, + * targetCert [2] TargetCert + * } + *+ * + *
+ * The targetCert field is currently not supported and must not be used + * according to RFC 3281. + */ +public class Target + extends ASN1Object + implements ASN1Choice +{ + public static final int targetName = 0; + public static final int targetGroup = 1; + + private GeneralName targName; + private GeneralName targGroup; + + /** + * Creates an instance of a Target from the given object. + *
+ * obj
can be a Target or a {@link ASN1TaggedObject}
+ *
+ * @param obj The object.
+ * @return A Target instance.
+ * @throws IllegalArgumentException if the given object cannot be
+ * interpreted as Target.
+ */
+ public static Target getInstance(Object obj)
+ {
+ if (obj == null || obj instanceof Target)
+ {
+ return (Target) obj;
+ }
+ else if (obj instanceof ASN1TaggedObject)
+ {
+ return new Target((ASN1TaggedObject)obj);
+ }
+
+ throw new IllegalArgumentException("unknown object in factory: "
+ + obj.getClass());
+ }
+
+ /**
+ * Constructor from ASN1TaggedObject.
+ *
+ * @param tagObj The tagged object.
+ * @throws IllegalArgumentException if the encoding is wrong.
+ */
+ private Target(ASN1TaggedObject tagObj)
+ {
+ switch (tagObj.getTagNo())
+ {
+ case targetName: // GeneralName is already a choice so explicit
+ targName = GeneralName.getInstance(tagObj, true);
+ break;
+ case targetGroup:
+ targGroup = GeneralName.getInstance(tagObj, true);
+ break;
+ default:
+ throw new IllegalArgumentException("unknown tag: " + tagObj.getTagNo());
+ }
+ }
+
+ /**
+ * Constructor from given details.
+ *
+ * Exactly one of the parameters must be not null
.
+ *
+ * @param type the choice type to apply to the name.
+ * @param name the general name.
+ * @throws IllegalArgumentException if type is invalid.
+ */
+ public Target(int type, GeneralName name)
+ {
+ this(new DERTaggedObject(type, name));
+ }
+
+ /**
+ * @return Returns the targetGroup.
+ */
+ public GeneralName getTargetGroup()
+ {
+ return targGroup;
+ }
+
+ /**
+ * @return Returns the targetName.
+ */
+ public GeneralName getTargetName()
+ {
+ return targName;
+ }
+
+ /**
+ * Produce an object suitable for an ASN1OutputStream.
+ *
+ * Returns:
+ *
+ *
+ * Target ::= CHOICE { + * targetName [0] GeneralName, + * targetGroup [1] GeneralName, + * targetCert [2] TargetCert + * } + *+ * + * @return a ASN1Primitive + */ + public ASN1Primitive toASN1Primitive() + { + // GeneralName is a choice already so most be explicitly tagged + if (targName != null) + { + return new DERTaggedObject(true, 0, targName); + } + else + { + return new DERTaggedObject(true, 1, targGroup); + } + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/TargetInformation.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/TargetInformation.java new file mode 100644 index 0000000..25fa242 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/TargetInformation.java @@ -0,0 +1,120 @@ +package org.bc.asn1.x509; + +import java.util.Enumeration; + +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DERSequence; + +/** + * Target information extension for attributes certificates according to RFC + * 3281. + * + *
+ * SEQUENCE OF Targets + *+ * + */ +public class TargetInformation + extends ASN1Object +{ + private ASN1Sequence targets; + + /** + * Creates an instance of a TargetInformation from the given object. + *
+ * obj
can be a TargetInformation or a {@link ASN1Sequence}
+ *
+ * @param obj The object.
+ * @return A TargetInformation instance.
+ * @throws IllegalArgumentException if the given object cannot be
+ * interpreted as TargetInformation.
+ */
+ public static TargetInformation getInstance(Object obj)
+ {
+ if (obj instanceof TargetInformation)
+ {
+ return (TargetInformation)obj;
+ }
+ else if (obj != null)
+ {
+ return new TargetInformation(ASN1Sequence.getInstance(obj));
+ }
+
+ return null;
+ }
+
+ /**
+ * Constructor from a ASN1Sequence.
+ *
+ * @param seq The ASN1Sequence.
+ * @throws IllegalArgumentException if the sequence does not contain
+ * correctly encoded Targets elements.
+ */
+ private TargetInformation(ASN1Sequence seq)
+ {
+ targets = seq;
+ }
+
+ /**
+ * Returns the targets in this target information extension.
+ *
+ * @return Returns the targets.
+ */
+ public Targets[] getTargetsObjects()
+ {
+ Targets[] copy = new Targets[targets.size()];
+ int count = 0;
+ for (Enumeration e = targets.getObjects(); e.hasMoreElements();)
+ {
+ copy[count++] = Targets.getInstance(e.nextElement());
+ }
+ return copy;
+ }
+
+ /**
+ * Constructs a target information from a single targets element.
+ * According to RFC 3281 only one targets element must be produced.
+ *
+ * @param targets A Targets instance.
+ */
+ public TargetInformation(Targets targets)
+ {
+ this.targets = new DERSequence(targets);
+ }
+
+ /**
+ * According to RFC 3281 only one targets element must be produced. If
+ * multiple targets are given they must be merged in
+ * into one targets element.
+ *
+ * @param targets An array with {@link Targets}.
+ */
+ public TargetInformation(Target[] targets)
+ {
+ this(new Targets(targets));
+ }
+
+ /**
+ * Produce an object suitable for an ASN1OutputStream.
+ *
+ * Returns:
+ *
+ *
+ * SEQUENCE OF Targets + *+ * + *
+ * According to RFC 3281 only one targets element must be produced. If + * multiple targets are given in the constructor they are merged into one + * targets element. If this was produced from a + * {@link org.bc.asn1.ASN1Sequence} the encoding is kept. + * + * @return a ASN1Primitive + */ + public ASN1Primitive toASN1Primitive() + { + return targets; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/Targets.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/Targets.java new file mode 100644 index 0000000..67d8649 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/Targets.java @@ -0,0 +1,121 @@ +package org.bc.asn1.x509; + +import java.util.Enumeration; + +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DERSequence; + +/** + * Targets structure used in target information extension for attribute + * certificates from RFC 3281. + * + *
+ * Targets ::= SEQUENCE OF Target + * + * Target ::= CHOICE { + * targetName [0] GeneralName, + * targetGroup [1] GeneralName, + * targetCert [2] TargetCert + * } + * + * TargetCert ::= SEQUENCE { + * targetCertificate IssuerSerial, + * targetName GeneralName OPTIONAL, + * certDigestInfo ObjectDigestInfo OPTIONAL + * } + *+ * + * @see org.bc.asn1.x509.Target + * @see org.bc.asn1.x509.TargetInformation + */ +public class Targets + extends ASN1Object +{ + private ASN1Sequence targets; + + /** + * Creates an instance of a Targets from the given object. + *
+ * obj
can be a Targets or a {@link ASN1Sequence}
+ *
+ * @param obj The object.
+ * @return A Targets instance.
+ * @throws IllegalArgumentException if the given object cannot be
+ * interpreted as Target.
+ */
+ public static Targets getInstance(Object obj)
+ {
+ if (obj instanceof Targets)
+ {
+ return (Targets)obj;
+ }
+ else if (obj != null)
+ {
+ return new Targets(ASN1Sequence.getInstance(obj));
+ }
+
+ return null;
+ }
+
+ /**
+ * Constructor from ASN1Sequence.
+ *
+ * @param targets The ASN.1 SEQUENCE.
+ * @throws IllegalArgumentException if the contents of the sequence are
+ * invalid.
+ */
+ private Targets(ASN1Sequence targets)
+ {
+ this.targets = targets;
+ }
+
+ /**
+ * Constructor from given targets.
+ *
+ * The vector is copied.
+ *
+ * @param targets A Vector
of {@link Target}s.
+ * @see Target
+ * @throws IllegalArgumentException if the vector contains not only Targets.
+ */
+ public Targets(Target[] targets)
+ {
+ this.targets = new DERSequence(targets);
+ }
+
+ /**
+ * Returns the targets in a Vector
.
+ *
+ * The vector is cloned before it is returned. + * + * @return Returns the targets. + */ + public Target[] getTargets() + { + Target[] targs = new Target[targets.size()]; + int count = 0; + for (Enumeration e = targets.getObjects(); e.hasMoreElements();) + { + targs[count++] = Target.getInstance(e.nextElement()); + } + return targs; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * + * Returns: + * + *
+ * Targets ::= SEQUENCE OF Target + *+ * + * @return a ASN1Primitive + */ + public ASN1Primitive toASN1Primitive() + { + return targets; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/Time.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/Time.java new file mode 100644 index 0000000..ed101b8 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/Time.java @@ -0,0 +1,133 @@ +package org.bc.asn1.x509; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.SimpleTimeZone; + +import org.bc.asn1.ASN1Choice; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERGeneralizedTime; +import org.bc.asn1.DERUTCTime; + +public class Time + extends ASN1Object + implements ASN1Choice +{ + ASN1Primitive time; + + public static Time getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(obj.getObject()); // must be explicitly tagged + } + + public Time( + ASN1Primitive time) + { + if (!(time instanceof DERUTCTime) + && !(time instanceof DERGeneralizedTime)) + { + throw new IllegalArgumentException("unknown object passed to Time"); + } + + this.time = time; + } + + /** + * creates a time object from a given date - if the date is between 1950 + * and 2049 a UTCTime object is generated, otherwise a GeneralizedTime + * is used. + */ + public Time( + Date date) + { + SimpleTimeZone tz = new SimpleTimeZone(0, "Z"); + SimpleDateFormat dateF = new SimpleDateFormat("yyyyMMddHHmmss"); + + dateF.setTimeZone(tz); + + String d = dateF.format(date) + "Z"; + int year = Integer.parseInt(d.substring(0, 4)); + + if (year < 1950 || year > 2049) + { + time = new DERGeneralizedTime(d); + } + else + { + time = new DERUTCTime(d.substring(2)); + } + } + + public static Time getInstance( + Object obj) + { + if (obj == null || obj instanceof Time) + { + return (Time)obj; + } + else if (obj instanceof DERUTCTime) + { + return new Time((DERUTCTime)obj); + } + else if (obj instanceof DERGeneralizedTime) + { + return new Time((DERGeneralizedTime)obj); + } + + throw new IllegalArgumentException("unknown object in factory: " + obj.getClass().getName()); + } + + public String getTime() + { + if (time instanceof DERUTCTime) + { + return ((DERUTCTime)time).getAdjustedTime(); + } + else + { + return ((DERGeneralizedTime)time).getTime(); + } + } + + public Date getDate() + { + try + { + if (time instanceof DERUTCTime) + { + return ((DERUTCTime)time).getAdjustedDate(); + } + else + { + return ((DERGeneralizedTime)time).getDate(); + } + } + catch (ParseException e) + { // this should never happen + throw new IllegalStateException("invalid date string: " + e.getMessage()); + } + } + + /** + * Produce an object suitable for an ASN1OutputStream. + *
+ * Time ::= CHOICE { + * utcTime UTCTime, + * generalTime GeneralizedTime } + *+ */ + public ASN1Primitive toASN1Primitive() + { + return time; + } + + public String toString() + { + return getTime(); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/UserNotice.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/UserNotice.java new file mode 100644 index 0000000..5e7e6c3 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/UserNotice.java @@ -0,0 +1,132 @@ +package org.bc.asn1.x509; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DERSequence; + +/** + *
UserNotice
class, used in
+ * CertificatePolicies
X509 extensions (in policy
+ * qualifiers).
+ * + * UserNotice ::= SEQUENCE { + * noticeRef NoticeReference OPTIONAL, + * explicitText DisplayText OPTIONAL} + * + *+ * + * @see PolicyQualifierId + * @see PolicyInformation + */ +public class UserNotice + extends ASN1Object +{ + private NoticeReference noticeRef; + private DisplayText explicitText; + + /** + * Creates a new
UserNotice
instance.
+ *
+ * @param noticeRef a NoticeReference
value
+ * @param explicitText a DisplayText
value
+ */
+ public UserNotice(
+ NoticeReference noticeRef,
+ DisplayText explicitText)
+ {
+ this.noticeRef = noticeRef;
+ this.explicitText = explicitText;
+ }
+
+ /**
+ * Creates a new UserNotice
instance.
+ *
+ * @param noticeRef a NoticeReference
value
+ * @param str the explicitText field as a String.
+ */
+ public UserNotice(
+ NoticeReference noticeRef,
+ String str)
+ {
+ this(noticeRef, new DisplayText(str));
+ }
+
+ /**
+ * Creates a new UserNotice
instance.
+ * Useful from reconstructing a UserNotice
instance
+ * from its encodable/encoded form.
+ *
+ * @param as an ASN1Sequence
value obtained from either
+ * calling @{link toASN1Primitive()} for a UserNotice
+ * instance or from parsing it from a DER-encoded stream.
+ */
+ private UserNotice(
+ ASN1Sequence as)
+ {
+ if (as.size() == 2)
+ {
+ noticeRef = NoticeReference.getInstance(as.getObjectAt(0));
+ explicitText = DisplayText.getInstance(as.getObjectAt(1));
+ }
+ else if (as.size() == 1)
+ {
+ if (as.getObjectAt(0).toASN1Primitive() instanceof ASN1Sequence)
+ {
+ noticeRef = NoticeReference.getInstance(as.getObjectAt(0));
+ }
+ else
+ {
+ explicitText = DisplayText.getInstance(as.getObjectAt(0));
+ }
+ }
+ else
+ {
+ throw new IllegalArgumentException("Bad sequence size: " + as.size());
+ }
+ }
+
+ public static UserNotice getInstance(
+ Object obj)
+ {
+ if (obj instanceof UserNotice)
+ {
+ return (UserNotice)obj;
+ }
+
+ if (obj != null)
+ {
+ return new UserNotice(ASN1Sequence.getInstance(obj));
+ }
+
+ return null;
+ }
+
+ public NoticeReference getNoticeRef()
+ {
+ return noticeRef;
+ }
+
+ public DisplayText getExplicitText()
+ {
+ return explicitText;
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector av = new ASN1EncodableVector();
+
+ if (noticeRef != null)
+ {
+ av.add(noticeRef);
+ }
+
+ if (explicitText != null)
+ {
+ av.add(explicitText);
+ }
+
+ return new DERSequence(av);
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/V1TBSCertificateGenerator.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/V1TBSCertificateGenerator.java
new file mode 100644
index 0000000..69ea8d5
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/V1TBSCertificateGenerator.java
@@ -0,0 +1,144 @@
+package org.bc.asn1.x509;
+
+import org.bc.asn1.ASN1EncodableVector;
+import org.bc.asn1.ASN1Integer;
+import org.bc.asn1.ASN1UTCTime;
+import org.bc.asn1.DERSequence;
+import org.bc.asn1.DERTaggedObject;
+import org.bc.asn1.x500.X500Name;
+
+/**
+ * Generator for Version 1 TBSCertificateStructures.
+ *
+ * TBSCertificate ::= SEQUENCE { + * version [ 0 ] Version DEFAULT v1(0), + * serialNumber CertificateSerialNumber, + * signature AlgorithmIdentifier, + * issuer Name, + * validity Validity, + * subject Name, + * subjectPublicKeyInfo SubjectPublicKeyInfo, + * } + *+ * + */ +public class V1TBSCertificateGenerator +{ + DERTaggedObject version = new DERTaggedObject(true, 0, new ASN1Integer(0)); + + ASN1Integer serialNumber; + AlgorithmIdentifier signature; + X500Name issuer; + Time startDate, endDate; + X500Name subject; + SubjectPublicKeyInfo subjectPublicKeyInfo; + + public V1TBSCertificateGenerator() + { + } + + public void setSerialNumber( + ASN1Integer serialNumber) + { + this.serialNumber = serialNumber; + } + + public void setSignature( + AlgorithmIdentifier signature) + { + this.signature = signature; + } + + /** + * @deprecated use X500Name method + */ + public void setIssuer( + X509Name issuer) + { + this.issuer = X500Name.getInstance(issuer.toASN1Primitive()); + } + + public void setIssuer( + X500Name issuer) + { + this.issuer = issuer; + } + + public void setStartDate( + Time startDate) + { + this.startDate = startDate; + } + + public void setStartDate( + ASN1UTCTime startDate) + { + this.startDate = new Time(startDate); + } + + public void setEndDate( + Time endDate) + { + this.endDate = endDate; + } + + public void setEndDate( + ASN1UTCTime endDate) + { + this.endDate = new Time(endDate); + } + + /** + * @deprecated use X500Name method + */ + public void setSubject( + X509Name subject) + { + this.subject = X500Name.getInstance(subject.toASN1Primitive()); + } + + public void setSubject( + X500Name subject) + { + this.subject = subject; + } + + public void setSubjectPublicKeyInfo( + SubjectPublicKeyInfo pubKeyInfo) + { + this.subjectPublicKeyInfo = pubKeyInfo; + } + + public TBSCertificate generateTBSCertificate() + { + if ((serialNumber == null) || (signature == null) + || (issuer == null) || (startDate == null) || (endDate == null) + || (subject == null) || (subjectPublicKeyInfo == null)) + { + throw new IllegalStateException("not all mandatory fields set in V1 TBScertificate generator"); + } + + ASN1EncodableVector seq = new ASN1EncodableVector(); + + // seq.add(version); - not required as default value. + seq.add(serialNumber); + seq.add(signature); + seq.add(issuer); + + // + // before and after dates + // + ASN1EncodableVector validity = new ASN1EncodableVector(); + + validity.add(startDate); + validity.add(endDate); + + seq.add(new DERSequence(validity)); + + seq.add(subject); + + seq.add(subjectPublicKeyInfo); + + return TBSCertificate.getInstance(new DERSequence(seq)); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/V2AttributeCertificateInfoGenerator.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/V2AttributeCertificateInfoGenerator.java new file mode 100644 index 0000000..3df68fe --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/V2AttributeCertificateInfoGenerator.java @@ -0,0 +1,158 @@ +package org.bc.asn1.x509; + +import org.bc.asn1.ASN1Encodable; +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1GeneralizedTime; +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1ObjectIdentifier; +import org.bc.asn1.DERBitString; +import org.bc.asn1.DERSequence; +import org.bc.asn1.DERSet; + +/** + * Generator for Version 2 AttributeCertificateInfo + *
+ * AttributeCertificateInfo ::= SEQUENCE { + * version AttCertVersion -- version is v2, + * holder Holder, + * issuer AttCertIssuer, + * signature AlgorithmIdentifier, + * serialNumber CertificateSerialNumber, + * attrCertValidityPeriod AttCertValidityPeriod, + * attributes SEQUENCE OF Attribute, + * issuerUniqueID UniqueIdentifier OPTIONAL, + * extensions Extensions OPTIONAL + * } + *+ * + */ +public class V2AttributeCertificateInfoGenerator +{ + private ASN1Integer version; + private Holder holder; + private AttCertIssuer issuer; + private AlgorithmIdentifier signature; + private ASN1Integer serialNumber; + private ASN1EncodableVector attributes; + private DERBitString issuerUniqueID; + private Extensions extensions; + + // Note: validity period start/end dates stored directly + //private AttCertValidityPeriod attrCertValidityPeriod; + private ASN1GeneralizedTime startDate, endDate; + + public V2AttributeCertificateInfoGenerator() + { + this.version = new ASN1Integer(1); + attributes = new ASN1EncodableVector(); + } + + public void setHolder(Holder holder) + { + this.holder = holder; + } + + public void addAttribute(String oid, ASN1Encodable value) + { + attributes.add(new Attribute(new ASN1ObjectIdentifier(oid), new DERSet(value))); + } + + /** + * @param attribute + */ + public void addAttribute(Attribute attribute) + { + attributes.add(attribute); + } + + public void setSerialNumber( + ASN1Integer serialNumber) + { + this.serialNumber = serialNumber; + } + + public void setSignature( + AlgorithmIdentifier signature) + { + this.signature = signature; + } + + public void setIssuer( + AttCertIssuer issuer) + { + this.issuer = issuer; + } + + public void setStartDate( + ASN1GeneralizedTime startDate) + { + this.startDate = startDate; + } + + public void setEndDate( + ASN1GeneralizedTime endDate) + { + this.endDate = endDate; + } + + public void setIssuerUniqueID( + DERBitString issuerUniqueID) + { + this.issuerUniqueID = issuerUniqueID; + } + + /** + * @deprecated use method taking Extensions + * @param extensions + */ + public void setExtensions( + X509Extensions extensions) + { + this.extensions = Extensions.getInstance(extensions.toASN1Primitive()); + } + + public void setExtensions( + Extensions extensions) + { + this.extensions = extensions; + } + + public AttributeCertificateInfo generateAttributeCertificateInfo() + { + if ((serialNumber == null) || (signature == null) + || (issuer == null) || (startDate == null) || (endDate == null) + || (holder == null) || (attributes == null)) + { + throw new IllegalStateException("not all mandatory fields set in V2 AttributeCertificateInfo generator"); + } + + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(version); + v.add(holder); + v.add(issuer); + v.add(signature); + v.add(serialNumber); + + // + // before and after dates => AttCertValidityPeriod + // + AttCertValidityPeriod validity = new AttCertValidityPeriod(startDate, endDate); + v.add(validity); + + // Attributes + v.add(new DERSequence(attributes)); + + if (issuerUniqueID != null) + { + v.add(issuerUniqueID); + } + + if (extensions != null) + { + v.add(extensions); + } + + return AttributeCertificateInfo.getInstance(new DERSequence(v)); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/V2Form.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/V2Form.java new file mode 100644 index 0000000..5444f02 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/V2Form.java @@ -0,0 +1,130 @@ +package org.bc.asn1.x509; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERSequence; +import org.bc.asn1.DERTaggedObject; + +public class V2Form + extends ASN1Object +{ + GeneralNames issuerName; + IssuerSerial baseCertificateID; + ObjectDigestInfo objectDigestInfo; + + public static V2Form getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static V2Form getInstance( + Object obj) + { + if (obj == null || obj instanceof V2Form) + { + return (V2Form)obj; + } + else if (obj instanceof ASN1Sequence) + { + return new V2Form((ASN1Sequence)obj); + } + + throw new IllegalArgumentException("unknown object in factory: " + obj.getClass().getName()); + } + + public V2Form( + GeneralNames issuerName) + { + this.issuerName = issuerName; + } + + public V2Form( + ASN1Sequence seq) + { + if (seq.size() > 3) + { + throw new IllegalArgumentException("Bad sequence size: " + seq.size()); + } + + int index = 0; + + if (!(seq.getObjectAt(0) instanceof ASN1TaggedObject)) + { + index++; + this.issuerName = GeneralNames.getInstance(seq.getObjectAt(0)); + } + + for (int i = index; i != seq.size(); i++) + { + ASN1TaggedObject o = ASN1TaggedObject.getInstance(seq.getObjectAt(i)); + if (o.getTagNo() == 0) + { + baseCertificateID = IssuerSerial.getInstance(o, false); + } + else if (o.getTagNo() == 1) + { + objectDigestInfo = ObjectDigestInfo.getInstance(o, false); + } + else + { + throw new IllegalArgumentException("Bad tag number: " + + o.getTagNo()); + } + } + } + + public GeneralNames getIssuerName() + { + return issuerName; + } + + public IssuerSerial getBaseCertificateID() + { + return baseCertificateID; + } + + public ObjectDigestInfo getObjectDigestInfo() + { + return objectDigestInfo; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + *
+ * V2Form ::= SEQUENCE { + * issuerName GeneralNames OPTIONAL, + * baseCertificateID [0] IssuerSerial OPTIONAL, + * objectDigestInfo [1] ObjectDigestInfo OPTIONAL + * -- issuerName MUST be present in this profile + * -- baseCertificateID and objectDigestInfo MUST NOT + * -- be present in this profile + * } + *+ */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + if (issuerName != null) + { + v.add(issuerName); + } + + if (baseCertificateID != null) + { + v.add(new DERTaggedObject(false, 0, baseCertificateID)); + } + + if (objectDigestInfo != null) + { + v.add(new DERTaggedObject(false, 1, objectDigestInfo)); + } + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/V2TBSCertListGenerator.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/V2TBSCertListGenerator.java new file mode 100644 index 0000000..00e9238 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/V2TBSCertListGenerator.java @@ -0,0 +1,281 @@ +package org.bc.asn1.x509; + +import java.io.IOException; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1GeneralizedTime; +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1UTCTime; +import org.bc.asn1.DEROctetString; +import org.bc.asn1.DERSequence; +import org.bc.asn1.DERTaggedObject; +import org.bc.asn1.x500.X500Name; + +/** + * Generator for Version 2 TBSCertList structures. + *
+ * TBSCertList ::= SEQUENCE { + * version Version OPTIONAL, + * -- if present, shall be v2 + * signature AlgorithmIdentifier, + * issuer Name, + * thisUpdate Time, + * nextUpdate Time OPTIONAL, + * revokedCertificates SEQUENCE OF SEQUENCE { + * userCertificate CertificateSerialNumber, + * revocationDate Time, + * crlEntryExtensions Extensions OPTIONAL + * -- if present, shall be v2 + * } OPTIONAL, + * crlExtensions [0] EXPLICIT Extensions OPTIONAL + * -- if present, shall be v2 + * } + *+ * + * Note: This class may be subject to change + */ +public class V2TBSCertListGenerator +{ + private ASN1Integer version = new ASN1Integer(1); + private AlgorithmIdentifier signature; + private X500Name issuer; + private Time thisUpdate, nextUpdate=null; + private Extensions extensions = null; + private ASN1EncodableVector crlentries = new ASN1EncodableVector(); + + private final static ASN1Sequence[] reasons; + + static + { + reasons = new ASN1Sequence[11]; + + reasons[0] = createReasonExtension(CRLReason.unspecified); + reasons[1] = createReasonExtension(CRLReason.keyCompromise); + reasons[2] = createReasonExtension(CRLReason.cACompromise); + reasons[3] = createReasonExtension(CRLReason.affiliationChanged); + reasons[4] = createReasonExtension(CRLReason.superseded); + reasons[5] = createReasonExtension(CRLReason.cessationOfOperation); + reasons[6] = createReasonExtension(CRLReason.certificateHold); + reasons[7] = createReasonExtension(7); // 7 -> unknown + reasons[8] = createReasonExtension(CRLReason.removeFromCRL); + reasons[9] = createReasonExtension(CRLReason.privilegeWithdrawn); + reasons[10] = createReasonExtension(CRLReason.aACompromise); + } + + public V2TBSCertListGenerator() + { + } + + + public void setSignature( + AlgorithmIdentifier signature) + { + this.signature = signature; + } + + /** + * @deprecated use X500Name method + */ + public void setIssuer( + X509Name issuer) + { + this.issuer = X500Name.getInstance(issuer.toASN1Primitive()); + } + + public void setIssuer(X500Name issuer) + { + this.issuer = issuer; + } + + public void setThisUpdate( + ASN1UTCTime thisUpdate) + { + this.thisUpdate = new Time(thisUpdate); + } + + public void setNextUpdate( + ASN1UTCTime nextUpdate) + { + this.nextUpdate = new Time(nextUpdate); + } + + public void setThisUpdate( + Time thisUpdate) + { + this.thisUpdate = thisUpdate; + } + + public void setNextUpdate( + Time nextUpdate) + { + this.nextUpdate = nextUpdate; + } + + public void addCRLEntry( + ASN1Sequence crlEntry) + { + crlentries.add(crlEntry); + } + + public void addCRLEntry(ASN1Integer userCertificate, ASN1UTCTime revocationDate, int reason) + { + addCRLEntry(userCertificate, new Time(revocationDate), reason); + } + + public void addCRLEntry(ASN1Integer userCertificate, Time revocationDate, int reason) + { + addCRLEntry(userCertificate, revocationDate, reason, null); + } + + public void addCRLEntry(ASN1Integer userCertificate, Time revocationDate, int reason, ASN1GeneralizedTime invalidityDate) + { + if (reason != 0) + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + if (reason < reasons.length) + { + if (reason < 0) + { + throw new IllegalArgumentException("invalid reason value: " + reason); + } + v.add(reasons[reason]); + } + else + { + v.add(createReasonExtension(reason)); + } + + if (invalidityDate != null) + { + v.add(createInvalidityDateExtension(revocationDate)); + } + + internalAddCRLEntry(userCertificate, revocationDate, new DERSequence(v)); + } + else if (invalidityDate != null) + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(createInvalidityDateExtension(revocationDate)); + + internalAddCRLEntry(userCertificate, revocationDate, new DERSequence(v)); + } + else + { + addCRLEntry(userCertificate, revocationDate, null); + } + } + + private void internalAddCRLEntry(ASN1Integer userCertificate, Time revocationDate, ASN1Sequence extensions) + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(userCertificate); + v.add(revocationDate); + + if (extensions != null) + { + v.add(extensions); + } + + addCRLEntry(new DERSequence(v)); + } + + public void addCRLEntry(ASN1Integer userCertificate, Time revocationDate, Extensions extensions) + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(userCertificate); + v.add(revocationDate); + + if (extensions != null) + { + v.add(extensions); + } + + addCRLEntry(new DERSequence(v)); + } + + public void setExtensions( + X509Extensions extensions) + { + setExtensions(Extensions.getInstance(extensions)); + } + + public void setExtensions( + Extensions extensions) + { + this.extensions = extensions; + } + + public TBSCertList generateTBSCertList() + { + if ((signature == null) || (issuer == null) || (thisUpdate == null)) + { + throw new IllegalStateException("Not all mandatory fields set in V2 TBSCertList generator."); + } + + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(version); + v.add(signature); + v.add(issuer); + + v.add(thisUpdate); + if (nextUpdate != null) + { + v.add(nextUpdate); + } + + // Add CRLEntries if they exist + if (crlentries.size() != 0) + { + v.add(new DERSequence(crlentries)); + } + + if (extensions != null) + { + v.add(new DERTaggedObject(0, extensions)); + } + + return new TBSCertList(new DERSequence(v)); + } + + private static ASN1Sequence createReasonExtension(int reasonCode) + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + CRLReason crlReason = CRLReason.lookup(reasonCode); + + try + { + v.add(Extension.reasonCode); + v.add(new DEROctetString(crlReason.getEncoded())); + } + catch (IOException e) + { + throw new IllegalArgumentException("error encoding reason: " + e); + } + + return new DERSequence(v); + } + + private static ASN1Sequence createInvalidityDateExtension(Time invalidityDate) + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + try + { + v.add(Extension.invalidityDate); + v.add(new DEROctetString(invalidityDate.getEncoded())); + } + catch (IOException e) + { + throw new IllegalArgumentException("error encoding reason: " + e); + } + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/V3TBSCertificateGenerator.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/V3TBSCertificateGenerator.java new file mode 100644 index 0000000..8056c1a --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/V3TBSCertificateGenerator.java @@ -0,0 +1,212 @@ +package org.bc.asn1.x509; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.DERBitString; +import org.bc.asn1.DERSequence; +import org.bc.asn1.DERTaggedObject; +import org.bc.asn1.DERUTCTime; +import org.bc.asn1.x500.X500Name; + +/** + * Generator for Version 3 TBSCertificateStructures. + *
+ * TBSCertificate ::= SEQUENCE { + * version [ 0 ] Version DEFAULT v1(0), + * serialNumber CertificateSerialNumber, + * signature AlgorithmIdentifier, + * issuer Name, + * validity Validity, + * subject Name, + * subjectPublicKeyInfo SubjectPublicKeyInfo, + * issuerUniqueID [ 1 ] IMPLICIT UniqueIdentifier OPTIONAL, + * subjectUniqueID [ 2 ] IMPLICIT UniqueIdentifier OPTIONAL, + * extensions [ 3 ] Extensions OPTIONAL + * } + *+ * + */ +public class V3TBSCertificateGenerator +{ + DERTaggedObject version = new DERTaggedObject(true, 0, new ASN1Integer(2)); + + ASN1Integer serialNumber; + AlgorithmIdentifier signature; + X500Name issuer; + Time startDate, endDate; + X500Name subject; + SubjectPublicKeyInfo subjectPublicKeyInfo; + Extensions extensions; + + private boolean altNamePresentAndCritical; + private DERBitString issuerUniqueID; + private DERBitString subjectUniqueID; + + public V3TBSCertificateGenerator() + { + } + + public void setSerialNumber( + ASN1Integer serialNumber) + { + this.serialNumber = serialNumber; + } + + public void setSignature( + AlgorithmIdentifier signature) + { + this.signature = signature; + } + + /** + * @deprecated use X500Name method + */ + public void setIssuer( + X509Name issuer) + { + this.issuer = X500Name.getInstance(issuer); + } + + public void setIssuer( + X500Name issuer) + { + this.issuer = issuer; + } + + public void setStartDate( + DERUTCTime startDate) + { + this.startDate = new Time(startDate); + } + + public void setStartDate( + Time startDate) + { + this.startDate = startDate; + } + + public void setEndDate( + DERUTCTime endDate) + { + this.endDate = new Time(endDate); + } + + public void setEndDate( + Time endDate) + { + this.endDate = endDate; + } + + /** + * @deprecated use X500Name method + */ + public void setSubject( + X509Name subject) + { + this.subject = X500Name.getInstance(subject.toASN1Primitive()); + } + + public void setSubject( + X500Name subject) + { + this.subject = subject; + } + + public void setIssuerUniqueID( + DERBitString uniqueID) + { + this.issuerUniqueID = uniqueID; + } + + public void setSubjectUniqueID( + DERBitString uniqueID) + { + this.subjectUniqueID = uniqueID; + } + + public void setSubjectPublicKeyInfo( + SubjectPublicKeyInfo pubKeyInfo) + { + this.subjectPublicKeyInfo = pubKeyInfo; + } + + /** + * @deprecated use method taking Extensions + * @param extensions + */ + public void setExtensions( + X509Extensions extensions) + { + setExtensions(Extensions.getInstance(extensions)); + } + + public void setExtensions( + Extensions extensions) + { + this.extensions = extensions; + if (extensions != null) + { + Extension altName = extensions.getExtension(Extension.subjectAlternativeName); + + if (altName != null && altName.isCritical()) + { + altNamePresentAndCritical = true; + } + } + } + + public TBSCertificate generateTBSCertificate() + { + if ((serialNumber == null) || (signature == null) + || (issuer == null) || (startDate == null) || (endDate == null) + || (subject == null && !altNamePresentAndCritical) || (subjectPublicKeyInfo == null)) + { + throw new IllegalStateException("not all mandatory fields set in V3 TBScertificate generator"); + } + + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(version); + v.add(serialNumber); + v.add(signature); + v.add(issuer); + + // + // before and after dates + // + ASN1EncodableVector validity = new ASN1EncodableVector(); + + validity.add(startDate); + validity.add(endDate); + + v.add(new DERSequence(validity)); + + if (subject != null) + { + v.add(subject); + } + else + { + v.add(new DERSequence()); + } + + v.add(subjectPublicKeyInfo); + + if (issuerUniqueID != null) + { + v.add(new DERTaggedObject(false, 1, issuerUniqueID)); + } + + if (subjectUniqueID != null) + { + v.add(new DERTaggedObject(false, 2, subjectUniqueID)); + } + + if (extensions != null) + { + v.add(new DERTaggedObject(true, 3, extensions)); + } + + return TBSCertificate.getInstance(new DERSequence(v)); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/X509AttributeIdentifiers.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/X509AttributeIdentifiers.java new file mode 100644 index 0000000..7befb9a --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/X509AttributeIdentifiers.java @@ -0,0 +1,29 @@ +package org.bc.asn1.x509; + +import org.bc.asn1.ASN1ObjectIdentifier; + +public interface X509AttributeIdentifiers +{ + /** + * @deprecated use id_at_role + */ + static final ASN1ObjectIdentifier RoleSyntax = new ASN1ObjectIdentifier("2.5.4.72"); + + static final ASN1ObjectIdentifier id_pe_ac_auditIdentity = X509ObjectIdentifiers.id_pe.branch("4"); + static final ASN1ObjectIdentifier id_pe_aaControls = X509ObjectIdentifiers.id_pe.branch("6"); + static final ASN1ObjectIdentifier id_pe_ac_proxying = X509ObjectIdentifiers.id_pe.branch("10"); + + static final ASN1ObjectIdentifier id_ce_targetInformation= X509ObjectIdentifiers.id_ce.branch("55"); + + static final ASN1ObjectIdentifier id_aca = X509ObjectIdentifiers.id_pkix.branch("10"); + + static final ASN1ObjectIdentifier id_aca_authenticationInfo = id_aca.branch("1"); + static final ASN1ObjectIdentifier id_aca_accessIdentity = id_aca.branch("2"); + static final ASN1ObjectIdentifier id_aca_chargingIdentity = id_aca.branch("3"); + static final ASN1ObjectIdentifier id_aca_group = id_aca.branch("4"); + // { id-aca 5 } is reserved + static final ASN1ObjectIdentifier id_aca_encAttrs = id_aca.branch("6"); + + static final ASN1ObjectIdentifier id_at_role = new ASN1ObjectIdentifier("2.5.4.72"); + static final ASN1ObjectIdentifier id_at_clearance = new ASN1ObjectIdentifier("2.5.1.5.55"); +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/X509CertificateStructure.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/X509CertificateStructure.java new file mode 100644 index 0000000..80ef3b8 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/X509CertificateStructure.java @@ -0,0 +1,129 @@ +package org.bc.asn1.x509; + +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERBitString; +import org.bc.asn1.pkcs.PKCSObjectIdentifiers; +import org.bc.asn1.x500.X500Name; + +/** + * an X509Certificate structure. + *
+ * Certificate ::= SEQUENCE { + * tbsCertificate TBSCertificate, + * signatureAlgorithm AlgorithmIdentifier, + * signature BIT STRING + * } + *+ * @deprecated use org.bouncycastle.asn1.x509.Certificate + */ +public class X509CertificateStructure + extends ASN1Object + implements X509ObjectIdentifiers, PKCSObjectIdentifiers +{ + ASN1Sequence seq; + TBSCertificateStructure tbsCert; + AlgorithmIdentifier sigAlgId; + DERBitString sig; + + public static X509CertificateStructure getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static X509CertificateStructure getInstance( + Object obj) + { + if (obj instanceof X509CertificateStructure) + { + return (X509CertificateStructure)obj; + } + else if (obj != null) + { + return new X509CertificateStructure(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public X509CertificateStructure( + ASN1Sequence seq) + { + this.seq = seq; + + // + // correct x509 certficate + // + if (seq.size() == 3) + { + tbsCert = TBSCertificateStructure.getInstance(seq.getObjectAt(0)); + sigAlgId = AlgorithmIdentifier.getInstance(seq.getObjectAt(1)); + + sig = DERBitString.getInstance(seq.getObjectAt(2)); + } + else + { + throw new IllegalArgumentException("sequence wrong size for a certificate"); + } + } + + public TBSCertificateStructure getTBSCertificate() + { + return tbsCert; + } + + public int getVersion() + { + return tbsCert.getVersion(); + } + + public ASN1Integer getSerialNumber() + { + return tbsCert.getSerialNumber(); + } + + public X500Name getIssuer() + { + return tbsCert.getIssuer(); + } + + public Time getStartDate() + { + return tbsCert.getStartDate(); + } + + public Time getEndDate() + { + return tbsCert.getEndDate(); + } + + public X500Name getSubject() + { + return tbsCert.getSubject(); + } + + public SubjectPublicKeyInfo getSubjectPublicKeyInfo() + { + return tbsCert.getSubjectPublicKeyInfo(); + } + + public AlgorithmIdentifier getSignatureAlgorithm() + { + return sigAlgId; + } + + public DERBitString getSignature() + { + return sig; + } + + public ASN1Primitive toASN1Primitive() + { + return seq; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/X509DefaultEntryConverter.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/X509DefaultEntryConverter.java new file mode 100644 index 0000000..6f2d9ba --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/X509DefaultEntryConverter.java @@ -0,0 +1,65 @@ +package org.bc.asn1.x509; + +import java.io.IOException; + +import org.bc.asn1.ASN1ObjectIdentifier; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.DERGeneralizedTime; +import org.bc.asn1.DERIA5String; +import org.bc.asn1.DERPrintableString; +import org.bc.asn1.DERUTF8String; + +/** + * The default converter for X509 DN entries when going from their + * string value to ASN.1 strings. + */ +public class X509DefaultEntryConverter + extends X509NameEntryConverter +{ + /** + * Apply default coversion for the given value depending on the oid + * and the character range of the value. + * + * @param oid the object identifier for the DN entry + * @param value the value associated with it + * @return the ASN.1 equivalent for the string value. + */ + public ASN1Primitive getConvertedValue( + ASN1ObjectIdentifier oid, + String value) + { + if (value.length() != 0 && value.charAt(0) == '#') + { + try + { + return convertHexEncoded(value, 1); + } + catch (IOException e) + { + throw new RuntimeException("can't recode value for oid " + oid.getId()); + } + } + else + { + if (value.length() != 0 && value.charAt(0) == '\\') + { + value = value.substring(1); + } + if (oid.equals(X509Name.EmailAddress) || oid.equals(X509Name.DC)) + { + return new DERIA5String(value); + } + else if (oid.equals(X509Name.DATE_OF_BIRTH)) // accept time string as well as # (for compatibility) + { + return new DERGeneralizedTime(value); + } + else if (oid.equals(X509Name.C) || oid.equals(X509Name.SN) || oid.equals(X509Name.DN_QUALIFIER) + || oid.equals(X509Name.TELEPHONE_NUMBER)) + { + return new DERPrintableString(value); + } + } + + return new DERUTF8String(value); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/X509Extension.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/X509Extension.java new file mode 100644 index 0000000..5ac4829 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/X509Extension.java @@ -0,0 +1,248 @@ +package org.bc.asn1.x509; + +import java.io.IOException; + +import org.bc.asn1.ASN1Encodable; +import org.bc.asn1.ASN1ObjectIdentifier; +import org.bc.asn1.ASN1OctetString; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.DERBoolean; + +/** + * an object for the elements in the X.509 V3 extension block. + */ +public class X509Extension +{ + /** + * Subject Directory Attributes + */ + public static final ASN1ObjectIdentifier subjectDirectoryAttributes = new ASN1ObjectIdentifier("2.5.29.9"); + + /** + * Subject Key Identifier + */ + public static final ASN1ObjectIdentifier subjectKeyIdentifier = new ASN1ObjectIdentifier("2.5.29.14"); + + /** + * Key Usage + */ + public static final ASN1ObjectIdentifier keyUsage = new ASN1ObjectIdentifier("2.5.29.15"); + + /** + * Private Key Usage Period + */ + public static final ASN1ObjectIdentifier privateKeyUsagePeriod = new ASN1ObjectIdentifier("2.5.29.16"); + + /** + * Subject Alternative Name + */ + public static final ASN1ObjectIdentifier subjectAlternativeName = new ASN1ObjectIdentifier("2.5.29.17"); + + /** + * Issuer Alternative Name + */ + public static final ASN1ObjectIdentifier issuerAlternativeName = new ASN1ObjectIdentifier("2.5.29.18"); + + /** + * Basic Constraints + */ + public static final ASN1ObjectIdentifier basicConstraints = new ASN1ObjectIdentifier("2.5.29.19"); + + /** + * CRL Number + */ + public static final ASN1ObjectIdentifier cRLNumber = new ASN1ObjectIdentifier("2.5.29.20"); + + /** + * Reason code + */ + public static final ASN1ObjectIdentifier reasonCode = new ASN1ObjectIdentifier("2.5.29.21"); + + /** + * Hold Instruction Code + */ + public static final ASN1ObjectIdentifier instructionCode = new ASN1ObjectIdentifier("2.5.29.23"); + + /** + * Invalidity Date + */ + public static final ASN1ObjectIdentifier invalidityDate = new ASN1ObjectIdentifier("2.5.29.24"); + + /** + * Delta CRL indicator + */ + public static final ASN1ObjectIdentifier deltaCRLIndicator = new ASN1ObjectIdentifier("2.5.29.27"); + + /** + * Issuing Distribution Point + */ + public static final ASN1ObjectIdentifier issuingDistributionPoint = new ASN1ObjectIdentifier("2.5.29.28"); + + /** + * Certificate Issuer + */ + public static final ASN1ObjectIdentifier certificateIssuer = new ASN1ObjectIdentifier("2.5.29.29"); + + /** + * Name Constraints + */ + public static final ASN1ObjectIdentifier nameConstraints = new ASN1ObjectIdentifier("2.5.29.30"); + + /** + * CRL Distribution Points + */ + public static final ASN1ObjectIdentifier cRLDistributionPoints = new ASN1ObjectIdentifier("2.5.29.31"); + + /** + * Certificate Policies + */ + public static final ASN1ObjectIdentifier certificatePolicies = new ASN1ObjectIdentifier("2.5.29.32"); + + /** + * Policy Mappings + */ + public static final ASN1ObjectIdentifier policyMappings = new ASN1ObjectIdentifier("2.5.29.33"); + + /** + * Authority Key Identifier + */ + public static final ASN1ObjectIdentifier authorityKeyIdentifier = new ASN1ObjectIdentifier("2.5.29.35"); + + /** + * Policy Constraints + */ + public static final ASN1ObjectIdentifier policyConstraints = new ASN1ObjectIdentifier("2.5.29.36"); + + /** + * Extended Key Usage + */ + public static final ASN1ObjectIdentifier extendedKeyUsage = new ASN1ObjectIdentifier("2.5.29.37"); + + /** + * Freshest CRL + */ + public static final ASN1ObjectIdentifier freshestCRL = new ASN1ObjectIdentifier("2.5.29.46"); + + /** + * Inhibit Any Policy + */ + public static final ASN1ObjectIdentifier inhibitAnyPolicy = new ASN1ObjectIdentifier("2.5.29.54"); + + /** + * Authority Info Access + */ + public static final ASN1ObjectIdentifier authorityInfoAccess = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.1"); + + /** + * Subject Info Access + */ + public static final ASN1ObjectIdentifier subjectInfoAccess = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.11"); + + /** + * Logo Type + */ + public static final ASN1ObjectIdentifier logoType = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.12"); + + /** + * BiometricInfo + */ + public static final ASN1ObjectIdentifier biometricInfo = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.2"); + + /** + * QCStatements + */ + public static final ASN1ObjectIdentifier qCStatements = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.3"); + + /** + * Audit identity extension in attribute certificates. + */ + public static final ASN1ObjectIdentifier auditIdentity = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.4"); + + /** + * NoRevAvail extension in attribute certificates. + */ + public static final ASN1ObjectIdentifier noRevAvail = new ASN1ObjectIdentifier("2.5.29.56"); + + /** + * TargetInformation extension in attribute certificates. + */ + public static final ASN1ObjectIdentifier targetInformation = new ASN1ObjectIdentifier("2.5.29.55"); + + boolean critical; + ASN1OctetString value; + + public X509Extension( + DERBoolean critical, + ASN1OctetString value) + { + this.critical = critical.isTrue(); + this.value = value; + } + + public X509Extension( + boolean critical, + ASN1OctetString value) + { + this.critical = critical; + this.value = value; + } + + public boolean isCritical() + { + return critical; + } + + public ASN1OctetString getValue() + { + return value; + } + + public ASN1Encodable getParsedValue() + { + return convertValueToObject(this); + } + + public int hashCode() + { + if (this.isCritical()) + { + return this.getValue().hashCode(); + } + + return ~this.getValue().hashCode(); + } + + public boolean equals( + Object o) + { + if (!(o instanceof X509Extension)) + { + return false; + } + + X509Extension other = (X509Extension)o; + + return other.getValue().equals(this.getValue()) + && (other.isCritical() == this.isCritical()); + } + + /** + * Convert the value of the passed in extension to an object + * @param ext the extension to parse + * @return the object the value string contains + * @exception IllegalArgumentException if conversion is not possible + */ + public static ASN1Primitive convertValueToObject( + X509Extension ext) + throws IllegalArgumentException + { + try + { + return ASN1Primitive.fromByteArray(ext.getValue().getOctets()); + } + catch (IOException e) + { + throw new IllegalArgumentException("can't convert extension: " + e); + } + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/X509Extensions.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/X509Extensions.java new file mode 100644 index 0000000..096d6b7 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/X509Extensions.java @@ -0,0 +1,489 @@ +package org.bc.asn1.x509; + +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Vector; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1ObjectIdentifier; +import org.bc.asn1.ASN1OctetString; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERBoolean; +import org.bc.asn1.DERObjectIdentifier; +import org.bc.asn1.DERSequence; + +/** + * @deprecated use Extensions + */ +public class X509Extensions + extends ASN1Object +{ + /** + * Subject Directory Attributes + * @deprecated use X509Extension value. + */ + public static final ASN1ObjectIdentifier SubjectDirectoryAttributes = new ASN1ObjectIdentifier("2.5.29.9"); + + /** + * Subject Key Identifier + * @deprecated use X509Extension value. + */ + public static final ASN1ObjectIdentifier SubjectKeyIdentifier = new ASN1ObjectIdentifier("2.5.29.14"); + + /** + * Key Usage + * @deprecated use X509Extension value. + */ + public static final ASN1ObjectIdentifier KeyUsage = new ASN1ObjectIdentifier("2.5.29.15"); + + /** + * Private Key Usage Period + * @deprecated use X509Extension value. + */ + public static final ASN1ObjectIdentifier PrivateKeyUsagePeriod = new ASN1ObjectIdentifier("2.5.29.16"); + + /** + * Subject Alternative Name + * @deprecated use X509Extension value. + */ + public static final ASN1ObjectIdentifier SubjectAlternativeName = new ASN1ObjectIdentifier("2.5.29.17"); + + /** + * Issuer Alternative Name + * @deprecated use X509Extension value. + */ + public static final ASN1ObjectIdentifier IssuerAlternativeName = new ASN1ObjectIdentifier("2.5.29.18"); + + /** + * Basic Constraints + * @deprecated use X509Extension value. + */ + public static final ASN1ObjectIdentifier BasicConstraints = new ASN1ObjectIdentifier("2.5.29.19"); + + /** + * CRL Number + * @deprecated use X509Extension value. + */ + public static final ASN1ObjectIdentifier CRLNumber = new ASN1ObjectIdentifier("2.5.29.20"); + + /** + * Reason code + * @deprecated use X509Extension value. + */ + public static final ASN1ObjectIdentifier ReasonCode = new ASN1ObjectIdentifier("2.5.29.21"); + + /** + * Hold Instruction Code + * @deprecated use X509Extension value. + */ + public static final ASN1ObjectIdentifier InstructionCode = new ASN1ObjectIdentifier("2.5.29.23"); + + /** + * Invalidity Date + * @deprecated use X509Extension value. + */ + public static final ASN1ObjectIdentifier InvalidityDate = new ASN1ObjectIdentifier("2.5.29.24"); + + /** + * Delta CRL indicator + * @deprecated use X509Extension value. + */ + public static final ASN1ObjectIdentifier DeltaCRLIndicator = new ASN1ObjectIdentifier("2.5.29.27"); + + /** + * Issuing Distribution Point + * @deprecated use X509Extension value. + */ + public static final ASN1ObjectIdentifier IssuingDistributionPoint = new ASN1ObjectIdentifier("2.5.29.28"); + + /** + * Certificate Issuer + * @deprecated use X509Extension value. + */ + public static final ASN1ObjectIdentifier CertificateIssuer = new ASN1ObjectIdentifier("2.5.29.29"); + + /** + * Name Constraints + * @deprecated use X509Extension value. + */ + public static final ASN1ObjectIdentifier NameConstraints = new ASN1ObjectIdentifier("2.5.29.30"); + + /** + * CRL Distribution Points + * @deprecated use X509Extension value. + */ + public static final ASN1ObjectIdentifier CRLDistributionPoints = new ASN1ObjectIdentifier("2.5.29.31"); + + /** + * Certificate Policies + * @deprecated use X509Extension value. + */ + public static final ASN1ObjectIdentifier CertificatePolicies = new ASN1ObjectIdentifier("2.5.29.32"); + + /** + * Policy Mappings + * @deprecated use X509Extension value. + */ + public static final ASN1ObjectIdentifier PolicyMappings = new ASN1ObjectIdentifier("2.5.29.33"); + + /** + * Authority Key Identifier + * @deprecated use X509Extension value. + */ + public static final ASN1ObjectIdentifier AuthorityKeyIdentifier = new ASN1ObjectIdentifier("2.5.29.35"); + + /** + * Policy Constraints + * @deprecated use X509Extension value. + */ + public static final ASN1ObjectIdentifier PolicyConstraints = new ASN1ObjectIdentifier("2.5.29.36"); + + /** + * Extended Key Usage + * @deprecated use X509Extension value. + */ + public static final ASN1ObjectIdentifier ExtendedKeyUsage = new ASN1ObjectIdentifier("2.5.29.37"); + + /** + * Freshest CRL + * @deprecated use X509Extension value. + */ + public static final ASN1ObjectIdentifier FreshestCRL = new ASN1ObjectIdentifier("2.5.29.46"); + + /** + * Inhibit Any Policy + * @deprecated use X509Extension value. + */ + public static final ASN1ObjectIdentifier InhibitAnyPolicy = new ASN1ObjectIdentifier("2.5.29.54"); + + /** + * Authority Info Access + * @deprecated use X509Extension value. + */ + public static final ASN1ObjectIdentifier AuthorityInfoAccess = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.1"); + + /** + * Subject Info Access + * @deprecated use X509Extension value. + */ + public static final ASN1ObjectIdentifier SubjectInfoAccess = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.11"); + + /** + * Logo Type + * @deprecated use X509Extension value. + */ + public static final ASN1ObjectIdentifier LogoType = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.12"); + + /** + * BiometricInfo + * @deprecated use X509Extension value. + */ + public static final ASN1ObjectIdentifier BiometricInfo = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.2"); + + /** + * QCStatements + * @deprecated use X509Extension value. + */ + public static final ASN1ObjectIdentifier QCStatements = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.3"); + + /** + * Audit identity extension in attribute certificates. + * @deprecated use X509Extension value. + */ + public static final ASN1ObjectIdentifier AuditIdentity = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.4"); + + /** + * NoRevAvail extension in attribute certificates. + * @deprecated use X509Extension value. + */ + public static final ASN1ObjectIdentifier NoRevAvail = new ASN1ObjectIdentifier("2.5.29.56"); + + /** + * TargetInformation extension in attribute certificates. + * @deprecated use X509Extension value. + */ + public static final ASN1ObjectIdentifier TargetInformation = new ASN1ObjectIdentifier("2.5.29.55"); + + private Hashtable extensions = new Hashtable(); + private Vector ordering = new Vector(); + + public static X509Extensions getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static X509Extensions getInstance( + Object obj) + { + if (obj == null || obj instanceof X509Extensions) + { + return (X509Extensions)obj; + } + + if (obj instanceof ASN1Sequence) + { + return new X509Extensions((ASN1Sequence)obj); + } + + if (obj instanceof Extensions) + { + return new X509Extensions((ASN1Sequence)((Extensions)obj).toASN1Primitive()); + } + + if (obj instanceof ASN1TaggedObject) + { + return getInstance(((ASN1TaggedObject)obj).getObject()); + } + + throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); + } + + /** + * Constructor from ASN1Sequence. + * + * the extensions are a list of constructed sequences, either with (OID, OctetString) or (OID, Boolean, OctetString) + */ + public X509Extensions( + ASN1Sequence seq) + { + Enumeration e = seq.getObjects(); + + while (e.hasMoreElements()) + { + ASN1Sequence s = ASN1Sequence.getInstance(e.nextElement()); + + if (s.size() == 3) + { + extensions.put(s.getObjectAt(0), new X509Extension(DERBoolean.getInstance(s.getObjectAt(1)), ASN1OctetString.getInstance(s.getObjectAt(2)))); + } + else if (s.size() == 2) + { + extensions.put(s.getObjectAt(0), new X509Extension(false, ASN1OctetString.getInstance(s.getObjectAt(1)))); + } + else + { + throw new IllegalArgumentException("Bad sequence size: " + s.size()); + } + + ordering.addElement(s.getObjectAt(0)); + } + } + + /** + * constructor from a table of extensions. + *
+ * it's is assumed the table contains OID/String pairs. + */ + public X509Extensions( + Hashtable extensions) + { + this(null, extensions); + } + + /** + * Constructor from a table of extensions with ordering. + *
+ * It's is assumed the table contains OID/String pairs. + * @deprecated use Extensions + */ + public X509Extensions( + Vector ordering, + Hashtable extensions) + { + Enumeration e; + + if (ordering == null) + { + e = extensions.keys(); + } + else + { + e = ordering.elements(); + } + + while (e.hasMoreElements()) + { + this.ordering.addElement(ASN1ObjectIdentifier.getInstance(e.nextElement())); + } + + e = this.ordering.elements(); + + while (e.hasMoreElements()) + { + ASN1ObjectIdentifier oid = ASN1ObjectIdentifier.getInstance(e.nextElement()); + X509Extension ext = (X509Extension)extensions.get(oid); + + this.extensions.put(oid, ext); + } + } + + /** + * Constructor from two vectors + * + * @param objectIDs a vector of the object identifiers. + * @param values a vector of the extension values. + * @deprecated use Extensions + */ + public X509Extensions( + Vector objectIDs, + Vector values) + { + Enumeration e = objectIDs.elements(); + + while (e.hasMoreElements()) + { + this.ordering.addElement(e.nextElement()); + } + + int count = 0; + + e = this.ordering.elements(); + + while (e.hasMoreElements()) + { + ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement(); + X509Extension ext = (X509Extension)values.elementAt(count); + + this.extensions.put(oid, ext); + count++; + } + } + + /** + * return an Enumeration of the extension field's object ids. + */ + public Enumeration oids() + { + return ordering.elements(); + } + + /** + * return the extension represented by the object identifier + * passed in. + * + * @return the extension if it's present, null otherwise. + */ + public X509Extension getExtension( + DERObjectIdentifier oid) + { + return (X509Extension)extensions.get(oid); + } + + /** + * @deprecated + * @param oid + * @return + */ + public X509Extension getExtension( + ASN1ObjectIdentifier oid) + { + return (X509Extension)extensions.get(oid); + } + + /** + *
+ * Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension + * + * Extension ::= SEQUENCE { + * extnId EXTENSION.&id ({ExtensionSet}), + * critical BOOLEAN DEFAULT FALSE, + * extnValue OCTET STRING } + *+ */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector vec = new ASN1EncodableVector(); + Enumeration e = ordering.elements(); + + while (e.hasMoreElements()) + { + ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement(); + X509Extension ext = (X509Extension)extensions.get(oid); + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(oid); + + if (ext.isCritical()) + { + v.add(DERBoolean.TRUE); + } + + v.add(ext.getValue()); + + vec.add(new DERSequence(v)); + } + + return new DERSequence(vec); + } + + public boolean equivalent( + X509Extensions other) + { + if (extensions.size() != other.extensions.size()) + { + return false; + } + + Enumeration e1 = extensions.keys(); + + while (e1.hasMoreElements()) + { + Object key = e1.nextElement(); + + if (!extensions.get(key).equals(other.extensions.get(key))) + { + return false; + } + } + + return true; + } + + public ASN1ObjectIdentifier[] getExtensionOIDs() + { + return toOidArray(ordering); + } + + public ASN1ObjectIdentifier[] getNonCriticalExtensionOIDs() + { + return getExtensionOIDs(false); + } + + public ASN1ObjectIdentifier[] getCriticalExtensionOIDs() + { + return getExtensionOIDs(true); + } + + private ASN1ObjectIdentifier[] getExtensionOIDs(boolean isCritical) + { + Vector oidVec = new Vector(); + + for (int i = 0; i != ordering.size(); i++) + { + Object oid = ordering.elementAt(i); + + if (((X509Extension)extensions.get(oid)).isCritical() == isCritical) + { + oidVec.addElement(oid); + } + } + + return toOidArray(oidVec); + } + + private ASN1ObjectIdentifier[] toOidArray(Vector oidVec) + { + ASN1ObjectIdentifier[] oids = new ASN1ObjectIdentifier[oidVec.size()]; + + for (int i = 0; i != oids.length; i++) + { + oids[i] = (ASN1ObjectIdentifier)oidVec.elementAt(i); + } + return oids; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/X509ExtensionsGenerator.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/X509ExtensionsGenerator.java new file mode 100644 index 0000000..a6c98c1 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/X509ExtensionsGenerator.java @@ -0,0 +1,117 @@ +package org.bc.asn1.x509; + +import java.io.IOException; +import java.util.Hashtable; +import java.util.Vector; + +import org.bc.asn1.ASN1Encodable; +import org.bc.asn1.ASN1Encoding; +import org.bc.asn1.ASN1ObjectIdentifier; +import org.bc.asn1.DERObjectIdentifier; +import org.bc.asn1.DEROctetString; + +/** + * Generator for X.509 extensions + * @deprecated use org.bouncycastle.asn1.x509.ExtensionsGenerator + */ +public class X509ExtensionsGenerator +{ + private Hashtable extensions = new Hashtable(); + private Vector extOrdering = new Vector(); + + /** + * Reset the generator + */ + public void reset() + { + extensions = new Hashtable(); + extOrdering = new Vector(); + } + + /** + * @deprecated use ASN1ObjectIdentifier + */ + public void addExtension( + DERObjectIdentifier oid, + boolean critical, + ASN1Encodable value) + { + addExtension(new ASN1ObjectIdentifier(oid.getId()), critical, value); + } + + /** + * @deprecated use ASN1ObjectIdentifier + */ + public void addExtension( + DERObjectIdentifier oid, + boolean critical, + byte[] value) + { + addExtension(new ASN1ObjectIdentifier(oid.getId()), critical, value); + } + + /** + * Add an extension with the given oid and the passed in value to be included + * in the OCTET STRING associated with the extension. + * + * @param oid OID for the extension. + * @param critical true if critical, false otherwise. + * @param value the ASN.1 object to be included in the extension. + */ + public void addExtension( + ASN1ObjectIdentifier oid, + boolean critical, + ASN1Encodable value) + { + try + { + this.addExtension(oid, critical, value.toASN1Primitive().getEncoded(ASN1Encoding.DER)); + } + catch (IOException e) + { + throw new IllegalArgumentException("error encoding value: " + e); + } + } + + /** + * Add an extension with the given oid and the passed in byte array to be wrapped in the + * OCTET STRING associated with the extension. + * + * @param oid OID for the extension. + * @param critical true if critical, false otherwise. + * @param value the byte array to be wrapped. + */ + public void addExtension( + ASN1ObjectIdentifier oid, + boolean critical, + byte[] value) + { + if (extensions.containsKey(oid)) + { + throw new IllegalArgumentException("extension " + oid + " already added"); + } + + extOrdering.addElement(oid); + extensions.put(oid, new X509Extension(critical, new DEROctetString(value))); + } + + /** + * Return true if there are no extension present in this generator. + * + * @return true if empty, false otherwise + */ + public boolean isEmpty() + { + return extOrdering.isEmpty(); + } + + /** + * Generate an X509Extensions object based on the current state of the generator. + * + * @return an X09Extensions object. + */ + public X509Extensions generate() + { + return new X509Extensions(extOrdering, extensions); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/X509Name.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/X509Name.java new file mode 100644 index 0000000..bb17373 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/X509Name.java @@ -0,0 +1,1280 @@ +package org.bc.asn1.x509; + +import java.io.IOException; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Vector; + +import org.bc.asn1.ASN1Encodable; +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Encoding; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1ObjectIdentifier; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1Set; +import org.bc.asn1.ASN1String; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERSequence; +import org.bc.asn1.DERSet; +import org.bc.asn1.DERUniversalString; +import org.bc.asn1.pkcs.PKCSObjectIdentifiers; +import org.bc.asn1.x500.X500Name; +import org.bc.util.Strings; +import org.bc.util.encoders.Hex; + +/** + *
+ * RDNSequence ::= SEQUENCE OF RelativeDistinguishedName + * + * RelativeDistinguishedName ::= SET SIZE (1..MAX) OF AttributeTypeAndValue + * + * AttributeTypeAndValue ::= SEQUENCE { + * type OBJECT IDENTIFIER, + * value ANY } + *+ * @deprecated use org.bouncycastle.asn1.x500.X500Name. + */ +public class X509Name + extends ASN1Object +{ + /** + * country code - StringType(SIZE(2)) + * @deprecated use a X500NameStyle + */ + public static final ASN1ObjectIdentifier C = new ASN1ObjectIdentifier("2.5.4.6"); + + /** + * organization - StringType(SIZE(1..64)) + * @deprecated use a X500NameStyle + */ + public static final ASN1ObjectIdentifier O = new ASN1ObjectIdentifier("2.5.4.10"); + + /** + * organizational unit name - StringType(SIZE(1..64)) + * @deprecated use a X500NameStyle + */ + public static final ASN1ObjectIdentifier OU = new ASN1ObjectIdentifier("2.5.4.11"); + + /** + * Title + * @deprecated use a X500NameStyle + */ + public static final ASN1ObjectIdentifier T = new ASN1ObjectIdentifier("2.5.4.12"); + + /** + * common name - StringType(SIZE(1..64)) + * @deprecated use a X500NameStyle + */ + public static final ASN1ObjectIdentifier CN = new ASN1ObjectIdentifier("2.5.4.3"); + + /** + * device serial number name - StringType(SIZE(1..64)) + */ + public static final ASN1ObjectIdentifier SN = new ASN1ObjectIdentifier("2.5.4.5"); + + /** + * street - StringType(SIZE(1..64)) + */ + public static final ASN1ObjectIdentifier STREET = new ASN1ObjectIdentifier("2.5.4.9"); + + /** + * device serial number name - StringType(SIZE(1..64)) + */ + public static final ASN1ObjectIdentifier SERIALNUMBER = SN; + + /** + * locality name - StringType(SIZE(1..64)) + */ + public static final ASN1ObjectIdentifier L = new ASN1ObjectIdentifier("2.5.4.7"); + + /** + * state, or province name - StringType(SIZE(1..64)) + */ + public static final ASN1ObjectIdentifier ST = new ASN1ObjectIdentifier("2.5.4.8"); + + /** + * Naming attributes of type X520name + */ + public static final ASN1ObjectIdentifier SURNAME = new ASN1ObjectIdentifier("2.5.4.4"); + public static final ASN1ObjectIdentifier GIVENNAME = new ASN1ObjectIdentifier("2.5.4.42"); + public static final ASN1ObjectIdentifier INITIALS = new ASN1ObjectIdentifier("2.5.4.43"); + public static final ASN1ObjectIdentifier GENERATION = new ASN1ObjectIdentifier("2.5.4.44"); + public static final ASN1ObjectIdentifier UNIQUE_IDENTIFIER = new ASN1ObjectIdentifier("2.5.4.45"); + + /** + * businessCategory - DirectoryString(SIZE(1..128) + */ + public static final ASN1ObjectIdentifier BUSINESS_CATEGORY = new ASN1ObjectIdentifier( + "2.5.4.15"); + + /** + * postalCode - DirectoryString(SIZE(1..40) + */ + public static final ASN1ObjectIdentifier POSTAL_CODE = new ASN1ObjectIdentifier( + "2.5.4.17"); + + /** + * dnQualifier - DirectoryString(SIZE(1..64) + */ + public static final ASN1ObjectIdentifier DN_QUALIFIER = new ASN1ObjectIdentifier( + "2.5.4.46"); + + /** + * RFC 3039 Pseudonym - DirectoryString(SIZE(1..64) + */ + public static final ASN1ObjectIdentifier PSEUDONYM = new ASN1ObjectIdentifier( + "2.5.4.65"); + + + /** + * RFC 3039 DateOfBirth - GeneralizedTime - YYYYMMDD000000Z + */ + public static final ASN1ObjectIdentifier DATE_OF_BIRTH = new ASN1ObjectIdentifier( + "1.3.6.1.5.5.7.9.1"); + + /** + * RFC 3039 PlaceOfBirth - DirectoryString(SIZE(1..128) + */ + public static final ASN1ObjectIdentifier PLACE_OF_BIRTH = new ASN1ObjectIdentifier( + "1.3.6.1.5.5.7.9.2"); + + /** + * RFC 3039 Gender - PrintableString (SIZE(1)) -- "M", "F", "m" or "f" + */ + public static final ASN1ObjectIdentifier GENDER = new ASN1ObjectIdentifier( + "1.3.6.1.5.5.7.9.3"); + + /** + * RFC 3039 CountryOfCitizenship - PrintableString (SIZE (2)) -- ISO 3166 + * codes only + */ + public static final ASN1ObjectIdentifier COUNTRY_OF_CITIZENSHIP = new ASN1ObjectIdentifier( + "1.3.6.1.5.5.7.9.4"); + + /** + * RFC 3039 CountryOfResidence - PrintableString (SIZE (2)) -- ISO 3166 + * codes only + */ + public static final ASN1ObjectIdentifier COUNTRY_OF_RESIDENCE = new ASN1ObjectIdentifier( + "1.3.6.1.5.5.7.9.5"); + + + /** + * ISIS-MTT NameAtBirth - DirectoryString(SIZE(1..64) + */ + public static final ASN1ObjectIdentifier NAME_AT_BIRTH = new ASN1ObjectIdentifier("1.3.36.8.3.14"); + + /** + * RFC 3039 PostalAddress - SEQUENCE SIZE (1..6) OF + * DirectoryString(SIZE(1..30)) + */ + public static final ASN1ObjectIdentifier POSTAL_ADDRESS = new ASN1ObjectIdentifier("2.5.4.16"); + + /** + * RFC 2256 dmdName + */ + public static final ASN1ObjectIdentifier DMD_NAME = new ASN1ObjectIdentifier("2.5.4.54"); + + /** + * id-at-telephoneNumber + */ + public static final ASN1ObjectIdentifier TELEPHONE_NUMBER = X509ObjectIdentifiers.id_at_telephoneNumber; + + /** + * id-at-name + */ + public static final ASN1ObjectIdentifier NAME = X509ObjectIdentifiers.id_at_name; + + /** + * Email address (RSA PKCS#9 extension) - IA5String. + *
Note: if you're trying to be ultra orthodox, don't use this! It shouldn't be in here. + * @deprecated use a X500NameStyle + */ + public static final ASN1ObjectIdentifier EmailAddress = PKCSObjectIdentifiers.pkcs_9_at_emailAddress; + + /** + * more from PKCS#9 + */ + public static final ASN1ObjectIdentifier UnstructuredName = PKCSObjectIdentifiers.pkcs_9_at_unstructuredName; + public static final ASN1ObjectIdentifier UnstructuredAddress = PKCSObjectIdentifiers.pkcs_9_at_unstructuredAddress; + + /** + * email address in Verisign certificates + */ + public static final ASN1ObjectIdentifier E = EmailAddress; + + /* + * others... + */ + public static final ASN1ObjectIdentifier DC = new ASN1ObjectIdentifier("0.9.2342.19200300.100.1.25"); + + /** + * LDAP User id. + */ + public static final ASN1ObjectIdentifier UID = new ASN1ObjectIdentifier("0.9.2342.19200300.100.1.1"); + + /** + * determines whether or not strings should be processed and printed + * from back to front. + */ + public static boolean DefaultReverse = false; + + /** + * default look up table translating OID values into their common symbols following + * the convention in RFC 2253 with a few extras + */ + public static final Hashtable DefaultSymbols = new Hashtable(); + + /** + * look up table translating OID values into their common symbols following the convention in RFC 2253 + * + */ + public static final Hashtable RFC2253Symbols = new Hashtable(); + + /** + * look up table translating OID values into their common symbols following the convention in RFC 1779 + * + */ + public static final Hashtable RFC1779Symbols = new Hashtable(); + + /** + * look up table translating common symbols into their OIDS. + */ + public static final Hashtable DefaultLookUp = new Hashtable(); + + /** + * look up table translating OID values into their common symbols + * @deprecated use DefaultSymbols + */ + public static final Hashtable OIDLookUp = DefaultSymbols; + + /** + * look up table translating string values into their OIDS - + * @deprecated use DefaultLookUp + */ + public static final Hashtable SymbolLookUp = DefaultLookUp; + + private static final Boolean TRUE = new Boolean(true); // for J2ME compatibility + private static final Boolean FALSE = new Boolean(false); + + static + { + DefaultSymbols.put(C, "C"); + DefaultSymbols.put(O, "O"); + DefaultSymbols.put(T, "T"); + DefaultSymbols.put(OU, "OU"); + DefaultSymbols.put(CN, "CN"); + DefaultSymbols.put(L, "L"); + DefaultSymbols.put(ST, "ST"); + DefaultSymbols.put(SN, "SERIALNUMBER"); + DefaultSymbols.put(EmailAddress, "E"); + DefaultSymbols.put(DC, "DC"); + DefaultSymbols.put(UID, "UID"); + DefaultSymbols.put(STREET, "STREET"); + DefaultSymbols.put(SURNAME, "SURNAME"); + DefaultSymbols.put(GIVENNAME, "GIVENNAME"); + DefaultSymbols.put(INITIALS, "INITIALS"); + DefaultSymbols.put(GENERATION, "GENERATION"); + DefaultSymbols.put(UnstructuredAddress, "unstructuredAddress"); + DefaultSymbols.put(UnstructuredName, "unstructuredName"); + DefaultSymbols.put(UNIQUE_IDENTIFIER, "UniqueIdentifier"); + DefaultSymbols.put(DN_QUALIFIER, "DN"); + DefaultSymbols.put(PSEUDONYM, "Pseudonym"); + DefaultSymbols.put(POSTAL_ADDRESS, "PostalAddress"); + DefaultSymbols.put(NAME_AT_BIRTH, "NameAtBirth"); + DefaultSymbols.put(COUNTRY_OF_CITIZENSHIP, "CountryOfCitizenship"); + DefaultSymbols.put(COUNTRY_OF_RESIDENCE, "CountryOfResidence"); + DefaultSymbols.put(GENDER, "Gender"); + DefaultSymbols.put(PLACE_OF_BIRTH, "PlaceOfBirth"); + DefaultSymbols.put(DATE_OF_BIRTH, "DateOfBirth"); + DefaultSymbols.put(POSTAL_CODE, "PostalCode"); + DefaultSymbols.put(BUSINESS_CATEGORY, "BusinessCategory"); + DefaultSymbols.put(TELEPHONE_NUMBER, "TelephoneNumber"); + DefaultSymbols.put(NAME, "Name"); + + RFC2253Symbols.put(C, "C"); + RFC2253Symbols.put(O, "O"); + RFC2253Symbols.put(OU, "OU"); + RFC2253Symbols.put(CN, "CN"); + RFC2253Symbols.put(L, "L"); + RFC2253Symbols.put(ST, "ST"); + RFC2253Symbols.put(STREET, "STREET"); + RFC2253Symbols.put(DC, "DC"); + RFC2253Symbols.put(UID, "UID"); + + RFC1779Symbols.put(C, "C"); + RFC1779Symbols.put(O, "O"); + RFC1779Symbols.put(OU, "OU"); + RFC1779Symbols.put(CN, "CN"); + RFC1779Symbols.put(L, "L"); + RFC1779Symbols.put(ST, "ST"); + RFC1779Symbols.put(STREET, "STREET"); + + DefaultLookUp.put("c", C); + DefaultLookUp.put("o", O); + DefaultLookUp.put("t", T); + DefaultLookUp.put("ou", OU); + DefaultLookUp.put("cn", CN); + DefaultLookUp.put("l", L); + DefaultLookUp.put("st", ST); + DefaultLookUp.put("sn", SN); + DefaultLookUp.put("serialnumber", SN); + DefaultLookUp.put("street", STREET); + DefaultLookUp.put("emailaddress", E); + DefaultLookUp.put("dc", DC); + DefaultLookUp.put("e", E); + DefaultLookUp.put("uid", UID); + DefaultLookUp.put("surname", SURNAME); + DefaultLookUp.put("givenname", GIVENNAME); + DefaultLookUp.put("initials", INITIALS); + DefaultLookUp.put("generation", GENERATION); + DefaultLookUp.put("unstructuredaddress", UnstructuredAddress); + DefaultLookUp.put("unstructuredname", UnstructuredName); + DefaultLookUp.put("uniqueidentifier", UNIQUE_IDENTIFIER); + DefaultLookUp.put("dn", DN_QUALIFIER); + DefaultLookUp.put("pseudonym", PSEUDONYM); + DefaultLookUp.put("postaladdress", POSTAL_ADDRESS); + DefaultLookUp.put("nameofbirth", NAME_AT_BIRTH); + DefaultLookUp.put("countryofcitizenship", COUNTRY_OF_CITIZENSHIP); + DefaultLookUp.put("countryofresidence", COUNTRY_OF_RESIDENCE); + DefaultLookUp.put("gender", GENDER); + DefaultLookUp.put("placeofbirth", PLACE_OF_BIRTH); + DefaultLookUp.put("dateofbirth", DATE_OF_BIRTH); + DefaultLookUp.put("postalcode", POSTAL_CODE); + DefaultLookUp.put("businesscategory", BUSINESS_CATEGORY); + DefaultLookUp.put("telephonenumber", TELEPHONE_NUMBER); + DefaultLookUp.put("name", NAME); + } + + private X509NameEntryConverter converter = null; + private Vector ordering = new Vector(); + private Vector values = new Vector(); + private Vector added = new Vector(); + + private ASN1Sequence seq; + + private boolean isHashCodeCalculated; + private int hashCodeValue; + + /** + * Return a X509Name based on the passed in tagged object. + * + * @param obj tag object holding name. + * @param explicit true if explicitly tagged false otherwise. + * @return the X509Name + */ + public static X509Name getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static X509Name getInstance( + Object obj) + { + if (obj == null || obj instanceof X509Name) + { + return (X509Name)obj; + } + else if (obj instanceof X500Name) + { + return new X509Name(ASN1Sequence.getInstance(((X500Name)obj).toASN1Primitive())); + } + else if (obj != null) + { + return new X509Name(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + protected X509Name() + { + // constructure use by new X500 Name class + } + /** + * Constructor from ASN1Sequence + * + * the principal will be a list of constructed sets, each containing an (OID, String) pair. + */ + public X509Name( + ASN1Sequence seq) + { + this.seq = seq; + + Enumeration e = seq.getObjects(); + + while (e.hasMoreElements()) + { + ASN1Set set = ASN1Set.getInstance(((ASN1Encodable)e.nextElement()).toASN1Primitive()); + + for (int i = 0; i < set.size(); i++) + { + ASN1Sequence s = ASN1Sequence.getInstance(set.getObjectAt(i).toASN1Primitive()); + + if (s.size() != 2) + { + throw new IllegalArgumentException("badly sized pair"); + } + + ordering.addElement(ASN1ObjectIdentifier.getInstance(s.getObjectAt(0))); + + ASN1Encodable value = s.getObjectAt(1); + if (value instanceof ASN1String && !(value instanceof DERUniversalString)) + { + String v = ((ASN1String)value).getString(); + if (v.length() > 0 && v.charAt(0) == '#') + { + values.addElement("\\" + v); + } + else + { + values.addElement(v); + } + } + else + { + try + { + values.addElement("#" + bytesToString(Hex.encode(value.toASN1Primitive().getEncoded(ASN1Encoding.DER)))); + } + catch (IOException e1) + { + throw new IllegalArgumentException("cannot encode value"); + } + } + added.addElement((i != 0) ? TRUE : FALSE); // to allow earlier JDK compatibility + } + } + } + + /** + * constructor from a table of attributes. + *
+ * it's is assumed the table contains OID/String pairs, and the contents + * of the table are copied into an internal table as part of the + * construction process. + *
+ * Note: if the name you are trying to generate should be + * following a specific ordering, you should use the constructor + * with the ordering specified below. + * @deprecated use an ordered constructor! The hashtable ordering is rarely correct + */ + public X509Name( + Hashtable attributes) + { + this(null, attributes); + } + + /** + * Constructor from a table of attributes with ordering. + *
+ * it's is assumed the table contains OID/String pairs, and the contents + * of the table are copied into an internal table as part of the + * construction process. The ordering vector should contain the OIDs + * in the order they are meant to be encoded or printed in toString. + */ + public X509Name( + Vector ordering, + Hashtable attributes) + { + this(ordering, attributes, new X509DefaultEntryConverter()); + } + + /** + * Constructor from a table of attributes with ordering. + *
+ * it's is assumed the table contains OID/String pairs, and the contents + * of the table are copied into an internal table as part of the + * construction process. The ordering vector should contain the OIDs + * in the order they are meant to be encoded or printed in toString. + *
+ * The passed in converter will be used to convert the strings into their + * ASN.1 counterparts. + */ + public X509Name( + Vector ordering, + Hashtable attributes, + X509NameEntryConverter converter) + { + this.converter = converter; + + if (ordering != null) + { + for (int i = 0; i != ordering.size(); i++) + { + this.ordering.addElement(ordering.elementAt(i)); + this.added.addElement(FALSE); + } + } + else + { + Enumeration e = attributes.keys(); + + while (e.hasMoreElements()) + { + this.ordering.addElement(e.nextElement()); + this.added.addElement(FALSE); + } + } + + for (int i = 0; i != this.ordering.size(); i++) + { + ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)this.ordering.elementAt(i); + + if (attributes.get(oid) == null) + { + throw new IllegalArgumentException("No attribute for object id - " + oid.getId() + " - passed to distinguished name"); + } + + this.values.addElement(attributes.get(oid)); // copy the hash table + } + } + + /** + * Takes two vectors one of the oids and the other of the values. + */ + public X509Name( + Vector oids, + Vector values) + { + this(oids, values, new X509DefaultEntryConverter()); + } + + /** + * Takes two vectors one of the oids and the other of the values. + *
+ * The passed in converter will be used to convert the strings into their
+ * ASN.1 counterparts.
+ */
+ public X509Name(
+ Vector oids,
+ Vector values,
+ X509NameEntryConverter converter)
+ {
+ this.converter = converter;
+
+ if (oids.size() != values.size())
+ {
+ throw new IllegalArgumentException("oids vector must be same length as values.");
+ }
+
+ for (int i = 0; i < oids.size(); i++)
+ {
+ this.ordering.addElement(oids.elementAt(i));
+ this.values.addElement(values.elementAt(i));
+ this.added.addElement(FALSE);
+ }
+ }
+
+// private Boolean isEncoded(String s)
+// {
+// if (s.charAt(0) == '#')
+// {
+// return TRUE;
+// }
+//
+// return FALSE;
+// }
+
+ /**
+ * Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or
+ * some such, converting it into an ordered set of name attributes.
+ */
+ public X509Name(
+ String dirName)
+ {
+ this(DefaultReverse, DefaultLookUp, dirName);
+ }
+
+ /**
+ * Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or
+ * some such, converting it into an ordered set of name attributes with each
+ * string value being converted to its associated ASN.1 type using the passed
+ * in converter.
+ */
+ public X509Name(
+ String dirName,
+ X509NameEntryConverter converter)
+ {
+ this(DefaultReverse, DefaultLookUp, dirName, converter);
+ }
+
+ /**
+ * Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or
+ * some such, converting it into an ordered set of name attributes. If reverse
+ * is true, create the encoded version of the sequence starting from the
+ * last element in the string.
+ */
+ public X509Name(
+ boolean reverse,
+ String dirName)
+ {
+ this(reverse, DefaultLookUp, dirName);
+ }
+
+ /**
+ * Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or
+ * some such, converting it into an ordered set of name attributes with each
+ * string value being converted to its associated ASN.1 type using the passed
+ * in converter. If reverse is true the ASN.1 sequence representing the DN will
+ * be built by starting at the end of the string, rather than the start.
+ */
+ public X509Name(
+ boolean reverse,
+ String dirName,
+ X509NameEntryConverter converter)
+ {
+ this(reverse, DefaultLookUp, dirName, converter);
+ }
+
+ /**
+ * Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or
+ * some such, converting it into an ordered set of name attributes. lookUp
+ * should provide a table of lookups, indexed by lowercase only strings and
+ * yielding a ASN1ObjectIdentifier, other than that OID. and numeric oids
+ * will be processed automatically.
+ *
+ * If reverse is true, create the encoded version of the sequence
+ * starting from the last element in the string.
+ * @param reverse true if we should start scanning from the end (RFC 2553).
+ * @param lookUp table of names and their oids.
+ * @param dirName the X.500 string to be parsed.
+ */
+ public X509Name(
+ boolean reverse,
+ Hashtable lookUp,
+ String dirName)
+ {
+ this(reverse, lookUp, dirName, new X509DefaultEntryConverter());
+ }
+
+ private ASN1ObjectIdentifier decodeOID(
+ String name,
+ Hashtable lookUp)
+ {
+ if (Strings.toUpperCase(name).startsWith("OID."))
+ {
+ return new ASN1ObjectIdentifier(name.substring(4));
+ }
+ else if (name.charAt(0) >= '0' && name.charAt(0) <= '9')
+ {
+ return new ASN1ObjectIdentifier(name);
+ }
+
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)lookUp.get(Strings.toLowerCase(name));
+ if (oid == null)
+ {
+ throw new IllegalArgumentException("Unknown object id - " + name + " - passed to distinguished name");
+ }
+
+ return oid;
+ }
+
+ /**
+ * Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or
+ * some such, converting it into an ordered set of name attributes. lookUp
+ * should provide a table of lookups, indexed by lowercase only strings and
+ * yielding a ASN1ObjectIdentifier, other than that OID. and numeric oids
+ * will be processed automatically. The passed in converter is used to convert the
+ * string values to the right of each equals sign to their ASN.1 counterparts.
+ *
+ * @param reverse true if we should start scanning from the end, false otherwise.
+ * @param lookUp table of names and oids.
+ * @param dirName the string dirName
+ * @param converter the converter to convert string values into their ASN.1 equivalents
+ */
+ public X509Name(
+ boolean reverse,
+ Hashtable lookUp,
+ String dirName,
+ X509NameEntryConverter converter)
+ {
+ this.converter = converter;
+ X509NameTokenizer nTok = new X509NameTokenizer(dirName);
+
+ while (nTok.hasMoreTokens())
+ {
+ String token = nTok.nextToken();
+ int index = token.indexOf('=');
+
+ if (index == -1)
+ {
+ throw new IllegalArgumentException("badly formatted directory string");
+ }
+
+ String name = token.substring(0, index);
+ String value = token.substring(index + 1);
+ ASN1ObjectIdentifier oid = decodeOID(name, lookUp);
+
+ if (value.indexOf('+') > 0)
+ {
+ X509NameTokenizer vTok = new X509NameTokenizer(value, '+');
+ String v = vTok.nextToken();
+
+ this.ordering.addElement(oid);
+ this.values.addElement(v);
+ this.added.addElement(FALSE);
+
+ while (vTok.hasMoreTokens())
+ {
+ String sv = vTok.nextToken();
+ int ndx = sv.indexOf('=');
+
+ String nm = sv.substring(0, ndx);
+ String vl = sv.substring(ndx + 1);
+ this.ordering.addElement(decodeOID(nm, lookUp));
+ this.values.addElement(vl);
+ this.added.addElement(TRUE);
+ }
+ }
+ else
+ {
+ this.ordering.addElement(oid);
+ this.values.addElement(value);
+ this.added.addElement(FALSE);
+ }
+ }
+
+ if (reverse)
+ {
+ Vector o = new Vector();
+ Vector v = new Vector();
+ Vector a = new Vector();
+
+ int count = 1;
+
+ for (int i = 0; i < this.ordering.size(); i++)
+ {
+ if (((Boolean)this.added.elementAt(i)).booleanValue())
+ {
+ o.insertElementAt(this.ordering.elementAt(i), count);
+ v.insertElementAt(this.values.elementAt(i), count);
+ a.insertElementAt(this.added.elementAt(i), count);
+ count++;
+ }
+ else
+ {
+ o.insertElementAt(this.ordering.elementAt(i), 0);
+ v.insertElementAt(this.values.elementAt(i), 0);
+ a.insertElementAt(this.added.elementAt(i), 0);
+ count = 1;
+ }
+ }
+
+ this.ordering = o;
+ this.values = v;
+ this.added = a;
+ }
+ }
+
+ /**
+ * return a vector of the oids in the name, in the order they were found.
+ */
+ public Vector getOIDs()
+ {
+ Vector v = new Vector();
+
+ for (int i = 0; i != ordering.size(); i++)
+ {
+ v.addElement(ordering.elementAt(i));
+ }
+
+ return v;
+ }
+
+ /**
+ * return a vector of the values found in the name, in the order they
+ * were found.
+ */
+ public Vector getValues()
+ {
+ Vector v = new Vector();
+
+ for (int i = 0; i != values.size(); i++)
+ {
+ v.addElement(values.elementAt(i));
+ }
+
+ return v;
+ }
+
+ /**
+ * return a vector of the values found in the name, in the order they
+ * were found, with the DN label corresponding to passed in oid.
+ */
+ public Vector getValues(
+ ASN1ObjectIdentifier oid)
+ {
+ Vector v = new Vector();
+
+ for (int i = 0; i != values.size(); i++)
+ {
+ if (ordering.elementAt(i).equals(oid))
+ {
+ String val = (String)values.elementAt(i);
+
+ if (val.length() > 2 && val.charAt(0) == '\\' && val.charAt(1) == '#')
+ {
+ v.addElement(val.substring(1));
+ }
+ else
+ {
+ v.addElement(val);
+ }
+ }
+ }
+
+ return v;
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+ if (seq == null)
+ {
+ ASN1EncodableVector vec = new ASN1EncodableVector();
+ ASN1EncodableVector sVec = new ASN1EncodableVector();
+ ASN1ObjectIdentifier lstOid = null;
+
+ for (int i = 0; i != ordering.size(); i++)
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)ordering.elementAt(i);
+
+ v.add(oid);
+
+ String str = (String)values.elementAt(i);
+
+ v.add(converter.getConvertedValue(oid, str));
+
+ if (lstOid == null
+ || ((Boolean)this.added.elementAt(i)).booleanValue())
+ {
+ sVec.add(new DERSequence(v));
+ }
+ else
+ {
+ vec.add(new DERSet(sVec));
+ sVec = new ASN1EncodableVector();
+
+ sVec.add(new DERSequence(v));
+ }
+
+ lstOid = oid;
+ }
+
+ vec.add(new DERSet(sVec));
+
+ seq = new DERSequence(vec);
+ }
+
+ return seq;
+ }
+
+ /**
+ * @param inOrder if true the order of both X509 names must be the same,
+ * as well as the values associated with each element.
+ */
+ public boolean equals(Object obj, boolean inOrder)
+ {
+ if (!inOrder)
+ {
+ return this.equals(obj);
+ }
+
+ if (obj == this)
+ {
+ return true;
+ }
+
+ if (!(obj instanceof X509Name || obj instanceof ASN1Sequence))
+ {
+ return false;
+ }
+
+ ASN1Primitive derO = ((ASN1Encodable)obj).toASN1Primitive();
+
+ if (this.toASN1Primitive().equals(derO))
+ {
+ return true;
+ }
+
+ X509Name other;
+
+ try
+ {
+ other = X509Name.getInstance(obj);
+ }
+ catch (IllegalArgumentException e)
+ {
+ return false;
+ }
+
+ int orderingSize = ordering.size();
+
+ if (orderingSize != other.ordering.size())
+ {
+ return false;
+ }
+
+ for (int i = 0; i < orderingSize; i++)
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)ordering.elementAt(i);
+ ASN1ObjectIdentifier oOid = (ASN1ObjectIdentifier)other.ordering.elementAt(i);
+
+ if (oid.equals(oOid))
+ {
+ String value = (String)values.elementAt(i);
+ String oValue = (String)other.values.elementAt(i);
+
+ if (!equivalentStrings(value, oValue))
+ {
+ return false;
+ }
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public int hashCode()
+ {
+ if (isHashCodeCalculated)
+ {
+ return hashCodeValue;
+ }
+
+ isHashCodeCalculated = true;
+
+ // this needs to be order independent, like equals
+ for (int i = 0; i != ordering.size(); i += 1)
+ {
+ String value = (String)values.elementAt(i);
+
+ value = canonicalize(value);
+ value = stripInternalSpaces(value);
+
+ hashCodeValue ^= ordering.elementAt(i).hashCode();
+ hashCodeValue ^= value.hashCode();
+ }
+
+ return hashCodeValue;
+ }
+
+ /**
+ * test for equality - note: case is ignored.
+ */
+ public boolean equals(Object obj)
+ {
+ if (obj == this)
+ {
+ return true;
+ }
+
+ if (!(obj instanceof X509Name || obj instanceof ASN1Sequence))
+ {
+ return false;
+ }
+
+ ASN1Primitive derO = ((ASN1Encodable)obj).toASN1Primitive();
+
+ if (this.toASN1Primitive().equals(derO))
+ {
+ return true;
+ }
+
+ X509Name other;
+
+ try
+ {
+ other = X509Name.getInstance(obj);
+ }
+ catch (IllegalArgumentException e)
+ {
+ return false;
+ }
+
+ int orderingSize = ordering.size();
+
+ if (orderingSize != other.ordering.size())
+ {
+ return false;
+ }
+
+ boolean[] indexes = new boolean[orderingSize];
+ int start, end, delta;
+
+ if (ordering.elementAt(0).equals(other.ordering.elementAt(0))) // guess forward
+ {
+ start = 0;
+ end = orderingSize;
+ delta = 1;
+ }
+ else // guess reversed - most common problem
+ {
+ start = orderingSize - 1;
+ end = -1;
+ delta = -1;
+ }
+
+ for (int i = start; i != end; i += delta)
+ {
+ boolean found = false;
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)ordering.elementAt(i);
+ String value = (String)values.elementAt(i);
+
+ for (int j = 0; j < orderingSize; j++)
+ {
+ if (indexes[j])
+ {
+ continue;
+ }
+
+ ASN1ObjectIdentifier oOid = (ASN1ObjectIdentifier)other.ordering.elementAt(j);
+
+ if (oid.equals(oOid))
+ {
+ String oValue = (String)other.values.elementAt(j);
+
+ if (equivalentStrings(value, oValue))
+ {
+ indexes[j] = true;
+ found = true;
+ break;
+ }
+ }
+ }
+
+ if (!found)
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ private boolean equivalentStrings(String s1, String s2)
+ {
+ String value = canonicalize(s1);
+ String oValue = canonicalize(s2);
+
+ if (!value.equals(oValue))
+ {
+ value = stripInternalSpaces(value);
+ oValue = stripInternalSpaces(oValue);
+
+ if (!value.equals(oValue))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ private String canonicalize(String s)
+ {
+ String value = Strings.toLowerCase(s.trim());
+
+ if (value.length() > 0 && value.charAt(0) == '#')
+ {
+ ASN1Primitive obj = decodeObject(value);
+
+ if (obj instanceof ASN1String)
+ {
+ value = Strings.toLowerCase(((ASN1String)obj).getString().trim());
+ }
+ }
+
+ return value;
+ }
+
+ private ASN1Primitive decodeObject(String oValue)
+ {
+ try
+ {
+ return ASN1Primitive.fromByteArray(Hex.decode(oValue.substring(1)));
+ }
+ catch (IOException e)
+ {
+ throw new IllegalStateException("unknown encoding in name: " + e);
+ }
+ }
+
+ private String stripInternalSpaces(
+ String str)
+ {
+ StringBuffer res = new StringBuffer();
+
+ if (str.length() != 0)
+ {
+ char c1 = str.charAt(0);
+
+ res.append(c1);
+
+ for (int k = 1; k < str.length(); k++)
+ {
+ char c2 = str.charAt(k);
+ if (!(c1 == ' ' && c2 == ' '))
+ {
+ res.append(c2);
+ }
+ c1 = c2;
+ }
+ }
+
+ return res.toString();
+ }
+
+ private void appendValue(
+ StringBuffer buf,
+ Hashtable oidSymbols,
+ ASN1ObjectIdentifier oid,
+ String value)
+ {
+ String sym = (String)oidSymbols.get(oid);
+
+ if (sym != null)
+ {
+ buf.append(sym);
+ }
+ else
+ {
+ buf.append(oid.getId());
+ }
+
+ buf.append('=');
+
+ int index = buf.length();
+
+ buf.append(value);
+
+ int end = buf.length();
+
+ if (value.length() >= 2 && value.charAt(0) == '\\' && value.charAt(1) == '#')
+ {
+ index += 2;
+ }
+
+ while (index != end)
+ {
+ if ((buf.charAt(index) == ',')
+ || (buf.charAt(index) == '"')
+ || (buf.charAt(index) == '\\')
+ || (buf.charAt(index) == '+')
+ || (buf.charAt(index) == '=')
+ || (buf.charAt(index) == '<')
+ || (buf.charAt(index) == '>')
+ || (buf.charAt(index) == ';'))
+ {
+ buf.insert(index, "\\");
+ index++;
+ end++;
+ }
+
+ index++;
+ }
+ }
+
+ /**
+ * convert the structure to a string - if reverse is true the
+ * oids and values are listed out starting with the last element
+ * in the sequence (ala RFC 2253), otherwise the string will begin
+ * with the first element of the structure. If no string definition
+ * for the oid is found in oidSymbols the string value of the oid is
+ * added. Two standard symbol tables are provided DefaultSymbols, and
+ * RFC2253Symbols as part of this class.
+ *
+ * @param reverse if true start at the end of the sequence and work back.
+ * @param oidSymbols look up table strings for oids.
+ */
+ public String toString(
+ boolean reverse,
+ Hashtable oidSymbols)
+ {
+ StringBuffer buf = new StringBuffer();
+ Vector components = new Vector();
+ boolean first = true;
+
+ StringBuffer ava = null;
+
+ for (int i = 0; i < ordering.size(); i++)
+ {
+ if (((Boolean)added.elementAt(i)).booleanValue())
+ {
+ ava.append('+');
+ appendValue(ava, oidSymbols,
+ (ASN1ObjectIdentifier)ordering.elementAt(i),
+ (String)values.elementAt(i));
+ }
+ else
+ {
+ ava = new StringBuffer();
+ appendValue(ava, oidSymbols,
+ (ASN1ObjectIdentifier)ordering.elementAt(i),
+ (String)values.elementAt(i));
+ components.addElement(ava);
+ }
+ }
+
+ if (reverse)
+ {
+ for (int i = components.size() - 1; i >= 0; i--)
+ {
+ if (first)
+ {
+ first = false;
+ }
+ else
+ {
+ buf.append(',');
+ }
+
+ buf.append(components.elementAt(i).toString());
+ }
+ }
+ else
+ {
+ for (int i = 0; i < components.size(); i++)
+ {
+ if (first)
+ {
+ first = false;
+ }
+ else
+ {
+ buf.append(',');
+ }
+
+ buf.append(components.elementAt(i).toString());
+ }
+ }
+
+ return buf.toString();
+ }
+
+ private String bytesToString(
+ byte[] data)
+ {
+ char[] cs = new char[data.length];
+
+ for (int i = 0; i != cs.length; i++)
+ {
+ cs[i] = (char)(data[i] & 0xff);
+ }
+
+ return new String(cs);
+ }
+
+ public String toString()
+ {
+ return toString(DefaultReverse, DefaultSymbols);
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/X509NameEntryConverter.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/X509NameEntryConverter.java
new file mode 100644
index 0000000..853994b
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/X509NameEntryConverter.java
@@ -0,0 +1,113 @@
+package org.bc.asn1.x509;
+
+import java.io.IOException;
+
+import org.bc.asn1.ASN1InputStream;
+import org.bc.asn1.ASN1ObjectIdentifier;
+import org.bc.asn1.ASN1Primitive;
+import org.bc.asn1.DERPrintableString;
+import org.bc.util.Strings;
+
+/**
+ * It turns out that the number of standard ways the fields in a DN should be
+ * encoded into their ASN.1 counterparts is rapidly approaching the
+ * number of machines on the internet. By default the X509Name class
+ * will produce UTF8Strings in line with the current recommendations (RFC 3280).
+ *
+ * An example of an encoder look like below: + *
+ * public class X509DirEntryConverter + * extends X509NameEntryConverter + * { + * public ASN1Primitive getConvertedValue( + * ASN1ObjectIdentifier oid, + * String value) + * { + * if (str.length() != 0 && str.charAt(0) == '#') + * { + * return convertHexEncoded(str, 1); + * } + * if (oid.equals(EmailAddress)) + * { + * return new DERIA5String(str); + * } + * else if (canBePrintable(str)) + * { + * return new DERPrintableString(str); + * } + * else if (canBeUTF8(str)) + * { + * return new DERUTF8String(str); + * } + * else + * { + * return new DERBMPString(str); + * } + * } + * } + */ +public abstract class X509NameEntryConverter +{ + /** + * Convert an inline encoded hex string rendition of an ASN.1 + * object back into its corresponding ASN.1 object. + * + * @param str the hex encoded object + * @param off the index at which the encoding starts + * @return the decoded object + */ + protected ASN1Primitive convertHexEncoded( + String str, + int off) + throws IOException + { + str = Strings.toLowerCase(str); + byte[] data = new byte[(str.length() - off) / 2]; + for (int index = 0; index != data.length; index++) + { + char left = str.charAt((index * 2) + off); + char right = str.charAt((index * 2) + off + 1); + + if (left < 'a') + { + data[index] = (byte)((left - '0') << 4); + } + else + { + data[index] = (byte)((left - 'a' + 10) << 4); + } + if (right < 'a') + { + data[index] |= (byte)(right - '0'); + } + else + { + data[index] |= (byte)(right - 'a' + 10); + } + } + + ASN1InputStream aIn = new ASN1InputStream(data); + + return aIn.readObject(); + } + + /** + * return true if the passed in String can be represented without + * loss as a PrintableString, false otherwise. + */ + protected boolean canBePrintable( + String str) + { + return DERPrintableString.isPrintableString(str); + } + + /** + * Convert the passed in String value into the appropriate ASN.1 + * encoded object. + * + * @param oid the oid associated with the value in the DN. + * @param value the value of the particular DN component. + * @return the ASN.1 equivalent for the value. + */ + public abstract ASN1Primitive getConvertedValue(ASN1ObjectIdentifier oid, String value); +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/X509NameTokenizer.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/X509NameTokenizer.java new file mode 100644 index 0000000..1018b6c --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/X509NameTokenizer.java @@ -0,0 +1,108 @@ +package org.bc.asn1.x509; + +/** + * class for breaking up an X500 Name into it's component tokens, ala + * java.util.StringTokenizer. We need this class as some of the + * lightweight Java environment don't support classes like + * StringTokenizer. + * @deprecated use X500NameTokenizer + */ +public class X509NameTokenizer +{ + private String value; + private int index; + private char separator; + private StringBuffer buf = new StringBuffer(); + + public X509NameTokenizer( + String oid) + { + this(oid, ','); + } + + public X509NameTokenizer( + String oid, + char separator) + { + this.value = oid; + this.index = -1; + this.separator = separator; + } + + public boolean hasMoreTokens() + { + return (index != value.length()); + } + + public String nextToken() + { + if (index == value.length()) + { + return null; + } + + int end = index + 1; + boolean quoted = false; + boolean escaped = false; + + buf.setLength(0); + + while (end != value.length()) + { + char c = value.charAt(end); + + if (c == '"') + { + if (!escaped) + { + quoted = !quoted; + } + else + { + if (c == '#' && buf.charAt(buf.length() - 1) == '=') + { + buf.append('\\'); + } + else if (c == '+' && separator != '+') + { + buf.append('\\'); + } + buf.append(c); + } + escaped = false; + } + else + { + if (escaped || quoted) + { + if (c == '#' && buf.charAt(buf.length() - 1) == '=') + { + buf.append('\\'); + } + else if (c == '+' && separator != '+') + { + buf.append('\\'); + } + buf.append(c); + escaped = false; + } + else if (c == '\\') + { + escaped = true; + } + else if (c == separator) + { + break; + } + else + { + buf.append(c); + } + } + end++; + } + + index = end; + return buf.toString().trim(); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/X509ObjectIdentifiers.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/X509ObjectIdentifiers.java new file mode 100644 index 0000000..0dd5598 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/X509ObjectIdentifiers.java @@ -0,0 +1,67 @@ +package org.bc.asn1.x509; + +import org.bc.asn1.ASN1ObjectIdentifier; + +public interface X509ObjectIdentifiers +{ + // + // base id + // + static final String id = "2.5.4"; + + static final ASN1ObjectIdentifier commonName = new ASN1ObjectIdentifier(id + ".3"); + static final ASN1ObjectIdentifier countryName = new ASN1ObjectIdentifier(id + ".6"); + static final ASN1ObjectIdentifier localityName = new ASN1ObjectIdentifier(id + ".7"); + static final ASN1ObjectIdentifier stateOrProvinceName = new ASN1ObjectIdentifier(id + ".8"); + static final ASN1ObjectIdentifier organization = new ASN1ObjectIdentifier(id + ".10"); + static final ASN1ObjectIdentifier organizationalUnitName = new ASN1ObjectIdentifier(id + ".11"); + + static final ASN1ObjectIdentifier id_at_telephoneNumber = new ASN1ObjectIdentifier("2.5.4.20"); + static final ASN1ObjectIdentifier id_at_name = new ASN1ObjectIdentifier(id + ".41"); + + // id-SHA1 OBJECT IDENTIFIER ::= + // {iso(1) identified-organization(3) oiw(14) secsig(3) algorithms(2) 26 } // + static final ASN1ObjectIdentifier id_SHA1 = new ASN1ObjectIdentifier("1.3.14.3.2.26"); + + // + // ripemd160 OBJECT IDENTIFIER ::= + // {iso(1) identified-organization(3) TeleTrust(36) algorithm(3) hashAlgorithm(2) RIPEMD-160(1)} + // + static final ASN1ObjectIdentifier ripemd160 = new ASN1ObjectIdentifier("1.3.36.3.2.1"); + + // + // ripemd160WithRSAEncryption OBJECT IDENTIFIER ::= + // {iso(1) identified-organization(3) TeleTrust(36) algorithm(3) signatureAlgorithm(3) rsaSignature(1) rsaSignatureWithripemd160(2) } + // + static final ASN1ObjectIdentifier ripemd160WithRSAEncryption = new ASN1ObjectIdentifier("1.3.36.3.3.1.2"); + + + static final ASN1ObjectIdentifier id_ea_rsa = new ASN1ObjectIdentifier("2.5.8.1.1"); + + // id-pkix + static final ASN1ObjectIdentifier id_pkix = new ASN1ObjectIdentifier("1.3.6.1.5.5.7"); + + // + // private internet extensions + // + static final ASN1ObjectIdentifier id_pe = new ASN1ObjectIdentifier(id_pkix + ".1"); + + // + // ISO ARC for standard certificate and CRL extensions + // + static final ASN1ObjectIdentifier id_ce = new ASN1ObjectIdentifier("2.5.29"); + + // + // authority information access + // + static final ASN1ObjectIdentifier id_ad = new ASN1ObjectIdentifier(id_pkix + ".48"); + static final ASN1ObjectIdentifier id_ad_caIssuers = new ASN1ObjectIdentifier(id_ad + ".2"); + static final ASN1ObjectIdentifier id_ad_ocsp = new ASN1ObjectIdentifier(id_ad + ".1"); + + // + // OID for ocsp and crl uri in AuthorityInformationAccess extension + // + static final ASN1ObjectIdentifier ocspAccessMethod = id_ad_ocsp; + static final ASN1ObjectIdentifier crlAccessMethod = id_ad_caIssuers; +} + diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/qualified/BiometricData.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/qualified/BiometricData.java new file mode 100644 index 0000000..d79c205 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/qualified/BiometricData.java @@ -0,0 +1,122 @@ +package org.bc.asn1.x509.qualified; + +import java.util.Enumeration; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1OctetString; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DERIA5String; +import org.bc.asn1.DERSequence; +import org.bc.asn1.x509.AlgorithmIdentifier; + +/** + * The BiometricData object. + *+ * BiometricData ::= SEQUENCE { + * typeOfBiometricData TypeOfBiometricData, + * hashAlgorithm AlgorithmIdentifier, + * biometricDataHash OCTET STRING, + * sourceDataUri IA5String OPTIONAL } + *+ */ +public class BiometricData + extends ASN1Object +{ + private TypeOfBiometricData typeOfBiometricData; + private AlgorithmIdentifier hashAlgorithm; + private ASN1OctetString biometricDataHash; + private DERIA5String sourceDataUri; + + public static BiometricData getInstance( + Object obj) + { + if (obj instanceof BiometricData) + { + return (BiometricData)obj; + } + + if (obj != null) + { + return new BiometricData(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + private BiometricData(ASN1Sequence seq) + { + Enumeration e = seq.getObjects(); + + // typeOfBiometricData + typeOfBiometricData = TypeOfBiometricData.getInstance(e.nextElement()); + // hashAlgorithm + hashAlgorithm = AlgorithmIdentifier.getInstance(e.nextElement()); + // biometricDataHash + biometricDataHash = ASN1OctetString.getInstance(e.nextElement()); + // sourceDataUri + if (e.hasMoreElements()) + { + sourceDataUri = DERIA5String.getInstance(e.nextElement()); + } + } + + public BiometricData( + TypeOfBiometricData typeOfBiometricData, + AlgorithmIdentifier hashAlgorithm, + ASN1OctetString biometricDataHash, + DERIA5String sourceDataUri) + { + this.typeOfBiometricData = typeOfBiometricData; + this.hashAlgorithm = hashAlgorithm; + this.biometricDataHash = biometricDataHash; + this.sourceDataUri = sourceDataUri; + } + + public BiometricData( + TypeOfBiometricData typeOfBiometricData, + AlgorithmIdentifier hashAlgorithm, + ASN1OctetString biometricDataHash) + { + this.typeOfBiometricData = typeOfBiometricData; + this.hashAlgorithm = hashAlgorithm; + this.biometricDataHash = biometricDataHash; + this.sourceDataUri = null; + } + + public TypeOfBiometricData getTypeOfBiometricData() + { + return typeOfBiometricData; + } + + public AlgorithmIdentifier getHashAlgorithm() + { + return hashAlgorithm; + } + + public ASN1OctetString getBiometricDataHash() + { + return biometricDataHash; + } + + public DERIA5String getSourceDataUri() + { + return sourceDataUri; + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector seq = new ASN1EncodableVector(); + seq.add(typeOfBiometricData); + seq.add(hashAlgorithm); + seq.add(biometricDataHash); + + if (sourceDataUri != null) + { + seq.add(sourceDataUri); + } + + return new DERSequence(seq); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/qualified/ETSIQCObjectIdentifiers.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/qualified/ETSIQCObjectIdentifiers.java new file mode 100644 index 0000000..e89a340 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/qualified/ETSIQCObjectIdentifiers.java @@ -0,0 +1,16 @@ +package org.bc.asn1.x509.qualified; + +import org.bc.asn1.ASN1ObjectIdentifier; + +public interface ETSIQCObjectIdentifiers +{ + // + // base id + // + static final ASN1ObjectIdentifier id_etsi_qcs = new ASN1ObjectIdentifier("0.4.0.1862.1"); + + static final ASN1ObjectIdentifier id_etsi_qcs_QcCompliance = id_etsi_qcs.branch("1"); + static final ASN1ObjectIdentifier id_etsi_qcs_LimiteValue = id_etsi_qcs.branch("2"); + static final ASN1ObjectIdentifier id_etsi_qcs_RetentionPeriod = id_etsi_qcs.branch("3"); + static final ASN1ObjectIdentifier id_etsi_qcs_QcSSCD = id_etsi_qcs.branch("4"); +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/qualified/Iso4217CurrencyCode.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/qualified/Iso4217CurrencyCode.java new file mode 100644 index 0000000..ce5ea72 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/qualified/Iso4217CurrencyCode.java @@ -0,0 +1,93 @@ +package org.bc.asn1.x509.qualified; + +import org.bc.asn1.ASN1Choice; +import org.bc.asn1.ASN1Encodable; +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.DERPrintableString; + +/** + * The Iso4217CurrencyCode object. + *+ * Iso4217CurrencyCode ::= CHOICE { + * alphabetic PrintableString (SIZE 3), --Recommended + * numeric INTEGER (1..999) } + * -- Alphabetic or numeric currency code as defined in ISO 4217 + * -- It is recommended that the Alphabetic form is used + *+ */ +public class Iso4217CurrencyCode + extends ASN1Object + implements ASN1Choice +{ + final int ALPHABETIC_MAXSIZE = 3; + final int NUMERIC_MINSIZE = 1; + final int NUMERIC_MAXSIZE = 999; + + ASN1Encodable obj; + int numeric; + + public static Iso4217CurrencyCode getInstance( + Object obj) + { + if (obj == null || obj instanceof Iso4217CurrencyCode) + { + return (Iso4217CurrencyCode)obj; + } + + if (obj instanceof ASN1Integer) + { + ASN1Integer numericobj = ASN1Integer.getInstance(obj); + int numeric = numericobj.getValue().intValue(); + return new Iso4217CurrencyCode(numeric); + } + else + if (obj instanceof DERPrintableString) + { + DERPrintableString alphabetic = DERPrintableString.getInstance(obj); + return new Iso4217CurrencyCode(alphabetic.getString()); + } + throw new IllegalArgumentException("unknown object in getInstance"); + } + + public Iso4217CurrencyCode( + int numeric) + { + if (numeric > NUMERIC_MAXSIZE || numeric < NUMERIC_MINSIZE) + { + throw new IllegalArgumentException("wrong size in numeric code : not in (" +NUMERIC_MINSIZE +".."+ NUMERIC_MAXSIZE +")"); + } + obj = new ASN1Integer(numeric); + } + + public Iso4217CurrencyCode( + String alphabetic) + { + if (alphabetic.length() > ALPHABETIC_MAXSIZE) + { + throw new IllegalArgumentException("wrong size in alphabetic code : max size is " + ALPHABETIC_MAXSIZE); + } + obj = new DERPrintableString(alphabetic); + } + + public boolean isAlphabetic() + { + return obj instanceof DERPrintableString; + } + + public String getAlphabetic() + { + return ((DERPrintableString)obj).getString(); + } + + public int getNumeric() + { + return ((ASN1Integer)obj).getValue().intValue(); + } + + public ASN1Primitive toASN1Primitive() + { + return obj.toASN1Primitive(); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/qualified/MonetaryValue.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/qualified/MonetaryValue.java new file mode 100644 index 0000000..81bebc5 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/qualified/MonetaryValue.java @@ -0,0 +1,92 @@ +package org.bc.asn1.x509.qualified; + +import java.math.BigInteger; +import java.util.Enumeration; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DERSequence; + +/** + * The MonetaryValue object. + *+ * MonetaryValue ::= SEQUENCE { + * currency Iso4217CurrencyCode, + * amount INTEGER, + * exponent INTEGER } + * -- value = amount * 10^exponent + *+ */ +public class MonetaryValue + extends ASN1Object +{ + private Iso4217CurrencyCode currency; + private ASN1Integer amount; + private ASN1Integer exponent; + + public static MonetaryValue getInstance( + Object obj) + { + if (obj instanceof MonetaryValue) + { + return (MonetaryValue)obj; + } + + if (obj != null) + { + return new MonetaryValue(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + private MonetaryValue( + ASN1Sequence seq) + { + Enumeration e = seq.getObjects(); + // currency + currency = Iso4217CurrencyCode.getInstance(e.nextElement()); + // hashAlgorithm + amount = ASN1Integer.getInstance(e.nextElement()); + // exponent + exponent = ASN1Integer.getInstance(e.nextElement()); + } + + public MonetaryValue( + Iso4217CurrencyCode currency, + int amount, + int exponent) + { + this.currency = currency; + this.amount = new ASN1Integer(amount); + this.exponent = new ASN1Integer(exponent); + } + + public Iso4217CurrencyCode getCurrency() + { + return currency; + } + + public BigInteger getAmount() + { + return amount.getValue(); + } + + public BigInteger getExponent() + { + return exponent.getValue(); + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector seq = new ASN1EncodableVector(); + seq.add(currency); + seq.add(amount); + seq.add(exponent); + + return new DERSequence(seq); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/qualified/QCStatement.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/qualified/QCStatement.java new file mode 100644 index 0000000..e39150c --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/qualified/QCStatement.java @@ -0,0 +1,95 @@ +package org.bc.asn1.x509.qualified; + +import java.util.Enumeration; + +import org.bc.asn1.ASN1Encodable; +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1ObjectIdentifier; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DERSequence; + +/** + * The QCStatement object. + *+ * QCStatement ::= SEQUENCE { + * statementId OBJECT IDENTIFIER, + * statementInfo ANY DEFINED BY statementId OPTIONAL} + *+ */ + +public class QCStatement + extends ASN1Object + implements ETSIQCObjectIdentifiers, RFC3739QCObjectIdentifiers +{ + ASN1ObjectIdentifier qcStatementId; + ASN1Encodable qcStatementInfo; + + public static QCStatement getInstance( + Object obj) + { + if (obj instanceof QCStatement) + { + return (QCStatement)obj; + } + if (obj != null) + { + return new QCStatement(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + private QCStatement( + ASN1Sequence seq) + { + Enumeration e = seq.getObjects(); + + // qcStatementId + qcStatementId = ASN1ObjectIdentifier.getInstance(e.nextElement()); + // qcstatementInfo + if (e.hasMoreElements()) + { + qcStatementInfo = (ASN1Encodable) e.nextElement(); + } + } + + public QCStatement( + ASN1ObjectIdentifier qcStatementId) + { + this.qcStatementId = qcStatementId; + this.qcStatementInfo = null; + } + + public QCStatement( + ASN1ObjectIdentifier qcStatementId, + ASN1Encodable qcStatementInfo) + { + this.qcStatementId = qcStatementId; + this.qcStatementInfo = qcStatementInfo; + } + + public ASN1ObjectIdentifier getStatementId() + { + return qcStatementId; + } + + public ASN1Encodable getStatementInfo() + { + return qcStatementInfo; + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector seq = new ASN1EncodableVector(); + seq.add(qcStatementId); + + if (qcStatementInfo != null) + { + seq.add(qcStatementInfo); + } + + return new DERSequence(seq); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/qualified/RFC3739QCObjectIdentifiers.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/qualified/RFC3739QCObjectIdentifiers.java new file mode 100644 index 0000000..4acee90 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/qualified/RFC3739QCObjectIdentifiers.java @@ -0,0 +1,14 @@ +package org.bc.asn1.x509.qualified; + +import org.bc.asn1.ASN1ObjectIdentifier; + +public interface RFC3739QCObjectIdentifiers +{ + // + // base id + // + static final ASN1ObjectIdentifier id_qcs = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.11"); + + static final ASN1ObjectIdentifier id_qcs_pkixQCSyntax_v1 = id_qcs.branch("1"); + static final ASN1ObjectIdentifier id_qcs_pkixQCSyntax_v2 = id_qcs.branch("2"); +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/qualified/SemanticsInformation.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/qualified/SemanticsInformation.java new file mode 100644 index 0000000..d522e86 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/qualified/SemanticsInformation.java @@ -0,0 +1,131 @@ +package org.bc.asn1.x509.qualified; + +import java.util.Enumeration; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1ObjectIdentifier; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DERSequence; +import org.bc.asn1.x509.GeneralName; + +/** + * The SemanticsInformation object. + *+ * SemanticsInformation ::= SEQUENCE { + * semanticsIdentifier OBJECT IDENTIFIER OPTIONAL, + * nameRegistrationAuthorities NameRegistrationAuthorities + * OPTIONAL } + * (WITH COMPONENTS {..., semanticsIdentifier PRESENT}| + * WITH COMPONENTS {..., nameRegistrationAuthorities PRESENT}) + * + * NameRegistrationAuthorities ::= SEQUENCE SIZE (1..MAX) OF + * GeneralName + *+ */ +public class SemanticsInformation + extends ASN1Object +{ + private ASN1ObjectIdentifier semanticsIdentifier; + private GeneralName[] nameRegistrationAuthorities; + + public static SemanticsInformation getInstance(Object obj) + { + if (obj instanceof SemanticsInformation) + { + return (SemanticsInformation)obj; + } + + if (obj != null) + { + return new SemanticsInformation(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + private SemanticsInformation(ASN1Sequence seq) + { + Enumeration e = seq.getObjects(); + if (seq.size() < 1) + { + throw new IllegalArgumentException("no objects in SemanticsInformation"); + } + + Object object = e.nextElement(); + if (object instanceof ASN1ObjectIdentifier) + { + semanticsIdentifier = ASN1ObjectIdentifier.getInstance(object); + if (e.hasMoreElements()) + { + object = e.nextElement(); + } + else + { + object = null; + } + } + + if (object != null) + { + ASN1Sequence generalNameSeq = ASN1Sequence.getInstance(object); + nameRegistrationAuthorities = new GeneralName[generalNameSeq.size()]; + for (int i= 0; i < generalNameSeq.size(); i++) + { + nameRegistrationAuthorities[i] = GeneralName.getInstance(generalNameSeq.getObjectAt(i)); + } + } + } + + public SemanticsInformation( + ASN1ObjectIdentifier semanticsIdentifier, + GeneralName[] generalNames) + { + this.semanticsIdentifier = semanticsIdentifier; + this.nameRegistrationAuthorities = generalNames; + } + + public SemanticsInformation(ASN1ObjectIdentifier semanticsIdentifier) + { + this.semanticsIdentifier = semanticsIdentifier; + this.nameRegistrationAuthorities = null; + } + + public SemanticsInformation(GeneralName[] generalNames) + { + this.semanticsIdentifier = null; + this.nameRegistrationAuthorities = generalNames; + } + + public ASN1ObjectIdentifier getSemanticsIdentifier() + { + return semanticsIdentifier; + } + + public GeneralName[] getNameRegistrationAuthorities() + { + return nameRegistrationAuthorities; + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector seq = new ASN1EncodableVector(); + + if (this.semanticsIdentifier != null) + { + seq.add(semanticsIdentifier); + } + if (this.nameRegistrationAuthorities != null) + { + ASN1EncodableVector seqname = new ASN1EncodableVector(); + for (int i = 0; i < nameRegistrationAuthorities.length; i++) + { + seqname.add(nameRegistrationAuthorities[i]); + } + seq.add(new DERSequence(seqname)); + } + + return new DERSequence(seq); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/qualified/TypeOfBiometricData.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/qualified/TypeOfBiometricData.java new file mode 100644 index 0000000..9f1900c --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/qualified/TypeOfBiometricData.java @@ -0,0 +1,90 @@ +package org.bc.asn1.x509.qualified; + +import org.bc.asn1.ASN1Choice; +import org.bc.asn1.ASN1Encodable; +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1ObjectIdentifier; +import org.bc.asn1.ASN1Primitive; + +/** + * The TypeOfBiometricData object. + *+ * TypeOfBiometricData ::= CHOICE { + * predefinedBiometricType PredefinedBiometricType, + * biometricDataOid OBJECT IDENTIFIER } + * + * PredefinedBiometricType ::= INTEGER { + * picture(0),handwritten-signature(1)} + * (picture|handwritten-signature) + *+ */ +public class TypeOfBiometricData + extends ASN1Object + implements ASN1Choice +{ + public static final int PICTURE = 0; + public static final int HANDWRITTEN_SIGNATURE = 1; + + ASN1Encodable obj; + + public static TypeOfBiometricData getInstance(Object obj) + { + if (obj == null || obj instanceof TypeOfBiometricData) + { + return (TypeOfBiometricData)obj; + } + + if (obj instanceof ASN1Integer) + { + ASN1Integer predefinedBiometricTypeObj = ASN1Integer.getInstance(obj); + int predefinedBiometricType = predefinedBiometricTypeObj.getValue().intValue(); + + return new TypeOfBiometricData(predefinedBiometricType); + } + else if (obj instanceof ASN1ObjectIdentifier) + { + ASN1ObjectIdentifier BiometricDataID = ASN1ObjectIdentifier.getInstance(obj); + return new TypeOfBiometricData(BiometricDataID); + } + + throw new IllegalArgumentException("unknown object in getInstance"); + } + + public TypeOfBiometricData(int predefinedBiometricType) + { + if (predefinedBiometricType == PICTURE || predefinedBiometricType == HANDWRITTEN_SIGNATURE) + { + obj = new ASN1Integer(predefinedBiometricType); + } + else + { + throw new IllegalArgumentException("unknow PredefinedBiometricType : " + predefinedBiometricType); + } + } + + public TypeOfBiometricData(ASN1ObjectIdentifier BiometricDataID) + { + obj = BiometricDataID; + } + + public boolean isPredefined() + { + return obj instanceof ASN1Integer; + } + + public int getPredefinedBiometricType() + { + return ((ASN1Integer)obj).getValue().intValue(); + } + + public ASN1ObjectIdentifier getBiometricDataOid() + { + return (ASN1ObjectIdentifier)obj; + } + + public ASN1Primitive toASN1Primitive() + { + return obj.toASN1Primitive(); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/sigi/NameOrPseudonym.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/sigi/NameOrPseudonym.java new file mode 100644 index 0000000..50ee75d --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/sigi/NameOrPseudonym.java @@ -0,0 +1,191 @@ +package org.bc.asn1.x509.sigi; + +import java.util.Enumeration; + +import org.bc.asn1.ASN1Choice; +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1String; +import org.bc.asn1.DERSequence; +import org.bc.asn1.x500.DirectoryString; + +/** + * Structure for a name or pseudonym. + * + *+ * NameOrPseudonym ::= CHOICE { + * surAndGivenName SEQUENCE { + * surName DirectoryString, + * givenName SEQUENCE OF DirectoryString + * }, + * pseudonym DirectoryString + * } + *+ * + * @see org.bc.asn1.x509.sigi.PersonalData + * + */ +public class NameOrPseudonym + extends ASN1Object + implements ASN1Choice +{ + private DirectoryString pseudonym; + + private DirectoryString surname; + + private ASN1Sequence givenName; + + public static NameOrPseudonym getInstance(Object obj) + { + if (obj == null || obj instanceof NameOrPseudonym) + { + return (NameOrPseudonym)obj; + } + + if (obj instanceof ASN1String) + { + return new NameOrPseudonym(DirectoryString.getInstance(obj)); + } + + if (obj instanceof ASN1Sequence) + { + return new NameOrPseudonym((ASN1Sequence)obj); + } + + throw new IllegalArgumentException("illegal object in getInstance: " + + obj.getClass().getName()); + } + + /** + * Constructor from DirectoryString. + * + * The sequence is of type NameOrPseudonym: + * + *+ * NameOrPseudonym ::= CHOICE { + * surAndGivenName SEQUENCE { + * surName DirectoryString, + * givenName SEQUENCE OF DirectoryString + * }, + * pseudonym DirectoryString + * } + *+ * @param pseudonym pseudonym value to use. + */ + public NameOrPseudonym(DirectoryString pseudonym) + { + this.pseudonym = pseudonym; + } + + /** + * Constructor from ASN1Sequence. + * + * The sequence is of type NameOrPseudonym: + * + *+ * NameOrPseudonym ::= CHOICE { + * surAndGivenName SEQUENCE { + * surName DirectoryString, + * givenName SEQUENCE OF DirectoryString + * }, + * pseudonym DirectoryString + * } + *+ * + * @param seq The ASN.1 sequence. + */ + private NameOrPseudonym(ASN1Sequence seq) + { + if (seq.size() != 2) + { + throw new IllegalArgumentException("Bad sequence size: " + + seq.size()); + } + + if (!(seq.getObjectAt(0) instanceof ASN1String)) + { + throw new IllegalArgumentException("Bad object encountered: " + + seq.getObjectAt(0).getClass()); + } + + surname = DirectoryString.getInstance(seq.getObjectAt(0)); + givenName = ASN1Sequence.getInstance(seq.getObjectAt(1)); + } + + /** + * Constructor from a given details. + * + * @param pseudonym The pseudonym. + */ + public NameOrPseudonym(String pseudonym) + { + this(new DirectoryString(pseudonym)); + } + + /** + * Constructor from a given details. + * + * @param surname The surname. + * @param givenName A sequence of directory strings making up the givenName + */ + public NameOrPseudonym(DirectoryString surname, ASN1Sequence givenName) + { + this.surname = surname; + this.givenName = givenName; + } + + public DirectoryString getPseudonym() + { + return pseudonym; + } + + public DirectoryString getSurname() + { + return surname; + } + + public DirectoryString[] getGivenName() + { + DirectoryString[] items = new DirectoryString[givenName.size()]; + int count = 0; + for (Enumeration e = givenName.getObjects(); e.hasMoreElements();) + { + items[count++] = DirectoryString.getInstance(e.nextElement()); + } + return items; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * + * Returns: + * + *+ * NameOrPseudonym ::= CHOICE { + * surAndGivenName SEQUENCE { + * surName DirectoryString, + * givenName SEQUENCE OF DirectoryString + * }, + * pseudonym DirectoryString + * } + *+ * + * @return a DERObject + */ + public ASN1Primitive toASN1Primitive() + { + if (pseudonym != null) + { + return pseudonym.toASN1Primitive(); + } + else + { + ASN1EncodableVector vec1 = new ASN1EncodableVector(); + vec1.add(surname); + vec1.add(givenName); + return new DERSequence(vec1); + } + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/sigi/PersonalData.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/sigi/PersonalData.java new file mode 100644 index 0000000..0e9c9f2 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/sigi/PersonalData.java @@ -0,0 +1,214 @@ +package org.bc.asn1.x509.sigi; + +import java.math.BigInteger; +import java.util.Enumeration; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1GeneralizedTime; +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERPrintableString; +import org.bc.asn1.DERSequence; +import org.bc.asn1.DERTaggedObject; +import org.bc.asn1.x500.DirectoryString; + +/** + * Contains personal data for the otherName field in the subjectAltNames + * extension. + * + *+ * PersonalData ::= SEQUENCE { + * nameOrPseudonym NameOrPseudonym, + * nameDistinguisher [0] INTEGER OPTIONAL, + * dateOfBirth [1] GeneralizedTime OPTIONAL, + * placeOfBirth [2] DirectoryString OPTIONAL, + * gender [3] PrintableString OPTIONAL, + * postalAddress [4] DirectoryString OPTIONAL + * } + *+ * + * @see org.bc.asn1.x509.sigi.NameOrPseudonym + * @see org.bc.asn1.x509.sigi.SigIObjectIdentifiers + */ +public class PersonalData + extends ASN1Object +{ + private NameOrPseudonym nameOrPseudonym; + private BigInteger nameDistinguisher; + private ASN1GeneralizedTime dateOfBirth; + private DirectoryString placeOfBirth; + private String gender; + private DirectoryString postalAddress; + + public static PersonalData getInstance(Object obj) + { + if (obj == null || obj instanceof PersonalData) + { + return (PersonalData)obj; + } + + if (obj instanceof ASN1Sequence) + { + return new PersonalData((ASN1Sequence)obj); + } + + throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); + } + + /** + * Constructor from ASN1Sequence. + * + * The sequence is of type NameOrPseudonym: + * + *+ * PersonalData ::= SEQUENCE { + * nameOrPseudonym NameOrPseudonym, + * nameDistinguisher [0] INTEGER OPTIONAL, + * dateOfBirth [1] GeneralizedTime OPTIONAL, + * placeOfBirth [2] DirectoryString OPTIONAL, + * gender [3] PrintableString OPTIONAL, + * postalAddress [4] DirectoryString OPTIONAL + * } + *+ * + * @param seq The ASN.1 sequence. + */ + private PersonalData(ASN1Sequence seq) + { + if (seq.size() < 1) + { + throw new IllegalArgumentException("Bad sequence size: " + + seq.size()); + } + + Enumeration e = seq.getObjects(); + + nameOrPseudonym = NameOrPseudonym.getInstance(e.nextElement()); + + while (e.hasMoreElements()) + { + ASN1TaggedObject o = ASN1TaggedObject.getInstance(e.nextElement()); + int tag = o.getTagNo(); + switch (tag) + { + case 0: + nameDistinguisher = ASN1Integer.getInstance(o, false).getValue(); + break; + case 1: + dateOfBirth = ASN1GeneralizedTime.getInstance(o, false); + break; + case 2: + placeOfBirth = DirectoryString.getInstance(o, true); + break; + case 3: + gender = DERPrintableString.getInstance(o, false).getString(); + break; + case 4: + postalAddress = DirectoryString.getInstance(o, true); + break; + default: + throw new IllegalArgumentException("Bad tag number: " + o.getTagNo()); + } + } + } + + /** + * Constructor from a given details. + * + * @param nameOrPseudonym Name or pseudonym. + * @param nameDistinguisher Name distinguisher. + * @param dateOfBirth Date of birth. + * @param placeOfBirth Place of birth. + * @param gender Gender. + * @param postalAddress Postal Address. + */ + public PersonalData(NameOrPseudonym nameOrPseudonym, + BigInteger nameDistinguisher, ASN1GeneralizedTime dateOfBirth, + DirectoryString placeOfBirth, String gender, DirectoryString postalAddress) + { + this.nameOrPseudonym = nameOrPseudonym; + this.dateOfBirth = dateOfBirth; + this.gender = gender; + this.nameDistinguisher = nameDistinguisher; + this.postalAddress = postalAddress; + this.placeOfBirth = placeOfBirth; + } + + public NameOrPseudonym getNameOrPseudonym() + { + return nameOrPseudonym; + } + + public BigInteger getNameDistinguisher() + { + return nameDistinguisher; + } + + public ASN1GeneralizedTime getDateOfBirth() + { + return dateOfBirth; + } + + public DirectoryString getPlaceOfBirth() + { + return placeOfBirth; + } + + public String getGender() + { + return gender; + } + + public DirectoryString getPostalAddress() + { + return postalAddress; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * + * Returns: + * + *+ * PersonalData ::= SEQUENCE { + * nameOrPseudonym NameOrPseudonym, + * nameDistinguisher [0] INTEGER OPTIONAL, + * dateOfBirth [1] GeneralizedTime OPTIONAL, + * placeOfBirth [2] DirectoryString OPTIONAL, + * gender [3] PrintableString OPTIONAL, + * postalAddress [4] DirectoryString OPTIONAL + * } + *+ * + * @return a DERObject + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector vec = new ASN1EncodableVector(); + vec.add(nameOrPseudonym); + if (nameDistinguisher != null) + { + vec.add(new DERTaggedObject(false, 0, new ASN1Integer(nameDistinguisher))); + } + if (dateOfBirth != null) + { + vec.add(new DERTaggedObject(false, 1, dateOfBirth)); + } + if (placeOfBirth != null) + { + vec.add(new DERTaggedObject(true, 2, placeOfBirth)); + } + if (gender != null) + { + vec.add(new DERTaggedObject(false, 3, new DERPrintableString(gender, true))); + } + if (postalAddress != null) + { + vec.add(new DERTaggedObject(true, 4, postalAddress)); + } + return new DERSequence(vec); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/sigi/SigIObjectIdentifiers.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/sigi/SigIObjectIdentifiers.java new file mode 100644 index 0000000..59be5fa --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x509/sigi/SigIObjectIdentifiers.java @@ -0,0 +1,45 @@ +package org.bc.asn1.x509.sigi; + +import org.bc.asn1.ASN1ObjectIdentifier; + +/** + * Object Identifiers of SigI specifciation (German Signature Law + * Interoperability specification). + */ +public interface SigIObjectIdentifiers +{ + public final static ASN1ObjectIdentifier id_sigi = new ASN1ObjectIdentifier("1.3.36.8"); + + /** + * Key purpose IDs for German SigI (Signature Interoperability + * Specification) + */ + public final static ASN1ObjectIdentifier id_sigi_kp = new ASN1ObjectIdentifier(id_sigi + ".2"); + + /** + * Certificate policy IDs for German SigI (Signature Interoperability + * Specification) + */ + public final static ASN1ObjectIdentifier id_sigi_cp = new ASN1ObjectIdentifier(id_sigi + ".1"); + + /** + * Other Name IDs for German SigI (Signature Interoperability Specification) + */ + public final static ASN1ObjectIdentifier id_sigi_on = new ASN1ObjectIdentifier(id_sigi + ".4"); + + /** + * To be used for for the generation of directory service certificates. + */ + public static final ASN1ObjectIdentifier id_sigi_kp_directoryService = new ASN1ObjectIdentifier(id_sigi_kp + ".1"); + + /** + * ID for PersonalData + */ + public static final ASN1ObjectIdentifier id_sigi_on_personalData = new ASN1ObjectIdentifier(id_sigi_on + ".1"); + + /** + * Certificate is conform to german signature law. + */ + public static final ASN1ObjectIdentifier id_sigi_cp_sigconform = new ASN1ObjectIdentifier(id_sigi_cp + ".1"); + +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x9/DHDomainParameters.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x9/DHDomainParameters.java new file mode 100644 index 0000000..f0cabe4 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x9/DHDomainParameters.java @@ -0,0 +1,139 @@ +package org.bc.asn1.x9; + +import java.util.Enumeration; + +import org.bc.asn1.ASN1Encodable; +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERSequence; + +public class DHDomainParameters + extends ASN1Object +{ + private ASN1Integer p, g, q, j; + private DHValidationParms validationParms; + + public static DHDomainParameters getInstance(ASN1TaggedObject obj, boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static DHDomainParameters getInstance(Object obj) + { + if (obj == null || obj instanceof DHDomainParameters) + { + return (DHDomainParameters)obj; + } + + if (obj instanceof ASN1Sequence) + { + return new DHDomainParameters((ASN1Sequence)obj); + } + + throw new IllegalArgumentException("Invalid DHDomainParameters: " + + obj.getClass().getName()); + } + + public DHDomainParameters(ASN1Integer p, ASN1Integer g, ASN1Integer q, ASN1Integer j, + DHValidationParms validationParms) + { + if (p == null) + { + throw new IllegalArgumentException("'p' cannot be null"); + } + if (g == null) + { + throw new IllegalArgumentException("'g' cannot be null"); + } + if (q == null) + { + throw new IllegalArgumentException("'q' cannot be null"); + } + + this.p = p; + this.g = g; + this.q = q; + this.j = j; + this.validationParms = validationParms; + } + + private DHDomainParameters(ASN1Sequence seq) + { + if (seq.size() < 3 || seq.size() > 5) + { + throw new IllegalArgumentException("Bad sequence size: " + seq.size()); + } + + Enumeration e = seq.getObjects(); + this.p = ASN1Integer.getInstance(e.nextElement()); + this.g = ASN1Integer.getInstance(e.nextElement()); + this.q = ASN1Integer.getInstance(e.nextElement()); + + ASN1Encodable next = getNext(e); + + if (next != null && next instanceof ASN1Integer) + { + this.j = ASN1Integer.getInstance(next); + next = getNext(e); + } + + if (next != null) + { + this.validationParms = DHValidationParms.getInstance(next.toASN1Primitive()); + } + } + + private static ASN1Encodable getNext(Enumeration e) + { + return e.hasMoreElements() ? (ASN1Encodable)e.nextElement() : null; + } + + public ASN1Integer getP() + { + return this.p; + } + + public ASN1Integer getG() + { + return this.g; + } + + public ASN1Integer getQ() + { + return this.q; + } + + public ASN1Integer getJ() + { + return this.j; + } + + public DHValidationParms getValidationParms() + { + return this.validationParms; + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + v.add(this.p); + v.add(this.g); + v.add(this.q); + + if (this.j != null) + { + v.add(this.j); + } + + if (this.validationParms != null) + { + v.add(this.validationParms); + } + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x9/DHPublicKey.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x9/DHPublicKey.java new file mode 100644 index 0000000..5dc07c2 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x9/DHPublicKey.java @@ -0,0 +1,52 @@ +package org.bc.asn1.x9; + +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1TaggedObject; + +public class DHPublicKey + extends ASN1Object +{ + private ASN1Integer y; + + public static DHPublicKey getInstance(ASN1TaggedObject obj, boolean explicit) + { + return getInstance(ASN1Integer.getInstance(obj, explicit)); + } + + public static DHPublicKey getInstance(Object obj) + { + if (obj == null || obj instanceof DHPublicKey) + { + return (DHPublicKey)obj; + } + + if (obj instanceof ASN1Integer) + { + return new DHPublicKey((ASN1Integer)obj); + } + + throw new IllegalArgumentException("Invalid DHPublicKey: " + obj.getClass().getName()); + } + + public DHPublicKey(ASN1Integer y) + { + if (y == null) + { + throw new IllegalArgumentException("'y' cannot be null"); + } + + this.y = y; + } + + public ASN1Integer getY() + { + return this.y; + } + + public ASN1Primitive toASN1Primitive() + { + return this.y; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x9/DHValidationParms.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x9/DHValidationParms.java new file mode 100644 index 0000000..7774c7e --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x9/DHValidationParms.java @@ -0,0 +1,80 @@ +package org.bc.asn1.x9; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.ASN1TaggedObject; +import org.bc.asn1.DERBitString; +import org.bc.asn1.DERSequence; + +public class DHValidationParms extends ASN1Object +{ + private DERBitString seed; + private ASN1Integer pgenCounter; + + public static DHValidationParms getInstance(ASN1TaggedObject obj, boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static DHValidationParms getInstance(Object obj) + { + if (obj == null || obj instanceof DHDomainParameters) + { + return (DHValidationParms)obj; + } + + if (obj instanceof ASN1Sequence) + { + return new DHValidationParms((ASN1Sequence)obj); + } + + throw new IllegalArgumentException("Invalid DHValidationParms: " + obj.getClass().getName()); + } + + public DHValidationParms(DERBitString seed, ASN1Integer pgenCounter) + { + if (seed == null) + { + throw new IllegalArgumentException("'seed' cannot be null"); + } + if (pgenCounter == null) + { + throw new IllegalArgumentException("'pgenCounter' cannot be null"); + } + + this.seed = seed; + this.pgenCounter = pgenCounter; + } + + private DHValidationParms(ASN1Sequence seq) + { + if (seq.size() != 2) + { + throw new IllegalArgumentException("Bad sequence size: " + seq.size()); + } + + this.seed = DERBitString.getInstance(seq.getObjectAt(0)); + this.pgenCounter = ASN1Integer.getInstance(seq.getObjectAt(1)); + } + + public DERBitString getSeed() + { + return this.seed; + } + + public ASN1Integer getPgenCounter() + { + return this.pgenCounter; + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + v.add(this.seed); + v.add(this.pgenCounter); + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x9/KeySpecificInfo.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x9/KeySpecificInfo.java new file mode 100644 index 0000000..173453e --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x9/KeySpecificInfo.java @@ -0,0 +1,68 @@ +package org.bc.asn1.x9; + +import java.util.Enumeration; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1ObjectIdentifier; +import org.bc.asn1.ASN1OctetString; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DERSequence; + +/** + * ASN.1 def for Diffie-Hellman key exchange KeySpecificInfo structure. See + * RFC 2631, or X9.42, for further details. + */ +public class KeySpecificInfo + extends ASN1Object +{ + private ASN1ObjectIdentifier algorithm; + private ASN1OctetString counter; + + public KeySpecificInfo( + ASN1ObjectIdentifier algorithm, + ASN1OctetString counter) + { + this.algorithm = algorithm; + this.counter = counter; + } + + public KeySpecificInfo( + ASN1Sequence seq) + { + Enumeration e = seq.getObjects(); + + algorithm = (ASN1ObjectIdentifier)e.nextElement(); + counter = (ASN1OctetString)e.nextElement(); + } + + public ASN1ObjectIdentifier getAlgorithm() + { + return algorithm; + } + + public ASN1OctetString getCounter() + { + return counter; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + *+ * KeySpecificInfo ::= SEQUENCE { + * algorithm OBJECT IDENTIFIER, + * counter OCTET STRING SIZE (4..4) + * } + *+ */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(algorithm); + v.add(counter); + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x9/OtherInfo.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x9/OtherInfo.java new file mode 100644 index 0000000..9b632ce --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x9/OtherInfo.java @@ -0,0 +1,96 @@ +package org.bc.asn1.x9; + +import java.util.Enumeration; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1OctetString; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DERSequence; +import org.bc.asn1.DERTaggedObject; + +/** + * ANS.1 def for Diffie-Hellman key exchange OtherInfo structure. See + * RFC 2631, or X9.42, for further details. + */ +public class OtherInfo + extends ASN1Object +{ + private KeySpecificInfo keyInfo; + private ASN1OctetString partyAInfo; + private ASN1OctetString suppPubInfo; + + public OtherInfo( + KeySpecificInfo keyInfo, + ASN1OctetString partyAInfo, + ASN1OctetString suppPubInfo) + { + this.keyInfo = keyInfo; + this.partyAInfo = partyAInfo; + this.suppPubInfo = suppPubInfo; + } + + public OtherInfo( + ASN1Sequence seq) + { + Enumeration e = seq.getObjects(); + + keyInfo = new KeySpecificInfo((ASN1Sequence)e.nextElement()); + + while (e.hasMoreElements()) + { + DERTaggedObject o = (DERTaggedObject)e.nextElement(); + + if (o.getTagNo() == 0) + { + partyAInfo = (ASN1OctetString)o.getObject(); + } + else if (o.getTagNo() == 2) + { + suppPubInfo = (ASN1OctetString)o.getObject(); + } + } + } + + public KeySpecificInfo getKeyInfo() + { + return keyInfo; + } + + public ASN1OctetString getPartyAInfo() + { + return partyAInfo; + } + + public ASN1OctetString getSuppPubInfo() + { + return suppPubInfo; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + *+ * OtherInfo ::= SEQUENCE { + * keyInfo KeySpecificInfo, + * partyAInfo [0] OCTET STRING OPTIONAL, + * suppPubInfo [2] OCTET STRING + * } + *+ */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(keyInfo); + + if (partyAInfo != null) + { + v.add(new DERTaggedObject(0, partyAInfo)); + } + + v.add(new DERTaggedObject(2, suppPubInfo)); + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x9/X962NamedCurves.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x9/X962NamedCurves.java new file mode 100644 index 0000000..67153d0 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x9/X962NamedCurves.java @@ -0,0 +1,621 @@ +package org.bc.asn1.x9; + +import java.math.BigInteger; +import java.util.Enumeration; +import java.util.Hashtable; + +import org.bc.asn1.ASN1ObjectIdentifier; +import org.bc.math.ec.ECCurve; +import org.bc.util.Strings; +import org.bc.util.encoders.Hex; + + +/** + * table of the current named curves defined in X.962 EC-DSA. + */ +public class X962NamedCurves +{ + static X9ECParametersHolder prime192v1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + ECCurve cFp192v1 = new ECCurve.Fp( + new BigInteger("6277101735386680763835789423207666416083908700390324961279"), + new BigInteger("fffffffffffffffffffffffffffffffefffffffffffffffc", 16), + new BigInteger("64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1", 16)); + + return new X9ECParameters( + cFp192v1, + cFp192v1.decodePoint( + Hex.decode("03188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012")), + new BigInteger("ffffffffffffffffffffffff99def836146bc9b1b4d22831", 16), + BigInteger.valueOf(1), + Hex.decode("3045AE6FC8422f64ED579528D38120EAE12196D5")); + } + }; + + static X9ECParametersHolder prime192v2 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + ECCurve cFp192v2 = new ECCurve.Fp( + new BigInteger("6277101735386680763835789423207666416083908700390324961279"), + new BigInteger("fffffffffffffffffffffffffffffffefffffffffffffffc", 16), + new BigInteger("cc22d6dfb95c6b25e49c0d6364a4e5980c393aa21668d953", 16)); + + return new X9ECParameters( + cFp192v2, + cFp192v2.decodePoint( + Hex.decode("03eea2bae7e1497842f2de7769cfe9c989c072ad696f48034a")), + new BigInteger("fffffffffffffffffffffffe5fb1a724dc80418648d8dd31", 16), + BigInteger.valueOf(1), + Hex.decode("31a92ee2029fd10d901b113e990710f0d21ac6b6")); + } + }; + + static X9ECParametersHolder prime192v3 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + ECCurve cFp192v3 = new ECCurve.Fp( + new BigInteger("6277101735386680763835789423207666416083908700390324961279"), + new BigInteger("fffffffffffffffffffffffffffffffefffffffffffffffc", 16), + new BigInteger("22123dc2395a05caa7423daeccc94760a7d462256bd56916", 16)); + + return new X9ECParameters( + cFp192v3, + cFp192v3.decodePoint( + Hex.decode("027d29778100c65a1da1783716588dce2b8b4aee8e228f1896")), + new BigInteger("ffffffffffffffffffffffff7a62d031c83f4294f640ec13", 16), + BigInteger.valueOf(1), + Hex.decode("c469684435deb378c4b65ca9591e2a5763059a2e")); + } + }; + + static X9ECParametersHolder prime239v1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + ECCurve cFp239v1 = new ECCurve.Fp( + new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"), + new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), + new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16)); + + return new X9ECParameters( + cFp239v1, + cFp239v1.decodePoint( + Hex.decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")), + new BigInteger("7fffffffffffffffffffffff7fffff9e5e9a9f5d9071fbd1522688909d0b", 16), + BigInteger.valueOf(1), + Hex.decode("e43bb460f0b80cc0c0b075798e948060f8321b7d")); + } + }; + + static X9ECParametersHolder prime239v2 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + ECCurve cFp239v2 = new ECCurve.Fp( + new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"), + new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), + new BigInteger("617fab6832576cbbfed50d99f0249c3fee58b94ba0038c7ae84c8c832f2c", 16)); + + return new X9ECParameters( + cFp239v2, + cFp239v2.decodePoint( + Hex.decode("0238af09d98727705120c921bb5e9e26296a3cdcf2f35757a0eafd87b830e7")), + new BigInteger("7fffffffffffffffffffffff800000cfa7e8594377d414c03821bc582063", 16), + BigInteger.valueOf(1), + Hex.decode("e8b4011604095303ca3b8099982be09fcb9ae616")); + } + }; + + static X9ECParametersHolder prime239v3 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + ECCurve cFp239v3 = new ECCurve.Fp( + new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"), + new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), + new BigInteger("255705fa2a306654b1f4cb03d6a750a30c250102d4988717d9ba15ab6d3e", 16)); + + return new X9ECParameters( + cFp239v3, + cFp239v3.decodePoint( + Hex.decode("036768ae8e18bb92cfcf005c949aa2c6d94853d0e660bbf854b1c9505fe95a")), + new BigInteger("7fffffffffffffffffffffff7fffff975deb41b3a6057c3c432146526551", 16), + BigInteger.valueOf(1), + Hex.decode("7d7374168ffe3471b60a857686a19475d3bfa2ff")); + } + }; + + static X9ECParametersHolder prime256v1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + ECCurve cFp256v1 = new ECCurve.Fp( + new BigInteger("115792089210356248762697446949407573530086143415290314195533631308867097853951"), + new BigInteger("ffffffff00000001000000000000000000000000fffffffffffffffffffffffc", 16), + new BigInteger("5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b", 16)); + + return new X9ECParameters( + cFp256v1, + cFp256v1.decodePoint( + Hex.decode("036b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296")), + new BigInteger("ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551", 16), + BigInteger.valueOf(1), + Hex.decode("c49d360886e704936a6678e1139d26b7819f7e90")); + } + }; + + /* + * F2m Curves + */ + static X9ECParametersHolder c2pnb163v1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + BigInteger c2m163v1n = new BigInteger("0400000000000000000001E60FC8821CC74DAEAFC1", 16); + BigInteger c2m163v1h = BigInteger.valueOf(2); + + ECCurve c2m163v1 = new ECCurve.F2m( + 163, + 1, 2, 8, + new BigInteger("072546B5435234A422E0789675F432C89435DE5242", 16), + new BigInteger("00C9517D06D5240D3CFF38C74B20B6CD4D6F9DD4D9", 16), + c2m163v1n, c2m163v1h); + + return new X9ECParameters( + c2m163v1, + c2m163v1.decodePoint( + Hex.decode("0307AF69989546103D79329FCC3D74880F33BBE803CB")), + c2m163v1n, c2m163v1h, + Hex.decode("D2C0FB15760860DEF1EEF4D696E6768756151754")); + } + }; + + static X9ECParametersHolder c2pnb163v2 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + BigInteger c2m163v2n = new BigInteger("03FFFFFFFFFFFFFFFFFFFDF64DE1151ADBB78F10A7", 16); + BigInteger c2m163v2h = BigInteger.valueOf(2); + + ECCurve c2m163v2 = new ECCurve.F2m( + 163, + 1, 2, 8, + new BigInteger("0108B39E77C4B108BED981ED0E890E117C511CF072", 16), + new BigInteger("0667ACEB38AF4E488C407433FFAE4F1C811638DF20", 16), + c2m163v2n, c2m163v2h); + + return new X9ECParameters( + c2m163v2, + c2m163v2.decodePoint( + Hex.decode("030024266E4EB5106D0A964D92C4860E2671DB9B6CC5")), + c2m163v2n, c2m163v2h, + null); + } + }; + + static X9ECParametersHolder c2pnb163v3 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + BigInteger c2m163v3n = new BigInteger("03FFFFFFFFFFFFFFFFFFFE1AEE140F110AFF961309", 16); + BigInteger c2m163v3h = BigInteger.valueOf(2); + + ECCurve c2m163v3 = new ECCurve.F2m( + 163, + 1, 2, 8, + new BigInteger("07A526C63D3E25A256A007699F5447E32AE456B50E", 16), + new BigInteger("03F7061798EB99E238FD6F1BF95B48FEEB4854252B", 16), + c2m163v3n, c2m163v3h); + + return new X9ECParameters( + c2m163v3, + c2m163v3.decodePoint( + Hex.decode("0202F9F87B7C574D0BDECF8A22E6524775F98CDEBDCB")), + c2m163v3n, c2m163v3h, + null); + } + }; + + static X9ECParametersHolder c2pnb176w1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + BigInteger c2m176w1n = new BigInteger("010092537397ECA4F6145799D62B0A19CE06FE26AD", 16); + BigInteger c2m176w1h = BigInteger.valueOf(0xFF6E); + + ECCurve c2m176w1 = new ECCurve.F2m( + 176, + 1, 2, 43, + new BigInteger("00E4E6DB2995065C407D9D39B8D0967B96704BA8E9C90B", 16), + new BigInteger("005DDA470ABE6414DE8EC133AE28E9BBD7FCEC0AE0FFF2", 16), + c2m176w1n, c2m176w1h); + + return new X9ECParameters( + c2m176w1, + c2m176w1.decodePoint( + Hex.decode("038D16C2866798B600F9F08BB4A8E860F3298CE04A5798")), + c2m176w1n, c2m176w1h, + null); + } + }; + + static X9ECParametersHolder c2tnb191v1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + BigInteger c2m191v1n = new BigInteger("40000000000000000000000004A20E90C39067C893BBB9A5", 16); + BigInteger c2m191v1h = BigInteger.valueOf(2); + + ECCurve c2m191v1 = new ECCurve.F2m( + 191, + 9, + new BigInteger("2866537B676752636A68F56554E12640276B649EF7526267", 16), + new BigInteger("2E45EF571F00786F67B0081B9495A3D95462F5DE0AA185EC", 16), + c2m191v1n, c2m191v1h); + + return new X9ECParameters( + c2m191v1, + c2m191v1.decodePoint( + Hex.decode("0236B3DAF8A23206F9C4F299D7B21A9C369137F2C84AE1AA0D")), + c2m191v1n, c2m191v1h, + Hex.decode("4E13CA542744D696E67687561517552F279A8C84")); + } + }; + + static X9ECParametersHolder c2tnb191v2 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + BigInteger c2m191v2n = new BigInteger("20000000000000000000000050508CB89F652824E06B8173", 16); + BigInteger c2m191v2h = BigInteger.valueOf(4); + + ECCurve c2m191v2 = new ECCurve.F2m( + 191, + 9, + new BigInteger("401028774D7777C7B7666D1366EA432071274F89FF01E718", 16), + new BigInteger("0620048D28BCBD03B6249C99182B7C8CD19700C362C46A01", 16), + c2m191v2n, c2m191v2h); + + return new X9ECParameters( + c2m191v2, + c2m191v2.decodePoint( + Hex.decode("023809B2B7CC1B28CC5A87926AAD83FD28789E81E2C9E3BF10")), + c2m191v2n, c2m191v2h, + null); + } + }; + + static X9ECParametersHolder c2tnb191v3 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + BigInteger c2m191v3n = new BigInteger("155555555555555555555555610C0B196812BFB6288A3EA3", 16); + BigInteger c2m191v3h = BigInteger.valueOf(6); + + ECCurve c2m191v3 = new ECCurve.F2m( + 191, + 9, + new BigInteger("6C01074756099122221056911C77D77E77A777E7E7E77FCB", 16), + new BigInteger("71FE1AF926CF847989EFEF8DB459F66394D90F32AD3F15E8", 16), + c2m191v3n, c2m191v3h); + + return new X9ECParameters( + c2m191v3, + c2m191v3.decodePoint( + Hex.decode("03375D4CE24FDE434489DE8746E71786015009E66E38A926DD")), + c2m191v3n, c2m191v3h, + null); + } + }; + + static X9ECParametersHolder c2pnb208w1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + BigInteger c2m208w1n = new BigInteger("0101BAF95C9723C57B6C21DA2EFF2D5ED588BDD5717E212F9D", 16); + BigInteger c2m208w1h = BigInteger.valueOf(0xFE48); + + ECCurve c2m208w1 = new ECCurve.F2m( + 208, + 1, 2, 83, + new BigInteger("0", 16), + new BigInteger("00C8619ED45A62E6212E1160349E2BFA844439FAFC2A3FD1638F9E", 16), + c2m208w1n, c2m208w1h); + + return new X9ECParameters( + c2m208w1, + c2m208w1.decodePoint( + Hex.decode("0289FDFBE4ABE193DF9559ECF07AC0CE78554E2784EB8C1ED1A57A")), + c2m208w1n, c2m208w1h, + null); + } + }; + + static X9ECParametersHolder c2tnb239v1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + BigInteger c2m239v1n = new BigInteger("2000000000000000000000000000000F4D42FFE1492A4993F1CAD666E447", 16); + BigInteger c2m239v1h = BigInteger.valueOf(4); + + ECCurve c2m239v1 = new ECCurve.F2m( + 239, + 36, + new BigInteger("32010857077C5431123A46B808906756F543423E8D27877578125778AC76", 16), + new BigInteger("790408F2EEDAF392B012EDEFB3392F30F4327C0CA3F31FC383C422AA8C16", 16), + c2m239v1n, c2m239v1h); + + return new X9ECParameters( + c2m239v1, + c2m239v1.decodePoint( + Hex.decode("0257927098FA932E7C0A96D3FD5B706EF7E5F5C156E16B7E7C86038552E91D")), + c2m239v1n, c2m239v1h, + null); + } + }; + + static X9ECParametersHolder c2tnb239v2 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + BigInteger c2m239v2n = new BigInteger("1555555555555555555555555555553C6F2885259C31E3FCDF154624522D", 16); + BigInteger c2m239v2h = BigInteger.valueOf(6); + + ECCurve c2m239v2 = new ECCurve.F2m( + 239, + 36, + new BigInteger("4230017757A767FAE42398569B746325D45313AF0766266479B75654E65F", 16), + new BigInteger("5037EA654196CFF0CD82B2C14A2FCF2E3FF8775285B545722F03EACDB74B", 16), + c2m239v2n, c2m239v2h); + + return new X9ECParameters( + c2m239v2, + c2m239v2.decodePoint( + Hex.decode("0228F9D04E900069C8DC47A08534FE76D2B900B7D7EF31F5709F200C4CA205")), + c2m239v2n, c2m239v2h, + null); + } + }; + + static X9ECParametersHolder c2tnb239v3 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + BigInteger c2m239v3n = new BigInteger("0CCCCCCCCCCCCCCCCCCCCCCCCCCCCCAC4912D2D9DF903EF9888B8A0E4CFF", 16); + BigInteger c2m239v3h = BigInteger.valueOf(10); + + ECCurve c2m239v3 = new ECCurve.F2m( + 239, + 36, + new BigInteger("01238774666A67766D6676F778E676B66999176666E687666D8766C66A9F", 16), + new BigInteger("6A941977BA9F6A435199ACFC51067ED587F519C5ECB541B8E44111DE1D40", 16), + c2m239v3n, c2m239v3h); + + return new X9ECParameters( + c2m239v3, + c2m239v3.decodePoint( + Hex.decode("0370F6E9D04D289C4E89913CE3530BFDE903977D42B146D539BF1BDE4E9C92")), + c2m239v3n, c2m239v3h, + null); + } + }; + + static X9ECParametersHolder c2pnb272w1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + BigInteger c2m272w1n = new BigInteger("0100FAF51354E0E39E4892DF6E319C72C8161603FA45AA7B998A167B8F1E629521", 16); + BigInteger c2m272w1h = BigInteger.valueOf(0xFF06); + + ECCurve c2m272w1 = new ECCurve.F2m( + 272, + 1, 3, 56, + new BigInteger("0091A091F03B5FBA4AB2CCF49C4EDD220FB028712D42BE752B2C40094DBACDB586FB20", 16), + new BigInteger("7167EFC92BB2E3CE7C8AAAFF34E12A9C557003D7C73A6FAF003F99F6CC8482E540F7", 16), + c2m272w1n, c2m272w1h); + + return new X9ECParameters( + c2m272w1, + c2m272w1.decodePoint( + Hex.decode("026108BABB2CEEBCF787058A056CBE0CFE622D7723A289E08A07AE13EF0D10D171DD8D")), + c2m272w1n, c2m272w1h, + null); + } + }; + + static X9ECParametersHolder c2pnb304w1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + BigInteger c2m304w1n = new BigInteger("0101D556572AABAC800101D556572AABAC8001022D5C91DD173F8FB561DA6899164443051D", 16); + BigInteger c2m304w1h = BigInteger.valueOf(0xFE2E); + + ECCurve c2m304w1 = new ECCurve.F2m( + 304, + 1, 2, 11, + new BigInteger("00FD0D693149A118F651E6DCE6802085377E5F882D1B510B44160074C1288078365A0396C8E681", 16), + new BigInteger("00BDDB97E555A50A908E43B01C798EA5DAA6788F1EA2794EFCF57166B8C14039601E55827340BE", 16), + c2m304w1n, c2m304w1h); + + return new X9ECParameters( + c2m304w1, + c2m304w1.decodePoint( + Hex.decode("02197B07845E9BE2D96ADB0F5F3C7F2CFFBD7A3EB8B6FEC35C7FD67F26DDF6285A644F740A2614")), + c2m304w1n, c2m304w1h, + null); + } + }; + + static X9ECParametersHolder c2tnb359v1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + BigInteger c2m359v1n = new BigInteger("01AF286BCA1AF286BCA1AF286BCA1AF286BCA1AF286BC9FB8F6B85C556892C20A7EB964FE7719E74F490758D3B", 16); + BigInteger c2m359v1h = BigInteger.valueOf(0x4C); + + ECCurve c2m359v1 = new ECCurve.F2m( + 359, + 68, + new BigInteger("5667676A654B20754F356EA92017D946567C46675556F19556A04616B567D223A5E05656FB549016A96656A557", 16), + new BigInteger("2472E2D0197C49363F1FE7F5B6DB075D52B6947D135D8CA445805D39BC345626089687742B6329E70680231988", 16), + c2m359v1n, c2m359v1h); + + return new X9ECParameters( + c2m359v1, + c2m359v1.decodePoint( + Hex.decode("033C258EF3047767E7EDE0F1FDAA79DAEE3841366A132E163ACED4ED2401DF9C6BDCDE98E8E707C07A2239B1B097")), + c2m359v1n, c2m359v1h, + null); + } + }; + + static X9ECParametersHolder c2pnb368w1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + BigInteger c2m368w1n = new BigInteger("010090512DA9AF72B08349D98A5DD4C7B0532ECA51CE03E2D10F3B7AC579BD87E909AE40A6F131E9CFCE5BD967", 16); + BigInteger c2m368w1h = BigInteger.valueOf(0xFF70); + + ECCurve c2m368w1 = new ECCurve.F2m( + 368, + 1, 2, 85, + new BigInteger("00E0D2EE25095206F5E2A4F9ED229F1F256E79A0E2B455970D8D0D865BD94778C576D62F0AB7519CCD2A1A906AE30D", 16), + new BigInteger("00FC1217D4320A90452C760A58EDCD30C8DD069B3C34453837A34ED50CB54917E1C2112D84D164F444F8F74786046A", 16), + c2m368w1n, c2m368w1h); + + return new X9ECParameters( + c2m368w1, + c2m368w1.decodePoint( + Hex.decode("021085E2755381DCCCE3C1557AFA10C2F0C0C2825646C5B34A394CBCFA8BC16B22E7E789E927BE216F02E1FB136A5F")), + c2m368w1n, c2m368w1h, + null); + } + }; + + static X9ECParametersHolder c2tnb431r1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + BigInteger c2m431r1n = new BigInteger("0340340340340340340340340340340340340340340340340340340323C313FAB50589703B5EC68D3587FEC60D161CC149C1AD4A91", 16); + BigInteger c2m431r1h = BigInteger.valueOf(0x2760); + + ECCurve c2m431r1 = new ECCurve.F2m( + 431, + 120, + new BigInteger("1A827EF00DD6FC0E234CAF046C6A5D8A85395B236CC4AD2CF32A0CADBDC9DDF620B0EB9906D0957F6C6FEACD615468DF104DE296CD8F", 16), + new BigInteger("10D9B4A3D9047D8B154359ABFB1B7F5485B04CEB868237DDC9DEDA982A679A5A919B626D4E50A8DD731B107A9962381FB5D807BF2618", 16), + c2m431r1n, c2m431r1h); + + return new X9ECParameters( + c2m431r1, + c2m431r1.decodePoint( + Hex.decode("02120FC05D3C67A99DE161D2F4092622FECA701BE4F50F4758714E8A87BBF2A658EF8C21E7C5EFE965361F6C2999C0C247B0DBD70CE6B7")), + c2m431r1n, c2m431r1h, + null); + } + }; + + static final Hashtable objIds = new Hashtable(); + static final Hashtable curves = new Hashtable(); + static final Hashtable names = new Hashtable(); + + static void defineCurve(String name, ASN1ObjectIdentifier oid, X9ECParametersHolder holder) + { + objIds.put(name, oid); + names.put(oid, name); + curves.put(oid, holder); + } + + static + { + defineCurve("prime192v1", X9ObjectIdentifiers.prime192v1, prime192v1); + defineCurve("prime192v2", X9ObjectIdentifiers.prime192v2, prime192v2); + defineCurve("prime192v3", X9ObjectIdentifiers.prime192v3, prime192v3); + defineCurve("prime239v1", X9ObjectIdentifiers.prime239v1, prime239v1); + defineCurve("prime239v2", X9ObjectIdentifiers.prime239v2, prime239v2); + defineCurve("prime239v3", X9ObjectIdentifiers.prime239v3, prime239v3); + defineCurve("prime256v1", X9ObjectIdentifiers.prime256v1, prime256v1); + defineCurve("c2pnb163v1", X9ObjectIdentifiers.c2pnb163v1, c2pnb163v1); + defineCurve("c2pnb163v2", X9ObjectIdentifiers.c2pnb163v2, c2pnb163v2); + defineCurve("c2pnb163v3", X9ObjectIdentifiers.c2pnb163v3, c2pnb163v3); + defineCurve("c2pnb176w1", X9ObjectIdentifiers.c2pnb176w1, c2pnb176w1); + defineCurve("c2tnb191v1", X9ObjectIdentifiers.c2tnb191v1, c2tnb191v1); + defineCurve("c2tnb191v2", X9ObjectIdentifiers.c2tnb191v2, c2tnb191v2); + defineCurve("c2tnb191v3", X9ObjectIdentifiers.c2tnb191v3, c2tnb191v3); + defineCurve("c2pnb208w1", X9ObjectIdentifiers.c2pnb208w1, c2pnb208w1); + defineCurve("c2tnb239v1", X9ObjectIdentifiers.c2tnb239v1, c2tnb239v1); + defineCurve("c2tnb239v2", X9ObjectIdentifiers.c2tnb239v2, c2tnb239v2); + defineCurve("c2tnb239v3", X9ObjectIdentifiers.c2tnb239v3, c2tnb239v3); + defineCurve("c2pnb272w1", X9ObjectIdentifiers.c2pnb272w1, c2pnb272w1); + defineCurve("c2pnb304w1", X9ObjectIdentifiers.c2pnb304w1, c2pnb304w1); + defineCurve("c2tnb359v1", X9ObjectIdentifiers.c2tnb359v1, c2tnb359v1); + defineCurve("c2pnb368w1", X9ObjectIdentifiers.c2pnb368w1, c2pnb368w1); + defineCurve("c2tnb431r1", X9ObjectIdentifiers.c2tnb431r1, c2tnb431r1); + } + + public static X9ECParameters getByName( + String name) + { + ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)objIds.get(Strings.toLowerCase(name)); + + if (oid != null) + { + return getByOID(oid); + } + + return null; + } + + /** + * return the X9ECParameters object for the named curve represented by + * the passed in object identifier. Null if the curve isn't present. + * + * @param oid an object identifier representing a named curve, if present. + */ + public static X9ECParameters getByOID( + ASN1ObjectIdentifier oid) + { + X9ECParametersHolder holder = (X9ECParametersHolder)curves.get(oid); + + if (holder != null) + { + return holder.getParameters(); + } + + return null; + } + + /** + * return the object identifier signified by the passed in name. Null + * if there is no object identifier associated with name. + * + * @return the object identifier associated with name, if present. + */ + public static ASN1ObjectIdentifier getOID( + String name) + { + return (ASN1ObjectIdentifier)objIds.get(Strings.toLowerCase(name)); + } + + /** + * return the named curve name represented by the given object identifier. + */ + public static String getName( + ASN1ObjectIdentifier oid) + { + return (String)names.get(oid); + } + + /** + * returns an enumeration containing the name strings for curves + * contained in this structure. + */ + public static Enumeration getNames() + { + return objIds.keys(); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x9/X962Parameters.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x9/X962Parameters.java new file mode 100644 index 0000000..49552f9 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x9/X962Parameters.java @@ -0,0 +1,86 @@ +package org.bc.asn1.x9; + +import org.bc.asn1.ASN1Choice; +import org.bc.asn1.ASN1Null; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1ObjectIdentifier; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1TaggedObject; + +public class X962Parameters + extends ASN1Object + implements ASN1Choice +{ + private ASN1Primitive params = null; + + public static X962Parameters getInstance( + Object obj) + { + if (obj == null || obj instanceof X962Parameters) + { + return (X962Parameters)obj; + } + + if (obj instanceof ASN1Primitive) + { + return new X962Parameters((ASN1Primitive)obj); + } + + throw new IllegalArgumentException("unknown object in getInstance()"); + } + + public static X962Parameters getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(obj.getObject()); // must be explicitly tagged + } + + public X962Parameters( + X9ECParameters ecParameters) + { + this.params = ecParameters.toASN1Primitive(); + } + + public X962Parameters( + ASN1ObjectIdentifier namedCurve) + { + this.params = namedCurve; + } + + public X962Parameters( + ASN1Primitive obj) + { + this.params = obj; + } + + public boolean isNamedCurve() + { + return (params instanceof ASN1ObjectIdentifier); + } + + public boolean isImplicitlyCA() + { + return (params instanceof ASN1Null); + } + + public ASN1Primitive getParameters() + { + return params; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + *+ * Parameters ::= CHOICE { + * ecParameters ECParameters, + * namedCurve CURVES.&id({CurveNames}), + * implicitlyCA NULL + * } + *+ */ + public ASN1Primitive toASN1Primitive() + { + return (ASN1Primitive)params; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x9/X9Curve.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x9/X9Curve.java new file mode 100644 index 0000000..03963f6 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x9/X9Curve.java @@ -0,0 +1,161 @@ +package org.bc.asn1.x9; + +import java.math.BigInteger; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1ObjectIdentifier; +import org.bc.asn1.ASN1OctetString; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DERBitString; +import org.bc.asn1.DERSequence; +import org.bc.math.ec.ECCurve; + +/** + * ASN.1 def for Elliptic-Curve Curve structure. See + * X9.62, for further details. + */ +public class X9Curve + extends ASN1Object + implements X9ObjectIdentifiers +{ + private ECCurve curve; + private byte[] seed; + private ASN1ObjectIdentifier fieldIdentifier = null; + + public X9Curve( + ECCurve curve) + { + this.curve = curve; + this.seed = null; + setFieldIdentifier(); + } + + public X9Curve( + ECCurve curve, + byte[] seed) + { + this.curve = curve; + this.seed = seed; + setFieldIdentifier(); + } + + public X9Curve( + X9FieldID fieldID, + ASN1Sequence seq) + { + fieldIdentifier = fieldID.getIdentifier(); + if (fieldIdentifier.equals(prime_field)) + { + BigInteger p = ((ASN1Integer)fieldID.getParameters()).getValue(); + X9FieldElement x9A = new X9FieldElement(p, (ASN1OctetString)seq.getObjectAt(0)); + X9FieldElement x9B = new X9FieldElement(p, (ASN1OctetString)seq.getObjectAt(1)); + curve = new ECCurve.Fp(p, x9A.getValue().toBigInteger(), x9B.getValue().toBigInteger()); + } + else + { + if (fieldIdentifier.equals(characteristic_two_field)) + { + // Characteristic two field + ASN1Sequence parameters = ASN1Sequence.getInstance(fieldID.getParameters()); + int m = ((ASN1Integer)parameters.getObjectAt(0)).getValue(). + intValue(); + ASN1ObjectIdentifier representation + = (ASN1ObjectIdentifier)parameters.getObjectAt(1); + + int k1 = 0; + int k2 = 0; + int k3 = 0; + if (representation.equals(tpBasis)) + { + // Trinomial basis representation + k1 = ((ASN1Integer)parameters.getObjectAt(2)).getValue(). + intValue(); + } + else + { + // Pentanomial basis representation + DERSequence pentanomial + = (DERSequence)parameters.getObjectAt(2); + k1 = ((ASN1Integer)pentanomial.getObjectAt(0)).getValue(). + intValue(); + k2 = ((ASN1Integer)pentanomial.getObjectAt(1)).getValue(). + intValue(); + k3 = ((ASN1Integer)pentanomial.getObjectAt(2)).getValue(). + intValue(); + } + X9FieldElement x9A = new X9FieldElement(m, k1, k2, k3, (ASN1OctetString)seq.getObjectAt(0)); + X9FieldElement x9B = new X9FieldElement(m, k1, k2, k3, (ASN1OctetString)seq.getObjectAt(1)); + // TODO Is it possible to get the order (n) and cofactor(h) too? + curve = new ECCurve.F2m(m, k1, k2, k3, x9A.getValue().toBigInteger(), x9B.getValue().toBigInteger()); + } + } + + if (seq.size() == 3) + { + seed = ((DERBitString)seq.getObjectAt(2)).getBytes(); + } + } + + private void setFieldIdentifier() + { + if (curve instanceof ECCurve.Fp) + { + fieldIdentifier = prime_field; + } + else if (curve instanceof ECCurve.F2m) + { + fieldIdentifier = characteristic_two_field; + } + else + { + throw new IllegalArgumentException("This type of ECCurve is not " + + "implemented"); + } + } + + public ECCurve getCurve() + { + return curve; + } + + public byte[] getSeed() + { + return seed; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + *+ * Curve ::= SEQUENCE { + * a FieldElement, + * b FieldElement, + * seed BIT STRING OPTIONAL + * } + *+ */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + if (fieldIdentifier.equals(prime_field)) + { + v.add(new X9FieldElement(curve.getA()).toASN1Primitive()); + v.add(new X9FieldElement(curve.getB()).toASN1Primitive()); + } + else if (fieldIdentifier.equals(characteristic_two_field)) + { + v.add(new X9FieldElement(curve.getA()).toASN1Primitive()); + v.add(new X9FieldElement(curve.getB()).toASN1Primitive()); + } + + if (seed != null) + { + v.add(new DERBitString(seed)); + } + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x9/X9ECParameters.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x9/X9ECParameters.java new file mode 100644 index 0000000..9b1c505 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x9/X9ECParameters.java @@ -0,0 +1,176 @@ +package org.bc.asn1.x9; + +import java.math.BigInteger; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1OctetString; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DERSequence; +import org.bc.math.ec.ECCurve; +import org.bc.math.ec.ECPoint; + +/** + * ASN.1 def for Elliptic-Curve ECParameters structure. See + * X9.62, for further details. + */ +public class X9ECParameters + extends ASN1Object + implements X9ObjectIdentifiers +{ + private static final BigInteger ONE = BigInteger.valueOf(1); + + private X9FieldID fieldID; + private ECCurve curve; + private ECPoint g; + private BigInteger n; + private BigInteger h; + private byte[] seed; + + private X9ECParameters( + ASN1Sequence seq) + { + if (!(seq.getObjectAt(0) instanceof ASN1Integer) + || !((ASN1Integer)seq.getObjectAt(0)).getValue().equals(ONE)) + { + throw new IllegalArgumentException("bad version in X9ECParameters"); + } + + X9Curve x9c = new X9Curve( + new X9FieldID((ASN1Sequence)seq.getObjectAt(1)), + (ASN1Sequence)seq.getObjectAt(2)); + + this.curve = x9c.getCurve(); + this.g = new X9ECPoint(curve, (ASN1OctetString)seq.getObjectAt(3)).getPoint(); + this.n = ((ASN1Integer)seq.getObjectAt(4)).getValue(); + this.seed = x9c.getSeed(); + + if (seq.size() == 6) + { + this.h = ((ASN1Integer)seq.getObjectAt(5)).getValue(); + } + } + + public static X9ECParameters getInstance(Object obj) + { + if (obj instanceof X9ECParameters) + { + return (X9ECParameters)obj; + } + + if (obj != null) + { + return new X9ECParameters(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public X9ECParameters( + ECCurve curve, + ECPoint g, + BigInteger n) + { + this(curve, g, n, ONE, null); + } + + public X9ECParameters( + ECCurve curve, + ECPoint g, + BigInteger n, + BigInteger h) + { + this(curve, g, n, h, null); + } + + public X9ECParameters( + ECCurve curve, + ECPoint g, + BigInteger n, + BigInteger h, + byte[] seed) + { + this.curve = curve; + this.g = g; + this.n = n; + this.h = h; + this.seed = seed; + + if (curve instanceof ECCurve.Fp) + { + this.fieldID = new X9FieldID(((ECCurve.Fp)curve).getQ()); + } + else + { + if (curve instanceof ECCurve.F2m) + { + ECCurve.F2m curveF2m = (ECCurve.F2m)curve; + this.fieldID = new X9FieldID(curveF2m.getM(), curveF2m.getK1(), + curveF2m.getK2(), curveF2m.getK3()); + } + } + } + + public ECCurve getCurve() + { + return curve; + } + + public ECPoint getG() + { + return g; + } + + public BigInteger getN() + { + return n; + } + + public BigInteger getH() + { + if (h == null) + { + return ONE; // TODO - this should be calculated, it will cause issues with custom curves. + } + + return h; + } + + public byte[] getSeed() + { + return seed; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + *+ * ECParameters ::= SEQUENCE { + * version INTEGER { ecpVer1(1) } (ecpVer1), + * fieldID FieldID {{FieldTypes}}, + * curve X9Curve, + * base X9ECPoint, + * order INTEGER, + * cofactor INTEGER OPTIONAL + * } + *+ */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(new ASN1Integer(1)); + v.add(fieldID); + v.add(new X9Curve(curve, seed)); + v.add(new X9ECPoint(g)); + v.add(new ASN1Integer(n)); + + if (h != null) + { + v.add(new ASN1Integer(h)); + } + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x9/X9ECParametersHolder.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x9/X9ECParametersHolder.java new file mode 100644 index 0000000..f1becb3 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x9/X9ECParametersHolder.java @@ -0,0 +1,18 @@ +package org.bc.asn1.x9; + +public abstract class X9ECParametersHolder +{ + private X9ECParameters params; + + public X9ECParameters getParameters() + { + if (params == null) + { + params = createParameters(); + } + + return params; + } + + protected abstract X9ECParameters createParameters(); +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x9/X9ECPoint.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x9/X9ECPoint.java new file mode 100644 index 0000000..b9ae23a --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x9/X9ECPoint.java @@ -0,0 +1,48 @@ +package org.bc.asn1.x9; + +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1OctetString; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.DEROctetString; +import org.bc.math.ec.ECCurve; +import org.bc.math.ec.ECPoint; + +/** + * class for describing an ECPoint as a DER object. + */ +public class X9ECPoint + extends ASN1Object +{ + ECPoint p; + + public X9ECPoint( + ECPoint p) + { + this.p = p; + } + + public X9ECPoint( + ECCurve c, + ASN1OctetString s) + { + this.p = c.decodePoint(s.getOctets()); + } + + public ECPoint getPoint() + { + return p; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + *+ * ECPoint ::= OCTET STRING + *+ *+ * Octet string produced using ECPoint.getEncoded(). + */ + public ASN1Primitive toASN1Primitive() + { + return new DEROctetString(p.getEncoded()); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x9/X9FieldElement.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x9/X9FieldElement.java new file mode 100644 index 0000000..f6e98cf --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x9/X9FieldElement.java @@ -0,0 +1,64 @@ +package org.bc.asn1.x9; + +import java.math.BigInteger; + +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1OctetString; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.DEROctetString; +import org.bc.math.ec.ECFieldElement; + +/** + * class for processing an FieldElement as a DER object. + */ +public class X9FieldElement + extends ASN1Object +{ + protected ECFieldElement f; + + private static X9IntegerConverter converter = new X9IntegerConverter(); + + public X9FieldElement(ECFieldElement f) + { + this.f = f; + } + + public X9FieldElement(BigInteger p, ASN1OctetString s) + { + this(new ECFieldElement.Fp(p, new BigInteger(1, s.getOctets()))); + } + + public X9FieldElement(int m, int k1, int k2, int k3, ASN1OctetString s) + { + this(new ECFieldElement.F2m(m, k1, k2, k3, new BigInteger(1, s.getOctets()))); + } + + public ECFieldElement getValue() + { + return f; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + *
+ * FieldElement ::= OCTET STRING + *+ *+ *
+ *
+ */ + public ASN1Primitive toASN1Primitive() + { + int byteCount = converter.getByteLength(f); + byte[] paddedBigInteger = converter.integerToBytes(f.toBigInteger(), byteCount); + + return new DEROctetString(paddedBigInteger); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x9/X9FieldID.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x9/X9FieldID.java new file mode 100644 index 0000000..7e97c0e --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x9/X9FieldID.java @@ -0,0 +1,109 @@ +package org.bc.asn1.x9; + +import java.math.BigInteger; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Integer; +import org.bc.asn1.ASN1Object; +import org.bc.asn1.ASN1ObjectIdentifier; +import org.bc.asn1.ASN1Primitive; +import org.bc.asn1.ASN1Sequence; +import org.bc.asn1.DERSequence; + +/** + * ASN.1 def for Elliptic-Curve Field ID structure. See + * X9.62, for further details. + */ +public class X9FieldID + extends ASN1Object + implements X9ObjectIdentifiers +{ + private ASN1ObjectIdentifier id; + private ASN1Primitive parameters; + + /** + * Constructor for elliptic curves over prime fields + *- if q is an odd prime then the field element is + * processed as an Integer and converted to an octet string + * according to x 9.62 4.3.1.
+ *- if q is 2m then the bit string + * contained in the field element is converted into an octet + * string with the same ordering padded at the front if necessary. + *
+ *F2
. + * @param primeP The primep
defining the prime field. + */ + public X9FieldID(BigInteger primeP) + { + this.id = prime_field; + this.parameters = new ASN1Integer(primeP); + } + + /** + * Constructor for elliptic curves over binary fields + *F2m
. + * @param m The exponentm
of + *F2m
. + * @param k1 The integerk1
wherexm + + * xk3 + xk2 + xk1 + 1
+ * represents the reduction polynomialf(z)
. + * @param k2 The integerk2
wherexm + + * xk3 + xk2 + xk1 + 1
+ * represents the reduction polynomialf(z)
. + * @param k3 The integerk3
wherexm + + * xk3 + xk2 + xk1 + 1
+ * represents the reduction polynomialf(z)
.. + */ + public X9FieldID(int m, int k1, int k2, int k3) + { + this.id = characteristic_two_field; + ASN1EncodableVector fieldIdParams = new ASN1EncodableVector(); + fieldIdParams.add(new ASN1Integer(m)); + + if (k2 == 0) + { + fieldIdParams.add(tpBasis); + fieldIdParams.add(new ASN1Integer(k1)); + } + else + { + fieldIdParams.add(ppBasis); + ASN1EncodableVector pentanomialParams = new ASN1EncodableVector(); + pentanomialParams.add(new ASN1Integer(k1)); + pentanomialParams.add(new ASN1Integer(k2)); + pentanomialParams.add(new ASN1Integer(k3)); + fieldIdParams.add(new DERSequence(pentanomialParams)); + } + + this.parameters = new DERSequence(fieldIdParams); + } + + public X9FieldID( + ASN1Sequence seq) + { + this.id = (ASN1ObjectIdentifier)seq.getObjectAt(0); + this.parameters = (ASN1Primitive)seq.getObjectAt(1); + } + + public ASN1ObjectIdentifier getIdentifier() + { + return id; + } + + public ASN1Primitive getParameters() + { + return parameters; + } + + /** + * Produce a DER encoding of the following structure. + *+ * FieldID ::= SEQUENCE { + * fieldType FIELD-ID.&id({IOSet}), + * parameters FIELD-ID.&Type({IOSet}{@fieldType}) + * } + *+ */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(this.id); + v.add(this.parameters); + + return new DERSequence(v); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x9/X9IntegerConverter.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x9/X9IntegerConverter.java new file mode 100644 index 0000000..9112502 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x9/X9IntegerConverter.java @@ -0,0 +1,47 @@ +package org.bc.asn1.x9; + +import java.math.BigInteger; + +import org.bc.math.ec.ECCurve; +import org.bc.math.ec.ECFieldElement; + +public class X9IntegerConverter +{ + public int getByteLength( + ECCurve c) + { + return (c.getFieldSize() + 7) / 8; + } + + public int getByteLength( + ECFieldElement fe) + { + return (fe.getFieldSize() + 7) / 8; + } + + public byte[] integerToBytes( + BigInteger s, + int qLength) + { + byte[] bytes = s.toByteArray(); + + if (qLength < bytes.length) + { + byte[] tmp = new byte[qLength]; + + System.arraycopy(bytes, bytes.length - tmp.length, tmp, 0, tmp.length); + + return tmp; + } + else if (qLength > bytes.length) + { + byte[] tmp = new byte[qLength]; + + System.arraycopy(bytes, 0, tmp, tmp.length - bytes.length, bytes.length); + + return tmp; + } + + return bytes; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x9/X9ObjectIdentifiers.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x9/X9ObjectIdentifiers.java new file mode 100644 index 0000000..a58423d --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/asn1/x9/X9ObjectIdentifiers.java @@ -0,0 +1,132 @@ +package org.bc.asn1.x9; + +import org.bc.asn1.ASN1ObjectIdentifier; + +public interface X9ObjectIdentifiers +{ + // + // X9.62 + // + // ansi-X9-62 OBJECT IDENTIFIER ::= { iso(1) member-body(2) + // us(840) ansi-x962(10045) } + // + static final ASN1ObjectIdentifier ansi_X9_62 = new ASN1ObjectIdentifier("1.2.840.10045"); + static final ASN1ObjectIdentifier id_fieldType = ansi_X9_62.branch("1"); + + static final ASN1ObjectIdentifier prime_field = id_fieldType.branch("1"); + + static final ASN1ObjectIdentifier characteristic_two_field = id_fieldType.branch("2"); + + static final ASN1ObjectIdentifier gnBasis = id_fieldType.branch("2.3.1"); + + static final ASN1ObjectIdentifier tpBasis = id_fieldType.branch("2.3.2"); + + static final ASN1ObjectIdentifier ppBasis = id_fieldType.branch("2.3.3"); + + static final ASN1ObjectIdentifier id_ecSigType = ansi_X9_62.branch("4"); + + static final ASN1ObjectIdentifier ecdsa_with_SHA1 = new ASN1ObjectIdentifier(id_ecSigType + ".1"); + + static final ASN1ObjectIdentifier id_publicKeyType = ansi_X9_62.branch("2"); + + static final ASN1ObjectIdentifier id_ecPublicKey = id_publicKeyType.branch("1"); + + static final ASN1ObjectIdentifier ecdsa_with_SHA2 = id_ecSigType.branch("3"); + + static final ASN1ObjectIdentifier ecdsa_with_SHA224 = ecdsa_with_SHA2.branch("1"); + + static final ASN1ObjectIdentifier ecdsa_with_SHA256 = ecdsa_with_SHA2.branch("2"); + + static final ASN1ObjectIdentifier ecdsa_with_SHA384 = ecdsa_with_SHA2.branch("3"); + + static final ASN1ObjectIdentifier ecdsa_with_SHA512 = ecdsa_with_SHA2.branch("4"); + + // + // named curves + // + static final ASN1ObjectIdentifier ellipticCurve = ansi_X9_62.branch("3"); + + // + // Two Curves + // + static final ASN1ObjectIdentifier cTwoCurve = ellipticCurve.branch("0"); + + static final ASN1ObjectIdentifier c2pnb163v1 = cTwoCurve.branch("1"); + static final ASN1ObjectIdentifier c2pnb163v2 = cTwoCurve.branch("2"); + static final ASN1ObjectIdentifier c2pnb163v3 = cTwoCurve.branch("3"); + static final ASN1ObjectIdentifier c2pnb176w1 = cTwoCurve.branch("4"); + static final ASN1ObjectIdentifier c2tnb191v1 = cTwoCurve.branch("5"); + static final ASN1ObjectIdentifier c2tnb191v2 = cTwoCurve.branch("6"); + static final ASN1ObjectIdentifier c2tnb191v3 = cTwoCurve.branch("7"); + static final ASN1ObjectIdentifier c2onb191v4 = cTwoCurve.branch("8"); + static final ASN1ObjectIdentifier c2onb191v5 = cTwoCurve.branch("9"); + static final ASN1ObjectIdentifier c2pnb208w1 = cTwoCurve.branch("10"); + static final ASN1ObjectIdentifier c2tnb239v1 = cTwoCurve.branch("11"); + static final ASN1ObjectIdentifier c2tnb239v2 = cTwoCurve.branch("12"); + static final ASN1ObjectIdentifier c2tnb239v3 = cTwoCurve.branch("13"); + static final ASN1ObjectIdentifier c2onb239v4 = cTwoCurve.branch("14"); + static final ASN1ObjectIdentifier c2onb239v5 = cTwoCurve.branch("15"); + static final ASN1ObjectIdentifier c2pnb272w1 = cTwoCurve.branch("16"); + static final ASN1ObjectIdentifier c2pnb304w1 = cTwoCurve.branch("17"); + static final ASN1ObjectIdentifier c2tnb359v1 = cTwoCurve.branch("18"); + static final ASN1ObjectIdentifier c2pnb368w1 = cTwoCurve.branch("19"); + static final ASN1ObjectIdentifier c2tnb431r1 = cTwoCurve.branch("20"); + + // + // Prime + // + static final ASN1ObjectIdentifier primeCurve = ellipticCurve.branch("1"); + + static final ASN1ObjectIdentifier prime192v1 = primeCurve.branch("1"); + static final ASN1ObjectIdentifier prime192v2 = primeCurve.branch("2"); + static final ASN1ObjectIdentifier prime192v3 = primeCurve.branch("3"); + static final ASN1ObjectIdentifier prime239v1 = primeCurve.branch("4"); + static final ASN1ObjectIdentifier prime239v2 = primeCurve.branch("5"); + static final ASN1ObjectIdentifier prime239v3 = primeCurve.branch("6"); + static final ASN1ObjectIdentifier prime256v1 = primeCurve.branch("7"); + + // + // DSA + // + // dsapublicnumber OBJECT IDENTIFIER ::= { iso(1) member-body(2) + // us(840) ansi-x957(10040) number-type(4) 1 } + static final ASN1ObjectIdentifier id_dsa = new ASN1ObjectIdentifier("1.2.840.10040.4.1"); + + /** + * id-dsa-with-sha1 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) x9-57 + * (10040) x9cm(4) 3 } + */ + public static final ASN1ObjectIdentifier id_dsa_with_sha1 = new ASN1ObjectIdentifier("1.2.840.10040.4.3"); + + /** + * X9.63 + */ + public static final ASN1ObjectIdentifier x9_63_scheme = new ASN1ObjectIdentifier("1.3.133.16.840.63.0"); + public static final ASN1ObjectIdentifier dhSinglePass_stdDH_sha1kdf_scheme = x9_63_scheme.branch("2"); + public static final ASN1ObjectIdentifier dhSinglePass_cofactorDH_sha1kdf_scheme = x9_63_scheme.branch("3"); + public static final ASN1ObjectIdentifier mqvSinglePass_sha1kdf_scheme = x9_63_scheme.branch("16"); + + /** + * X9.42 + */ + + static final ASN1ObjectIdentifier ansi_X9_42 = new ASN1ObjectIdentifier("1.2.840.10046"); + + // + // Diffie-Hellman + // + // dhpublicnumber OBJECT IDENTIFIER ::= { iso(1) member-body(2) + // us(840) ansi-x942(10046) number-type(2) 1 } + // + public static final ASN1ObjectIdentifier dhpublicnumber = ansi_X9_42.branch("2.1"); + + public static final ASN1ObjectIdentifier x9_42_schemes = ansi_X9_42.branch("3"); + public static final ASN1ObjectIdentifier dhStatic = x9_42_schemes.branch("1"); + public static final ASN1ObjectIdentifier dhEphem = x9_42_schemes.branch("2"); + public static final ASN1ObjectIdentifier dhOneFlow = x9_42_schemes.branch("3"); + public static final ASN1ObjectIdentifier dhHybrid1 = x9_42_schemes.branch("4"); + public static final ASN1ObjectIdentifier dhHybrid2 = x9_42_schemes.branch("5"); + public static final ASN1ObjectIdentifier dhHybridOneFlow = x9_42_schemes.branch("6"); + public static final ASN1ObjectIdentifier mqv2 = x9_42_schemes.branch("7"); + public static final ASN1ObjectIdentifier mqv1 = x9_42_schemes.branch("8"); +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/ArmoredInputStream.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/ArmoredInputStream.java new file mode 100644 index 0000000..e923a55 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/ArmoredInputStream.java @@ -0,0 +1,471 @@ +package org.bc.bcpg; + +import java.io.*; +import java.util.Vector; + +/** + * reader for Base64 armored objects - read the headers and then start returning + * bytes when the data is reached. An IOException is thrown if the CRC check + * fails. + */ +public class ArmoredInputStream + extends InputStream +{ + /* + * set up the decoding table. + */ + private static final byte[] decodingTable; + + static + { + decodingTable = new byte[128]; + + for (int i = 'A'; i <= 'Z'; i++) + { + decodingTable[i] = (byte)(i - 'A'); + } + + for (int i = 'a'; i <= 'z'; i++) + { + decodingTable[i] = (byte)(i - 'a' + 26); + } + + for (int i = '0'; i <= '9'; i++) + { + decodingTable[i] = (byte)(i - '0' + 52); + } + + decodingTable['+'] = 62; + decodingTable['/'] = 63; + } + + /** + * decode the base 64 encoded input data. + * + * @return the offset the data starts in out. + */ + private int decode( + int in0, + int in1, + int in2, + int in3, + int[] out) + throws EOFException + { + int b1, b2, b3, b4; + + if (in3 < 0) + { + throw new EOFException("unexpected end of file in armored stream."); + } + + if (in2 == '=') + { + b1 = decodingTable[in0] &0xff; + b2 = decodingTable[in1] & 0xff; + + out[2] = ((b1 << 2) | (b2 >> 4)) & 0xff; + + return 2; + } + else if (in3 == '=') + { + b1 = decodingTable[in0]; + b2 = decodingTable[in1]; + b3 = decodingTable[in2]; + + out[1] = ((b1 << 2) | (b2 >> 4)) & 0xff; + out[2] = ((b2 << 4) | (b3 >> 2)) & 0xff; + + return 1; + } + else + { + b1 = decodingTable[in0]; + b2 = decodingTable[in1]; + b3 = decodingTable[in2]; + b4 = decodingTable[in3]; + + out[0] = ((b1 << 2) | (b2 >> 4)) & 0xff; + out[1] = ((b2 << 4) | (b3 >> 2)) & 0xff; + out[2] = ((b3 << 6) | b4) & 0xff; + + return 0; + } + } + + InputStream in; + boolean start = true; + int[] outBuf = new int[3]; + int bufPtr = 3; + CRC24 crc = new CRC24(); + boolean crcFound = false; + boolean hasHeaders = true; + String header = null; + boolean newLineFound = false; + boolean clearText = false; + boolean restart = false; + Vector headerList= new Vector(); + int lastC = 0; + boolean isEndOfStream; + + /** + * Create a stream for reading a PGP armoured message, parsing up to a header + * and then reading the data that follows. + * + * @param in + */ + public ArmoredInputStream( + InputStream in) + throws IOException + { + this(in, true); + } + + /** + * Create an armoured input stream which will assume the data starts + * straight away, or parse for headers first depending on the value of + * hasHeaders. + * + * @param in + * @param hasHeaders true if headers are to be looked for, false otherwise. + */ + public ArmoredInputStream( + InputStream in, + boolean hasHeaders) + throws IOException + { + this.in = in; + this.hasHeaders = hasHeaders; + + if (hasHeaders) + { + parseHeaders(); + } + + start = false; + } + + public int available() + throws IOException + { + return in.available(); + } + + private boolean parseHeaders() + throws IOException + { + header = null; + + int c; + int last = 0; + boolean headerFound = false; + + headerList = new Vector(); + + // + // if restart we already have a header + // + if (restart) + { + headerFound = true; + } + else + { + while ((c = in.read()) >= 0) + { + if (c == '-' && (last == 0 || last == '\n' || last == '\r')) + { + headerFound = true; + break; + } + + last = c; + } + } + + if (headerFound) + { + StringBuffer buf = new StringBuffer("-"); + boolean eolReached = false; + boolean crLf = false; + + if (restart) // we've had to look ahead two '-' + { + buf.append('-'); + } + + while ((c = in.read()) >= 0) + { + if (last == '\r' && c == '\n') + { + crLf = true; + } + if (eolReached && (last != '\r' && c == '\n')) + { + break; + } + if (eolReached && c == '\r') + { + break; + } + if (c == '\r' || (last != '\r' && c == '\n')) + { + String line = buf.toString(); + if (line.trim().length() == 0) + { + break; + } + headerList.addElement(line); + buf.setLength(0); + } + + if (c != '\n' && c != '\r') + { + buf.append((char)c); + eolReached = false; + } + else + { + if (c == '\r' || (last != '\r' && c == '\n')) + { + eolReached = true; + } + } + + last = c; + } + + if (crLf) + { + in.read(); // skip last \n + } + } + + if (headerList.size() > 0) + { + header = (String)headerList.elementAt(0); + } + + clearText = "-----BEGIN PGP SIGNED MESSAGE-----".equals(header); + newLineFound = true; + + return headerFound; + } + + /** + * @return true if we are inside the clear text section of a PGP + * signed message. + */ + public boolean isClearText() + { + return clearText; + } + + /** + * @return true if the stream is actually at end of file. + */ + public boolean isEndOfStream() + { + return isEndOfStream; + } + + /** + * Return the armor header line (if there is one) + * @return the armor header line, null if none present. + */ + public String getArmorHeaderLine() + { + return header; + } + + /** + * Return the armor headers (the lines after the armor header line), + * @return an array of armor headers, null if there aren't any. + */ + public String[] getArmorHeaders() + { + if (headerList.size() <= 1) + { + return null; + } + + String[] hdrs = new String[headerList.size() - 1]; + + for (int i = 0; i != hdrs.length; i++) + { + hdrs[i] = (String)headerList.elementAt(i + 1); + } + + return hdrs; + } + + private int readIgnoreSpace() + throws IOException + { + int c = in.read(); + + while (c == ' ' || c == '\t') + { + c = in.read(); + } + + return c; + } + + public int read() + throws IOException + { + int c; + + if (start) + { + if (hasHeaders) + { + parseHeaders(); + } + + crc.reset(); + start = false; + } + + if (clearText) + { + c = in.read(); + + if (c == '\r' || (c == '\n' && lastC != '\r')) + { + newLineFound = true; + } + else if (newLineFound && c == '-') + { + c = in.read(); + if (c == '-') // a header, not dash escaped + { + clearText = false; + start = true; + restart = true; + } + else // a space - must be a dash escape + { + c = in.read(); + } + newLineFound = false; + } + else + { + if (c != '\n' && lastC != '\r') + { + newLineFound = false; + } + } + + lastC = c; + + if (c < 0) + { + isEndOfStream = true; + } + + return c; + } + + if (bufPtr > 2 || crcFound) + { + c = readIgnoreSpace(); + + if (c == '\r' || c == '\n') + { + c = readIgnoreSpace(); + + while (c == '\n' || c == '\r') + { + c = readIgnoreSpace(); + } + + if (c < 0) // EOF + { + isEndOfStream = true; + return -1; + } + + if (c == '=') // crc reached + { + bufPtr = decode(readIgnoreSpace(), readIgnoreSpace(), readIgnoreSpace(), readIgnoreSpace(), outBuf); + if (bufPtr == 0) + { + int i = ((outBuf[0] & 0xff) << 16) + | ((outBuf[1] & 0xff) << 8) + | (outBuf[2] & 0xff); + + crcFound = true; + + if (i != crc.getValue()) + { + throw new IOException("crc check failed in armored message."); + } + return read(); + } + else + { + throw new IOException("no crc found in armored message."); + } + } + else if (c == '-') // end of record reached + { + while ((c = in.read()) >= 0) + { + if (c == '\n' || c == '\r') + { + break; + } + } + + if (!crcFound) + { + throw new IOException("crc check not found."); + } + + crcFound = false; + start = true; + bufPtr = 3; + + if (c < 0) + { + isEndOfStream = true; + } + + return -1; + } + else // data + { + bufPtr = decode(c, readIgnoreSpace(), readIgnoreSpace(), readIgnoreSpace(), outBuf); + } + } + else + { + if (c >= 0) + { + bufPtr = decode(c, readIgnoreSpace(), readIgnoreSpace(), readIgnoreSpace(), outBuf); + } + else + { + isEndOfStream = true; + return -1; + } + } + } + + c = outBuf[bufPtr++]; + + crc.update(c); + + return c; + } + + public void close() + throws IOException + { + in.close(); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/ArmoredOutputStream.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/ArmoredOutputStream.java new file mode 100644 index 0000000..26cbf3c --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/ArmoredOutputStream.java @@ -0,0 +1,410 @@ +package org.bc.bcpg; + +import java.io.*; +import java.util.Enumeration; +import java.util.Hashtable; + +/** + * Basic output stream. + */ +public class ArmoredOutputStream + extends OutputStream +{ + private static final byte[] encodingTable = + { + (byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F', (byte)'G', + (byte)'H', (byte)'I', (byte)'J', (byte)'K', (byte)'L', (byte)'M', (byte)'N', + (byte)'O', (byte)'P', (byte)'Q', (byte)'R', (byte)'S', (byte)'T', (byte)'U', + (byte)'V', (byte)'W', (byte)'X', (byte)'Y', (byte)'Z', + (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f', (byte)'g', + (byte)'h', (byte)'i', (byte)'j', (byte)'k', (byte)'l', (byte)'m', (byte)'n', + (byte)'o', (byte)'p', (byte)'q', (byte)'r', (byte)'s', (byte)'t', (byte)'u', + (byte)'v', + (byte)'w', (byte)'x', (byte)'y', (byte)'z', + (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5', (byte)'6', + (byte)'7', (byte)'8', (byte)'9', + (byte)'+', (byte)'/' + }; + + /** + * encode the input data producing a base 64 encoded byte array. + */ + private void encode( + OutputStream out, + int[] data, + int len) + throws IOException + { + int d1, d2, d3; + + switch (len) + { + case 0: /* nothing left to do */ + break; + case 1: + d1 = data[0]; + + out.write(encodingTable[(d1 >>> 2) & 0x3f]); + out.write(encodingTable[(d1 << 4) & 0x3f]); + out.write('='); + out.write('='); + break; + case 2: + d1 = data[0]; + d2 = data[1]; + + out.write(encodingTable[(d1 >>> 2) & 0x3f]); + out.write(encodingTable[((d1 << 4) | (d2 >>> 4)) & 0x3f]); + out.write(encodingTable[(d2 << 2) & 0x3f]); + out.write('='); + break; + case 3: + d1 = data[0]; + d2 = data[1]; + d3 = data[2]; + + out.write(encodingTable[(d1 >>> 2) & 0x3f]); + out.write(encodingTable[((d1 << 4) | (d2 >>> 4)) & 0x3f]); + out.write(encodingTable[((d2 << 2) | (d3 >>> 6)) & 0x3f]); + out.write(encodingTable[d3 & 0x3f]); + break; + default: + throw new IOException("unknown length in encode"); + } + } + + OutputStream out; + int[] buf = new int[3]; + int bufPtr = 0; + CRC24 crc = new CRC24(); + int chunkCount = 0; + int lastb; + + boolean start = true; + boolean clearText = false; + boolean newLine = false; + + String nl = System.getProperty("line.separator"); + + String type; + String headerStart = "-----BEGIN PGP "; + String headerTail = "-----"; + String footerStart = "-----END PGP "; + String footerTail = "-----"; + + String version = "BCPG v@RELEASE_NAME@"; + + Hashtable headers = new Hashtable(); + + public ArmoredOutputStream( + OutputStream out) + { + this.out = out; + + if (nl == null) + { + nl = "\r\n"; + } + + resetHeaders(); + } + + public ArmoredOutputStream( + OutputStream out, + Hashtable headers) + { + this(out); + + Enumeration e = headers.keys(); + + while (e.hasMoreElements()) + { + Object key = e.nextElement(); + + this.headers.put(key, headers.get(key)); + } + } + + /** + * Set an additional header entry. + * + * @param name the name of the header entry. + * @param value the value of the header entry. + */ + public void setHeader( + String name, + String value) + { + this.headers.put(name, value); + } + + /** + * Reset the headers to only contain a Version string. + */ + public void resetHeaders() + { + headers.clear(); + headers.put("Version", version); + } + + /** + * Start a clear text signed message. + * @param hashAlgorithm + */ + public void beginClearText( + int hashAlgorithm) + throws IOException + { + String hash; + + switch (hashAlgorithm) + { + case HashAlgorithmTags.SHA1: + hash = "SHA1"; + break; + case HashAlgorithmTags.SHA256: + hash = "SHA256"; + break; + case HashAlgorithmTags.SHA384: + hash = "SHA384"; + break; + case HashAlgorithmTags.SHA512: + hash = "SHA512"; + break; + case HashAlgorithmTags.MD2: + hash = "MD2"; + break; + case HashAlgorithmTags.MD5: + hash = "MD5"; + break; + case HashAlgorithmTags.RIPEMD160: + hash = "RIPEMD160"; + break; + default: + throw new IOException("unknown hash algorithm tag in beginClearText: " + hashAlgorithm); + } + + String armorHdr = "-----BEGIN PGP SIGNED MESSAGE-----" + nl; + String hdrs = "Hash: " + hash + nl + nl; + + for (int i = 0; i != armorHdr.length(); i++) + { + out.write(armorHdr.charAt(i)); + } + + for (int i = 0; i != hdrs.length(); i++) + { + out.write(hdrs.charAt(i)); + } + + clearText = true; + newLine = true; + lastb = 0; + } + + public void endClearText() + { + clearText = false; + } + + private void writeHeaderEntry( + String name, + String value) + throws IOException + { + for (int i = 0; i != name.length(); i++) + { + out.write(name.charAt(i)); + } + + out.write(':'); + out.write(' '); + + for (int i = 0; i != value.length(); i++) + { + out.write(value.charAt(i)); + } + + for (int i = 0; i != nl.length(); i++) + { + out.write(nl.charAt(i)); + } + } + + public void write( + int b) + throws IOException + { + if (clearText) + { + out.write(b); + + if (newLine) + { + if (!(b == '\n' && lastb == '\r')) + { + newLine = false; + } + if (b == '-') + { + out.write(' '); + out.write('-'); // dash escape + } + } + if (b == '\r' || (b == '\n' && lastb != '\r')) + { + newLine = true; + } + lastb = b; + return; + } + + if (start) + { + boolean newPacket = (b & 0x40) != 0; + int tag = 0; + + if (newPacket) + { + tag = b & 0x3f; + } + else + { + tag = (b & 0x3f) >> 2; + } + + switch (tag) + { + case PacketTags.PUBLIC_KEY: + type = "PUBLIC KEY BLOCK"; + break; + case PacketTags.SECRET_KEY: + type = "PRIVATE KEY BLOCK"; + break; + case PacketTags.SIGNATURE: + type = "SIGNATURE"; + break; + default: + type = "MESSAGE"; + } + + for (int i = 0; i != headerStart.length(); i++) + { + out.write(headerStart.charAt(i)); + } + + for (int i = 0; i != type.length(); i++) + { + out.write(type.charAt(i)); + } + + for (int i = 0; i != headerTail.length(); i++) + { + out.write(headerTail.charAt(i)); + } + + for (int i = 0; i != nl.length(); i++) + { + out.write(nl.charAt(i)); + } + + writeHeaderEntry("Version", (String)headers.get("Version")); + + Enumeration e = headers.keys(); + while (e.hasMoreElements()) + { + String key = (String)e.nextElement(); + + if (!key.equals("Version")) + { + writeHeaderEntry(key, (String)headers.get(key)); + } + } + + for (int i = 0; i != nl.length(); i++) + { + out.write(nl.charAt(i)); + } + + start = false; + } + + if (bufPtr == 3) + { + encode(out, buf, bufPtr); + bufPtr = 0; + if ((++chunkCount & 0xf) == 0) + { + for (int i = 0; i != nl.length(); i++) + { + out.write(nl.charAt(i)); + } + } + } + + crc.update(b); + buf[bufPtr++] = b & 0xff; + } + + public void flush() + throws IOException + { + } + + /** + * Note: close does nor close the underlying stream. So it is possible to write + * multiple objects using armoring to a single stream. + */ + public void close() + throws IOException + { + if (type != null) + { + encode(out, buf, bufPtr); + + for (int i = 0; i != nl.length(); i++) + { + out.write(nl.charAt(i)); + } + out.write('='); + + int crcV = crc.getValue(); + + buf[0] = ((crcV >> 16) & 0xff); + buf[1] = ((crcV >> 8) & 0xff); + buf[2] = (crcV & 0xff); + + encode(out, buf, 3); + + for (int i = 0; i != nl.length(); i++) + { + out.write(nl.charAt(i)); + } + + for (int i = 0; i != footerStart.length(); i++) + { + out.write(footerStart.charAt(i)); + } + + for (int i = 0; i != type.length(); i++) + { + out.write(type.charAt(i)); + } + + for (int i = 0; i != footerTail.length(); i++) + { + out.write(footerTail.charAt(i)); + } + + for (int i = 0; i != nl.length(); i++) + { + out.write(nl.charAt(i)); + } + + out.flush(); + + type = null; + start = true; + } + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/BCPGInputStream.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/BCPGInputStream.java new file mode 100644 index 0000000..76c7b4a --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/BCPGInputStream.java @@ -0,0 +1,385 @@ +package org.bc.bcpg; + +import org.bc.util.io.Streams; + +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStream; + +/** + * reader for PGP objects + */ +public class BCPGInputStream + extends InputStream implements PacketTags +{ + InputStream in; + boolean next = false; + int nextB; + + public BCPGInputStream( + InputStream in) + { + this.in = in; + } + + public int available() + throws IOException + { + return in.available(); + } + + public int read() + throws IOException + { + if (next) + { + next = false; + + return nextB; + } + else + { + return in.read(); + } + } + + public int read( + byte[] buf, + int off, + int len) + throws IOException + { + if (len == 0) + { + return 0; + } + + if (!next) + { + return in.read(buf, off, len); + } + + // We have next byte waiting, so return it + + if (nextB < 0) + { + return -1; // EOF + } + + buf[off] = (byte)nextB; // May throw NullPointerException... + next = false; // ...so only set this afterwards + + return 1; + } + + public void readFully( + byte[] buf, + int off, + int len) + throws IOException + { + if (Streams.readFully(this, buf, off, len) < len) + { + throw new EOFException(); + } + } + + public void readFully( + byte[] buf) + throws IOException + { + readFully(buf, 0, buf.length); + } + + /** + * returns the next packet tag in the stream. + * + * @return the tag number. + * + * @throws IOException + */ + public int nextPacketTag() + throws IOException + { + if (!next) + { + try + { + nextB = in.read(); + } + catch (EOFException e) + { + nextB = -1; + } + } + + next = true; + + if (nextB >= 0) + { + if ((nextB & 0x40) != 0) // new + { + return (nextB & 0x3f); + } + else // old + { + return ((nextB & 0x3f) >> 2); + } + } + + return nextB; + } + + public Packet readPacket() + throws IOException + { + int hdr = this.read(); + + if (hdr < 0) + { + return null; + } + + if ((hdr & 0x80) == 0) + { + throw new IOException("invalid header encountered"); + } + + boolean newPacket = (hdr & 0x40) != 0; + int tag = 0; + int bodyLen = 0; + boolean partial = false; + + if (newPacket) + { + tag = hdr & 0x3f; + + int l = this.read(); + + if (l < 192) + { + bodyLen = l; + } + else if (l <= 223) + { + int b = in.read(); + + bodyLen = ((l - 192) << 8) + (b) + 192; + } + else if (l == 255) + { + bodyLen = (in.read() << 24) | (in.read() << 16) | (in.read() << 8) | in.read(); + } + else + { + partial = true; + bodyLen = 1 << (l & 0x1f); + } + } + else + { + int lengthType = hdr & 0x3; + + tag = (hdr & 0x3f) >> 2; + + switch (lengthType) + { + case 0: + bodyLen = this.read(); + break; + case 1: + bodyLen = (this.read() << 8) | this.read(); + break; + case 2: + bodyLen = (this.read() << 24) | (this.read() << 16) | (this.read() << 8) | this.read(); + break; + case 3: + partial = true; + break; + default: + throw new IOException("unknown length type encountered"); + } + } + + BCPGInputStream objStream; + + if (bodyLen == 0 && partial) + { + objStream = this; + } + else + { + objStream = new BCPGInputStream(new PartialInputStream(this, partial, bodyLen)); + } + + switch (tag) + { + case RESERVED: + return new InputStreamPacket(objStream); + case PUBLIC_KEY_ENC_SESSION: + return new PublicKeyEncSessionPacket(objStream); + case SIGNATURE: + return new SignaturePacket(objStream); + case SYMMETRIC_KEY_ENC_SESSION: + return new SymmetricKeyEncSessionPacket(objStream); + case ONE_PASS_SIGNATURE: + return new OnePassSignaturePacket(objStream); + case SECRET_KEY: + return new SecretKeyPacket(objStream); + case PUBLIC_KEY: + return new PublicKeyPacket(objStream); + case SECRET_SUBKEY: + return new SecretSubkeyPacket(objStream); + case COMPRESSED_DATA: + return new CompressedDataPacket(objStream); + case SYMMETRIC_KEY_ENC: + return new SymmetricEncDataPacket(objStream); + case MARKER: + return new MarkerPacket(objStream); + case LITERAL_DATA: + return new LiteralDataPacket(objStream); + case TRUST: + return new TrustPacket(objStream); + case USER_ID: + return new UserIDPacket(objStream); + case USER_ATTRIBUTE: + return new UserAttributePacket(objStream); + case PUBLIC_SUBKEY: + return new PublicSubkeyPacket(objStream); + case SYM_ENC_INTEGRITY_PRO: + return new SymmetricEncIntegrityPacket(objStream); + case MOD_DETECTION_CODE: + return new ModDetectionCodePacket(objStream); + case EXPERIMENTAL_1: + case EXPERIMENTAL_2: + case EXPERIMENTAL_3: + case EXPERIMENTAL_4: + return new ExperimentalPacket(tag, objStream); + default: + throw new IOException("unknown packet type encountered: " + tag); + } + } + + public void close() + throws IOException + { + in.close(); + } + + /** + * a stream that overlays our input stream, allowing the user to only read a segment of it. + * + * NB: dataLength will be negative if the segment length is in the upper range above 2**31. + */ + private static class PartialInputStream + extends InputStream + { + private BCPGInputStream in; + private boolean partial; + private int dataLength; + + PartialInputStream( + BCPGInputStream in, + boolean partial, + int dataLength) + { + this.in = in; + this.partial = partial; + this.dataLength = dataLength; + } + + public int available() + throws IOException + { + int avail = in.available(); + + if (avail <= dataLength || dataLength < 0) + { + return avail; + } + else + { + if (partial && dataLength == 0) + { + return 1; + } + return dataLength; + } + } + + private int loadDataLength() + throws IOException + { + int l = in.read(); + + if (l < 0) + { + return -1; + } + + partial = false; + if (l < 192) + { + dataLength = l; + } + else if (l <= 223) + { + dataLength = ((l - 192) << 8) + (in.read()) + 192; + } + else if (l == 255) + { + dataLength = (in.read() << 24) | (in.read() << 16) | (in.read() << 8) | in.read(); + } + else + { + partial = true; + dataLength = 1 << (l & 0x1f); + } + + return dataLength; + } + + public int read(byte[] buf, int offset, int len) + throws IOException + { + do + { + if (dataLength != 0) + { + int readLen = (dataLength > len || dataLength < 0) ? len : dataLength; + readLen = in.read(buf, offset, readLen); + if (readLen < 0) + { + throw new EOFException("premature end of stream in PartialInputStream"); + } + dataLength -= readLen; + return readLen; + } + } + while (partial && loadDataLength() >= 0); + + return -1; + } + + public int read() + throws IOException + { + do + { + if (dataLength != 0) + { + int ch = in.read(); + if (ch < 0) + { + throw new EOFException("premature end of stream in PartialInputStream"); + } + dataLength--; + return ch; + } + } + while (partial && loadDataLength() >= 0); + + return -1; + } + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/BCPGKey.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/BCPGKey.java new file mode 100644 index 0000000..4f94739 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/BCPGKey.java @@ -0,0 +1,24 @@ +package org.bc.bcpg; + +/** + * base interface for a PGP key + */ +public interface BCPGKey +{ + /** + * Return the base format for this key - in the case of the symmetric keys it will generally + * be raw indicating that the key is just a straight byte representation, for an asymmetric + * key the format will be PGP, indicating the key is a string of MPIs encoded in PGP format. + * + * @return "RAW" or "PGP" + */ + public String getFormat(); + + /** + * return a string of bytes giving the encoded format of the key, as described by it's format. + * + * @return byte[] + */ + public byte[] getEncoded(); + +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/BCPGObject.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/BCPGObject.java new file mode 100644 index 0000000..5f8c5c9 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/BCPGObject.java @@ -0,0 +1,24 @@ +package org.bc.bcpg; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +/** + * base class for a PGP object. + */ +public abstract class BCPGObject +{ + public byte[] getEncoded() + throws IOException + { + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + BCPGOutputStream pOut = new BCPGOutputStream(bOut); + + pOut.writeObject(this); + + return bOut.toByteArray(); + } + + public abstract void encode(BCPGOutputStream out) + throws IOException; +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/BCPGOutputStream.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/BCPGOutputStream.java new file mode 100644 index 0000000..bb03036 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/BCPGOutputStream.java @@ -0,0 +1,360 @@ +package org.bc.bcpg; + +import java.io.*; + +/** + * Basic output stream. + */ +public class BCPGOutputStream + extends OutputStream + implements PacketTags, CompressionAlgorithmTags +{ + OutputStream out; + private byte[] partialBuffer; + private int partialBufferLength; + private int partialPower; + private int partialOffset; + + private static final int BUF_SIZE_POWER = 16; // 2^16 size buffer on long files + + public BCPGOutputStream( + OutputStream out) + { + this.out = out; + } + + /** + * Create a stream representing an old style partial object. + * + * @param tag the packet tag for the object. + */ + public BCPGOutputStream( + OutputStream out, + int tag) + throws IOException + { + this.out = out; + this.writeHeader(tag, true, true, 0); + } + + /** + * Create a stream representing a general packet. + * + * @param out + * @param tag + * @param length + * @param oldFormat + * @throws IOException + */ + public BCPGOutputStream( + OutputStream out, + int tag, + long length, + boolean oldFormat) + throws IOException + { + this.out = out; + + if (length > 0xFFFFFFFFL) + { + this.writeHeader(tag, false, true, 0); + this.partialBufferLength = 1 << BUF_SIZE_POWER; + this.partialBuffer = new byte[partialBufferLength]; + this.partialPower = BUF_SIZE_POWER; + this.partialOffset = 0; + } + else + { + this.writeHeader(tag, oldFormat, false, length); + } + } + + /** + * + * @param tag + * @param length + * @throws IOException + */ + public BCPGOutputStream( + OutputStream out, + int tag, + long length) + throws IOException + { + this.out = out; + + this.writeHeader(tag, false, false, length); + } + + /** + * Create a new style partial input stream buffered into chunks. + * + * @param out output stream to write to. + * @param tag packet tag. + * @param buffer size of chunks making up the packet. + * @throws IOException + */ + public BCPGOutputStream( + OutputStream out, + int tag, + byte[] buffer) + throws IOException + { + this.out = out; + this.writeHeader(tag, false, true, 0); + + this.partialBuffer = buffer; + + int length = partialBuffer.length; + + for (partialPower = 0; length != 1; partialPower++) + { + length >>>= 1; + } + + if (partialPower > 30) + { + throw new IOException("Buffer cannot be greater than 2^30 in length."); + } + + this.partialBufferLength = 1 << partialPower; + this.partialOffset = 0; + } + + private void writeNewPacketLength( + long bodyLen) + throws IOException + { + if (bodyLen < 192) + { + out.write((byte)bodyLen); + } + else if (bodyLen <= 8383) + { + bodyLen -= 192; + + out.write((byte)(((bodyLen >> 8) & 0xff) + 192)); + out.write((byte)bodyLen); + } + else + { + out.write(0xff); + out.write((byte)(bodyLen >> 24)); + out.write((byte)(bodyLen >> 16)); + out.write((byte)(bodyLen >> 8)); + out.write((byte)bodyLen); + } + } + + private void writeHeader( + int tag, + boolean oldPackets, + boolean partial, + long bodyLen) + throws IOException + { + int hdr = 0x80; + + if (partialBuffer != null) + { + partialFlush(true); + partialBuffer = null; + } + + if (oldPackets) + { + hdr |= tag << 2; + + if (partial) + { + this.write(hdr | 0x03); + } + else + { + if (bodyLen <= 0xff) + { + this.write(hdr); + this.write((byte)bodyLen); + } + else if (bodyLen <= 0xffff) + { + this.write(hdr | 0x01); + this.write((byte)(bodyLen >> 8)); + this.write((byte)(bodyLen)); + } + else + { + this.write(hdr | 0x02); + this.write((byte)(bodyLen >> 24)); + this.write((byte)(bodyLen >> 16)); + this.write((byte)(bodyLen >> 8)); + this.write((byte)bodyLen); + } + } + } + else + { + hdr |= 0x40 | tag; + this.write(hdr); + + if (partial) + { + partialOffset = 0; + } + else + { + this.writeNewPacketLength(bodyLen); + } + } + } + + private void partialFlush( + boolean isLast) + throws IOException + { + if (isLast) + { + writeNewPacketLength(partialOffset); + out.write(partialBuffer, 0, partialOffset); + } + else + { + out.write(0xE0 | partialPower); + out.write(partialBuffer, 0, partialBufferLength); + } + + partialOffset = 0; + } + + private void writePartial( + byte b) + throws IOException + { + if (partialOffset == partialBufferLength) + { + partialFlush(false); + } + + partialBuffer[partialOffset++] = b; + } + + private void writePartial( + byte[] buf, + int off, + int len) + throws IOException + { + if (partialOffset == partialBufferLength) + { + partialFlush(false); + } + + if (len <= (partialBufferLength - partialOffset)) + { + System.arraycopy(buf, off, partialBuffer, partialOffset, len); + partialOffset += len; + } + else + { + System.arraycopy(buf, off, partialBuffer, partialOffset, partialBufferLength - partialOffset); + off += partialBufferLength - partialOffset; + len -= partialBufferLength - partialOffset; + partialFlush(false); + + while (len > partialBufferLength) + { + System.arraycopy(buf, off, partialBuffer, 0, partialBufferLength); + off += partialBufferLength; + len -= partialBufferLength; + partialFlush(false); + } + + System.arraycopy(buf, off, partialBuffer, 0, len); + partialOffset += len; + } + } + + public void write( + int b) + throws IOException + { + if (partialBuffer != null) + { + writePartial((byte)b); + } + else + { + out.write(b); + } + } + + public void write( + byte[] bytes, + int off, + int len) + throws IOException + { + if (partialBuffer != null) + { + writePartial(bytes, off, len); + } + else + { + out.write(bytes, off, len); + } + } + + public void writePacket( + ContainedPacket p) + throws IOException + { + p.encode(this); + } + + void writePacket( + int tag, + byte[] body, + boolean oldFormat) + throws IOException + { + this.writeHeader(tag, oldFormat, false, body.length); + this.write(body); + } + + public void writeObject( + BCPGObject o) + throws IOException + { + o.encode(this); + } + + /** + * Flush the underlying stream. + */ + public void flush() + throws IOException + { + out.flush(); + } + + /** + * Finish writing out the current packet without closing the underlying stream. + */ + public void finish() + throws IOException + { + if (partialBuffer != null) + { + partialFlush(true); + partialBuffer = null; + } + } + + public void close() + throws IOException + { + this.finish(); + out.flush(); + out.close(); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/CRC24.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/CRC24.java new file mode 100644 index 0000000..20c2575 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/CRC24.java @@ -0,0 +1,37 @@ +package org.bc.bcpg; + +public class CRC24 +{ + private static final int CRC24_INIT = 0x0b704ce; + private static final int CRC24_POLY = 0x1864cfb; + + private int crc = CRC24_INIT; + + public CRC24() + { + } + + public void update( + int b) + { + crc ^= b << 16; + for (int i = 0; i < 8; i++) + { + crc <<= 1; + if ((crc & 0x1000000) != 0) + { + crc ^= CRC24_POLY; + } + } + } + + public int getValue() + { + return crc; + } + + public void reset() + { + crc = CRC24_INIT; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/CompressedDataPacket.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/CompressedDataPacket.java new file mode 100644 index 0000000..882b585 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/CompressedDataPacket.java @@ -0,0 +1,31 @@ +package org.bc.bcpg; + +import java.io.*; + +/** + * generic compressed data object. + */ +public class CompressedDataPacket + extends InputStreamPacket +{ + int algorithm; + + CompressedDataPacket( + BCPGInputStream in) + throws IOException + { + super(in); + + algorithm = in.read(); + } + + /** + * return the algorithm tag value. + * + * @return algorithm tag value. + */ + public int getAlgorithm() + { + return algorithm; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/CompressionAlgorithmTags.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/CompressionAlgorithmTags.java new file mode 100644 index 0000000..6e3c3bd --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/CompressionAlgorithmTags.java @@ -0,0 +1,12 @@ +package org.bc.bcpg; + +/** + * Basic tags for compression algorithms + */ +public interface CompressionAlgorithmTags +{ + public static final int UNCOMPRESSED = 0; // Uncompressed + public static final int ZIP = 1; // ZIP (RFC 1951) + public static final int ZLIB = 2; // ZLIB (RFC 1950) + public static final int BZIP2 = 3; // BZ2 +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/ContainedPacket.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/ContainedPacket.java new file mode 100644 index 0000000..2224152 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/ContainedPacket.java @@ -0,0 +1,25 @@ +package org.bc.bcpg; + +import java.io.*; + +/** + * Basic type for a PGP packet. + */ +public abstract class ContainedPacket + extends Packet +{ + public byte[] getEncoded() + throws IOException + { + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + BCPGOutputStream pOut = new BCPGOutputStream(bOut); + + pOut.writePacket(this); + + return bOut.toByteArray(); + } + + public abstract void encode( + BCPGOutputStream pOut) + throws IOException; +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/DSAPublicBCPGKey.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/DSAPublicBCPGKey.java new file mode 100644 index 0000000..d1836d5 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/DSAPublicBCPGKey.java @@ -0,0 +1,116 @@ +package org.bc.bcpg; + +import java.io.*; +import java.math.BigInteger; + +/** + * base class for a DSA Public Key. + */ +public class DSAPublicBCPGKey + extends BCPGObject implements BCPGKey +{ + MPInteger p; + MPInteger q; + MPInteger g; + MPInteger y; + + /** + * @param in the stream to read the packet from. + */ + public DSAPublicBCPGKey( + BCPGInputStream in) + throws IOException + { + this.p = new MPInteger(in); + this.q = new MPInteger(in); + this.g = new MPInteger(in); + this.y = new MPInteger(in); + } + + public DSAPublicBCPGKey( + BigInteger p, + BigInteger q, + BigInteger g, + BigInteger y) + { + this.p = new MPInteger(p); + this.q = new MPInteger(q); + this.g = new MPInteger(g); + this.y = new MPInteger(y); + } + + /** + * return "PGP" + * + * @see org.bc.bcpg.BCPGKey#getFormat() + */ + public String getFormat() + { + return "PGP"; + } + + /** + * return the standard PGP encoding of the key. + * + * @see org.bc.bcpg.BCPGKey#getEncoded() + */ + public byte[] getEncoded() + { + try + { + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + BCPGOutputStream pgpOut = new BCPGOutputStream(bOut); + + pgpOut.writeObject(this); + + return bOut.toByteArray(); + } + catch (IOException e) + { + return null; + } + } + + public void encode( + BCPGOutputStream out) + throws IOException + { + out.writeObject(p); + out.writeObject(q); + out.writeObject(g); + out.writeObject(y); + } + + /** + * @return g + */ + public BigInteger getG() + { + return g.getValue(); + } + + /** + * @return p + */ + public BigInteger getP() + { + return p.getValue(); + } + + /** + * @return q + */ + public BigInteger getQ() + { + return q.getValue(); + } + + /** + * @return g + */ + public BigInteger getY() + { + return y.getValue(); + } + +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/DSASecretBCPGKey.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/DSASecretBCPGKey.java new file mode 100644 index 0000000..ee6c0dc --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/DSASecretBCPGKey.java @@ -0,0 +1,82 @@ +package org.bc.bcpg; + +import java.io.*; +import java.math.BigInteger; + +/** + * base class for a DSA Secret Key. + */ +public class DSASecretBCPGKey + extends BCPGObject implements BCPGKey +{ + MPInteger x; + + /** + * + * @param in + * @throws IOException + */ + public DSASecretBCPGKey( + BCPGInputStream in) + throws IOException + { + this.x = new MPInteger(in); + } + + /** + * + * @param x + */ + public DSASecretBCPGKey( + BigInteger x) + { + this.x = new MPInteger(x); + } + + /** + * return "PGP" + * + * @see org.bc.bcpg.BCPGKey#getFormat() + */ + public String getFormat() + { + return "PGP"; + } + + /** + * return the standard PGP encoding of the key. + * + * @see org.bc.bcpg.BCPGKey#getEncoded() + */ + public byte[] getEncoded() + { + try + { + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + BCPGOutputStream pgpOut = new BCPGOutputStream(bOut); + + pgpOut.writeObject(this); + + return bOut.toByteArray(); + } + catch (IOException e) + { + return null; + } + } + + public void encode( + BCPGOutputStream out) + throws IOException + { + out.writeObject(x); + } + + /** + * @return x + */ + public BigInteger getX() + { + return x.getValue(); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/ElGamalPublicBCPGKey.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/ElGamalPublicBCPGKey.java new file mode 100644 index 0000000..393d948 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/ElGamalPublicBCPGKey.java @@ -0,0 +1,93 @@ +package org.bc.bcpg; + +import java.io.*; +import java.math.BigInteger; + +/** + * base class for an ElGamal Public Key. + */ +public class ElGamalPublicBCPGKey + extends BCPGObject implements BCPGKey +{ + MPInteger p; + MPInteger g; + MPInteger y; + + /** + * + */ + public ElGamalPublicBCPGKey( + BCPGInputStream in) + throws IOException + { + this.p = new MPInteger(in); + this.g = new MPInteger(in); + this.y = new MPInteger(in); + } + + public ElGamalPublicBCPGKey( + BigInteger p, + BigInteger g, + BigInteger y) + { + this.p = new MPInteger(p); + this.g = new MPInteger(g); + this.y = new MPInteger(y); + } + + /** + * return "PGP" + * + * @see org.bc.bcpg.BCPGKey#getFormat() + */ + public String getFormat() + { + return "PGP"; + } + + /** + * return the standard PGP encoding of the key. + * + * @see org.bc.bcpg.BCPGKey#getEncoded() + */ + public byte[] getEncoded() + { + try + { + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + BCPGOutputStream pgpOut = new BCPGOutputStream(bOut); + + pgpOut.writeObject(this); + + return bOut.toByteArray(); + } + catch (IOException e) + { + return null; + } + } + + public BigInteger getP() + { + return p.getValue(); + } + + public BigInteger getG() + { + return g.getValue(); + } + + public BigInteger getY() + { + return y.getValue(); + } + + public void encode( + BCPGOutputStream out) + throws IOException + { + out.writeObject(p); + out.writeObject(g); + out.writeObject(y); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/ElGamalSecretBCPGKey.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/ElGamalSecretBCPGKey.java new file mode 100644 index 0000000..aaeca54 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/ElGamalSecretBCPGKey.java @@ -0,0 +1,79 @@ +package org.bc.bcpg; + +import java.io.*; +import java.math.BigInteger; + +/** + * base class for an ElGamal Secret Key. + */ +public class ElGamalSecretBCPGKey + extends BCPGObject implements BCPGKey +{ + MPInteger x; + + /** + * + * @param in + * @throws IOException + */ + public ElGamalSecretBCPGKey( + BCPGInputStream in) + throws IOException + { + this.x = new MPInteger(in); + } + + /** + * + * @param x + */ + public ElGamalSecretBCPGKey( + BigInteger x) + { + this.x = new MPInteger(x); + } + + /** + * return "PGP" + * + * @see org.bc.bcpg.BCPGKey#getFormat() + */ + public String getFormat() + { + return "PGP"; + } + + public BigInteger getX() + { + return x.getValue(); + } + + /** + * return the standard PGP encoding of the key. + * + * @see org.bc.bcpg.BCPGKey#getEncoded() + */ + public byte[] getEncoded() + { + try + { + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + BCPGOutputStream pgpOut = new BCPGOutputStream(bOut); + + pgpOut.writeObject(this); + + return bOut.toByteArray(); + } + catch (IOException e) + { + return null; + } + } + + public void encode( + BCPGOutputStream out) + throws IOException + { + out.writeObject(x); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/ExperimentalPacket.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/ExperimentalPacket.java new file mode 100644 index 0000000..6bdfb52 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/ExperimentalPacket.java @@ -0,0 +1,64 @@ +package org.bc.bcpg; + +import java.io.*; + +/** + * basic packet for an experimental packet. + */ +public class ExperimentalPacket + extends ContainedPacket implements PublicKeyAlgorithmTags +{ + private int tag; + private byte[] contents; + + /** + * + * @param in + * @throws IOException + */ + ExperimentalPacket( + int tag, + BCPGInputStream in) + throws IOException + { + this.tag = tag; + + if (in.available() != 0) + { + ByteArrayOutputStream bOut = new ByteArrayOutputStream(in.available()); + + int b; + while ((b = in.read()) >= 0) + { + bOut.write(b); + } + + contents = bOut.toByteArray(); + } + else + { + contents = new byte[0]; + } + } + + public int getTag() + { + return tag; + } + + public byte[] getContents() + { + byte[] tmp = new byte[contents.length]; + + System.arraycopy(contents, 0, tmp, 0, tmp.length); + + return tmp; + } + + public void encode( + BCPGOutputStream out) + throws IOException + { + out.writePacket(tag, contents, true); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/HashAlgorithmTags.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/HashAlgorithmTags.java new file mode 100644 index 0000000..916562d --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/HashAlgorithmTags.java @@ -0,0 +1,20 @@ +package org.bc.bcpg; + +/** + * basic tags for hash algorithms + */ +public interface HashAlgorithmTags +{ + public static final int MD5 = 1; // MD5 + public static final int SHA1 = 2; // SHA-1 + public static final int RIPEMD160 = 3; // RIPE-MD/160 + public static final int DOUBLE_SHA = 4; // Reserved for double-width SHA (experimental) + public static final int MD2 = 5; // MD2 + public static final int TIGER_192 = 6; // Reserved for TIGER/192 + public static final int HAVAL_5_160 = 7; // Reserved for HAVAL (5 pass, 160-bit) + + public static final int SHA256 = 8; // SHA-256 + public static final int SHA384 = 9; // SHA-384 + public static final int SHA512 = 10; // SHA-512 + public static final int SHA224 = 11; // SHA-224 +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/InputStreamPacket.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/InputStreamPacket.java new file mode 100644 index 0000000..62058e4 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/InputStreamPacket.java @@ -0,0 +1,26 @@ +package org.bc.bcpg; + +/** + * + */ +public class InputStreamPacket + extends Packet +{ + private BCPGInputStream in; + + public InputStreamPacket( + BCPGInputStream in) + { + this.in = in; + } + + /** + * Note: you can only read from this once... + * + * @return the InputStream + */ + public BCPGInputStream getInputStream() + { + return in; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/LiteralDataPacket.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/LiteralDataPacket.java new file mode 100644 index 0000000..b84f4a6 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/LiteralDataPacket.java @@ -0,0 +1,74 @@ +package org.bc.bcpg; + +import java.io.IOException; + +import org.bc.util.Strings; + +/** + * generic literal data packet. + */ +public class LiteralDataPacket + extends InputStreamPacket +{ + int format; + byte[] fileName; + long modDate; + + LiteralDataPacket( + BCPGInputStream in) + throws IOException + { + super(in); + + format = in.read(); + int l = in.read(); + + fileName = new byte[l]; + for (int i = 0; i != fileName.length; i++) + { + fileName[i] = (byte)in.read(); + } + + modDate = ((long)in.read() << 24) | (in.read() << 16) | (in.read() << 8) | in.read(); + } + + /** + * return the format tag value. + * + * @return format tag value. + */ + public int getFormat() + { + return format; + } + + /** + * Return the modification time of the file in milli-seconds. + * + * @return the modification time in millis + */ + public long getModificationTime() + { + return modDate * 1000L; + } + + /** + * @return filename + */ + public String getFileName() + { + return Strings.fromUTF8ByteArray(fileName); + } + + public byte[] getRawFileName() + { + byte[] tmp = new byte[fileName.length]; + + for (int i = 0; i != tmp.length; i++) + { + tmp[i] = fileName[i]; + } + + return tmp; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/MPInteger.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/MPInteger.java new file mode 100644 index 0000000..c17ee64 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/MPInteger.java @@ -0,0 +1,62 @@ +package org.bc.bcpg; + +import java.io.*; +import java.math.BigInteger; + +/** + * a multiple precision integer + */ +public class MPInteger + extends BCPGObject +{ + BigInteger value = null; + + public MPInteger( + BCPGInputStream in) + throws IOException + { + int length = (in.read() << 8) | in.read(); + byte[] bytes = new byte[(length + 7) / 8]; + + in.readFully(bytes); + + value = new BigInteger(1, bytes); + } + + public MPInteger( + BigInteger value) + { + if (value == null || value.signum() < 0) + { + throw new IllegalArgumentException("value must not be null, or negative"); + } + + this.value = value; + } + + public BigInteger getValue() + { + return value; + } + + public void encode( + BCPGOutputStream out) + throws IOException + { + int length = value.bitLength(); + + out.write(length >> 8); + out.write(length); + + byte[] bytes = value.toByteArray(); + + if (bytes[0] == 0) + { + out.write(bytes, 1, bytes.length - 1); + } + else + { + out.write(bytes, 0, bytes.length); + } + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/MarkerPacket.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/MarkerPacket.java new file mode 100644 index 0000000..575367d --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/MarkerPacket.java @@ -0,0 +1,28 @@ +package org.bc.bcpg; + +import java.io.IOException; + +/** + * Basic type for a marker packet + */ +public class MarkerPacket + extends ContainedPacket +{ + // "PGP" + + byte[] marker = { (byte)0x50, (byte)0x47, (byte)0x50 }; + + public MarkerPacket( + BCPGInputStream in) + throws IOException + { + in.readFully(marker); + } + + public void encode( + BCPGOutputStream out) + throws IOException + { + out.writePacket(MARKER, marker, true); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/ModDetectionCodePacket.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/ModDetectionCodePacket.java new file mode 100644 index 0000000..720494d --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/ModDetectionCodePacket.java @@ -0,0 +1,45 @@ +package org.bc.bcpg; + +import java.io.*; + +/** + * basic packet for a modification detection code packet. + */ +public class ModDetectionCodePacket + extends ContainedPacket +{ + private byte[] digest; + + ModDetectionCodePacket( + BCPGInputStream in) + throws IOException + { + this.digest = new byte[20]; + in.readFully(this.digest); + } + + public ModDetectionCodePacket( + byte[] digest) + throws IOException + { + this.digest = new byte[digest.length]; + + System.arraycopy(digest, 0, this.digest, 0, this.digest.length); + } + + public byte[] getDigest() + { + byte[] tmp = new byte[digest.length]; + + System.arraycopy(digest, 0, tmp, 0, tmp.length); + + return tmp; + } + + public void encode( + BCPGOutputStream out) + throws IOException + { + out.writePacket(MOD_DETECTION_CODE, digest, false); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/OnePassSignaturePacket.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/OnePassSignaturePacket.java new file mode 100644 index 0000000..6c59398 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/OnePassSignaturePacket.java @@ -0,0 +1,115 @@ +package org.bc.bcpg; + +import java.io.*; + +/** + * generic signature object + */ +public class OnePassSignaturePacket + extends ContainedPacket +{ + private int version; + private int sigType; + private int hashAlgorithm; + private int keyAlgorithm; + private long keyID; + private int nested; + + OnePassSignaturePacket( + BCPGInputStream in) + throws IOException + { + version = in.read(); + sigType = in.read(); + hashAlgorithm = in.read(); + keyAlgorithm = in.read(); + + keyID |= (long)in.read() << 56; + keyID |= (long)in.read() << 48; + keyID |= (long)in.read() << 40; + keyID |= (long)in.read() << 32; + keyID |= (long)in.read() << 24; + keyID |= (long)in.read() << 16; + keyID |= (long)in.read() << 8; + keyID |= in.read(); + + nested = in.read(); + } + + public OnePassSignaturePacket( + int sigType, + int hashAlgorithm, + int keyAlgorithm, + long keyID, + boolean isNested) + { + this.version = 3; + this.sigType = sigType; + this.hashAlgorithm = hashAlgorithm; + this.keyAlgorithm = keyAlgorithm; + this.keyID = keyID; + this.nested = (isNested) ? 0 : 1; + } + + /** + * Return the signature type. + * @return the signature type + */ + public int getSignatureType() + { + return sigType; + } + + /** + * return the encryption algorithm tag + */ + public int getKeyAlgorithm() + { + return keyAlgorithm; + } + + /** + * return the hashAlgorithm tag + */ + public int getHashAlgorithm() + { + return hashAlgorithm; + } + + /** + * @return long + */ + public long getKeyID() + { + return keyID; + } + + /** + * + */ + public void encode( + BCPGOutputStream out) + throws IOException + { + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + BCPGOutputStream pOut = new BCPGOutputStream(bOut); + + pOut.write(version); + pOut.write(sigType); + pOut.write(hashAlgorithm); + pOut.write(keyAlgorithm); + + pOut.write((byte)(keyID >> 56)); + pOut.write((byte)(keyID >> 48)); + pOut.write((byte)(keyID >> 40)); + pOut.write((byte)(keyID >> 32)); + pOut.write((byte)(keyID >> 24)); + pOut.write((byte)(keyID >> 16)); + pOut.write((byte)(keyID >> 8)); + pOut.write((byte)(keyID)); + + pOut.write(nested); + + out.writePacket(ONE_PASS_SIGNATURE, bOut.toByteArray(), true); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/OutputStreamPacket.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/OutputStreamPacket.java new file mode 100644 index 0000000..4d1a587 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/OutputStreamPacket.java @@ -0,0 +1,18 @@ +package org.bc.bcpg; + +import java.io.IOException; + +public abstract class OutputStreamPacket +{ + protected BCPGOutputStream out; + + public OutputStreamPacket( + BCPGOutputStream out) + { + this.out = out; + } + + public abstract BCPGOutputStream open() throws IOException; + + public abstract void close() throws IOException; +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/Packet.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/Packet.java new file mode 100644 index 0000000..b4bde42 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/Packet.java @@ -0,0 +1,9 @@ +package org.bc.bcpg; + +/** + */ +public class Packet + implements PacketTags +{ + +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/PacketTags.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/PacketTags.java new file mode 100644 index 0000000..88d6051 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/PacketTags.java @@ -0,0 +1,31 @@ +package org.bc.bcpg; + +/** + * Basic PGP packet tag types. + */ +public interface PacketTags +{ + public static final int RESERVED = 0 ; // Reserved - a packet tag must not have this value + public static final int PUBLIC_KEY_ENC_SESSION = 1; // Public-Key Encrypted Session Key Packet + public static final int SIGNATURE = 2; // Signature Packet + public static final int SYMMETRIC_KEY_ENC_SESSION = 3; // Symmetric-Key Encrypted Session Key Packet + public static final int ONE_PASS_SIGNATURE = 4 ; // One-Pass Signature Packet + public static final int SECRET_KEY = 5; // Secret Key Packet + public static final int PUBLIC_KEY = 6 ; // Public Key Packet + public static final int SECRET_SUBKEY = 7; // Secret Subkey Packet + public static final int COMPRESSED_DATA = 8; // Compressed Data Packet + public static final int SYMMETRIC_KEY_ENC = 9; // Symmetrically Encrypted Data Packet + public static final int MARKER = 10; // Marker Packet + public static final int LITERAL_DATA = 11; // Literal Data Packet + public static final int TRUST = 12; // Trust Packet + public static final int USER_ID = 13; // User ID Packet + public static final int PUBLIC_SUBKEY = 14; // Public Subkey Packet + public static final int USER_ATTRIBUTE = 17; // User attribute + public static final int SYM_ENC_INTEGRITY_PRO = 18; // Symmetric encrypted, integrity protected + public static final int MOD_DETECTION_CODE = 19; // Modification detection code + + public static final int EXPERIMENTAL_1 = 60; // Private or Experimental Values + public static final int EXPERIMENTAL_2 = 61; + public static final int EXPERIMENTAL_3 = 62; + public static final int EXPERIMENTAL_4 = 63; +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/PublicKeyAlgorithmTags.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/PublicKeyAlgorithmTags.java new file mode 100644 index 0000000..0fa0b2a --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/PublicKeyAlgorithmTags.java @@ -0,0 +1,29 @@ +package org.bc.bcpg; + +/** + * Public Key Algorithm tag numbers + */ +public interface PublicKeyAlgorithmTags +{ + public static final int RSA_GENERAL = 1; // RSA (Encrypt or Sign) + public static final int RSA_ENCRYPT = 2; // RSA Encrypt-Only + public static final int RSA_SIGN = 3; // RSA Sign-Only + public static final int ELGAMAL_ENCRYPT = 16; // Elgamal (Encrypt-Only), see [ELGAMAL] + public static final int DSA = 17; // DSA (Digital Signature Standard) + public static final int EC = 18; // Reserved for Elliptic Curve + public static final int ECDSA = 19; // Reserved for ECDSA + public static final int ELGAMAL_GENERAL = 20; // Elgamal (Encrypt or Sign) + public static final int DIFFIE_HELLMAN = 21; // Reserved for Diffie-Hellman (X9.42, as defined for IETF-S/MIME) + + public static final int EXPERIMENTAL_1 = 100; + public static final int EXPERIMENTAL_2 = 101; + public static final int EXPERIMENTAL_3 = 102; + public static final int EXPERIMENTAL_4 = 103; + public static final int EXPERIMENTAL_5 = 104; + public static final int EXPERIMENTAL_6 = 105; + public static final int EXPERIMENTAL_7 = 106; + public static final int EXPERIMENTAL_8 = 107; + public static final int EXPERIMENTAL_9 = 108; + public static final int EXPERIMENTAL_10 = 109; + public static final int EXPERIMENTAL_11 = 110; +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/PublicKeyEncSessionPacket.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/PublicKeyEncSessionPacket.java new file mode 100644 index 0000000..214b66a --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/PublicKeyEncSessionPacket.java @@ -0,0 +1,112 @@ +package org.bc.bcpg; + +import java.io.*; +import java.math.BigInteger; + +/** + * basic packet for a PGP public key + */ +public class PublicKeyEncSessionPacket + extends ContainedPacket implements PublicKeyAlgorithmTags +{ + private int version; + private long keyID; + private int algorithm; + private BigInteger[] data; + + PublicKeyEncSessionPacket( + BCPGInputStream in) + throws IOException + { + version = in.read(); + + keyID |= (long)in.read() << 56; + keyID |= (long)in.read() << 48; + keyID |= (long)in.read() << 40; + keyID |= (long)in.read() << 32; + keyID |= (long)in.read() << 24; + keyID |= (long)in.read() << 16; + keyID |= (long)in.read() << 8; + keyID |= in.read(); + + algorithm = in.read(); + + switch (algorithm) + { + case RSA_ENCRYPT: + case RSA_GENERAL: + data = new BigInteger[1]; + + data[0] = new MPInteger(in).getValue(); + break; + case ELGAMAL_ENCRYPT: + case ELGAMAL_GENERAL: + data = new BigInteger[2]; + + data[0] = new MPInteger(in).getValue(); + data[1] = new MPInteger(in).getValue(); + break; + default: + throw new IOException("unknown PGP public key algorithm encountered"); + } + } + + public PublicKeyEncSessionPacket( + long keyID, + int algorithm, + BigInteger[] data) + { + this.version = 3; + this.keyID = keyID; + this.algorithm = algorithm; + this.data = data; + } + + public int getVersion() + { + return version; + } + + public long getKeyID() + { + return keyID; + } + + public int getAlgorithm() + { + return algorithm; + } + + public BigInteger[] getEncSessionKey() + { + return data; + } + + public void encode( + BCPGOutputStream out) + throws IOException + { + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + BCPGOutputStream pOut = new BCPGOutputStream(bOut); + + pOut.write(version); + + pOut.write((byte)(keyID >> 56)); + pOut.write((byte)(keyID >> 48)); + pOut.write((byte)(keyID >> 40)); + pOut.write((byte)(keyID >> 32)); + pOut.write((byte)(keyID >> 24)); + pOut.write((byte)(keyID >> 16)); + pOut.write((byte)(keyID >> 8)); + pOut.write((byte)(keyID)); + + pOut.write(algorithm); + + for (int i = 0; i != data.length; i++) + { + pOut.writeObject(new MPInteger(data[i])); + } + + out.writePacket(PUBLIC_KEY_ENC_SESSION , bOut.toByteArray(), true); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/PublicKeyPacket.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/PublicKeyPacket.java new file mode 100644 index 0000000..83e8246 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/PublicKeyPacket.java @@ -0,0 +1,126 @@ +package org.bc.bcpg; + +import java.io.*; +import java.util.Date; + +/** + * basic packet for a PGP public key + */ +public class PublicKeyPacket + extends ContainedPacket implements PublicKeyAlgorithmTags +{ + private int version; + private long time; + private int validDays; + private int algorithm; + private BCPGKey key; + + PublicKeyPacket( + BCPGInputStream in) + throws IOException + { + version = in.read(); + time = ((long)in.read() << 24) | (in.read() << 16) | (in.read() << 8) | in.read(); + + if (version <= 3) + { + validDays = (in.read() << 8) | in.read(); + } + + algorithm = (byte)in.read(); + + switch (algorithm) + { + case RSA_ENCRYPT: + case RSA_GENERAL: + case RSA_SIGN: + key = new RSAPublicBCPGKey(in); + break; + case DSA: + key = new DSAPublicBCPGKey(in); + break; + case ELGAMAL_ENCRYPT: + case ELGAMAL_GENERAL: + key = new ElGamalPublicBCPGKey(in); + break; + default: + throw new IOException("unknown PGP public key algorithm encountered"); + } + } + + /** + * Construct version 4 public key packet. + * + * @param algorithm + * @param time + * @param key + */ + public PublicKeyPacket( + int algorithm, + Date time, + BCPGKey key) + { + this.version = 4; + this.time = time.getTime() / 1000; + this.algorithm = algorithm; + this.key = key; + } + + public int getVersion() + { + return version; + } + + public int getAlgorithm() + { + return algorithm; + } + + public int getValidDays() + { + return validDays; + } + + public Date getTime() + { + return new Date(time * 1000); + } + + public BCPGKey getKey() + { + return key; + } + + public byte[] getEncodedContents() + throws IOException + { + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + BCPGOutputStream pOut = new BCPGOutputStream(bOut); + + pOut.write(version); + + pOut.write((byte)(time >> 24)); + pOut.write((byte)(time >> 16)); + pOut.write((byte)(time >> 8)); + pOut.write((byte)time); + + if (version <= 3) + { + pOut.write((byte)(validDays >> 8)); + pOut.write((byte)validDays); + } + + pOut.write(algorithm); + + pOut.writeObject((BCPGObject)key); + + return bOut.toByteArray(); + } + + public void encode( + BCPGOutputStream out) + throws IOException + { + out.writePacket(PUBLIC_KEY, getEncodedContents(), true); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/PublicSubkeyPacket.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/PublicSubkeyPacket.java new file mode 100644 index 0000000..bbab9ec --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/PublicSubkeyPacket.java @@ -0,0 +1,40 @@ +package org.bc.bcpg; + +import java.io.*; +import java.util.Date; + +/** + * basic packet for a PGP public key + */ +public class PublicSubkeyPacket + extends PublicKeyPacket +{ + PublicSubkeyPacket( + BCPGInputStream in) + throws IOException + { + super(in); + } + + /** + * Construct version 4 public key packet. + * + * @param algorithm + * @param time + * @param key + */ + public PublicSubkeyPacket( + int algorithm, + Date time, + BCPGKey key) + { + super(algorithm, time, key); + } + + public void encode( + BCPGOutputStream out) + throws IOException + { + out.writePacket(PUBLIC_SUBKEY, getEncodedContents(), true); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/RSAPublicBCPGKey.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/RSAPublicBCPGKey.java new file mode 100644 index 0000000..435e472 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/RSAPublicBCPGKey.java @@ -0,0 +1,91 @@ +package org.bc.bcpg; + +import java.math.BigInteger; +import java.io.*; + +/** + * base class for an RSA Public Key. + */ +public class RSAPublicBCPGKey + extends BCPGObject implements BCPGKey +{ + MPInteger n; + MPInteger e; + + /** + * Construct an RSA public key from the passed in stream. + * + * @param in + * @throws IOException + */ + public RSAPublicBCPGKey( + BCPGInputStream in) + throws IOException + { + this.n = new MPInteger(in); + this.e = new MPInteger(in); + } + + /** + * + * @param n the modulus + * @param e the public exponent + */ + public RSAPublicBCPGKey( + BigInteger n, + BigInteger e) + { + this.n = new MPInteger(n); + this.e = new MPInteger(e); + } + + public BigInteger getPublicExponent() + { + return e.getValue(); + } + + public BigInteger getModulus() + { + return n.getValue(); + } + + /** + * return "PGP" + * + * @see org.bc.bcpg.BCPGKey#getFormat() + */ + public String getFormat() + { + return "PGP"; + } + + /** + * return the standard PGP encoding of the key. + * + * @see org.bc.bcpg.BCPGKey#getEncoded() + */ + public byte[] getEncoded() + { + try + { + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + BCPGOutputStream pgpOut = new BCPGOutputStream(bOut); + + pgpOut.writeObject(this); + + return bOut.toByteArray(); + } + catch (IOException e) + { + return null; + } + } + + public void encode( + BCPGOutputStream out) + throws IOException + { + out.writeObject(n); + out.writeObject(e); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/RSASecretBCPGKey.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/RSASecretBCPGKey.java new file mode 100644 index 0000000..ef7204b --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/RSASecretBCPGKey.java @@ -0,0 +1,176 @@ +package org.bc.bcpg; + +import java.io.*; +import java.math.BigInteger; + +/** + * base class for an RSA Secret (or Private) Key. + */ +public class RSASecretBCPGKey + extends BCPGObject implements BCPGKey +{ + MPInteger d; + MPInteger p; + MPInteger q; + MPInteger u; + + BigInteger expP, expQ, crt; + + /** + * + * @param in + * @throws IOException + */ + public RSASecretBCPGKey( + BCPGInputStream in) + throws IOException + { + this.d = new MPInteger(in); + this.p = new MPInteger(in); + this.q = new MPInteger(in); + this.u = new MPInteger(in); + + expP = d.getValue().remainder(p.getValue().subtract(BigInteger.valueOf(1))); + expQ = d.getValue().remainder(q.getValue().subtract(BigInteger.valueOf(1))); + crt = q.getValue().modInverse(p.getValue()); + } + + /** + * + * @param d + * @param p + * @param q + */ + public RSASecretBCPGKey( + BigInteger d, + BigInteger p, + BigInteger q) + { + // + // pgp requires (p < q) + // + int cmp = p.compareTo(q); + if (cmp >= 0) + { + if (cmp == 0) + { + throw new IllegalArgumentException("p and q cannot be equal"); + } + + BigInteger tmp = p; + p = q; + q = tmp; + } + + this.d = new MPInteger(d); + this.p = new MPInteger(p); + this.q = new MPInteger(q); + this.u = new MPInteger(p.modInverse(q)); + + expP = d.remainder(p.subtract(BigInteger.valueOf(1))); + expQ = d.remainder(q.subtract(BigInteger.valueOf(1))); + crt = q.modInverse(p); + } + + /** + * return the modulus for this key. + * + * @return BigInteger + */ + public BigInteger getModulus() + { + return p.getValue().multiply(q.getValue()); + } + + /** + * return the private exponent for this key. + * + * @return BigInteger + */ + public BigInteger getPrivateExponent() + { + return d.getValue(); + } + + /** + * return the prime P + */ + public BigInteger getPrimeP() + { + return p.getValue(); + } + + /** + * return the prime Q + */ + public BigInteger getPrimeQ() + { + return q.getValue(); + } + + /** + * return the prime exponent of p + */ + public BigInteger getPrimeExponentP() + { + return expP; + } + + /** + * return the prime exponent of q + */ + public BigInteger getPrimeExponentQ() + { + return expQ; + } + + /** + * return the crt coefficient + */ + public BigInteger getCrtCoefficient() + { + return crt; + } + + /** + * return "PGP" + * + * @see org.bc.bcpg.BCPGKey#getFormat() + */ + public String getFormat() + { + return "PGP"; + } + + /** + * return the standard PGP encoding of the key. + * + * @see org.bc.bcpg.BCPGKey#getEncoded() + */ + public byte[] getEncoded() + { + try + { + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + BCPGOutputStream pgpOut = new BCPGOutputStream(bOut); + + pgpOut.writeObject(this); + + return bOut.toByteArray(); + } + catch (IOException e) + { + return null; + } + } + + public void encode( + BCPGOutputStream out) + throws IOException + { + out.writeObject(d); + out.writeObject(p); + out.writeObject(q); + out.writeObject(u); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/S2K.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/S2K.java new file mode 100644 index 0000000..bae88bc --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/S2K.java @@ -0,0 +1,149 @@ +package org.bc.bcpg; + +import java.io.*; + +/** + * The string to key specifier class + */ +public class S2K + extends BCPGObject +{ + private static final int EXPBIAS = 6; + + public static final int SIMPLE = 0; + public static final int SALTED = 1; + public static final int SALTED_AND_ITERATED = 3; + public static final int GNU_DUMMY_S2K = 101; + + int type; + int algorithm; + byte[] iv; + int itCount = -1; + int protectionMode = -1; + + S2K( + InputStream in) + throws IOException + { + DataInputStream dIn = new DataInputStream(in); + + type = dIn.read(); + algorithm = dIn.read(); + + // + // if this happens we have a dummy-S2K packet. + // + if (type != GNU_DUMMY_S2K) + { + if (type != 0) + { + iv = new byte[8]; + dIn.readFully(iv, 0, iv.length); + + if (type == 3) + { + itCount = dIn.read(); + } + } + } + else + { + dIn.read(); // G + dIn.read(); // N + dIn.read(); // U + protectionMode = dIn.read(); // protection mode + } + } + + public S2K( + int algorithm) + { + this.type = 0; + this.algorithm = algorithm; + } + + public S2K( + int algorithm, + byte[] iv) + { + this.type = 1; + this.algorithm = algorithm; + this.iv = iv; + } + + public S2K( + int algorithm, + byte[] iv, + int itCount) + { + this.type = 3; + this.algorithm = algorithm; + this.iv = iv; + this.itCount = itCount; + } + + public int getType() + { + return type; + } + + /** + * return the hash algorithm for this S2K + */ + public int getHashAlgorithm() + { + return algorithm; + } + + /** + * return the iv for the key generation algorithm + */ + public byte[] getIV() + { + return iv; + } + + /** + * return the iteration count + */ + public long getIterationCount() + { + return (16 + (itCount & 15)) << ((itCount >> 4) + EXPBIAS); + } + + /** + * the protection mode - only if GNU_DUMMY_S2K + */ + public int getProtectionMode() + { + return protectionMode; + } + + public void encode( + BCPGOutputStream out) + throws IOException + { + out.write(type); + out.write(algorithm); + + if (type != GNU_DUMMY_S2K) + { + if (type != 0) + { + out.write(iv); + } + + if (type == 3) + { + out.write(itCount); + } + } + else + { + out.write('G'); + out.write('N'); + out.write('U'); + out.write(protectionMode); + } + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/SecretKeyPacket.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/SecretKeyPacket.java new file mode 100644 index 0000000..31b8fb5 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/SecretKeyPacket.java @@ -0,0 +1,189 @@ +package org.bc.bcpg; + +import java.io.*; + +/** + * basic packet for a PGP secret key + */ +public class SecretKeyPacket + extends ContainedPacket implements PublicKeyAlgorithmTags +{ + public static final int USAGE_NONE = 0x00; + public static final int USAGE_CHECKSUM = 0xff; + public static final int USAGE_SHA1 = 0xfe; + + private PublicKeyPacket pubKeyPacket; + private byte[] secKeyData; + private int s2kUsage; + private int encAlgorithm; + private S2K s2k; + private byte[] iv; + + /** + * + * @param in + * @throws IOException + */ + SecretKeyPacket( + BCPGInputStream in) + throws IOException + { + if (this instanceof SecretSubkeyPacket) + { + pubKeyPacket = new PublicSubkeyPacket(in); + } + else + { + pubKeyPacket = new PublicKeyPacket(in); + } + + s2kUsage = in.read(); + + if (s2kUsage == USAGE_CHECKSUM || s2kUsage == USAGE_SHA1) + { + encAlgorithm = in.read(); + s2k = new S2K(in); + } + else + { + encAlgorithm = s2kUsage; + } + + if (!(s2k != null && s2k.getType() == S2K.GNU_DUMMY_S2K && s2k.getProtectionMode() == 0x01)) + { + if (s2kUsage != 0) + { + if (encAlgorithm < 7) + { + iv = new byte[8]; + } + else + { + iv = new byte[16]; + } + in.readFully(iv, 0, iv.length); + } + } + + if (in.available() != 0) + { + secKeyData = new byte[in.available()]; + + in.readFully(secKeyData); + } + } + + /** + * + * @param pubKeyPacket + * @param encAlgorithm + * @param s2k + * @param iv + * @param secKeyData + */ + public SecretKeyPacket( + PublicKeyPacket pubKeyPacket, + int encAlgorithm, + S2K s2k, + byte[] iv, + byte[] secKeyData) + { + this.pubKeyPacket = pubKeyPacket; + this.encAlgorithm = encAlgorithm; + + if (encAlgorithm != SymmetricKeyAlgorithmTags.NULL) + { + this.s2kUsage = USAGE_CHECKSUM; + } + else + { + this.s2kUsage = USAGE_NONE; + } + + this.s2k = s2k; + this.iv = iv; + this.secKeyData = secKeyData; + } + + public SecretKeyPacket( + PublicKeyPacket pubKeyPacket, + int encAlgorithm, + int s2kUsage, + S2K s2k, + byte[] iv, + byte[] secKeyData) + { + this.pubKeyPacket = pubKeyPacket; + this.encAlgorithm = encAlgorithm; + this.s2kUsage = s2kUsage; + this.s2k = s2k; + this.iv = iv; + this.secKeyData = secKeyData; + } + + public int getEncAlgorithm() + { + return encAlgorithm; + } + + public int getS2KUsage() + { + return s2kUsage; + } + + public byte[] getIV() + { + return iv; + } + + public S2K getS2K() + { + return s2k; + } + + public PublicKeyPacket getPublicKeyPacket() + { + return pubKeyPacket; + } + + public byte[] getSecretKeyData() + { + return secKeyData; + } + + public byte[] getEncodedContents() + throws IOException + { + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + BCPGOutputStream pOut = new BCPGOutputStream(bOut); + + pOut.write(pubKeyPacket.getEncodedContents()); + + pOut.write(s2kUsage); + + if (s2kUsage == USAGE_CHECKSUM || s2kUsage == USAGE_SHA1) + { + pOut.write(encAlgorithm); + pOut.writeObject(s2k); + } + + if (iv != null) + { + pOut.write(iv); + } + + if (secKeyData != null && secKeyData.length > 0) + { + pOut.write(secKeyData); + } + + return bOut.toByteArray(); + } + + public void encode( + BCPGOutputStream out) + throws IOException + { + out.writePacket(SECRET_KEY, getEncodedContents(), true); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/SecretSubkeyPacket.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/SecretSubkeyPacket.java new file mode 100644 index 0000000..12308b8 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/SecretSubkeyPacket.java @@ -0,0 +1,58 @@ +package org.bc.bcpg; + +import java.io.*; + +/** + * basic packet for a PGP secret key + */ +public class SecretSubkeyPacket + extends SecretKeyPacket +{ + /** + * + * @param in + * @throws IOException + */ + SecretSubkeyPacket( + BCPGInputStream in) + throws IOException + { + super(in); + } + + /** + * + * @param pubKeyPacket + * @param encAlgorithm + * @param s2k + * @param iv + * @param secKeyData + */ + public SecretSubkeyPacket( + PublicKeyPacket pubKeyPacket, + int encAlgorithm, + S2K s2k, + byte[] iv, + byte[] secKeyData) + { + super(pubKeyPacket, encAlgorithm, s2k, iv, secKeyData); + } + + public SecretSubkeyPacket( + PublicKeyPacket pubKeyPacket, + int encAlgorithm, + int s2kUsage, + S2K s2k, + byte[] iv, + byte[] secKeyData) + { + super(pubKeyPacket, encAlgorithm, s2kUsage, s2k, iv, secKeyData); + } + + public void encode( + BCPGOutputStream out) + throws IOException + { + out.writePacket(SECRET_SUBKEY, getEncodedContents(), true); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/SignaturePacket.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/SignaturePacket.java new file mode 100644 index 0000000..c2c2ee0 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/SignaturePacket.java @@ -0,0 +1,515 @@ +package org.bc.bcpg; + +import org.bc.bcpg.sig.IssuerKeyID; +import org.bc.bcpg.sig.SignatureCreationTime; +import org.bc.util.Arrays; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.Vector; + +/** + * generic signature packet + */ +public class SignaturePacket + extends ContainedPacket implements PublicKeyAlgorithmTags +{ + private int version; + private int signatureType; + private long creationTime; + private long keyID; + private int keyAlgorithm; + private int hashAlgorithm; + private MPInteger[] signature; + private byte[] fingerPrint; + private SignatureSubpacket[] hashedData; + private SignatureSubpacket[] unhashedData; + private byte[] signatureEncoding; + + SignaturePacket( + BCPGInputStream in) + throws IOException + { + version = in.read(); + + if (version == 3 || version == 2) + { + int l = in.read(); + + signatureType = in.read(); + creationTime = (((long)in.read() << 24) | (in.read() << 16) | (in.read() << 8) | in.read()) * 1000; + keyID |= (long)in.read() << 56; + keyID |= (long)in.read() << 48; + keyID |= (long)in.read() << 40; + keyID |= (long)in.read() << 32; + keyID |= (long)in.read() << 24; + keyID |= (long)in.read() << 16; + keyID |= (long)in.read() << 8; + keyID |= in.read(); + keyAlgorithm = in.read(); + hashAlgorithm = in.read(); + } + else if (version == 4) + { + signatureType = in.read(); + keyAlgorithm = in.read(); + hashAlgorithm = in.read(); + + int hashedLength = (in.read() << 8) | in.read(); + byte[] hashed = new byte[hashedLength]; + + in.readFully(hashed); + + // + // read the signature sub packet data. + // + SignatureSubpacket sub; + SignatureSubpacketInputStream sIn = new SignatureSubpacketInputStream( + new ByteArrayInputStream(hashed)); + + Vector v = new Vector(); + while ((sub = sIn.readPacket()) != null) + { + v.addElement(sub); + } + + hashedData = new SignatureSubpacket[v.size()]; + + for (int i = 0; i != hashedData.length; i++) + { + SignatureSubpacket p = (SignatureSubpacket)v.elementAt(i); + if (p instanceof IssuerKeyID) + { + keyID = ((IssuerKeyID)p).getKeyID(); + } + else if (p instanceof SignatureCreationTime) + { + creationTime = ((SignatureCreationTime)p).getTime().getTime(); + } + + hashedData[i] = p; + } + + int unhashedLength = (in.read() << 8) | in.read(); + byte[] unhashed = new byte[unhashedLength]; + + in.readFully(unhashed); + + sIn = new SignatureSubpacketInputStream( + new ByteArrayInputStream(unhashed)); + + v.removeAllElements(); + while ((sub = sIn.readPacket()) != null) + { + v.addElement(sub); + } + + unhashedData = new SignatureSubpacket[v.size()]; + + for (int i = 0; i != unhashedData.length; i++) + { + SignatureSubpacket p = (SignatureSubpacket)v.elementAt(i); + if (p instanceof IssuerKeyID) + { + keyID = ((IssuerKeyID)p).getKeyID(); + } + + unhashedData[i] = p; + } + } + else + { + throw new RuntimeException("unsupported version: " + version); + } + + fingerPrint = new byte[2]; + in.readFully(fingerPrint); + + switch (keyAlgorithm) + { + case RSA_GENERAL: + case RSA_SIGN: + MPInteger v = new MPInteger(in); + + signature = new MPInteger[1]; + signature[0] = v; + break; + case DSA: + MPInteger r = new MPInteger(in); + MPInteger s = new MPInteger(in); + + signature = new MPInteger[2]; + signature[0] = r; + signature[1] = s; + break; + case ELGAMAL_ENCRYPT: // yep, this really does happen sometimes. + case ELGAMAL_GENERAL: + MPInteger p = new MPInteger(in); + MPInteger g = new MPInteger(in); + MPInteger y = new MPInteger(in); + + signature = new MPInteger[3]; + signature[0] = p; + signature[1] = g; + signature[2] = y; + break; + default: + if (keyAlgorithm >= PublicKeyAlgorithmTags.EXPERIMENTAL_1 && keyAlgorithm <= PublicKeyAlgorithmTags.EXPERIMENTAL_11) + { + signature = null; + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + int ch; + while ((ch = in.read()) >= 0) + { + bOut.write(ch); + } + signatureEncoding = bOut.toByteArray(); + } + else + { + throw new IOException("unknown signature key algorithm: " + keyAlgorithm); + } + } + } + + /** + * Generate a version 4 signature packet. + * + * @param signatureType + * @param keyAlgorithm + * @param hashAlgorithm + * @param hashedData + * @param unhashedData + * @param fingerPrint + * @param signature + */ + public SignaturePacket( + int signatureType, + long keyID, + int keyAlgorithm, + int hashAlgorithm, + SignatureSubpacket[] hashedData, + SignatureSubpacket[] unhashedData, + byte[] fingerPrint, + MPInteger[] signature) + { + this(4, signatureType, keyID, keyAlgorithm, hashAlgorithm, hashedData, unhashedData, fingerPrint, signature); + } + + /** + * Generate a version 2/3 signature packet. + * + * @param signatureType + * @param keyAlgorithm + * @param hashAlgorithm + * @param fingerPrint + * @param signature + */ + public SignaturePacket( + int version, + int signatureType, + long keyID, + int keyAlgorithm, + int hashAlgorithm, + long creationTime, + byte[] fingerPrint, + MPInteger[] signature) + { + this(version, signatureType, keyID, keyAlgorithm, hashAlgorithm, null, null, fingerPrint, signature); + + this.creationTime = creationTime; + } + + public SignaturePacket( + int version, + int signatureType, + long keyID, + int keyAlgorithm, + int hashAlgorithm, + SignatureSubpacket[] hashedData, + SignatureSubpacket[] unhashedData, + byte[] fingerPrint, + MPInteger[] signature) + { + this.version = version; + this.signatureType = signatureType; + this.keyID = keyID; + this.keyAlgorithm = keyAlgorithm; + this.hashAlgorithm = hashAlgorithm; + this.hashedData = hashedData; + this.unhashedData = unhashedData; + this.fingerPrint = fingerPrint; + this.signature = signature; + + if (hashedData != null) + { + setCreationTime(); + } + } + + /** + * get the version number + */ + public int getVersion() + { + return version; + } + + /** + * return the signature type. + */ + public int getSignatureType() + { + return signatureType; + } + + /** + * return the keyID + * @return the keyID that created the signature. + */ + public long getKeyID() + { + return keyID; + } + + /** + * return the signature trailer that must be included with the data + * to reconstruct the signature + * + * @return byte[] + */ + public byte[] getSignatureTrailer() + { + byte[] trailer = null; + + if (version == 3 || version == 2) + { + trailer = new byte[5]; + + long time = creationTime / 1000; + + trailer[0] = (byte)signatureType; + trailer[1] = (byte)(time >> 24); + trailer[2] = (byte)(time >> 16); + trailer[3] = (byte)(time >> 8); + trailer[4] = (byte)(time); + } + else + { + ByteArrayOutputStream sOut = new ByteArrayOutputStream(); + + try + { + sOut.write((byte)this.getVersion()); + sOut.write((byte)this.getSignatureType()); + sOut.write((byte)this.getKeyAlgorithm()); + sOut.write((byte)this.getHashAlgorithm()); + + ByteArrayOutputStream hOut = new ByteArrayOutputStream(); + SignatureSubpacket[] hashed = this.getHashedSubPackets(); + + for (int i = 0; i != hashed.length; i++) + { + hashed[i].encode(hOut); + } + + byte[] data = hOut.toByteArray(); + + sOut.write((byte)(data.length >> 8)); + sOut.write((byte)data.length); + sOut.write(data); + + byte[] hData = sOut.toByteArray(); + + sOut.write((byte)this.getVersion()); + sOut.write((byte)0xff); + sOut.write((byte)(hData.length>> 24)); + sOut.write((byte)(hData.length >> 16)); + sOut.write((byte)(hData.length >> 8)); + sOut.write((byte)(hData.length)); + } + catch (IOException e) + { + throw new RuntimeException("exception generating trailer: " + e); + } + + trailer = sOut.toByteArray(); + } + + return trailer; + } + + /** + * return the encryption algorithm tag + */ + public int getKeyAlgorithm() + { + return keyAlgorithm; + } + + /** + * return the hashAlgorithm tag + */ + public int getHashAlgorithm() + { + return hashAlgorithm; + } + + /** + * return the signature as a set of integers - note this is normalised to be the + * ASN.1 encoding of what appears in the signature packet. + */ + public MPInteger[] getSignature() + { + return signature; + } + + /** + * Return the byte encoding of the signature section. + * @return uninterpreted signature bytes. + */ + public byte[] getSignatureBytes() + { + if (signatureEncoding == null) + { + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + BCPGOutputStream bcOut = new BCPGOutputStream(bOut); + + for (int i = 0; i != signature.length; i++) + { + try + { + bcOut.writeObject(signature[i]); + } + catch (IOException e) + { + throw new RuntimeException("internal error: " + e); + } + } + return bOut.toByteArray(); + } + else + { + return Arrays.clone(signatureEncoding); + } + } + public SignatureSubpacket[] getHashedSubPackets() + { + return hashedData; + } + + public SignatureSubpacket[] getUnhashedSubPackets() + { + return unhashedData; + } + + /** + * Return the creation time of the signature in milli-seconds. + * + * @return the creation time in millis + */ + public long getCreationTime() + { + return creationTime; + } + + public void encode( + BCPGOutputStream out) + throws IOException + { + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + BCPGOutputStream pOut = new BCPGOutputStream(bOut); + + pOut.write(version); + + if (version == 3 || version == 2) + { + pOut.write(5); // the length of the next block + + long time = creationTime / 1000; + + pOut.write(signatureType); + pOut.write((byte)(time >> 24)); + pOut.write((byte)(time >> 16)); + pOut.write((byte)(time >> 8)); + pOut.write((byte)time); + + pOut.write((byte)(keyID >> 56)); + pOut.write((byte)(keyID >> 48)); + pOut.write((byte)(keyID >> 40)); + pOut.write((byte)(keyID >> 32)); + pOut.write((byte)(keyID >> 24)); + pOut.write((byte)(keyID >> 16)); + pOut.write((byte)(keyID >> 8)); + pOut.write((byte)(keyID)); + + pOut.write(keyAlgorithm); + pOut.write(hashAlgorithm); + } + else if (version == 4) + { + pOut.write(signatureType); + pOut.write(keyAlgorithm); + pOut.write(hashAlgorithm); + + ByteArrayOutputStream sOut = new ByteArrayOutputStream(); + + for (int i = 0; i != hashedData.length; i++) + { + hashedData[i].encode(sOut); + } + + byte[] data = sOut.toByteArray(); + + pOut.write(data.length >> 8); + pOut.write(data.length); + pOut.write(data); + + sOut.reset(); + + for (int i = 0; i != unhashedData.length; i++) + { + unhashedData[i].encode(sOut); + } + + data = sOut.toByteArray(); + + pOut.write(data.length >> 8); + pOut.write(data.length); + pOut.write(data); + } + else + { + throw new IOException("unknown version: " + version); + } + + pOut.write(fingerPrint); + + if (signature != null) + { + for (int i = 0; i != signature.length; i++) + { + pOut.writeObject(signature[i]); + } + } + else + { + pOut.write(signatureEncoding); + } + + out.writePacket(SIGNATURE, bOut.toByteArray(), true); + } + + private void setCreationTime() + { + for (int i = 0; i != hashedData.length; i++) + { + if (hashedData[i] instanceof SignatureCreationTime) + { + creationTime = ((SignatureCreationTime)hashedData[i]).getTime().getTime(); + break; + } + } + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/SignatureSubpacket.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/SignatureSubpacket.java new file mode 100644 index 0000000..1118943 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/SignatureSubpacket.java @@ -0,0 +1,80 @@ +package org.bc.bcpg; + +import java.io.*; + +/** + * Basic type for a PGP Signature sub-packet. + */ +public class SignatureSubpacket +{ + int type; + boolean critical; + + protected byte[] data; + + protected SignatureSubpacket( + int type, + boolean critical, + byte[] data) + { + this.type = type; + this.critical = critical; + this.data = data; + } + + public int getType() + { + return type; + } + + public boolean isCritical() + { + return critical; + } + + /** + * return the generic data making up the packet. + */ + public byte[] getData() + { + return data; + } + + public void encode( + OutputStream out) + throws IOException + { + int bodyLen = data.length + 1; + + if (bodyLen < 192) + { + out.write((byte)bodyLen); + } + else if (bodyLen <= 8383) + { + bodyLen -= 192; + + out.write((byte)(((bodyLen >> 8) & 0xff) + 192)); + out.write((byte)bodyLen); + } + else + { + out.write(0xff); + out.write((byte)(bodyLen >> 24)); + out.write((byte)(bodyLen >> 16)); + out.write((byte)(bodyLen >> 8)); + out.write((byte)bodyLen); + } + + if (critical) + { + out.write(0x80 | type); + } + else + { + out.write(type); + } + + out.write(data); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/SignatureSubpacketInputStream.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/SignatureSubpacketInputStream.java new file mode 100644 index 0000000..cb13144 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/SignatureSubpacketInputStream.java @@ -0,0 +1,123 @@ +package org.bc.bcpg; + +import org.bc.bcpg.sig.Exportable; +import org.bc.bcpg.sig.IssuerKeyID; +import org.bc.bcpg.sig.KeyExpirationTime; +import org.bc.bcpg.sig.KeyFlags; +import org.bc.bcpg.sig.NotationData; +import org.bc.bcpg.sig.PreferredAlgorithms; +import org.bc.bcpg.sig.PrimaryUserID; +import org.bc.bcpg.sig.Revocable; +import org.bc.bcpg.sig.SignatureCreationTime; +import org.bc.bcpg.sig.SignatureExpirationTime; +import org.bc.bcpg.sig.SignerUserID; +import org.bc.bcpg.sig.TrustSignature; +import org.bc.util.io.Streams; + +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStream; + +/** + * reader for signature sub-packets + */ +public class SignatureSubpacketInputStream + extends InputStream implements SignatureSubpacketTags +{ + InputStream in; + + public SignatureSubpacketInputStream( + InputStream in) + { + this.in = in; + } + + public int available() + throws IOException + { + return in.available(); + } + + public int read() + throws IOException + { + return in.read(); + } + + public SignatureSubpacket readPacket() + throws IOException + { + int l = this.read(); + int bodyLen = 0; + + if (l < 0) + { + return null; + } + + if (l < 192) + { + bodyLen = l; + } + else if (l <= 223) + { + bodyLen = ((l - 192) << 8) + (in.read()) + 192; + } + else if (l == 255) + { + bodyLen = (in.read() << 24) | (in.read() << 16) | (in.read() << 8) | in.read(); + } + else + { + // TODO Error? + } + + int tag = in.read(); + + if (tag < 0) + { + throw new EOFException("unexpected EOF reading signature sub packet"); + } + + byte[] data = new byte[bodyLen - 1]; + if (Streams.readFully(in, data) < data.length) + { + throw new EOFException(); + } + + boolean isCritical = ((tag & 0x80) != 0); + int type = tag & 0x7f; + + switch (type) + { + case CREATION_TIME: + return new SignatureCreationTime(isCritical, data); + case KEY_EXPIRE_TIME: + return new KeyExpirationTime(isCritical, data); + case EXPIRE_TIME: + return new SignatureExpirationTime(isCritical, data); + case REVOCABLE: + return new Revocable(isCritical, data); + case EXPORTABLE: + return new Exportable(isCritical, data); + case ISSUER_KEY_ID: + return new IssuerKeyID(isCritical, data); + case TRUST_SIG: + return new TrustSignature(isCritical, data); + case PREFERRED_COMP_ALGS: + case PREFERRED_HASH_ALGS: + case PREFERRED_SYM_ALGS: + return new PreferredAlgorithms(type, isCritical, data); + case KEY_FLAGS: + return new KeyFlags(isCritical, data); + case PRIMARY_USER_ID: + return new PrimaryUserID(isCritical, data); + case SIGNER_USER_ID: + return new SignerUserID(isCritical, data); + case NOTATION_DATA: + return new NotationData(isCritical, data); + } + + return new SignatureSubpacket(type, isCritical, data); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/SignatureSubpacketTags.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/SignatureSubpacketTags.java new file mode 100644 index 0000000..2c10fb3 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/SignatureSubpacketTags.java @@ -0,0 +1,32 @@ +package org.bc.bcpg; + +/** + * Basic PGP signature sub-packet tag types. + */ +public interface SignatureSubpacketTags +{ + public static final int CREATION_TIME = 2; // signature creation time + public static final int EXPIRE_TIME = 3; // signature expiration time + public static final int EXPORTABLE = 4; // exportable certification + public static final int TRUST_SIG = 5; // trust signature + public static final int REG_EXP = 6; // regular expression + public static final int REVOCABLE = 7; // revocable + public static final int KEY_EXPIRE_TIME = 9; // key expiration time + public static final int PLACEHOLDER = 10; // placeholder for backward compatibility + public static final int PREFERRED_SYM_ALGS = 11; // preferred symmetric algorithms + public static final int REVOCATION_KEY = 12; // revocation key + public static final int ISSUER_KEY_ID = 16; // issuer key ID + public static final int NOTATION_DATA = 20; // notation data + public static final int PREFERRED_HASH_ALGS = 21; // preferred hash algorithms + public static final int PREFERRED_COMP_ALGS = 22; // preferred compression algorithms + public static final int KEY_SERVER_PREFS = 23; // key server preferences + public static final int PREFERRED_KEY_SERV = 24; // preferred key server + public static final int PRIMARY_USER_ID = 25; // primary user id + public static final int POLICY_URL = 26; // policy URL + public static final int KEY_FLAGS = 27; // key flags + public static final int SIGNER_USER_ID = 28; // signer's user id + public static final int REVOCATION_REASON = 29; // reason for revocation + public static final int FEATURES = 30; // features + public static final int SIGNATURE_TARGET = 31; // signature target + public static final int EMBEDDED_SIGNATURE = 32; // embedded signature +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/SymmetricEncDataPacket.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/SymmetricEncDataPacket.java new file mode 100644 index 0000000..5722d26 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/SymmetricEncDataPacket.java @@ -0,0 +1,14 @@ +package org.bc.bcpg; + +/** + * Basic type for a symmetric key encrypted packet + */ +public class SymmetricEncDataPacket + extends InputStreamPacket +{ + public SymmetricEncDataPacket( + BCPGInputStream in) + { + super(in); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/SymmetricEncIntegrityPacket.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/SymmetricEncIntegrityPacket.java new file mode 100644 index 0000000..318a54e --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/SymmetricEncIntegrityPacket.java @@ -0,0 +1,20 @@ +package org.bc.bcpg; + +import java.io.*; + +/** + */ +public class SymmetricEncIntegrityPacket + extends InputStreamPacket +{ + int version; + + SymmetricEncIntegrityPacket( + BCPGInputStream in) + throws IOException + { + super(in); + + version = in.read(); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/SymmetricKeyAlgorithmTags.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/SymmetricKeyAlgorithmTags.java new file mode 100644 index 0000000..aa1ab7f --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/SymmetricKeyAlgorithmTags.java @@ -0,0 +1,19 @@ +package org.bc.bcpg; + +/** + * Basic tags for symmetric key algorithms + */ +public interface SymmetricKeyAlgorithmTags +{ + public static final int NULL = 0; // Plaintext or unencrypted data + public static final int IDEA = 1; // IDEA [IDEA] + public static final int TRIPLE_DES = 2; // Triple-DES (DES-EDE, as per spec -168 bit key derived from 192) + public static final int CAST5 = 3; // CAST5 (128 bit key, as per RFC 2144) + public static final int BLOWFISH = 4; // Blowfish (128 bit key, 16 rounds) [BLOWFISH] + public static final int SAFER = 5; // SAFER-SK128 (13 rounds) [SAFER] + public static final int DES = 6; // Reserved for DES/SK + public static final int AES_128 = 7; // Reserved for AES with 128-bit key + public static final int AES_192 = 8; // Reserved for AES with 192-bit key + public static final int AES_256 = 9; // Reserved for AES with 256-bit key + public static final int TWOFISH = 10; // Reserved for Twofish +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/SymmetricKeyEncSessionPacket.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/SymmetricKeyEncSessionPacket.java new file mode 100644 index 0000000..459134c --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/SymmetricKeyEncSessionPacket.java @@ -0,0 +1,94 @@ +package org.bc.bcpg; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +/** + * Basic type for a symmetric encrypted session key packet + */ +public class SymmetricKeyEncSessionPacket + extends ContainedPacket +{ + private int version; + private int encAlgorithm; + private S2K s2k; + private byte[] secKeyData; + + public SymmetricKeyEncSessionPacket( + BCPGInputStream in) + throws IOException + { + version = in.read(); + encAlgorithm = in.read(); + + s2k = new S2K(in); + + if (in.available() != 0) + { + secKeyData = new byte[in.available()]; + in.readFully(secKeyData, 0, secKeyData.length); + } + } + + public SymmetricKeyEncSessionPacket( + int encAlgorithm, + S2K s2k, + byte[] secKeyData) + { + this.version = 4; + this.encAlgorithm = encAlgorithm; + this.s2k = s2k; + this.secKeyData = secKeyData; + } + + /** + * @return int + */ + public int getEncAlgorithm() + { + return encAlgorithm; + } + + /** + * @return S2K + */ + public S2K getS2K() + { + return s2k; + } + + /** + * @return byte[] + */ + public byte[] getSecKeyData() + { + return secKeyData; + } + + /** + * @return int + */ + public int getVersion() + { + return version; + } + + public void encode( + BCPGOutputStream out) + throws IOException + { + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + BCPGOutputStream pOut = new BCPGOutputStream(bOut); + + pOut.write(version); + pOut.write(encAlgorithm); + pOut.writeObject(s2k); + + if (secKeyData != null && secKeyData.length > 0) + { + pOut.write(secKeyData); + } + + out.writePacket(SYMMETRIC_KEY_ENC_SESSION, bOut.toByteArray(), true); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/TrustPacket.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/TrustPacket.java new file mode 100644 index 0000000..9f15776 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/TrustPacket.java @@ -0,0 +1,48 @@ +package org.bc.bcpg; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +/** + * Basic type for a trust packet + */ +public class TrustPacket + extends ContainedPacket +{ + byte[] levelAndTrustAmount; + + public TrustPacket( + BCPGInputStream in) + throws IOException + { + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + int ch; + + while ((ch = in.read()) >= 0) + { + bOut.write(ch); + } + + levelAndTrustAmount = bOut.toByteArray(); + } + + public TrustPacket( + int trustCode) + { + this.levelAndTrustAmount = new byte[1]; + + this.levelAndTrustAmount[0] = (byte)trustCode; + } + + public byte[] getLevelAndTrustAmount() + { + return levelAndTrustAmount; + } + + public void encode( + BCPGOutputStream out) + throws IOException + { + out.writePacket(TRUST, levelAndTrustAmount, true); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/UserAttributePacket.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/UserAttributePacket.java new file mode 100644 index 0000000..0c08a40 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/UserAttributePacket.java @@ -0,0 +1,60 @@ +package org.bc.bcpg; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.Vector; + +/** + * Basic type for a user attribute packet. + */ +public class UserAttributePacket + extends ContainedPacket +{ + private UserAttributeSubpacket[] subpackets; + + public UserAttributePacket( + BCPGInputStream in) + throws IOException + { + UserAttributeSubpacketInputStream sIn = new UserAttributeSubpacketInputStream(in); + UserAttributeSubpacket sub; + + Vector v= new Vector(); + while ((sub = sIn.readPacket()) != null) + { + v.addElement(sub); + } + + subpackets = new UserAttributeSubpacket[v.size()]; + + for (int i = 0; i != subpackets.length; i++) + { + subpackets[i] = (UserAttributeSubpacket)v.elementAt(i); + } + } + + public UserAttributePacket( + UserAttributeSubpacket[] subpackets) + { + this.subpackets = subpackets; + } + + public UserAttributeSubpacket[] getSubpackets() + { + return subpackets; + } + + public void encode( + BCPGOutputStream out) + throws IOException + { + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + for (int i = 0; i != subpackets.length; i++) + { + subpackets[i].encode(bOut); + } + + out.writePacket(USER_ATTRIBUTE, bOut.toByteArray(), false); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/UserAttributeSubpacket.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/UserAttributeSubpacket.java new file mode 100644 index 0000000..ef3d545 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/UserAttributeSubpacket.java @@ -0,0 +1,91 @@ +package org.bc.bcpg; + +import org.bc.util.Arrays; + +import java.io.IOException; +import java.io.OutputStream; + +/** + * Basic type for a user attribute sub-packet. + */ +public class UserAttributeSubpacket +{ + int type; + + protected byte[] data; + + protected UserAttributeSubpacket( + int type, + byte[] data) + { + this.type = type; + this.data = data; + } + + public int getType() + { + return type; + } + + /** + * return the generic data making up the packet. + */ + public byte[] getData() + { + return data; + } + + public void encode( + OutputStream out) + throws IOException + { + int bodyLen = data.length + 1; + + if (bodyLen < 192) + { + out.write((byte)bodyLen); + } + else if (bodyLen <= 8383) + { + bodyLen -= 192; + + out.write((byte)(((bodyLen >> 8) & 0xff) + 192)); + out.write((byte)bodyLen); + } + else + { + out.write(0xff); + out.write((byte)(bodyLen >> 24)); + out.write((byte)(bodyLen >> 16)); + out.write((byte)(bodyLen >> 8)); + out.write((byte)bodyLen); + } + + out.write(type); + out.write(data); + } + + public boolean equals( + Object o) + { + if (o == this) + { + return true; + } + + if (!(o instanceof UserAttributeSubpacket)) + { + return false; + } + + UserAttributeSubpacket other = (UserAttributeSubpacket)o; + + return this.type == other.type + && Arrays.areEqual(this.data, other.data); + } + + public int hashCode() + { + return type ^ Arrays.hashCode(data); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/UserAttributeSubpacketInputStream.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/UserAttributeSubpacketInputStream.java new file mode 100644 index 0000000..86dfe46 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/UserAttributeSubpacketInputStream.java @@ -0,0 +1,116 @@ +package org.bc.bcpg; + +import java.io.*; + +import org.bc.bcpg.attr.ImageAttribute; + +/** + * reader for user attribute sub-packets + */ +public class UserAttributeSubpacketInputStream + extends InputStream implements UserAttributeSubpacketTags +{ + InputStream in; + + public UserAttributeSubpacketInputStream( + InputStream in) + { + this.in = in; + } + + public int available() + throws IOException + { + return in.available(); + } + + public int read() + throws IOException + { + return in.read(); + } + + private void readFully( + byte[] buf, + int off, + int len) + throws IOException + { + if (len > 0) + { + int b = this.read(); + + if (b < 0) + { + throw new EOFException(); + } + + buf[off] = (byte)b; + off++; + len--; + } + + while (len > 0) + { + int l = in.read(buf, off, len); + + if (l < 0) + { + throw new EOFException(); + } + + off += l; + len -= l; + } + } + + public UserAttributeSubpacket readPacket() + throws IOException + { + int l = this.read(); + int bodyLen = 0; + + if (l < 0) + { + return null; + } + + if (l < 192) + { + bodyLen = l; + } + else if (l <= 223) + { + bodyLen = ((l - 192) << 8) + (in.read()) + 192; + } + else if (l == 255) + { + bodyLen = (in.read() << 24) | (in.read() << 16) | (in.read() << 8) | in.read(); + } + else + { + // TODO Error? + } + + int tag = in.read(); + + if (tag < 0) + { + throw new EOFException("unexpected EOF reading user attribute sub packet"); + } + + byte[] data = new byte[bodyLen - 1]; + + this.readFully(data, 0, data.length); + + int type = tag; + + switch (type) + { + case IMAGE_ATTRIBUTE: + return new ImageAttribute(data); + } + + return new UserAttributeSubpacket(type, data); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/UserAttributeSubpacketTags.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/UserAttributeSubpacketTags.java new file mode 100644 index 0000000..2714471 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/UserAttributeSubpacketTags.java @@ -0,0 +1,9 @@ +package org.bc.bcpg; + +/** + * Basic PGP user attribute sub-packet tag types. + */ +public interface UserAttributeSubpacketTags +{ + public static final int IMAGE_ATTRIBUTE = 1; +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/UserIDPacket.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/UserIDPacket.java new file mode 100644 index 0000000..49e1b19 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/UserIDPacket.java @@ -0,0 +1,40 @@ +package org.bc.bcpg; + +import java.io.IOException; + +import org.bc.util.Strings; + +/** + * Basic type for a user ID packet. + */ +public class UserIDPacket + extends ContainedPacket +{ + private byte[] idData; + + public UserIDPacket( + BCPGInputStream in) + throws IOException + { + idData = new byte[in.available()]; + in.readFully(idData); + } + + public UserIDPacket( + String id) + { + this.idData = Strings.toUTF8ByteArray(id); + } + + public String getID() + { + return Strings.fromUTF8ByteArray(idData); + } + + public void encode( + BCPGOutputStream out) + throws IOException + { + out.writePacket(USER_ID, idData, true); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/attr/ImageAttribute.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/attr/ImageAttribute.java new file mode 100644 index 0000000..28be9f9 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/attr/ImageAttribute.java @@ -0,0 +1,77 @@ +package org.bc.bcpg.attr; + +import org.bc.bcpg.UserAttributeSubpacket; +import org.bc.bcpg.UserAttributeSubpacketTags; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +/** + * Basic type for a image attribute packet. + */ +public class ImageAttribute + extends UserAttributeSubpacket +{ + public static final int JPEG = 1; + + private static final byte[] ZEROES = new byte[12]; + + private int hdrLength; + private int version; + private int encoding; + private byte[] imageData; + + public ImageAttribute( + byte[] data) + { + super(UserAttributeSubpacketTags.IMAGE_ATTRIBUTE, data); + + hdrLength = ((data[1] & 0xff) << 8) | (data[0] & 0xff); + version = data[2] & 0xff; + encoding = data[3] & 0xff; + + imageData = new byte[data.length - hdrLength]; + System.arraycopy(data, hdrLength, imageData, 0, imageData.length); + } + + public ImageAttribute( + int imageType, + byte[] imageData) + { + this(toByteArray(imageType, imageData)); + } + + private static byte[] toByteArray(int imageType, byte[] imageData) + { + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + try + { + bOut.write(0x10); bOut.write(0x00); bOut.write(0x01); + bOut.write(imageType); + bOut.write(ZEROES); + bOut.write(imageData); + } + catch (IOException e) + { + throw new RuntimeException("unable to encode to byte array!"); + } + + return bOut.toByteArray(); + } + + public int version() + { + return version; + } + + public int getEncoding() + { + return encoding; + } + + public byte[] getImageData() + { + return imageData; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/sig/EmbeddedSignature.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/sig/EmbeddedSignature.java new file mode 100644 index 0000000..5dc5639 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/sig/EmbeddedSignature.java @@ -0,0 +1,18 @@ +package org.bc.bcpg.sig; + +import org.bc.bcpg.SignatureSubpacket; +import org.bc.bcpg.SignatureSubpacketTags; + +/** + * Packet embedded signature + */ +public class EmbeddedSignature + extends SignatureSubpacket +{ + public EmbeddedSignature( + boolean critical, + byte[] data) + { + super(SignatureSubpacketTags.EMBEDDED_SIGNATURE, critical, data); + } +} \ No newline at end of file diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/sig/Exportable.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/sig/Exportable.java new file mode 100644 index 0000000..24da479 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/sig/Exportable.java @@ -0,0 +1,46 @@ +package org.bc.bcpg.sig; + +import org.bc.bcpg.SignatureSubpacket; +import org.bc.bcpg.SignatureSubpacketTags; + +/** + * packet giving signature creation time. + */ +public class Exportable + extends SignatureSubpacket +{ + private static byte[] booleanToByteArray( + boolean value) + { + byte[] data = new byte[1]; + + if (value) + { + data[0] = 1; + return data; + } + else + { + return data; + } + } + + public Exportable( + boolean critical, + byte[] data) + { + super(SignatureSubpacketTags.EXPORTABLE, critical, data); + } + + public Exportable( + boolean critical, + boolean isExportable) + { + super(SignatureSubpacketTags.EXPORTABLE, critical, booleanToByteArray(isExportable)); + } + + public boolean isExportable() + { + return data[0] != 0; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/sig/Features.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/sig/Features.java new file mode 100644 index 0000000..7250139 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/sig/Features.java @@ -0,0 +1,98 @@ +package org.bc.bcpg.sig; + +import org.bc.bcpg.SignatureSubpacket; +import org.bc.bcpg.SignatureSubpacketTags; + +public class Features + extends SignatureSubpacket +{ + + /** Identifier for the modification detection feature */ + public static final byte FEATURE_MODIFICATION_DETECTION = 1; + + private static final byte[] featureToByteArray(byte feature) + { + byte[] data = new byte[1]; + data[0] = feature; + return data; + } + + public Features(boolean critical, byte[] data) + { + super(SignatureSubpacketTags.FEATURES, critical, data); + } + + public Features(boolean critical, byte feature) + { + super(SignatureSubpacketTags.FEATURES, critical, featureToByteArray(feature)); + } + + /** + * Returns if modification detection is supported. + */ + public boolean supportsModificationDetection() + { + return supportsFeature(FEATURE_MODIFICATION_DETECTION); + } + + +// /** Class should be immutable. +// * Set modification detection support. +// */ +// public void setSupportsModificationDetection(boolean support) +// { +// setSupportsFeature(FEATURE_MODIFICATION_DETECTION, support); +// } + + + /** + * Returns if a particular feature is supported. + */ + public boolean supportsFeature(byte feature) + { + for (int i = 0; i < data.length; i++) + { + if (data[i] == feature) + { + return true; + } + } + return false; + } + + + /** + * Sets support for a particular feature. + */ + private void setSupportsFeature(byte feature, boolean support) + { + if (feature == 0) + { + throw new IllegalArgumentException("feature == 0"); + } + if (supportsFeature(feature) != support) + { + if (support == true) + { + byte[] temp = new byte[data.length + 1]; + System.arraycopy(data, 0, temp, 0, data.length); + temp[data.length] = feature; + data = temp; + } + else + { + for (int i = 0; i < data.length; i++) + { + if (data[i] == feature) + { + byte[] temp = new byte[data.length - 1]; + System.arraycopy(data, 0, temp, 0, i); + System.arraycopy(data, i + 1, temp, i, temp.length - i); + data = temp; + i = data.length + 1; + } + } + } + } + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/sig/IssuerKeyID.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/sig/IssuerKeyID.java new file mode 100644 index 0000000..d893ab4 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/sig/IssuerKeyID.java @@ -0,0 +1,50 @@ +package org.bc.bcpg.sig; + +import org.bc.bcpg.SignatureSubpacket; +import org.bc.bcpg.SignatureSubpacketTags; + +/** + * packet giving signature creation time. + */ +public class IssuerKeyID + extends SignatureSubpacket +{ + protected static byte[] keyIDToBytes( + long keyId) + { + byte[] data = new byte[8]; + + data[0] = (byte)(keyId >> 56); + data[1] = (byte)(keyId >> 48); + data[2] = (byte)(keyId >> 40); + data[3] = (byte)(keyId >> 32); + data[4] = (byte)(keyId >> 24); + data[5] = (byte)(keyId >> 16); + data[6] = (byte)(keyId >> 8); + data[7] = (byte)keyId; + + return data; + } + + public IssuerKeyID( + boolean critical, + byte[] data) + { + super(SignatureSubpacketTags.ISSUER_KEY_ID, critical, data); + } + + public IssuerKeyID( + boolean critical, + long keyID) + { + super(SignatureSubpacketTags.ISSUER_KEY_ID, critical, keyIDToBytes(keyID)); + } + + public long getKeyID() + { + long keyID = ((long)(data[0] & 0xff) << 56) | ((long)(data[1] & 0xff) << 48) | ((long)(data[2] & 0xff) << 40) | ((long)(data[3] & 0xff) << 32) + | ((long)(data[4] & 0xff) << 24) | ((data[5] & 0xff) << 16) | ((data[6] & 0xff) << 8) | (data[7] & 0xff); + + return keyID; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/sig/KeyExpirationTime.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/sig/KeyExpirationTime.java new file mode 100644 index 0000000..eb4cfd8 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/sig/KeyExpirationTime.java @@ -0,0 +1,50 @@ +package org.bc.bcpg.sig; + +import org.bc.bcpg.SignatureSubpacket; +import org.bc.bcpg.SignatureSubpacketTags; + +/** + * packet giving time after creation at which the key expires. + */ +public class KeyExpirationTime + extends SignatureSubpacket +{ + protected static byte[] timeToBytes( + long t) + { + byte[] data = new byte[4]; + + data[0] = (byte)(t >> 24); + data[1] = (byte)(t >> 16); + data[2] = (byte)(t >> 8); + data[3] = (byte)t; + + return data; + } + + public KeyExpirationTime( + boolean critical, + byte[] data) + { + super(SignatureSubpacketTags.KEY_EXPIRE_TIME, critical, data); + } + + public KeyExpirationTime( + boolean critical, + long seconds) + { + super(SignatureSubpacketTags.KEY_EXPIRE_TIME, critical, timeToBytes(seconds)); + } + + /** + * Return the number of seconds after creation time a key is valid for. + * + * @return second count for key validity. + */ + public long getTime() + { + long time = ((long)(data[0] & 0xff) << 24) | ((data[1] & 0xff) << 16) | ((data[2] & 0xff) << 8) | (data[3] & 0xff); + + return time; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/sig/KeyFlags.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/sig/KeyFlags.java new file mode 100644 index 0000000..6ca161a --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/sig/KeyFlags.java @@ -0,0 +1,73 @@ +package org.bc.bcpg.sig; + +import org.bc.bcpg.SignatureSubpacket; +import org.bc.bcpg.SignatureSubpacketTags; + +/** + * Packet holding the key flag values. + */ +public class KeyFlags + extends SignatureSubpacket +{ + public static final int CERTIFY_OTHER = 0x01; + public static final int SIGN_DATA = 0x02; + public static final int ENCRYPT_COMMS = 0x04; + public static final int ENCRYPT_STORAGE = 0x08; + public static final int SPLIT = 0x10; + public static final int AUTHENTICATION = 0x20; + public static final int SHARED = 0x80; + + private static byte[] intToByteArray( + int v) + { + byte[] tmp = new byte[4]; + int size = 0; + + for (int i = 0; i != 4; i++) + { + tmp[i] = (byte)(v >> (i * 8)); + if (tmp[i] != 0) + { + size = i; + } + } + + byte[] data = new byte[size + 1]; + + System.arraycopy(tmp, 0, data, 0, data.length); + + return data; + } + + public KeyFlags( + boolean critical, + byte[] data) + { + super(SignatureSubpacketTags.KEY_FLAGS, critical, data); + } + + public KeyFlags( + boolean critical, + int flags) + { + super(SignatureSubpacketTags.KEY_FLAGS, critical, intToByteArray(flags)); + } + + /** + * Return the flag values contained in the first 4 octets (note: at the moment + * the standard only uses the first one). + * + * @return flag values. + */ + public int getFlags() + { + int flags = 0; + + for (int i = 0; i != data.length; i++) + { + flags |= (data[i] & 0xff) << (i * 8); + } + + return flags; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/sig/NotationData.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/sig/NotationData.java new file mode 100644 index 0000000..ed10ea8 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/sig/NotationData.java @@ -0,0 +1,104 @@ +package org.bc.bcpg.sig; + +import org.bc.bcpg.SignatureSubpacket; +import org.bc.bcpg.SignatureSubpacketTags; +import org.bc.util.Strings; + +import java.io.ByteArrayOutputStream; + +/** + * Class provided a NotationData object according to + * RFC2440, Chapter 5.2.3.15. Notation Data + */ +public class NotationData + extends SignatureSubpacket +{ + public static final int HEADER_FLAG_LENGTH = 4; + public static final int HEADER_NAME_LENGTH = 2; + public static final int HEADER_VALUE_LENGTH = 2; + + public NotationData(boolean critical, byte[] data) + { + super(SignatureSubpacketTags.NOTATION_DATA, critical, data); + } + + public NotationData( + boolean critical, + boolean humanReadable, + String notationName, + String notationValue) + { + super(SignatureSubpacketTags.NOTATION_DATA, critical, createData(humanReadable, notationName, notationValue)); + } + + private static byte[] createData(boolean humanReadable, String notationName, String notationValue) + { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + +// (4 octets of flags, 2 octets of name length (M), +// 2 octets of value length (N), +// M octets of name data, +// N octets of value data) + + // flags + out.write(humanReadable ? 0x80 : 0x00); + out.write(0x0); + out.write(0x0); + out.write(0x0); + + byte[] nameData, valueData = null; + int nameLength, valueLength; + + nameData = Strings.toUTF8ByteArray(notationName); + nameLength = Math.min(nameData.length, 0xFF); + + valueData = Strings.toUTF8ByteArray(notationValue); + valueLength = Math.min(valueData.length, 0xFF); + + // name length + out.write((nameLength >>> 8) & 0xFF); + out.write((nameLength >>> 0) & 0xFF); + + // value length + out.write((valueLength >>> 8) & 0xFF); + out.write((valueLength >>> 0) & 0xFF); + + // name + out.write(nameData, 0, nameLength); + + // value + out.write(valueData, 0, valueLength); + + return out.toByteArray(); + } + + public boolean isHumanReadable() + { + return data[0] == (byte)0x80; + } + + public String getNotationName() + { + int nameLength = ((data[HEADER_FLAG_LENGTH] << 8) + (data[HEADER_FLAG_LENGTH + 1] << 0)); + + byte bName[] = new byte[nameLength]; + System.arraycopy(data, HEADER_FLAG_LENGTH + HEADER_NAME_LENGTH + HEADER_VALUE_LENGTH, bName, 0, nameLength); + + return Strings.fromUTF8ByteArray(bName); + } + + public String getNotationValue() + { + return Strings.fromUTF8ByteArray(getNotationValueBytes()); + } + + public byte[] getNotationValueBytes() + { + int nameLength = ((data[HEADER_FLAG_LENGTH] << 8) + (data[HEADER_FLAG_LENGTH + 1] << 0)); + int valueLength = ((data[HEADER_FLAG_LENGTH + HEADER_NAME_LENGTH] << 8) + (data[HEADER_FLAG_LENGTH + HEADER_NAME_LENGTH + 1] << 0)); + + byte bValue[] = new byte[valueLength]; + System.arraycopy(data, HEADER_FLAG_LENGTH + HEADER_NAME_LENGTH + HEADER_VALUE_LENGTH + nameLength, bValue, 0, valueLength); + return bValue; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/sig/PreferredAlgorithms.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/sig/PreferredAlgorithms.java new file mode 100644 index 0000000..58dbe3c --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/sig/PreferredAlgorithms.java @@ -0,0 +1,59 @@ +package org.bc.bcpg.sig; + +import org.bc.bcpg.SignatureSubpacket; + +/** + * packet giving signature creation time. + */ +public class PreferredAlgorithms + extends SignatureSubpacket +{ + private static byte[] intToByteArray( + int[] v) + { + byte[] data = new byte[v.length]; + + for (int i = 0; i != v.length; i++) + { + data[i] = (byte)v[i]; + } + + return data; + } + + public PreferredAlgorithms( + int type, + boolean critical, + byte[] data) + { + super(type, critical, data); + } + + public PreferredAlgorithms( + int type, + boolean critical, + int[] preferrences) + { + super(type, critical, intToByteArray(preferrences)); + } + + /** + * @deprecated mispelt! + */ + public int[] getPreferrences() + { + return getPreferences(); + } + + public int[] getPreferences() + { + int[] v = new int[data.length]; + + for (int i = 0; i != v.length; i++) + { + v[i] = data[i] & 0xff; + } + + return v; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/sig/PrimaryUserID.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/sig/PrimaryUserID.java new file mode 100644 index 0000000..2ef61d5 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/sig/PrimaryUserID.java @@ -0,0 +1,46 @@ +package org.bc.bcpg.sig; + +import org.bc.bcpg.SignatureSubpacket; +import org.bc.bcpg.SignatureSubpacketTags; + +/** + * packet giving whether or not the signature is signed using the primary user ID for the key. + */ +public class PrimaryUserID + extends SignatureSubpacket +{ + private static byte[] booleanToByteArray( + boolean value) + { + byte[] data = new byte[1]; + + if (value) + { + data[0] = 1; + return data; + } + else + { + return data; + } + } + + public PrimaryUserID( + boolean critical, + byte[] data) + { + super(SignatureSubpacketTags.PRIMARY_USER_ID, critical, data); + } + + public PrimaryUserID( + boolean critical, + boolean isPrimaryUserID) + { + super(SignatureSubpacketTags.PRIMARY_USER_ID, critical, booleanToByteArray(isPrimaryUserID)); + } + + public boolean isPrimaryUserID() + { + return data[0] != 0; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/sig/Revocable.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/sig/Revocable.java new file mode 100644 index 0000000..3236fe7 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/sig/Revocable.java @@ -0,0 +1,46 @@ +package org.bc.bcpg.sig; + +import org.bc.bcpg.SignatureSubpacket; +import org.bc.bcpg.SignatureSubpacketTags; + +/** + * packet giving whether or not is revocable. + */ +public class Revocable + extends SignatureSubpacket +{ + private static byte[] booleanToByteArray( + boolean value) + { + byte[] data = new byte[1]; + + if (value) + { + data[0] = 1; + return data; + } + else + { + return data; + } + } + + public Revocable( + boolean critical, + byte[] data) + { + super(SignatureSubpacketTags.REVOCABLE, critical, data); + } + + public Revocable( + boolean critical, + boolean isRevocable) + { + super(SignatureSubpacketTags.REVOCABLE, critical, booleanToByteArray(isRevocable)); + } + + public boolean isRevocable() + { + return data[0] != 0; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/sig/RevocationKey.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/sig/RevocationKey.java new file mode 100644 index 0000000..35f1a9d --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/sig/RevocationKey.java @@ -0,0 +1,52 @@ +package org.bc.bcpg.sig; + +import org.bc.bcpg.SignatureSubpacket; +import org.bc.bcpg.SignatureSubpacketTags; + +/** + * Represents revocation key OpenPGP signature sub packet. + */ +public class RevocationKey extends SignatureSubpacket +{ + // 1 octet of class, + // 1 octet of public-key algorithm ID, + // 20 octets of fingerprint + public RevocationKey(boolean isCritical, byte[] data) + { + super(SignatureSubpacketTags.REVOCATION_KEY, isCritical, data); + } + + public RevocationKey(boolean isCritical, byte signatureClass, int keyAlgorithm, + byte[] fingerprint) + { + super(SignatureSubpacketTags.REVOCATION_KEY, isCritical, createData(signatureClass, + (byte)(keyAlgorithm & 0xff), fingerprint)); + } + + private static byte[] createData(byte signatureClass, byte keyAlgorithm, byte[] fingerprint) + { + byte[] data = new byte[2 + fingerprint.length]; + data[0] = signatureClass; + data[1] = keyAlgorithm; + System.arraycopy(fingerprint, 0, data, 2, fingerprint.length); + return data; + } + + public byte getSignatureClass() + { + return this.getData()[0]; + } + + public int getAlgorithm() + { + return this.getData()[1]; + } + + public byte[] getFingerprint() + { + byte[] data = this.getData(); + byte[] fingerprint = new byte[data.length - 2]; + System.arraycopy(data, 2, fingerprint, 0, fingerprint.length); + return fingerprint; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/sig/RevocationKeyTags.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/sig/RevocationKeyTags.java new file mode 100644 index 0000000..3af9f85 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/sig/RevocationKeyTags.java @@ -0,0 +1,8 @@ +package org.bc.bcpg.sig; + +public interface RevocationKeyTags +{ + public static final byte CLASS_DEFAULT = (byte)0x80; + public static final byte CLASS_SENSITIVE = (byte)0x40; + +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/sig/RevocationReason.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/sig/RevocationReason.java new file mode 100644 index 0000000..b24655c --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/sig/RevocationReason.java @@ -0,0 +1,51 @@ +package org.bc.bcpg.sig; + +import org.bc.bcpg.SignatureSubpacket; +import org.bc.bcpg.SignatureSubpacketTags; +import org.bc.util.Strings; + +/** + * Represents revocation reason OpenPGP signature sub packet. + */ +public class RevocationReason extends SignatureSubpacket +{ + public RevocationReason(boolean isCritical, byte[] data) + { + super(SignatureSubpacketTags.REVOCATION_REASON, isCritical, data); + } + + public RevocationReason(boolean isCritical, byte reason, String description) + { + super(SignatureSubpacketTags.REVOCATION_REASON, isCritical, createData(reason, description)); + } + + private static byte[] createData(byte reason, String description) + { + byte[] descriptionBytes = Strings.toUTF8ByteArray(description); + byte[] data = new byte[1 + descriptionBytes.length]; + + data[0] = reason; + System.arraycopy(descriptionBytes, 0, data, 1, descriptionBytes.length); + + return data; + } + + public byte getRevocationReason() + { + return getData()[0]; + } + + public String getRevocationDescription() + { + byte[] data = getData(); + if (data.length == 1) + { + return ""; + } + + byte[] description = new byte[data.length - 1]; + System.arraycopy(data, 1, description, 0, description.length); + + return Strings.fromUTF8ByteArray(description); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/sig/RevocationReasonTags.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/sig/RevocationReasonTags.java new file mode 100644 index 0000000..94e505a --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/sig/RevocationReasonTags.java @@ -0,0 +1,12 @@ +package org.bc.bcpg.sig; + +public interface RevocationReasonTags +{ + public static final byte NO_REASON = 0; // No reason specified (key revocations or cert revocations) + public static final byte KEY_SUPERSEDED = 1; // Key is superseded (key revocations) + public static final byte KEY_COMPROMISED = 2; // Key material has been compromised (key revocations) + public static final byte KEY_RETIRED = 3; // Key is retired and no longer used (key revocations) + public static final byte USER_NO_LONGER_VALID = 32; // User ID information is no longer valid (cert revocations) + + // 100-110 - Private Use +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/sig/SignatureCreationTime.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/sig/SignatureCreationTime.java new file mode 100644 index 0000000..e777de5 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/sig/SignatureCreationTime.java @@ -0,0 +1,48 @@ +package org.bc.bcpg.sig; + +import java.util.Date; + +import org.bc.bcpg.SignatureSubpacket; +import org.bc.bcpg.SignatureSubpacketTags; + +/** + * packet giving signature creation time. + */ +public class SignatureCreationTime + extends SignatureSubpacket +{ + protected static byte[] timeToBytes( + Date date) + { + byte[] data = new byte[4]; + long t = date.getTime() / 1000; + + data[0] = (byte)(t >> 24); + data[1] = (byte)(t >> 16); + data[2] = (byte)(t >> 8); + data[3] = (byte)t; + + return data; + } + + public SignatureCreationTime( + boolean critical, + byte[] data) + { + super(SignatureSubpacketTags.CREATION_TIME, critical, data); + } + + public SignatureCreationTime( + boolean critical, + Date date) + { + super(SignatureSubpacketTags.CREATION_TIME, critical, timeToBytes(date)); + } + + public Date getTime() + { + long time = ((long)(data[0] & 0xff) << 24) | ((data[1] & 0xff) << 16) | ((data[2] & 0xff) << 8) | (data[3] & 0xff); + + return new Date(time * 1000); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/sig/SignatureExpirationTime.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/sig/SignatureExpirationTime.java new file mode 100644 index 0000000..d823143 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/sig/SignatureExpirationTime.java @@ -0,0 +1,48 @@ +package org.bc.bcpg.sig; + +import org.bc.bcpg.SignatureSubpacket; +import org.bc.bcpg.SignatureSubpacketTags; + +/** + * packet giving signature expiration time. + */ +public class SignatureExpirationTime + extends SignatureSubpacket +{ + protected static byte[] timeToBytes( + long t) + { + byte[] data = new byte[4]; + + data[0] = (byte)(t >> 24); + data[1] = (byte)(t >> 16); + data[2] = (byte)(t >> 8); + data[3] = (byte)t; + + return data; + } + + public SignatureExpirationTime( + boolean critical, + byte[] data) + { + super(SignatureSubpacketTags.EXPIRE_TIME, critical, data); + } + + public SignatureExpirationTime( + boolean critical, + long seconds) + { + super(SignatureSubpacketTags.EXPIRE_TIME, critical, timeToBytes(seconds)); + } + + /** + * return time in seconds before signature expires after creation time. + */ + public long getTime() + { + long time = ((long)(data[0] & 0xff) << 24) | ((data[1] & 0xff) << 16) | ((data[2] & 0xff) << 8) | (data[3] & 0xff); + + return time; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/sig/SignerUserID.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/sig/SignerUserID.java new file mode 100644 index 0000000..2a5f8f8 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/sig/SignerUserID.java @@ -0,0 +1,50 @@ +package org.bc.bcpg.sig; + +import org.bc.bcpg.SignatureSubpacket; +import org.bc.bcpg.SignatureSubpacketTags; + +/** + * packet giving the User ID of the signer. + */ +public class SignerUserID + extends SignatureSubpacket +{ + private static byte[] userIDToBytes( + String id) + { + byte[] idData = new byte[id.length()]; + + for (int i = 0; i != id.length(); i++) + { + idData[i] = (byte)id.charAt(i); + } + + return idData; + } + + public SignerUserID( + boolean critical, + byte[] data) + { + super(SignatureSubpacketTags.SIGNER_USER_ID, critical, data); + } + + public SignerUserID( + boolean critical, + String userID) + { + super(SignatureSubpacketTags.SIGNER_USER_ID, critical, userIDToBytes(userID)); + } + + public String getID() + { + char[] chars = new char[data.length]; + + for (int i = 0; i != chars.length; i++) + { + chars[i] = (char)(data[i] & 0xff); + } + + return new String(chars); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/sig/TrustSignature.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/sig/TrustSignature.java new file mode 100644 index 0000000..0facf88 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/bcpg/sig/TrustSignature.java @@ -0,0 +1,48 @@ +package org.bc.bcpg.sig; + +import org.bc.bcpg.SignatureSubpacket; +import org.bc.bcpg.SignatureSubpacketTags; + +/** + * packet giving trust. + */ +public class TrustSignature + extends SignatureSubpacket +{ + private static byte[] intToByteArray( + int v1, + int v2) + { + byte[] data = new byte[2]; + + data[0] = (byte)v1; + data[1] = (byte)v2; + + return data; + } + + public TrustSignature( + boolean critical, + byte[] data) + { + super(SignatureSubpacketTags.TRUST_SIG, critical, data); + } + + public TrustSignature( + boolean critical, + int depth, + int trustAmount) + { + super(SignatureSubpacketTags.TRUST_SIG, critical, intToByteArray(depth, trustAmount)); + } + + public int getDepth() + { + return data[0] & 0xff; + } + + public int getTrustAmount() + { + return data[1] & 0xff; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/AsymmetricBlockCipher.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/AsymmetricBlockCipher.java new file mode 100644 index 0000000..726c488 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/AsymmetricBlockCipher.java @@ -0,0 +1,45 @@ +package org.bc.crypto; + + +/** + * base interface that a public/private key block cipher needs + * to conform to. + */ +public interface AsymmetricBlockCipher +{ + /** + * initialise the cipher. + * + * @param forEncryption if true the cipher is initialised for + * encryption, if false for decryption. + * @param param the key and other data required by the cipher. + */ + public void init(boolean forEncryption, CipherParameters param); + + /** + * returns the largest size an input block can be. + * + * @return maximum size for an input block. + */ + public int getInputBlockSize(); + + /** + * returns the maximum size of the block produced by this cipher. + * + * @return maximum size of the output block produced by the cipher. + */ + public int getOutputBlockSize(); + + /** + * process the block of len bytes stored in in from offset inOff. + * + * @param in the input data + * @param inOff offset into the in array where the data starts + * @param len the length of the block to be processed. + * @return the resulting byte array of the encryption/decryption process. + * @exception InvalidCipherTextException data decrypts improperly. + * @exception DataLengthException the input data is too large for the cipher. + */ + public byte[] processBlock(byte[] in, int inOff, int len) + throws InvalidCipherTextException; +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/AsymmetricCipherKeyPair.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/AsymmetricCipherKeyPair.java new file mode 100644 index 0000000..e897ff3 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/AsymmetricCipherKeyPair.java @@ -0,0 +1,61 @@ +package org.bc.crypto; + +import org.bc.crypto.params.AsymmetricKeyParameter; + +/** + * a holding class for public/private parameter pairs. + */ +public class AsymmetricCipherKeyPair +{ + private AsymmetricKeyParameter publicParam; + private AsymmetricKeyParameter privateParam; + + /** + * basic constructor. + * + * @param publicParam a public key parameters object. + * @param privateParam the corresponding private key parameters. + */ + public AsymmetricCipherKeyPair( + AsymmetricKeyParameter publicParam, + AsymmetricKeyParameter privateParam) + { + this.publicParam = publicParam; + this.privateParam = privateParam; + } + + /** + * basic constructor. + * + * @param publicParam a public key parameters object. + * @param privateParam the corresponding private key parameters. + * @deprecated use AsymmetricKeyParameter + */ + public AsymmetricCipherKeyPair( + CipherParameters publicParam, + CipherParameters privateParam) + { + this.publicParam = (AsymmetricKeyParameter)publicParam; + this.privateParam = (AsymmetricKeyParameter)privateParam; + } + + /** + * return the public key parameters. + * + * @return the public key parameters. + */ + public AsymmetricKeyParameter getPublic() + { + return publicParam; + } + + /** + * return the private key parameters. + * + * @return the private key parameters. + */ + public AsymmetricKeyParameter getPrivate() + { + return privateParam; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/AsymmetricCipherKeyPairGenerator.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/AsymmetricCipherKeyPairGenerator.java new file mode 100644 index 0000000..5ae47e2 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/AsymmetricCipherKeyPairGenerator.java @@ -0,0 +1,22 @@ +package org.bc.crypto; + +/** + * interface that a public/private key pair generator should conform to. + */ +public interface AsymmetricCipherKeyPairGenerator +{ + /** + * intialise the key pair generator. + * + * @param param the parameters the key pair is to be initialised with. + */ + public void init(KeyGenerationParameters param); + + /** + * return an AsymmetricCipherKeyPair containing the generated keys. + * + * @return an AsymmetricCipherKeyPair containing the generated keys. + */ + public AsymmetricCipherKeyPair generateKeyPair(); +} + diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/BasicAgreement.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/BasicAgreement.java new file mode 100644 index 0000000..cd7d689 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/BasicAgreement.java @@ -0,0 +1,26 @@ +package org.bc.crypto; + +import java.math.BigInteger; + +/** + * The basic interface that basic Diffie-Hellman implementations + * conforms to. + */ +public interface BasicAgreement +{ + /** + * initialise the agreement engine. + */ + void init(CipherParameters param); + + /** + * return the field size for the agreement algorithm in bytes. + */ + int getFieldSize(); + + /** + * given a public key from a given party calculate the next + * message in the agreement sequence. + */ + BigInteger calculateAgreement(CipherParameters pubKey); +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/BlockCipher.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/BlockCipher.java new file mode 100644 index 0000000..8e71dbc --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/BlockCipher.java @@ -0,0 +1,56 @@ +package org.bc.crypto; + + +/** + * Block cipher engines are expected to conform to this interface. + */ +public interface BlockCipher +{ + /** + * Initialise the cipher. + * + * @param forEncryption if true the cipher is initialised for + * encryption, if false for decryption. + * @param params the key and other data required by the cipher. + * @exception IllegalArgumentException if the params argument is + * inappropriate. + */ + public void init(boolean forEncryption, CipherParameters params) + throws IllegalArgumentException; + + /** + * Return the name of the algorithm the cipher implements. + * + * @return the name of the algorithm the cipher implements. + */ + public String getAlgorithmName(); + + /** + * Return the block size for this cipher (in bytes). + * + * @return the block size for this cipher in bytes. + */ + public int getBlockSize(); + + /** + * Process one block of input from the array in and write it to + * the out array. + * + * @param in the array containing the input data. + * @param inOff offset into the in array the data starts at. + * @param out the array the output data will be copied into. + * @param outOff the offset into the out array the output will start at. + * @exception DataLengthException if there isn't enough data in in, or + * space in out. + * @exception IllegalStateException if the cipher isn't initialised. + * @return the number of bytes processed and produced. + */ + public int processBlock(byte[] in, int inOff, byte[] out, int outOff) + throws DataLengthException, IllegalStateException; + + /** + * Reset the cipher. After resetting the cipher is in the same state + * as it was after the last init (if there was one). + */ + public void reset(); +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/BufferedAsymmetricBlockCipher.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/BufferedAsymmetricBlockCipher.java new file mode 100644 index 0000000..6ce7910 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/BufferedAsymmetricBlockCipher.java @@ -0,0 +1,171 @@ +package org.bc.crypto; + +/** + * a buffer wrapper for an asymmetric block cipher, allowing input + * to be accumulated in a piecemeal fashion until final processing. + */ +public class BufferedAsymmetricBlockCipher +{ + protected byte[] buf; + protected int bufOff; + + private final AsymmetricBlockCipher cipher; + + /** + * base constructor. + * + * @param cipher the cipher this buffering object wraps. + */ + public BufferedAsymmetricBlockCipher( + AsymmetricBlockCipher cipher) + { + this.cipher = cipher; + } + + /** + * return the underlying cipher for the buffer. + * + * @return the underlying cipher for the buffer. + */ + public AsymmetricBlockCipher getUnderlyingCipher() + { + return cipher; + } + + /** + * return the amount of data sitting in the buffer. + * + * @return the amount of data sitting in the buffer. + */ + public int getBufferPosition() + { + return bufOff; + } + + /** + * initialise the buffer and the underlying cipher. + * + * @param forEncryption if true the cipher is initialised for + * encryption, if false for decryption. + * @param params the key and other data required by the cipher. + */ + public void init( + boolean forEncryption, + CipherParameters params) + { + reset(); + + cipher.init(forEncryption, params); + + // + // we allow for an extra byte where people are using their own padding + // mechanisms on a raw cipher. + // + buf = new byte[cipher.getInputBlockSize() + (forEncryption ? 1 : 0)]; + bufOff = 0; + } + + /** + * returns the largest size an input block can be. + * + * @return maximum size for an input block. + */ + public int getInputBlockSize() + { + return cipher.getInputBlockSize(); + } + + /** + * returns the maximum size of the block produced by this cipher. + * + * @return maximum size of the output block produced by the cipher. + */ + public int getOutputBlockSize() + { + return cipher.getOutputBlockSize(); + } + + /** + * add another byte for processing. + * + * @param in the input byte. + */ + public void processByte( + byte in) + { + if (bufOff >= buf.length) + { + throw new DataLengthException("attempt to process message too long for cipher"); + } + + buf[bufOff++] = in; + } + + /** + * add len bytes to the buffer for processing. + * + * @param in the input data + * @param inOff offset into the in array where the data starts + * @param len the length of the block to be processed. + */ + public void processBytes( + byte[] in, + int inOff, + int len) + { + if (len == 0) + { + return; + } + + if (len < 0) + { + throw new IllegalArgumentException("Can't have a negative input length!"); + } + + if (bufOff + len > buf.length) + { + throw new DataLengthException("attempt to process message too long for cipher"); + } + + System.arraycopy(in, inOff, buf, bufOff, len); + bufOff += len; + } + + /** + * process the contents of the buffer using the underlying + * cipher. + * + * @return the result of the encryption/decryption process on the + * buffer. + * @exception InvalidCipherTextException if we are given a garbage block. + */ + public byte[] doFinal() + throws InvalidCipherTextException + { + byte[] out = cipher.processBlock(buf, 0, bufOff); + + reset(); + + return out; + } + + /** + * Reset the buffer and the underlying cipher. + */ + public void reset() + { + /* + * clean the buffer. + */ + if (buf != null) + { + for (int i = 0; i < buf.length; i++) + { + buf[i] = 0; + } + } + + bufOff = 0; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/BufferedBlockCipher.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/BufferedBlockCipher.java new file mode 100644 index 0000000..05e7f9b --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/BufferedBlockCipher.java @@ -0,0 +1,313 @@ +package org.bc.crypto; + + +/** + * A wrapper class that allows block ciphers to be used to process data in + * a piecemeal fashion. The BufferedBlockCipher outputs a block only when the + * buffer is full and more data is being added, or on a doFinal. + *+ * Note: in the case where the underlying cipher is either a CFB cipher or an + * OFB one the last block may not be a multiple of the block size. + */ +public class BufferedBlockCipher +{ + protected byte[] buf; + protected int bufOff; + + protected boolean forEncryption; + protected BlockCipher cipher; + + protected boolean partialBlockOkay; + protected boolean pgpCFB; + + /** + * constructor for subclasses + */ + protected BufferedBlockCipher() + { + } + + /** + * Create a buffered block cipher without padding. + * + * @param cipher the underlying block cipher this buffering object wraps. + */ + public BufferedBlockCipher( + BlockCipher cipher) + { + this.cipher = cipher; + + buf = new byte[cipher.getBlockSize()]; + bufOff = 0; + + // + // check if we can handle partial blocks on doFinal. + // + String name = cipher.getAlgorithmName(); + int idx = name.indexOf('/') + 1; + + pgpCFB = (idx > 0 && name.startsWith("PGP", idx)); + + if (pgpCFB) + { + partialBlockOkay = true; + } + else + { + partialBlockOkay = (idx > 0 && (name.startsWith("CFB", idx) || name.startsWith("OFB", idx) || name.startsWith("OpenPGP", idx) || name.startsWith("SIC", idx) || name.startsWith("GCTR", idx))); + } + } + + /** + * return the cipher this object wraps. + * + * @return the cipher this object wraps. + */ + public BlockCipher getUnderlyingCipher() + { + return cipher; + } + + /** + * initialise the cipher. + * + * @param forEncryption if true the cipher is initialised for + * encryption, if false for decryption. + * @param params the key and other data required by the cipher. + * @exception IllegalArgumentException if the params argument is + * inappropriate. + */ + public void init( + boolean forEncryption, + CipherParameters params) + throws IllegalArgumentException + { + this.forEncryption = forEncryption; + + reset(); + + cipher.init(forEncryption, params); + } + + /** + * return the blocksize for the underlying cipher. + * + * @return the blocksize for the underlying cipher. + */ + public int getBlockSize() + { + return cipher.getBlockSize(); + } + + /** + * return the size of the output buffer required for an update + * an input of len bytes. + * + * @param len the length of the input. + * @return the space required to accommodate a call to update + * with len bytes of input. + */ + public int getUpdateOutputSize( + int len) + { + int total = len + bufOff; + int leftOver; + + if (pgpCFB) + { + leftOver = total % buf.length - (cipher.getBlockSize() + 2); + } + else + { + leftOver = total % buf.length; + } + + return total - leftOver; + } + + /** + * return the size of the output buffer required for an update plus a + * doFinal with an input of 'length' bytes. + * + * @param length the length of the input. + * @return the space required to accommodate a call to update and doFinal + * with 'length' bytes of input. + */ + public int getOutputSize( + int length) + { + // Note: Can assume partialBlockOkay is true for purposes of this calculation + return length + bufOff; + } + + /** + * process a single byte, producing an output block if neccessary. + * + * @param in the input byte. + * @param out the space for any output that might be produced. + * @param outOff the offset from which the output will be copied. + * @return the number of output bytes copied to out. + * @exception DataLengthException if there isn't enough space in out. + * @exception IllegalStateException if the cipher isn't initialised. + */ + public int processByte( + byte in, + byte[] out, + int outOff) + throws DataLengthException, IllegalStateException + { + int resultLen = 0; + + buf[bufOff++] = in; + + if (bufOff == buf.length) + { + resultLen = cipher.processBlock(buf, 0, out, outOff); + bufOff = 0; + } + + return resultLen; + } + + /** + * process an array of bytes, producing output if necessary. + * + * @param in the input byte array. + * @param inOff the offset at which the input data starts. + * @param len the number of bytes to be copied out of the input array. + * @param out the space for any output that might be produced. + * @param outOff the offset from which the output will be copied. + * @return the number of output bytes copied to out. + * @exception DataLengthException if there isn't enough space in out. + * @exception IllegalStateException if the cipher isn't initialised. + */ + public int processBytes( + byte[] in, + int inOff, + int len, + byte[] out, + int outOff) + throws DataLengthException, IllegalStateException + { + if (len < 0) + { + throw new IllegalArgumentException("Can't have a negative input length!"); + } + + int blockSize = getBlockSize(); + int length = getUpdateOutputSize(len); + + if (length > 0) + { + if ((outOff + length) > out.length) + { + throw new OutputLengthException("output buffer too short"); + } + } + + int resultLen = 0; + int gapLen = buf.length - bufOff; + + if (len > gapLen) + { + System.arraycopy(in, inOff, buf, bufOff, gapLen); + + resultLen += cipher.processBlock(buf, 0, out, outOff); + + bufOff = 0; + len -= gapLen; + inOff += gapLen; + + while (len > buf.length) + { + resultLen += cipher.processBlock(in, inOff, out, outOff + resultLen); + + len -= blockSize; + inOff += blockSize; + } + } + + System.arraycopy(in, inOff, buf, bufOff, len); + + bufOff += len; + + if (bufOff == buf.length) + { + resultLen += cipher.processBlock(buf, 0, out, outOff + resultLen); + bufOff = 0; + } + + return resultLen; + } + + /** + * Process the last block in the buffer. + * + * @param out the array the block currently being held is copied into. + * @param outOff the offset at which the copying starts. + * @return the number of output bytes copied to out. + * @exception DataLengthException if there is insufficient space in out for + * the output, or the input is not block size aligned and should be. + * @exception IllegalStateException if the underlying cipher is not + * initialised. + * @exception InvalidCipherTextException if padding is expected and not found. + * @exception DataLengthException if the input is not block size + * aligned. + */ + public int doFinal( + byte[] out, + int outOff) + throws DataLengthException, IllegalStateException, InvalidCipherTextException + { + try + { + int resultLen = 0; + + if (outOff + bufOff > out.length) + { + throw new OutputLengthException("output buffer too short for doFinal()"); + } + + if (bufOff != 0) + { + if (!partialBlockOkay) + { + throw new DataLengthException("data not block size aligned"); + } + + cipher.processBlock(buf, 0, buf, 0); + resultLen = bufOff; + bufOff = 0; + System.arraycopy(buf, 0, out, outOff, resultLen); + } + + return resultLen; + } + finally + { + reset(); + } + } + + /** + * Reset the buffer and cipher. After resetting the object is in the same + * state as it was after the last init (if there was one). + */ + public void reset() + { + // + // clean the buffer. + // + for (int i = 0; i < buf.length; i++) + { + buf[i] = 0; + } + + bufOff = 0; + + // + // reset the underlying cipher. + // + cipher.reset(); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/CipherKeyGenerator.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/CipherKeyGenerator.java new file mode 100644 index 0000000..94e2aed --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/CipherKeyGenerator.java @@ -0,0 +1,38 @@ +package org.bc.crypto; + +import java.security.SecureRandom; + +/** + * The base class for symmetric, or secret, cipher key generators. + */ +public class CipherKeyGenerator +{ + protected SecureRandom random; + protected int strength; + + /** + * initialise the key generator. + * + * @param param the parameters to be used for key generation + */ + public void init( + KeyGenerationParameters param) + { + this.random = param.getRandom(); + this.strength = (param.getStrength() + 7) / 8; + } + + /** + * generate a secret key. + * + * @return a byte array containing the key value. + */ + public byte[] generateKey() + { + byte[] key = new byte[strength]; + + random.nextBytes(key); + + return key; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/CipherParameters.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/CipherParameters.java new file mode 100644 index 0000000..683093c --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/CipherParameters.java @@ -0,0 +1,8 @@ +package org.bc.crypto; + +/** + * all parameter classes implement this. + */ +public interface CipherParameters +{ +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/CryptoException.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/CryptoException.java new file mode 100644 index 0000000..17411a8 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/CryptoException.java @@ -0,0 +1,48 @@ +package org.bc.crypto; + +/** + * the foundation class for the hard exceptions thrown by the crypto packages. + */ +public class CryptoException + extends Exception +{ + private Throwable cause; + + /** + * base constructor. + */ + public CryptoException() + { + } + + /** + * create a CryptoException with the given message. + * + * @param message the message to be carried with the exception. + */ + public CryptoException( + String message) + { + super(message); + } + + /** + * Create a CryptoException with the given message and underlying cause. + * + * @param message message describing exception. + * @param cause the throwable that was the underlying cause. + */ + public CryptoException( + String message, + Throwable cause) + { + super(message); + + this.cause = cause; + } + + public Throwable getCause() + { + return cause; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/DSA.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/DSA.java new file mode 100644 index 0000000..2dc5ac8 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/DSA.java @@ -0,0 +1,36 @@ +package org.bc.crypto; + +import java.math.BigInteger; + +/** + * interface for classes implementing algorithms modeled similar to the Digital Signature Alorithm. + */ +public interface DSA +{ + /** + * initialise the signer for signature generation or signature + * verification. + * + * @param forSigning true if we are generating a signature, false + * otherwise. + * @param param key parameters for signature generation. + */ + public void init(boolean forSigning, CipherParameters param); + + /** + * sign the passed in message (usually the output of a hash function). + * + * @param message the message to be signed. + * @return two big integers representing the r and s values respectively. + */ + public BigInteger[] generateSignature(byte[] message); + + /** + * verify the message message against the signature values r and s. + * + * @param message the message that was supposed to have been signed. + * @param r the r signature value. + * @param s the s signature value. + */ + public boolean verifySignature(byte[] message, BigInteger r, BigInteger s); +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/DataLengthException.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/DataLengthException.java new file mode 100644 index 0000000..b9d76a0 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/DataLengthException.java @@ -0,0 +1,29 @@ +package org.bc.crypto; + +/** + * this exception is thrown if a buffer that is meant to have output + * copied into it turns out to be too short, or if we've been given + * insufficient input. In general this exception will get thrown rather + * than an ArrayOutOfBounds exception. + */ +public class DataLengthException + extends RuntimeCryptoException +{ + /** + * base constructor. + */ + public DataLengthException() + { + } + + /** + * create a DataLengthException with the given message. + * + * @param message the message to be carried with the exception. + */ + public DataLengthException( + String message) + { + super(message); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/DerivationFunction.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/DerivationFunction.java new file mode 100644 index 0000000..b545911 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/DerivationFunction.java @@ -0,0 +1,17 @@ +package org.bc.crypto; + +/** + * base interface for general purpose byte derivation functions. + */ +public interface DerivationFunction +{ + public void init(DerivationParameters param); + + /** + * return the message digest used as the basis for the function + */ + public Digest getDigest(); + + public int generateBytes(byte[] out, int outOff, int len) + throws DataLengthException, IllegalArgumentException; +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/DerivationParameters.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/DerivationParameters.java new file mode 100644 index 0000000..75e1075 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/DerivationParameters.java @@ -0,0 +1,8 @@ +package org.bc.crypto; + +/** + * Parameters for key/byte stream derivation classes + */ +public interface DerivationParameters +{ +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/Digest.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/Digest.java new file mode 100644 index 0000000..feeb99e --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/Digest.java @@ -0,0 +1,51 @@ +package org.bc.crypto; + +/** + * interface that a message digest conforms to. + */ +public interface Digest +{ + /** + * return the algorithm name + * + * @return the algorithm name + */ + public String getAlgorithmName(); + + /** + * return the size, in bytes, of the digest produced by this message digest. + * + * @return the size, in bytes, of the digest produced by this message digest. + */ + public int getDigestSize(); + + /** + * update the message digest with a single byte. + * + * @param in the input byte to be entered. + */ + public void update(byte in); + + /** + * update the message digest with a block of bytes. + * + * @param in the byte array containing the data. + * @param inOff the offset into the byte array where the data starts. + * @param len the length of the data. + */ + public void update(byte[] in, int inOff, int len); + + /** + * close the digest, producing the final digest value. The doFinal + * call leaves the digest reset. + * + * @param out the array the digest is to be copied into. + * @param outOff the offset into the out array the digest is to start at. + */ + public int doFinal(byte[] out, int outOff); + + /** + * reset the digest back to it's initial state. + */ + public void reset(); +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/EphemeralKeyPair.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/EphemeralKeyPair.java new file mode 100644 index 0000000..28d03b3 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/EphemeralKeyPair.java @@ -0,0 +1,23 @@ +package org.bc.crypto; + +public class EphemeralKeyPair +{ + private AsymmetricCipherKeyPair keyPair; + private KeyEncoder publicKeyEncoder; + + public EphemeralKeyPair(AsymmetricCipherKeyPair keyPair, KeyEncoder publicKeyEncoder) + { + this.keyPair = keyPair; + this.publicKeyEncoder = publicKeyEncoder; + } + + public AsymmetricCipherKeyPair getKeyPair() + { + return keyPair; + } + + public byte[] getEncodedPublicKey() + { + return publicKeyEncoder.getEncoded(keyPair.getPublic()); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/ExtendedDigest.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/ExtendedDigest.java new file mode 100644 index 0000000..07eef70 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/ExtendedDigest.java @@ -0,0 +1,13 @@ +package org.bc.crypto; + +public interface ExtendedDigest + extends Digest +{ + /** + * Return the size in bytes of the internal buffer the digest applies it's compression + * function to. + * + * @return byte length of the digests internal buffer. + */ + public int getByteLength(); +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/InvalidCipherTextException.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/InvalidCipherTextException.java new file mode 100644 index 0000000..48c9f9b --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/InvalidCipherTextException.java @@ -0,0 +1,40 @@ +package org.bc.crypto; + +/** + * this exception is thrown whenever we find something we don't expect in a + * message. + */ +public class InvalidCipherTextException + extends CryptoException +{ + /** + * base constructor. + */ + public InvalidCipherTextException() + { + } + + /** + * create a InvalidCipherTextException with the given message. + * + * @param message the message to be carried with the exception. + */ + public InvalidCipherTextException( + String message) + { + super(message); + } + + /** + * create a InvalidCipherTextException with the given message. + * + * @param message the message to be carried with the exception. + * @param cause the root cause of the exception. + */ + public InvalidCipherTextException( + String message, + Throwable cause) + { + super(message, cause); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/KeyEncoder.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/KeyEncoder.java new file mode 100644 index 0000000..1164ae9 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/KeyEncoder.java @@ -0,0 +1,8 @@ +package org.bc.crypto; + +import org.bc.crypto.params.AsymmetricKeyParameter; + +public interface KeyEncoder +{ + byte[] getEncoded(AsymmetricKeyParameter keyParameter); +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/KeyGenerationParameters.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/KeyGenerationParameters.java new file mode 100644 index 0000000..dff6433 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/KeyGenerationParameters.java @@ -0,0 +1,48 @@ +package org.bc.crypto; + +import java.security.SecureRandom; + +/** + * The base class for parameters to key generators. + */ +public class KeyGenerationParameters +{ + private SecureRandom random; + private int strength; + + /** + * initialise the generator with a source of randomness + * and a strength (in bits). + * + * @param random the random byte source. + * @param strength the size, in bits, of the keys we want to produce. + */ + public KeyGenerationParameters( + SecureRandom random, + int strength) + { + this.random = random; + this.strength = strength; + } + + /** + * return the random source associated with this + * generator. + * + * @return the generators random source. + */ + public SecureRandom getRandom() + { + return random; + } + + /** + * return the bit strength for keys produced by this generator, + * + * @return the strength of the keys this generator produces (in bits). + */ + public int getStrength() + { + return strength; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/KeyParser.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/KeyParser.java new file mode 100644 index 0000000..a5634cd --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/KeyParser.java @@ -0,0 +1,12 @@ +package org.bc.crypto; + +import java.io.IOException; +import java.io.InputStream; + +import org.bc.crypto.params.AsymmetricKeyParameter; + +public interface KeyParser +{ + AsymmetricKeyParameter readKey(InputStream stream) + throws IOException; +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/Mac.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/Mac.java new file mode 100644 index 0000000..09f18af --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/Mac.java @@ -0,0 +1,71 @@ +package org.bc.crypto; + + +/** + * The base interface for implementations of message authentication codes (MACs). + */ +public interface Mac +{ + /** + * Initialise the MAC. + * + * @param params the key and other data required by the MAC. + * @exception IllegalArgumentException if the params argument is + * inappropriate. + */ + public void init(CipherParameters params) + throws IllegalArgumentException; + + /** + * Return the name of the algorithm the MAC implements. + * + * @return the name of the algorithm the MAC implements. + */ + public String getAlgorithmName(); + + /** + * Return the block size for this MAC (in bytes). + * + * @return the block size for this MAC in bytes. + */ + public int getMacSize(); + + /** + * add a single byte to the mac for processing. + * + * @param in the byte to be processed. + * @exception IllegalStateException if the MAC is not initialised. + */ + public void update(byte in) + throws IllegalStateException; + + /** + * @param in the array containing the input. + * @param inOff the index in the array the data begins at. + * @param len the length of the input starting at inOff. + * @exception IllegalStateException if the MAC is not initialised. + * @exception DataLengthException if there isn't enough data in in. + */ + public void update(byte[] in, int inOff, int len) + throws DataLengthException, IllegalStateException; + + /** + * Compute the final stage of the MAC writing the output to the out + * parameter. + *
+ * doFinal leaves the MAC in the same state it was after the last init. + * + * @param out the array the MAC is to be output to. + * @param outOff the offset into the out buffer the output is to start at. + * @exception DataLengthException if there isn't enough space in out. + * @exception IllegalStateException if the MAC is not initialised. + */ + public int doFinal(byte[] out, int outOff) + throws DataLengthException, IllegalStateException; + + /** + * Reset the MAC. At the end of resetting the MAC should be in the + * in the same state it was after the last init (if there was one). + */ + public void reset(); +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/MaxBytesExceededException.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/MaxBytesExceededException.java new file mode 100644 index 0000000..dd3fc14 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/MaxBytesExceededException.java @@ -0,0 +1,27 @@ +package org.bc.crypto; + +/** + * this exception is thrown whenever a cipher requires a change of key, iv + * or similar after x amount of bytes enciphered + */ +public class MaxBytesExceededException + extends RuntimeCryptoException +{ + /** + * base constructor. + */ + public MaxBytesExceededException() + { + } + + /** + * create an with the given message. + * + * @param message the message to be carried with the exception. + */ + public MaxBytesExceededException( + String message) + { + super(message); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/OutputLengthException.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/OutputLengthException.java new file mode 100644 index 0000000..5de00ce --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/OutputLengthException.java @@ -0,0 +1,10 @@ +package org.bc.crypto; + +public class OutputLengthException + extends DataLengthException +{ + public OutputLengthException(String msg) + { + super(msg); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/PBEParametersGenerator.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/PBEParametersGenerator.java new file mode 100644 index 0000000..549edd7 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/PBEParametersGenerator.java @@ -0,0 +1,164 @@ +package org.bc.crypto; + +import org.bc.util.Strings; + +/** + * super class for all Password Based Encryption (PBE) parameter generator classes. + */ +public abstract class PBEParametersGenerator +{ + protected byte[] password; + protected byte[] salt; + protected int iterationCount; + + /** + * base constructor. + */ + protected PBEParametersGenerator() + { + } + + /** + * initialise the PBE generator. + * + * @param password the password converted into bytes (see below). + * @param salt the salt to be mixed with the password. + * @param iterationCount the number of iterations the "mixing" function + * is to be applied for. + */ + public void init( + byte[] password, + byte[] salt, + int iterationCount) + { + this.password = password; + this.salt = salt; + this.iterationCount = iterationCount; + } + + /** + * return the password byte array. + * + * @return the password byte array. + */ + public byte[] getPassword() + { + return password; + } + + /** + * return the salt byte array. + * + * @return the salt byte array. + */ + public byte[] getSalt() + { + return salt; + } + + /** + * return the iteration count. + * + * @return the iteration count. + */ + public int getIterationCount() + { + return iterationCount; + } + + /** + * generate derived parameters for a key of length keySize. + * + * @param keySize the length, in bits, of the key required. + * @return a parameters object representing a key. + */ + public abstract CipherParameters generateDerivedParameters(int keySize); + + /** + * generate derived parameters for a key of length keySize, and + * an initialisation vector (IV) of length ivSize. + * + * @param keySize the length, in bits, of the key required. + * @param ivSize the length, in bits, of the iv required. + * @return a parameters object representing a key and an IV. + */ + public abstract CipherParameters generateDerivedParameters(int keySize, int ivSize); + + /** + * generate derived parameters for a key of length keySize, specifically + * for use with a MAC. + * + * @param keySize the length, in bits, of the key required. + * @return a parameters object representing a key. + */ + public abstract CipherParameters generateDerivedMacParameters(int keySize); + + /** + * converts a password to a byte array according to the scheme in + * PKCS5 (ascii, no padding) + * + * @param password a character array representing the password. + * @return a byte array representing the password. + */ + public static byte[] PKCS5PasswordToBytes( + char[] password) + { + if (password != null) + { + byte[] bytes = new byte[password.length]; + + for (int i = 0; i != bytes.length; i++) + { + bytes[i] = (byte)password[i]; + } + + return bytes; + } + else + { + return new byte[0]; + } + } + + /** + * converts a password to a byte array according to the scheme in + * PKCS5 (UTF-8, no padding) + * + * @param password a character array representing the password. + * @return a byte array representing the password. + */ + public static byte[] PKCS5PasswordToUTF8Bytes( + char[] password) + { + return Strings.toUTF8ByteArray(password); + } + + /** + * converts a password to a byte array according to the scheme in + * PKCS12 (unicode, big endian, 2 zero pad bytes at the end). + * + * @param password a character array representing the password. + * @return a byte array representing the password. + */ + public static byte[] PKCS12PasswordToBytes( + char[] password) + { + if (password != null && password.length > 0) + { + // +1 for extra 2 pad bytes. + byte[] bytes = new byte[(password.length + 1) * 2]; + + for (int i = 0; i != password.length; i ++) + { + bytes[i * 2] = (byte)(password[i] >>> 8); + bytes[i * 2 + 1] = (byte)password[i]; + } + + return bytes; + } + else + { + return new byte[0]; + } + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/RuntimeCryptoException.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/RuntimeCryptoException.java new file mode 100644 index 0000000..98daa3a --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/RuntimeCryptoException.java @@ -0,0 +1,26 @@ +package org.bc.crypto; + +/** + * the foundation class for the exceptions thrown by the crypto packages. + */ +public class RuntimeCryptoException + extends RuntimeException +{ + /** + * base constructor. + */ + public RuntimeCryptoException() + { + } + + /** + * create a RuntimeCryptoException with the given message. + * + * @param message the message to be carried with the exception. + */ + public RuntimeCryptoException( + String message) + { + super(message); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/Signer.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/Signer.java new file mode 100644 index 0000000..b1d8bc8 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/Signer.java @@ -0,0 +1,43 @@ +package org.bc.crypto; + +/** + * Generic signer interface for hash based and message recovery signers. + */ +public interface Signer +{ + /** + * Initialise the signer for signing or verification. + * + * @param forSigning true if for signing, false otherwise + * @param param necessary parameters. + */ + public void init(boolean forSigning, CipherParameters param); + + /** + * update the internal digest with the byte b + */ + public void update(byte b); + + /** + * update the internal digest with the byte array in + */ + public void update(byte[] in, int off, int len); + + /** + * generate a signature for the message we've been loaded with using + * the key we were initialised with. + */ + public byte[] generateSignature() + throws CryptoException, DataLengthException; + + /** + * return true if the internal state represents the signature described + * in the passed in array. + */ + public boolean verifySignature(byte[] signature); + + /** + * reset the internal state + */ + public void reset(); +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/SignerWithRecovery.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/SignerWithRecovery.java new file mode 100644 index 0000000..1407e32 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/SignerWithRecovery.java @@ -0,0 +1,34 @@ +package org.bc.crypto; + +/** + * Signer with message recovery. + */ +public interface SignerWithRecovery + extends Signer +{ + /** + * Returns true if the signer has recovered the full message as + * part of signature verification. + * + * @return true if full message recovered. + */ + public boolean hasFullMessage(); + + /** + * Returns a reference to what message was recovered (if any). + * + * @return full/partial message, null if nothing. + */ + public byte[] getRecoveredMessage(); + + /** + * Perform an update with the recovered message before adding any other data. This must + * be the first update method called, and calling it will result in the signer assuming + * that further calls to update will include message content past what is recoverable. + * + * @param signature the signature that we are in the process of verifying. + * @throws IllegalStateException + */ + public void updateWithRecoveredMessage(byte[] signature) + throws InvalidCipherTextException; +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/StreamBlockCipher.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/StreamBlockCipher.java new file mode 100644 index 0000000..e04723e --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/StreamBlockCipher.java @@ -0,0 +1,108 @@ +package org.bc.crypto; + +/** + * a wrapper for block ciphers with a single byte block size, so that they + * can be treated like stream ciphers. + */ +public class StreamBlockCipher + implements StreamCipher +{ + private BlockCipher cipher; + + private byte[] oneByte = new byte[1]; + + /** + * basic constructor. + * + * @param cipher the block cipher to be wrapped. + * @exception IllegalArgumentException if the cipher has a block size other than + * one. + */ + public StreamBlockCipher( + BlockCipher cipher) + { + if (cipher.getBlockSize() != 1) + { + throw new IllegalArgumentException("block cipher block size != 1."); + } + + this.cipher = cipher; + } + + /** + * initialise the underlying cipher. + * + * @param forEncryption true if we are setting up for encryption, false otherwise. + * @param params the necessary parameters for the underlying cipher to be initialised. + */ + public void init( + boolean forEncryption, + CipherParameters params) + { + cipher.init(forEncryption, params); + } + + /** + * return the name of the algorithm we are wrapping. + * + * @return the name of the algorithm we are wrapping. + */ + public String getAlgorithmName() + { + return cipher.getAlgorithmName(); + } + + /** + * encrypt/decrypt a single byte returning the result. + * + * @param in the byte to be processed. + * @return the result of processing the input byte. + */ + public byte returnByte( + byte in) + { + oneByte[0] = in; + + cipher.processBlock(oneByte, 0, oneByte, 0); + + return oneByte[0]; + } + + /** + * process a block of bytes from in putting the result into out. + * + * @param in the input byte array. + * @param inOff the offset into the in array where the data to be processed starts. + * @param len the number of bytes to be processed. + * @param out the output buffer the processed bytes go into. + * @param outOff the offset into the output byte array the processed data stars at. + * @exception DataLengthException if the output buffer is too small. + */ + public void processBytes( + byte[] in, + int inOff, + int len, + byte[] out, + int outOff) + throws DataLengthException + { + if (outOff + len > out.length) + { + throw new DataLengthException("output buffer too small in processBytes()"); + } + + for (int i = 0; i != len; i++) + { + cipher.processBlock(in, inOff + i, out, outOff + i); + } + } + + /** + * reset the underlying cipher. This leaves it in the same state + * it was at after the last init (if there was one). + */ + public void reset() + { + cipher.reset(); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/StreamCipher.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/StreamCipher.java new file mode 100644 index 0000000..6335363 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/StreamCipher.java @@ -0,0 +1,53 @@ +package org.bc.crypto; + +/** + * the interface stream ciphers conform to. + */ +public interface StreamCipher +{ + /** + * Initialise the cipher. + * + * @param forEncryption if true the cipher is initialised for + * encryption, if false for decryption. + * @param params the key and other data required by the cipher. + * @exception IllegalArgumentException if the params argument is + * inappropriate. + */ + public void init(boolean forEncryption, CipherParameters params) + throws IllegalArgumentException; + + /** + * Return the name of the algorithm the cipher implements. + * + * @return the name of the algorithm the cipher implements. + */ + public String getAlgorithmName(); + + /** + * encrypt/decrypt a single byte returning the result. + * + * @param in the byte to be processed. + * @return the result of processing the input byte. + */ + public byte returnByte(byte in); + + /** + * process a block of bytes from in putting the result into out. + * + * @param in the input byte array. + * @param inOff the offset into the in array where the data to be processed starts. + * @param len the number of bytes to be processed. + * @param out the output buffer the processed bytes go into. + * @param outOff the offset into the output byte array the processed data starts at. + * @exception DataLengthException if the output buffer is too small. + */ + public void processBytes(byte[] in, int inOff, int len, byte[] out, int outOff) + throws DataLengthException; + + /** + * reset the cipher. This leaves it in the same state + * it was at after the last init (if there was one). + */ + public void reset(); +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/Wrapper.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/Wrapper.java new file mode 100644 index 0000000..7868a30 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/Wrapper.java @@ -0,0 +1,18 @@ +package org.bc.crypto; + +public interface Wrapper +{ + public void init(boolean forWrapping, CipherParameters param); + + /** + * Return the name of the algorithm the wrapper implements. + * + * @return the name of the algorithm the wrapper implements. + */ + public String getAlgorithmName(); + + public byte[] wrap(byte[] in, int inOff, int inLen); + + public byte[] unwrap(byte[] in, int inOff, int inLen) + throws InvalidCipherTextException; +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/agreement/DHAgreement.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/agreement/DHAgreement.java new file mode 100644 index 0000000..9d6aa2a --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/agreement/DHAgreement.java @@ -0,0 +1,94 @@ +package org.bc.crypto.agreement; + +import java.math.BigInteger; +import java.security.SecureRandom; + +import org.bc.crypto.AsymmetricCipherKeyPair; +import org.bc.crypto.CipherParameters; +import org.bc.crypto.generators.DHKeyPairGenerator; +import org.bc.crypto.params.AsymmetricKeyParameter; +import org.bc.crypto.params.DHKeyGenerationParameters; +import org.bc.crypto.params.DHParameters; +import org.bc.crypto.params.DHPrivateKeyParameters; +import org.bc.crypto.params.DHPublicKeyParameters; +import org.bc.crypto.params.ParametersWithRandom; + +/** + * a Diffie-Hellman key exchange engine. + *
+ * note: This uses MTI/A0 key agreement in order to make the key agreement + * secure against passive attacks. If you're doing Diffie-Hellman and both + * parties have long term public keys you should look at using this. For + * further information have a look at RFC 2631. + *
+ * It's possible to extend this to more than two parties as well, for the moment + * that is left as an exercise for the reader. + */ +public class DHAgreement +{ + private DHPrivateKeyParameters key; + private DHParameters dhParams; + private BigInteger privateValue; + private SecureRandom random; + + public void init( + CipherParameters param) + { + AsymmetricKeyParameter kParam; + + if (param instanceof ParametersWithRandom) + { + ParametersWithRandom rParam = (ParametersWithRandom)param; + + this.random = rParam.getRandom(); + kParam = (AsymmetricKeyParameter)rParam.getParameters(); + } + else + { + this.random = new SecureRandom(); + kParam = (AsymmetricKeyParameter)param; + } + + + if (!(kParam instanceof DHPrivateKeyParameters)) + { + throw new IllegalArgumentException("DHEngine expects DHPrivateKeyParameters"); + } + + this.key = (DHPrivateKeyParameters)kParam; + this.dhParams = key.getParameters(); + } + + /** + * calculate our initial message. + */ + public BigInteger calculateMessage() + { + DHKeyPairGenerator dhGen = new DHKeyPairGenerator(); + dhGen.init(new DHKeyGenerationParameters(random, dhParams)); + AsymmetricCipherKeyPair dhPair = dhGen.generateKeyPair(); + + this.privateValue = ((DHPrivateKeyParameters)dhPair.getPrivate()).getX(); + + return ((DHPublicKeyParameters)dhPair.getPublic()).getY(); + } + + /** + * given a message from a given party and the corresponding public key, + * calculate the next message in the agreement sequence. In this case + * this will represent the shared secret. + */ + public BigInteger calculateAgreement( + DHPublicKeyParameters pub, + BigInteger message) + { + if (!pub.getParameters().equals(dhParams)) + { + throw new IllegalArgumentException("Diffie-Hellman public key has wrong parameters."); + } + + BigInteger p = dhParams.getP(); + + return message.modPow(key.getX(), p).multiply(pub.getY().modPow(privateValue, p)).mod(p); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/agreement/DHBasicAgreement.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/agreement/DHBasicAgreement.java new file mode 100644 index 0000000..85871aa --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/agreement/DHBasicAgreement.java @@ -0,0 +1,71 @@ +package org.bc.crypto.agreement; + +import java.math.BigInteger; + +import org.bc.crypto.BasicAgreement; +import org.bc.crypto.CipherParameters; +import org.bc.crypto.params.AsymmetricKeyParameter; +import org.bc.crypto.params.DHParameters; +import org.bc.crypto.params.DHPrivateKeyParameters; +import org.bc.crypto.params.DHPublicKeyParameters; +import org.bc.crypto.params.ParametersWithRandom; + +/** + * a Diffie-Hellman key agreement class. + *
+ * note: This is only the basic algorithm, it doesn't take advantage of + * long term public keys if they are available. See the DHAgreement class + * for a "better" implementation. + */ +public class DHBasicAgreement + implements BasicAgreement +{ + private DHPrivateKeyParameters key; + private DHParameters dhParams; + + public void init( + CipherParameters param) + { + AsymmetricKeyParameter kParam; + + if (param instanceof ParametersWithRandom) + { + ParametersWithRandom rParam = (ParametersWithRandom)param; + kParam = (AsymmetricKeyParameter)rParam.getParameters(); + } + else + { + kParam = (AsymmetricKeyParameter)param; + } + + if (!(kParam instanceof DHPrivateKeyParameters)) + { + throw new IllegalArgumentException("DHEngine expects DHPrivateKeyParameters"); + } + + this.key = (DHPrivateKeyParameters)kParam; + this.dhParams = key.getParameters(); + } + + public int getFieldSize() + { + return (key.getParameters().getP().bitLength() + 7) / 8; + } + + /** + * given a short term public key from a given party calculate the next + * message in the agreement sequence. + */ + public BigInteger calculateAgreement( + CipherParameters pubKey) + { + DHPublicKeyParameters pub = (DHPublicKeyParameters)pubKey; + + if (!pub.getParameters().equals(dhParams)) + { + throw new IllegalArgumentException("Diffie-Hellman public key has wrong parameters."); + } + + return pub.getY().modPow(key.getX(), dhParams.getP()); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/agreement/ECDHBasicAgreement.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/agreement/ECDHBasicAgreement.java new file mode 100644 index 0000000..6d98ce9 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/agreement/ECDHBasicAgreement.java @@ -0,0 +1,51 @@ +package org.bc.crypto.agreement; + +import java.math.BigInteger; + +import org.bc.crypto.BasicAgreement; +import org.bc.crypto.CipherParameters; +import org.bc.crypto.params.ECPrivateKeyParameters; +import org.bc.crypto.params.ECPublicKeyParameters; +import org.bc.math.ec.ECPoint; + +/** + * P1363 7.2.1 ECSVDP-DH + * + * ECSVDP-DH is Elliptic Curve Secret Value Derivation Primitive, + * Diffie-Hellman version. It is based on the work of [DH76], [Mil86], + * and [Kob87]. This primitive derives a shared secret value from one + * party's private key and another party's public key, where both have + * the same set of EC domain parameters. If two parties correctly + * execute this primitive, they will produce the same output. This + * primitive can be invoked by a scheme to derive a shared secret key; + * specifically, it may be used with the schemes ECKAS-DH1 and + * DL/ECKAS-DH2. It assumes that the input keys are valid (see also + * Section 7.2.2). + */ +public class ECDHBasicAgreement + implements BasicAgreement +{ + private ECPrivateKeyParameters key; + + public void init( + CipherParameters key) + { + this.key = (ECPrivateKeyParameters)key; + } + + public int getFieldSize() + { + return (key.getParameters().getCurve().getFieldSize() + 7) / 8; + } + + public BigInteger calculateAgreement( + CipherParameters pubKey) + { + ECPublicKeyParameters pub = (ECPublicKeyParameters)pubKey; + ECPoint P = pub.getQ().multiply(key.getD()); + + // if (p.isInfinity()) throw new RuntimeException("d*Q == infinity"); + + return P.getX().toBigInteger(); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/agreement/ECDHCBasicAgreement.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/agreement/ECDHCBasicAgreement.java new file mode 100644 index 0000000..279ffc0 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/agreement/ECDHCBasicAgreement.java @@ -0,0 +1,58 @@ +package org.bc.crypto.agreement; + +import java.math.BigInteger; + +import org.bc.crypto.BasicAgreement; +import org.bc.crypto.CipherParameters; +import org.bc.crypto.params.ECDomainParameters; +import org.bc.crypto.params.ECPrivateKeyParameters; +import org.bc.crypto.params.ECPublicKeyParameters; +import org.bc.math.ec.ECPoint; + +/** + * P1363 7.2.2 ECSVDP-DHC + * + * ECSVDP-DHC is Elliptic Curve Secret Value Derivation Primitive, + * Diffie-Hellman version with cofactor multiplication. It is based on + * the work of [DH76], [Mil86], [Kob87], [LMQ98] and [Kal98a]. This + * primitive derives a shared secret value from one party's private key + * and another party's public key, where both have the same set of EC + * domain parameters. If two parties correctly execute this primitive, + * they will produce the same output. This primitive can be invoked by a + * scheme to derive a shared secret key; specifically, it may be used + * with the schemes ECKAS-DH1 and DL/ECKAS-DH2. It does not assume the + * validity of the input public key (see also Section 7.2.1). + *
+ * Note: As stated P1363 compatibility mode with ECDH can be preset, and + * in this case the implementation doesn't have a ECDH compatibility mode + * (if you want that just use ECDHBasicAgreement and note they both implement + * BasicAgreement!). + */ +public class ECDHCBasicAgreement + implements BasicAgreement +{ + ECPrivateKeyParameters key; + + public void init( + CipherParameters key) + { + this.key = (ECPrivateKeyParameters)key; + } + + public int getFieldSize() + { + return (key.getParameters().getCurve().getFieldSize() + 7) / 8; + } + + public BigInteger calculateAgreement( + CipherParameters pubKey) + { + ECPublicKeyParameters pub = (ECPublicKeyParameters)pubKey; + ECDomainParameters params = pub.getParameters(); + ECPoint P = pub.getQ().multiply(params.getH().multiply(key.getD())); + + // if (p.isInfinity()) throw new RuntimeException("Invalid public key"); + + return P.getX().toBigInteger(); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/agreement/ECMQVBasicAgreement.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/agreement/ECMQVBasicAgreement.java new file mode 100644 index 0000000..9599535 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/agreement/ECMQVBasicAgreement.java @@ -0,0 +1,91 @@ +package org.bc.crypto.agreement; + +import java.math.BigInteger; + +import org.bc.crypto.BasicAgreement; +import org.bc.crypto.CipherParameters; +import org.bc.crypto.params.ECDomainParameters; +import org.bc.crypto.params.ECPrivateKeyParameters; +import org.bc.crypto.params.ECPublicKeyParameters; +import org.bc.crypto.params.MQVPrivateParameters; +import org.bc.crypto.params.MQVPublicParameters; +import org.bc.math.ec.ECAlgorithms; +import org.bc.math.ec.ECConstants; +import org.bc.math.ec.ECPoint; + +public class ECMQVBasicAgreement + implements BasicAgreement +{ + MQVPrivateParameters privParams; + + public void init( + CipherParameters key) + { + this.privParams = (MQVPrivateParameters)key; + } + + public int getFieldSize() + { + return (privParams.getStaticPrivateKey().getParameters().getCurve().getFieldSize() + 7) / 8; + } + + public BigInteger calculateAgreement(CipherParameters pubKey) + { + MQVPublicParameters pubParams = (MQVPublicParameters)pubKey; + + ECPrivateKeyParameters staticPrivateKey = privParams.getStaticPrivateKey(); + + ECPoint agreement = calculateMqvAgreement(staticPrivateKey.getParameters(), staticPrivateKey, + privParams.getEphemeralPrivateKey(), privParams.getEphemeralPublicKey(), + pubParams.getStaticPublicKey(), pubParams.getEphemeralPublicKey()); + + return agreement.getX().toBigInteger(); + } + + // The ECMQV Primitive as described in SEC-1, 3.4 + private ECPoint calculateMqvAgreement( + ECDomainParameters parameters, + ECPrivateKeyParameters d1U, + ECPrivateKeyParameters d2U, + ECPublicKeyParameters Q2U, + ECPublicKeyParameters Q1V, + ECPublicKeyParameters Q2V) + { + BigInteger n = parameters.getN(); + int e = (n.bitLength() + 1) / 2; + BigInteger powE = ECConstants.ONE.shiftLeft(e); + + // The Q2U public key is optional + ECPoint q; + if (Q2U == null) + { + q = parameters.getG().multiply(d2U.getD()); + } + else + { + q = Q2U.getQ(); + } + + BigInteger x = q.getX().toBigInteger(); + BigInteger xBar = x.mod(powE); + BigInteger Q2UBar = xBar.setBit(e); + BigInteger s = d1U.getD().multiply(Q2UBar).mod(n).add(d2U.getD()).mod(n); + + BigInteger xPrime = Q2V.getQ().getX().toBigInteger(); + BigInteger xPrimeBar = xPrime.mod(powE); + BigInteger Q2VBar = xPrimeBar.setBit(e); + + BigInteger hs = parameters.getH().multiply(s).mod(n); + +// ECPoint p = Q1V.getQ().multiply(Q2VBar).add(Q2V.getQ()).multiply(hs); + ECPoint p = ECAlgorithms.sumOfTwoMultiplies( + Q1V.getQ(), Q2VBar.multiply(hs).mod(n), Q2V.getQ(), hs); + + if (p.isInfinity()) + { + throw new IllegalStateException("Infinity is not a valid agreement value for MQV"); + } + + return p; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/agreement/jpake/JPAKEParticipant.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/agreement/jpake/JPAKEParticipant.java new file mode 100644 index 0000000..486a632 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/agreement/jpake/JPAKEParticipant.java @@ -0,0 +1,573 @@ +package org.bc.crypto.agreement.jpake; + +import java.math.BigInteger; +import java.security.SecureRandom; + +import org.bc.crypto.CryptoException; +import org.bc.crypto.Digest; +import org.bc.crypto.digests.SHA256Digest; +import org.bc.util.Arrays; + +/** + * A participant in a Password Authenticated Key Exchange by Juggling (J-PAKE) exchange. + *
+ * + * The J-PAKE exchange is defined by Feng Hao and Peter Ryan in the paper + * + * "Password Authenticated Key Exchange by Juggling, 2008." + * + * + * The J-PAKE protocol is symmetric. + * There is no notion of a client or server, but rather just two participants. + * An instance of {@link JPAKEParticipant} represents one participant, and + * is the primary interface for executing the exchange. + * + * + * To execute an exchange, construct a {@link JPAKEParticipant} on each end, + * and call the following 7 methods + * (once and only once, in the given order, for each participant, sending messages between them as described): + *+ *
+ * + * + * Each side should derive a session key from the keying material returned by {@link #calculateKeyingMaterial()}. + * The caller is responsible for deriving the session key using a secure key derivation function (KDF). + * + * + * Round 3 is an optional key confirmation process. + * If you do not execute round 3, then there is no assurance that both participants are using the same key. + * (i.e. if the participants used different passwords, then their session keys will differ.) + * + * + * If the round 3 validation succeeds, then the keys are guaranteed to be the same on both sides. + * + * + * The symmetric design can easily support the asymmetric cases when one party initiates the communication. + * e.g. Sometimes the round1 payload and round2 payload may be sent in one pass. + * Also, in some cases, the key confirmation payload can be sent together with the round2 payload. + * These are the trivial techniques to optimize the communication. + * + * + * The key confirmation process is implemented as specified in + * NIST SP 800-56A Revision 1, + * Section 8.2 Unilateral Key Confirmation for Key Agreement Schemes. + * + * + * This class is stateful and NOT threadsafe. + * Each instance should only be used for ONE complete J-PAKE exchange + * (i.e. a new {@link JPAKEParticipant} should be constructed for each new J-PAKE exchange). + * + * + * See {@link JPAKEExample} for example usage. + */ +public class JPAKEParticipant +{ + /* + * Possible internal states. Used for state checking. + */ + + public static final int STATE_INITIALIZED = 0; + public static final int STATE_ROUND_1_CREATED = 10; + public static final int STATE_ROUND_1_VALIDATED = 20; + public static final int STATE_ROUND_2_CREATED = 30; + public static final int STATE_ROUND_2_VALIDATED = 40; + public static final int STATE_KEY_CALCULATED = 50; + public static final int STATE_ROUND_3_CREATED = 60; + public static final int STATE_ROUND_3_VALIDATED = 70; + + /** + * Unique identifier of this participant. + * The two participants in the exchange must NOT share the same id. + */ + private final String participantId; + + /** + * Shared secret. This only contains the secret between construction + * and the call to {@link #calculateKeyingMaterial()}. + * + * i.e. When {@link #calculateKeyingMaterial()} is called, this buffer overwritten with 0's, + * and the field is set to null. + */ + private char[] password; + + /** + * Digest to use during calculations. + */ + private final Digest digest; + + /** + * Source of secure random data. + */ + private final SecureRandom random; + + private final BigInteger p; + private final BigInteger q; + private final BigInteger g; + + /** + * The participantId of the other participant in this exchange. + */ + private String partnerParticipantId; + + /** + * Alice's x1 or Bob's x3. + */ + private BigInteger x1; + /** + * Alice's x2 or Bob's x4. + */ + private BigInteger x2; + /** + * Alice's g^x1 or Bob's g^x3. + */ + private BigInteger gx1; + /** + * Alice's g^x2 or Bob's g^x4. + */ + private BigInteger gx2; + /** + * Alice's g^x3 or Bob's g^x1. + */ + private BigInteger gx3; + /** + * Alice's g^x4 or Bob's g^x2. + */ + private BigInteger gx4; + /** + * Alice's B or Bob's A. + */ + private BigInteger b; + + /** + * The current state. + * See the STATE_* constants for possible values. + */ + private int state; + + /** + * Convenience constructor for a new {@link JPAKEParticipant} that uses + * the {@link JPAKEPrimeOrderGroups#NIST_3072} prime order group, + * a SHA-256 digest, and a default {@link SecureRandom} implementation. + * + * After construction, the {@link #getState() state} will be {@link #STATE_INITIALIZED}. + * + * @param participantId unique identifier of this participant. + * The two participants in the exchange must NOT share the same id. + * @param password shared secret. + * A defensive copy of this array is made (and cleared once {@link #calculateKeyingMaterial()} is called). + * Caller should clear the input password as soon as possible. + * @throws NullPointerException if any argument is null + * @throws IllegalArgumentException if password is empty + */ + public JPAKEParticipant( + String participantId, + char[] password) + { + this( + participantId, + password, + JPAKEPrimeOrderGroups.NIST_3072); + } + + + /** + * Convenience constructor for a new {@link JPAKEParticipant} that uses + * a SHA-256 digest and a default {@link SecureRandom} implementation. + * + * After construction, the {@link #getState() state} will be {@link #STATE_INITIALIZED}. + * + * @param participantId unique identifier of this participant. + * The two participants in the exchange must NOT share the same id. + * @param password shared secret. + * A defensive copy of this array is made (and cleared once {@link #calculateKeyingMaterial()} is called). + * Caller should clear the input password as soon as possible. + * @param group prime order group. + * See {@link JPAKEPrimeOrderGroups} for standard groups + * @throws NullPointerException if any argument is null + * @throws IllegalArgumentException if password is empty + */ + public JPAKEParticipant( + String participantId, + char[] password, + JPAKEPrimeOrderGroup group) + { + this( + participantId, + password, + group, + new SHA256Digest(), + new SecureRandom()); + } + + + /** + * Construct a new {@link JPAKEParticipant}. + * + * After construction, the {@link #getState() state} will be {@link #STATE_INITIALIZED}. + * + * @param participantId unique identifier of this participant. + * The two participants in the exchange must NOT share the same id. + * @param password shared secret. + * A defensive copy of this array is made (and cleared once {@link #calculateKeyingMaterial()} is called). + * Caller should clear the input password as soon as possible. + * @param group prime order group. + * See {@link JPAKEPrimeOrderGroups} for standard groups + * @param digest digest to use during zero knowledge proofs and key confirmation (SHA-256 or stronger preferred) + * @param random source of secure random data for x1 and x2, and for the zero knowledge proofs + * @throws NullPointerException if any argument is null + * @throws IllegalArgumentException if password is empty + */ + public JPAKEParticipant( + String participantId, + char[] password, + JPAKEPrimeOrderGroup group, + Digest digest, + SecureRandom random) + { + JPAKEUtil.validateNotNull(participantId, "participantId"); + JPAKEUtil.validateNotNull(password, "password"); + JPAKEUtil.validateNotNull(group, "p"); + JPAKEUtil.validateNotNull(digest, "digest"); + JPAKEUtil.validateNotNull(random, "random"); + if (password.length == 0) + { + throw new IllegalArgumentException("Password must not be empty."); + } + + this.participantId = participantId; + + /* + * Create a defensive copy so as to fully encapsulate the password. + * + * This array will contain the password for the lifetime of this + * participant BEFORE {@link #calculateKeyingMaterial()} is called. + * + * i.e. When {@link #calculateKeyingMaterial()} is called, the array will be cleared + * in order to remove the password from memory. + * + * The caller is responsible for clearing the original password array + * given as input to this constructor. + */ + this.password = Arrays.copyOf(password, password.length); + + this.p = group.getP(); + this.q = group.getQ(); + this.g = group.getG(); + + this.digest = digest; + this.random = random; + + this.state = STATE_INITIALIZED; + } + + /** + * Gets the current state of this participant. + * See the STATE_* constants for possible values. + */ + public int getState() + { + return this.state; + } + + /** + * Creates and returns the payload to send to the other participant during round 1. + * + * + * After execution, the {@link #getState() state} will be {@link #STATE_ROUND_1_CREATED}. + */ + public JPAKERound1Payload createRound1PayloadToSend() + { + if (this.state >= STATE_ROUND_1_CREATED) + { + throw new IllegalStateException("Round1 payload already created for " + participantId); + } + + this.x1 = JPAKEUtil.generateX1(q, random); + this.x2 = JPAKEUtil.generateX2(q, random); + + this.gx1 = JPAKEUtil.calculateGx(p, g, x1); + this.gx2 = JPAKEUtil.calculateGx(p, g, x2); + BigInteger[] knowledgeProofForX1 = JPAKEUtil.calculateZeroKnowledgeProof(p, q, g, gx1, x1, participantId, digest, random); + BigInteger[] knowledgeProofForX2 = JPAKEUtil.calculateZeroKnowledgeProof(p, q, g, gx2, x2, participantId, digest, random); + + this.state = STATE_ROUND_1_CREATED; + + return new JPAKERound1Payload(participantId, gx1, gx2, knowledgeProofForX1, knowledgeProofForX2); + } + + /** + * Validates the payload received from the other participant during round 1. + * + * + * Must be called prior to {@link #createRound2PayloadToSend()}. + * + * + * After execution, the {@link #getState() state} will be {@link #STATE_ROUND_1_VALIDATED}. + * + * @throws CryptoException if validation fails. + * @throws IllegalStateException if called multiple times. + */ + public void validateRound1PayloadReceived(JPAKERound1Payload round1PayloadReceived) + throws CryptoException + { + if (this.state >= STATE_ROUND_1_VALIDATED) + { + throw new IllegalStateException("Validation already attempted for round1 payload for" + participantId); + } + this.partnerParticipantId = round1PayloadReceived.getParticipantId(); + this.gx3 = round1PayloadReceived.getGx1(); + this.gx4 = round1PayloadReceived.getGx2(); + + BigInteger[] knowledgeProofForX3 = round1PayloadReceived.getKnowledgeProofForX1(); + BigInteger[] knowledgeProofForX4 = round1PayloadReceived.getKnowledgeProofForX2(); + + JPAKEUtil.validateParticipantIdsDiffer(participantId, round1PayloadReceived.getParticipantId()); + JPAKEUtil.validateGx4(gx4); + JPAKEUtil.validateZeroKnowledgeProof(p, q, g, gx3, knowledgeProofForX3, round1PayloadReceived.getParticipantId(), digest); + JPAKEUtil.validateZeroKnowledgeProof(p, q, g, gx4, knowledgeProofForX4, round1PayloadReceived.getParticipantId(), digest); + + this.state = STATE_ROUND_1_VALIDATED; + } + + /** + * Creates and returns the payload to send to the other participant during round 2. + * + * + * {@link #validateRound1PayloadReceived(JPAKERound1Payload)} must be called prior to this method. + * + * + * After execution, the {@link #getState() state} will be {@link #STATE_ROUND_2_CREATED}. + * + * @throws IllegalStateException if called prior to {@link #validateRound1PayloadReceived(JPAKERound1Payload)}, or multiple times + */ + public JPAKERound2Payload createRound2PayloadToSend() + { + if (this.state >= STATE_ROUND_2_CREATED) + { + throw new IllegalStateException("Round2 payload already created for " + this.participantId); + } + if (this.state < STATE_ROUND_1_VALIDATED) + { + throw new IllegalStateException("Round1 payload must be validated prior to creating Round2 payload for " + this.participantId); + } + BigInteger gA = JPAKEUtil.calculateGA(p, gx1, gx3, gx4); + BigInteger s = JPAKEUtil.calculateS(password); + BigInteger x2s = JPAKEUtil.calculateX2s(q, x2, s); + BigInteger A = JPAKEUtil.calculateA(p, q, gA, x2s); + BigInteger[] knowledgeProofForX2s = JPAKEUtil.calculateZeroKnowledgeProof(p, q, gA, A, x2s, participantId, digest, random); + + this.state = STATE_ROUND_2_CREATED; + + return new JPAKERound2Payload(participantId, A, knowledgeProofForX2s); + } + + /** + * Validates the payload received from the other participant during round 2. + * + * + * Note that this DOES NOT detect a non-common password. + * The only indication of a non-common password is through derivation + * of different keys (which can be detected explicitly by executing round 3 and round 4) + * + * + * Must be called prior to {@link #calculateKeyingMaterial()}. + * + * + * After execution, the {@link #getState() state} will be {@link #STATE_ROUND_2_VALIDATED}. + * + * @throws CryptoException if validation fails. + * @throws IllegalStateException if called prior to {@link #validateRound1PayloadReceived(JPAKERound1Payload)}, or multiple times + */ + public void validateRound2PayloadReceived(JPAKERound2Payload round2PayloadReceived) + throws CryptoException + { + if (this.state >= STATE_ROUND_2_VALIDATED) + { + throw new IllegalStateException("Validation already attempted for round2 payload for" + participantId); + } + if (this.state < STATE_ROUND_1_VALIDATED) + { + throw new IllegalStateException("Round1 payload must be validated prior to validating Round2 payload for " + this.participantId); + } + BigInteger gB = JPAKEUtil.calculateGA(p, gx3, gx1, gx2); + this.b = round2PayloadReceived.getA(); + BigInteger[] knowledgeProofForX4s = round2PayloadReceived.getKnowledgeProofForX2s(); + + JPAKEUtil.validateParticipantIdsDiffer(participantId, round2PayloadReceived.getParticipantId()); + JPAKEUtil.validateParticipantIdsEqual(this.partnerParticipantId, round2PayloadReceived.getParticipantId()); + JPAKEUtil.validateGa(gB); + JPAKEUtil.validateZeroKnowledgeProof(p, q, gB, b, knowledgeProofForX4s, round2PayloadReceived.getParticipantId(), digest); + + this.state = STATE_ROUND_2_VALIDATED; + } + + /** + * Calculates and returns the key material. + * A session key must be derived from this key material using a secure key derivation function (KDF). + * The KDF used to derive the key is handled externally (i.e. not by {@link JPAKEParticipant}). + * + * + * The keying material will be identical for each participant if and only if + * each participant's password is the same. i.e. If the participants do not + * share the same password, then each participant will derive a different key. + * Therefore, if you immediately start using a key derived from + * the keying material, then you must handle detection of incorrect keys. + * If you want to handle this detection explicitly, you can optionally perform + * rounds 3 and 4. See {@link JPAKEParticipant} for details on how to execute + * rounds 3 and 4. + * + * + * The keying material will be in the range [0, p-1]. + * + * + * {@link #validateRound2PayloadReceived(JPAKERound2Payload)} must be called prior to this method. + * + * + * As a side effect, the internal {@link #password} array is cleared, since it is no longer needed. + * + * + * After execution, the {@link #getState() state} will be {@link #STATE_KEY_CALCULATED}. + * + * @throws IllegalStateException if called prior to {@link #validateRound2PayloadReceived(JPAKERound2Payload)}, + * or if called multiple times. + */ + public BigInteger calculateKeyingMaterial() + { + if (this.state >= STATE_KEY_CALCULATED) + { + throw new IllegalStateException("Key already calculated for " + participantId); + } + if (this.state < STATE_ROUND_2_VALIDATED) + { + throw new IllegalStateException("Round2 payload must be validated prior to creating key for " + participantId); + } + BigInteger s = JPAKEUtil.calculateS(password); + + /* + * Clear the password array from memory, since we don't need it anymore. + * + * Also set the field to null as a flag to indicate that the key has already been calculated. + */ + Arrays.fill(password, (char)0); + this.password = null; + + BigInteger keyingMaterial = JPAKEUtil.calculateKeyingMaterial(p, q, gx4, x2, s, b); + + /* + * Clear the ephemeral private key fields as well. + * Note that we're relying on the garbage collector to do its job to clean these up. + * The old objects will hang around in memory until the garbage collector destroys them. + * + * If the ephemeral private keys x1 and x2 are leaked, + * the attacker might be able to brute-force the password. + */ + this.x1 = null; + this.x2 = null; + this.b = null; + + /* + * Do not clear gx* yet, since those are needed by round 3. + */ + + this.state = STATE_KEY_CALCULATED; + + return keyingMaterial; + } + + + /** + * Creates and returns the payload to send to the other participant during round 3. + * + * + * See {@link JPAKEParticipant} for more details on round 3. + * + * + * After execution, the {@link #getState() state} will be {@link #STATE_ROUND_3_CREATED}. + * + * @param keyingMaterial The keying material as returned from {@link #calculateKeyingMaterial()}. + * @throws IllegalStateException if called prior to {@link #calculateKeyingMaterial()}, or multiple times + */ + public JPAKERound3Payload createRound3PayloadToSend(BigInteger keyingMaterial) + { + if (this.state >= STATE_ROUND_3_CREATED) + { + throw new IllegalStateException("Round3 payload already created for " + this.participantId); + } + if (this.state < STATE_KEY_CALCULATED) + { + throw new IllegalStateException("Keying material must be calculated prior to creating Round3 payload for " + this.participantId); + } + + BigInteger macTag = JPAKEUtil.calculateMacTag( + this.participantId, + this.partnerParticipantId, + this.gx1, + this.gx2, + this.gx3, + this.gx4, + keyingMaterial, + this.digest); + + this.state = STATE_ROUND_3_CREATED; + + return new JPAKERound3Payload(participantId, macTag); + } + + /** + * Validates the payload received from the other participant during round 3. + * + * + * See {@link JPAKEParticipant} for more details on round 3. + * + * + * After execution, the {@link #getState() state} will be {@link #STATE_ROUND_3_VALIDATED}. + * + * @param keyingMaterial The keying material as returned from {@link #calculateKeyingMaterial()}. + * @throws CryptoException if validation fails. + * @throws IllegalStateException if called prior to {@link #calculateKeyingMaterial()}, or multiple times + */ + public void validateRound3PayloadReceived(JPAKERound3Payload round3PayloadReceived, BigInteger keyingMaterial) + throws CryptoException + { + if (this.state >= STATE_ROUND_3_VALIDATED) + { + throw new IllegalStateException("Validation already attempted for round3 payload for" + participantId); + } + if (this.state < STATE_KEY_CALCULATED) + { + throw new IllegalStateException("Keying material must be calculated validated prior to validating Round3 payload for " + this.participantId); + } + JPAKEUtil.validateParticipantIdsDiffer(participantId, round3PayloadReceived.getParticipantId()); + JPAKEUtil.validateParticipantIdsEqual(this.partnerParticipantId, round3PayloadReceived.getParticipantId()); + + JPAKEUtil.validateMacTag( + this.participantId, + this.partnerParticipantId, + this.gx1, + this.gx2, + this.gx3, + this.gx4, + keyingMaterial, + this.digest, + round3PayloadReceived.getMacTag()); + + + /* + * Clear the rest of the fields. + */ + this.gx1 = null; + this.gx2 = null; + this.gx3 = null; + this.gx4 = null; + + this.state = STATE_ROUND_3_VALIDATED; + } + +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/agreement/jpake/JPAKEPrimeOrderGroup.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/agreement/jpake/JPAKEPrimeOrderGroup.java new file mode 100644 index 0000000..26eb5ef --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/agreement/jpake/JPAKEPrimeOrderGroup.java @@ -0,0 +1,122 @@ +package org.bc.crypto.agreement.jpake; + +import java.math.BigInteger; + +/** + * A pre-computed prime order group for use during a J-PAKE exchange. + * + * + * Typically a Schnorr group is used. In general, J-PAKE can use any prime order group + * that is suitable for public key cryptography, including elliptic curve cryptography. + * + * + * See {@link JPAKEPrimeOrderGroups} for convenient standard groups. + * + * + * NIST publishes + * many groups that can be used for the desired level of security. + */ +public class JPAKEPrimeOrderGroup +{ + private final BigInteger p; + private final BigInteger q; + private final BigInteger g; + + /** + * Constructs a new {@link JPAKEPrimeOrderGroup}. + * + * + * In general, you should use one of the pre-approved groups from + * {@link JPAKEPrimeOrderGroups}, rather than manually constructing one. + * + * + * The following basic checks are performed: + *- {@link #createRound1PayloadToSend()} - and send the payload to the other participant
+ *- {@link #validateRound1PayloadReceived(JPAKERound1Payload)} - use the payload received from the other participant
+ *- {@link #createRound2PayloadToSend()} - and send the payload to the other participant
+ *- {@link #validateRound2PayloadReceived(JPAKERound2Payload)} - use the payload received from the other participant
+ *- {@link #calculateKeyingMaterial()}
+ *- {@link #createRound3PayloadToSend(BigInteger)} - and send the payload to the other participant
+ *- {@link #validateRound3PayloadReceived(JPAKERound3Payload, BigInteger)} - use the payload received from the other participant
+ *
+ * Alice could simply check ga != 1 to ensure it is a generator. + * In fact, as we will explain in Section 3, (x1 + x3 + x4 ) is random over Zq even in the face of active attacks. + * Hence, the probability for ga = 1 is extremely small - on the order of 2^160 for 160-bit q. + *+ * + * @throws CryptoException if ga is 1 + */ + public static void validateGa(BigInteger ga) + throws CryptoException + { + if (ga.equals(ONE)) + { + throw new CryptoException("ga is equal to 1. It should not be. The chances of this happening are on the order of 2^160 for a 160-bit q. Try again."); + } + } + + /** + * Validates the zero knowledge proof (generated by + * {@link #calculateZeroKnowledgeProof(BigInteger, BigInteger, BigInteger, BigInteger, BigInteger, String, Digest, SecureRandom)}) + * is correct. + * + * @throws CryptoException if the zero knowledge proof is not correct + */ + public static void validateZeroKnowledgeProof( + BigInteger p, + BigInteger q, + BigInteger g, + BigInteger gx, + BigInteger[] zeroKnowledgeProof, + String participantId, + Digest digest) + throws CryptoException + { + + /* sig={g^v,r} */ + BigInteger gv = zeroKnowledgeProof[0]; + BigInteger r = zeroKnowledgeProof[1]; + + BigInteger h = calculateHashForZeroKnowledgeProof(g, gv, gx, participantId, digest); + if (!(gx.compareTo(ZERO) == 1 && // g^x > 0 + gx.compareTo(p) == -1 && // g^x < p + gx.modPow(q, p).compareTo(ONE) == 0 && // g^x^q mod q = 1 + /* + * Below, I took an straightforward way to compute g^r * g^x^h, + * which needs 2 exp. Using a simultaneous computation technique + * would only need 1 exp. + */ + g.modPow(r, p).multiply(gx.modPow(h, p)).mod(p).compareTo(gv) == 0)) // g^v=g^r * g^x^h + { + throw new CryptoException("Zero-knowledge proof validation failed"); + } + } + + /** + * Calculates the keying material, which can be done after round 2 has completed. + * A session key must be derived from this key material using a secure key derivation function (KDF). + * The KDF used to derive the key is handled externally (i.e. not by {@link JPAKEParticipant}). + * + * + *
+ * KeyingMaterial = (B/g^{x2*x4*s})^x2 + *+ */ + public static BigInteger calculateKeyingMaterial( + BigInteger p, + BigInteger q, + BigInteger gx4, + BigInteger x2, + BigInteger s, + BigInteger B) + { + return gx4.modPow(x2.multiply(s).negate().mod(q), p).multiply(B).modPow(x2, p); + } + + /** + * Validates that the given participant ids are not equal. + * (For the J-PAKE exchange, each participant must use a unique id.) + * + * @throws CryptoException if the participantId strings are equal. + */ + public static void validateParticipantIdsDiffer(String participantId1, String participantId2) + throws CryptoException + { + if (participantId1.equals(participantId2)) + { + throw new CryptoException( + "Both participants are using the same participantId (" + + participantId1 + + "). This is not allowed. " + + "Each participant must use a unique participantId."); + } + } + + /** + * Validates that the given participant ids are equal. + * This is used to ensure that the payloads received from + * each round all come from the same participant. + * + * @throws CryptoException if the participantId strings are equal. + */ + public static void validateParticipantIdsEqual(String expectedParticipantId, String actualParticipantId) + throws CryptoException + { + if (!expectedParticipantId.equals(actualParticipantId)) + { + throw new CryptoException( + "Received payload from incorrect partner (" + + actualParticipantId + + "). Expected to receive payload from " + + expectedParticipantId + + "."); + } + } + + /** + * Validates that the given object is not null. + * + * @param object object in question + * @param description name of the object (to be used in exception message) + * @throws NullPointerException if the object is null. + */ + public static void validateNotNull(Object object, String description) + { + if (object == null) + { + throw new NullPointerException(description + " must not be null"); + } + } + + /** + * Calculates the MacTag (to be used for key confirmation), as defined by + * NIST SP 800-56A Revision 1, + * Section 8.2 Unilateral Key Confirmation for Key Agreement Schemes. + * + * + *
+ * MacTag = HMAC(MacKey, MacLen, MacData) + * + * MacKey = H(K || "JPAKE_KC") + * + * MacData = "KC_1_U" || participantId || partnerParticipantId || gx1 || gx2 || gx3 || gx4 + * + * Note that both participants use "KC_1_U" because the sender of the round 3 message + * is always the initiator for key confirmation. + * + * HMAC = {@link HMac} used with the given {@link Digest} + * H = The given {@link Digest}
+ * MacKey = H(K || "JPAKE_KC") + *+ */ + private static byte[] calculateMacKey(BigInteger keyingMaterial, Digest digest) + { + digest.reset(); + + updateDigest(digest, keyingMaterial); + /* + * This constant is used to ensure that the macKey is NOT the same as the derived key. + */ + updateDigest(digest, "JPAKE_KC"); + + byte[] output = new byte[digest.getDigestSize()]; + digest.doFinal(output, 0); + + return output; + } + + /** + * Validates the MacTag received from the partner participant. + * + * + * @param partnerMacTag the MacTag received from the partner. + * @throws CryptoException if the participantId strings are equal. + */ + public static void validateMacTag( + String participantId, + String partnerParticipantId, + BigInteger gx1, + BigInteger gx2, + BigInteger gx3, + BigInteger gx4, + BigInteger keyingMaterial, + Digest digest, + BigInteger partnerMacTag) + throws CryptoException + { + /* + * Calculate the expected MacTag using the parameters as the partner + * would have used when the partner called calculateMacTag. + * + * i.e. basically all the parameters are reversed. + * participantId <-> partnerParticipantId + * x1 <-> x3 + * x2 <-> x4 + */ + BigInteger expectedMacTag = calculateMacTag( + partnerParticipantId, + participantId, + gx3, + gx4, + gx1, + gx2, + keyingMaterial, + digest); + + if (!expectedMacTag.equals(partnerMacTag)) + { + throw new CryptoException( + "Partner MacTag validation failed. " + + "Therefore, the password, MAC, or digest algorithm of each participant does not match."); + } + } + + private static void updateDigest(Digest digest, BigInteger bigInteger) + { + byte[] byteArray = BigIntegers.asUnsignedByteArray(bigInteger); + digest.update(byteArray, 0, byteArray.length); + Arrays.fill(byteArray, (byte)0); + } + + private static void updateDigestIncludingSize(Digest digest, BigInteger bigInteger) + { + byte[] byteArray = BigIntegers.asUnsignedByteArray(bigInteger); + digest.update(intToByteArray(byteArray.length), 0, 4); + digest.update(byteArray, 0, byteArray.length); + Arrays.fill(byteArray, (byte)0); + } + + private static void updateDigest(Digest digest, String string) + { + byte[] byteArray = Strings.toUTF8ByteArray(string); + digest.update(byteArray, 0, byteArray.length); + Arrays.fill(byteArray, (byte)0); + } + + private static void updateDigestIncludingSize(Digest digest, String string) + { + byte[] byteArray = Strings.toUTF8ByteArray(string); + digest.update(intToByteArray(byteArray.length), 0, 4); + digest.update(byteArray, 0, byteArray.length); + Arrays.fill(byteArray, (byte)0); + } + + private static void updateMac(Mac mac, BigInteger bigInteger) + { + byte[] byteArray = BigIntegers.asUnsignedByteArray(bigInteger); + mac.update(byteArray, 0, byteArray.length); + Arrays.fill(byteArray, (byte)0); + } + + private static void updateMac(Mac mac, String string) + { + byte[] byteArray = Strings.toUTF8ByteArray(string); + mac.update(byteArray, 0, byteArray.length); + Arrays.fill(byteArray, (byte)0); + } + + private static byte[] intToByteArray(int value) + { + return new byte[]{ + (byte)(value >>> 24), + (byte)(value >>> 16), + (byte)(value >>> 8), + (byte)value + }; + } + +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/agreement/kdf/DHKDFParameters.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/agreement/kdf/DHKDFParameters.java new file mode 100644 index 0000000..5b1ce16 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/agreement/kdf/DHKDFParameters.java @@ -0,0 +1,54 @@ +package org.bc.crypto.agreement.kdf; + +import org.bc.asn1.ASN1ObjectIdentifier; +import org.bc.asn1.DERObjectIdentifier; +import org.bc.crypto.DerivationParameters; + +public class DHKDFParameters + implements DerivationParameters +{ + private ASN1ObjectIdentifier algorithm; + private int keySize; + private byte[] z; + private byte[] extraInfo; + + public DHKDFParameters( + DERObjectIdentifier algorithm, + int keySize, + byte[] z) + { + this(algorithm, keySize, z, null); + } + + public DHKDFParameters( + DERObjectIdentifier algorithm, + int keySize, + byte[] z, + byte[] extraInfo) + { + this.algorithm = new ASN1ObjectIdentifier(algorithm.getId()); + this.keySize = keySize; + this.z = z; + this.extraInfo = extraInfo; + } + + public ASN1ObjectIdentifier getAlgorithm() + { + return algorithm; + } + + public int getKeySize() + { + return keySize; + } + + public byte[] getZ() + { + return z; + } + + public byte[] getExtraInfo() + { + return extraInfo; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/agreement/kdf/DHKEKGenerator.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/agreement/kdf/DHKEKGenerator.java new file mode 100644 index 0000000..e39e482 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/agreement/kdf/DHKEKGenerator.java @@ -0,0 +1,142 @@ +package org.bc.crypto.agreement.kdf; + +import java.io.IOException; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Encoding; +import org.bc.asn1.DERObjectIdentifier; +import org.bc.asn1.DEROctetString; +import org.bc.asn1.DERSequence; +import org.bc.asn1.DERTaggedObject; +import org.bc.crypto.DataLengthException; +import org.bc.crypto.DerivationFunction; +import org.bc.crypto.DerivationParameters; +import org.bc.crypto.Digest; + +/** + * RFC 2631 Diffie-hellman KEK derivation function. + */ +public class DHKEKGenerator + implements DerivationFunction +{ + private final Digest digest; + + private DERObjectIdentifier algorithm; + private int keySize; + private byte[] z; + private byte[] partyAInfo; + + public DHKEKGenerator( + Digest digest) + { + this.digest = digest; + } + + public void init(DerivationParameters param) + { + DHKDFParameters params = (DHKDFParameters)param; + + this.algorithm = params.getAlgorithm(); + this.keySize = params.getKeySize(); + this.z = params.getZ(); + this.partyAInfo = params.getExtraInfo(); + } + + public Digest getDigest() + { + return digest; + } + + public int generateBytes(byte[] out, int outOff, int len) + throws DataLengthException, IllegalArgumentException + { + if ((out.length - len) < outOff) + { + throw new DataLengthException("output buffer too small"); + } + + long oBytes = len; + int outLen = digest.getDigestSize(); + + // + // this is at odds with the standard implementation, the + // maximum value should be hBits * (2^32 - 1) where hBits + // is the digest output size in bits. We can't have an + // array with a long index at the moment... + // + if (oBytes > ((2L << 32) - 1)) + { + throw new IllegalArgumentException("Output length too large"); + } + + int cThreshold = (int)((oBytes + outLen - 1) / outLen); + + byte[] dig = new byte[digest.getDigestSize()]; + + int counter = 1; + + for (int i = 0; i < cThreshold; i++) + { + digest.update(z, 0, z.length); + + // OtherInfo + ASN1EncodableVector v1 = new ASN1EncodableVector(); + // KeySpecificInfo + ASN1EncodableVector v2 = new ASN1EncodableVector(); + + v2.add(algorithm); + v2.add(new DEROctetString(integerToBytes(counter))); + + v1.add(new DERSequence(v2)); + + if (partyAInfo != null) + { + v1.add(new DERTaggedObject(true, 0, new DEROctetString(partyAInfo))); + } + + v1.add(new DERTaggedObject(true, 2, new DEROctetString(integerToBytes(keySize)))); + + try + { + byte[] other = new DERSequence(v1).getEncoded(ASN1Encoding.DER); + + digest.update(other, 0, other.length); + } + catch (IOException e) + { + throw new IllegalArgumentException("unable to encode parameter info: " + e.getMessage()); + } + + digest.doFinal(dig, 0); + + if (len > outLen) + { + System.arraycopy(dig, 0, out, outOff, outLen); + outOff += outLen; + len -= outLen; + } + else + { + System.arraycopy(dig, 0, out, outOff, len); + } + + counter++; + } + + digest.reset(); + + return len; + } + + private byte[] integerToBytes(int keySize) + { + byte[] val = new byte[4]; + + val[0] = (byte)(keySize >> 24); + val[1] = (byte)(keySize >> 16); + val[2] = (byte)(keySize >> 8); + val[3] = (byte)keySize; + + return val; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/agreement/kdf/ECDHKEKGenerator.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/agreement/kdf/ECDHKEKGenerator.java new file mode 100644 index 0000000..8cade89 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/agreement/kdf/ECDHKEKGenerator.java @@ -0,0 +1,85 @@ +package org.bc.crypto.agreement.kdf; + +import java.io.IOException; + +import org.bc.asn1.ASN1EncodableVector; +import org.bc.asn1.ASN1Encoding; +import org.bc.asn1.ASN1ObjectIdentifier; +import org.bc.asn1.DERNull; +import org.bc.asn1.DEROctetString; +import org.bc.asn1.DERSequence; +import org.bc.asn1.DERTaggedObject; +import org.bc.asn1.x509.AlgorithmIdentifier; +import org.bc.crypto.DataLengthException; +import org.bc.crypto.DerivationFunction; +import org.bc.crypto.DerivationParameters; +import org.bc.crypto.Digest; +import org.bc.crypto.generators.KDF2BytesGenerator; +import org.bc.crypto.params.KDFParameters; + +/** + * X9.63 based key derivation function for ECDH CMS. + */ +public class ECDHKEKGenerator + implements DerivationFunction +{ + private DerivationFunction kdf; + + private ASN1ObjectIdentifier algorithm; + private int keySize; + private byte[] z; + + public ECDHKEKGenerator( + Digest digest) + { + this.kdf = new KDF2BytesGenerator(digest); + } + + public void init(DerivationParameters param) + { + DHKDFParameters params = (DHKDFParameters)param; + + this.algorithm = params.getAlgorithm(); + this.keySize = params.getKeySize(); + this.z = params.getZ(); + } + + public Digest getDigest() + { + return kdf.getDigest(); + } + + public int generateBytes(byte[] out, int outOff, int len) + throws DataLengthException, IllegalArgumentException + { + // TODO Create an ASN.1 class for this (RFC3278) + // ECC-CMS-SharedInfo + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(new AlgorithmIdentifier(algorithm, DERNull.INSTANCE)); + v.add(new DERTaggedObject(true, 2, new DEROctetString(integerToBytes(keySize)))); + + try + { + kdf.init(new KDFParameters(z, new DERSequence(v).getEncoded(ASN1Encoding.DER))); + } + catch (IOException e) + { + throw new IllegalArgumentException("unable to initialise kdf: " + e.getMessage()); + } + + return kdf.generateBytes(out, outOff, len); + } + + private byte[] integerToBytes(int keySize) + { + byte[] val = new byte[4]; + + val[0] = (byte)(keySize >> 24); + val[1] = (byte)(keySize >> 16); + val[2] = (byte)(keySize >> 8); + val[3] = (byte)keySize; + + return val; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/agreement/srp/SRP6Client.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/agreement/srp/SRP6Client.java new file mode 100644 index 0000000..7a64ac3 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/agreement/srp/SRP6Client.java @@ -0,0 +1,93 @@ +package org.bc.crypto.agreement.srp; + +import java.math.BigInteger; +import java.security.SecureRandom; + +import org.bc.crypto.CryptoException; +import org.bc.crypto.Digest; + +/** + * Implements the client side SRP-6a protocol. Note that this class is stateful, and therefore NOT threadsafe. + * This implementation of SRP is based on the optimized message sequence put forth by Thomas Wu in the paper + * "SRP-6: Improvements and Refinements to the Secure Remote Password Protocol, 2002" + */ +public class SRP6Client +{ + protected BigInteger N; + protected BigInteger g; + + protected BigInteger a; + protected BigInteger A; + + protected BigInteger B; + + protected BigInteger x; + protected BigInteger u; + protected BigInteger S; + + protected Digest digest; + protected SecureRandom random; + + public SRP6Client() + { + } + + /** + * Initialises the client to begin new authentication attempt + * @param N The safe prime associated with the client's verifier + * @param g The group parameter associated with the client's verifier + * @param digest The digest algorithm associated with the client's verifier + * @param random For key generation + */ + public void init(BigInteger N, BigInteger g, Digest digest, SecureRandom random) + { + this.N = N; + this.g = g; + this.digest = digest; + this.random = random; + } + + /** + * Generates client's credentials given the client's salt, identity and password + * @param salt The salt used in the client's verifier. + * @param identity The user's identity (eg. username) + * @param password The user's password + * @return Client's public value to send to server + */ + public BigInteger generateClientCredentials(byte[] salt, byte[] identity, byte[] password) + { + this.x = SRP6Util.calculateX(digest, N, salt, identity, password); + this.a = selectPrivateValue(); + this.A = g.modPow(a, N); + + return A; + } + + /** + * Generates client's verification message given the server's credentials + * @param serverB The server's credentials + * @return Client's verification message for the server + * @throws CryptoException If server's credentials are invalid + */ + public BigInteger calculateSecret(BigInteger serverB) throws CryptoException + { + this.B = SRP6Util.validatePublicValue(N, serverB); + this.u = SRP6Util.calculateU(digest, N, A, B); + this.S = calculateS(); + + return S; + } + + protected BigInteger selectPrivateValue() + { + return SRP6Util.generatePrivateValue(digest, N, g, random); + } + + private BigInteger calculateS() + { + BigInteger k = SRP6Util.calculateK(digest, N, g); + BigInteger exp = u.multiply(x).add(a); + BigInteger tmp = g.modPow(x, N).multiply(k).mod(N); + return B.subtract(tmp).mod(N).modPow(exp, N); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/agreement/srp/SRP6Server.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/agreement/srp/SRP6Server.java new file mode 100644 index 0000000..7cb1fb2 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/agreement/srp/SRP6Server.java @@ -0,0 +1,90 @@ +package org.bc.crypto.agreement.srp; + +import java.math.BigInteger; +import java.security.SecureRandom; + +import org.bc.crypto.CryptoException; +import org.bc.crypto.Digest; + +/** + * Implements the server side SRP-6a protocol. Note that this class is stateful, and therefore NOT threadsafe. + * This implementation of SRP is based on the optimized message sequence put forth by Thomas Wu in the paper + * "SRP-6: Improvements and Refinements to the Secure Remote Password Protocol, 2002" + */ +public class SRP6Server +{ + protected BigInteger N; + protected BigInteger g; + protected BigInteger v; + + protected SecureRandom random; + protected Digest digest; + + protected BigInteger A; + + protected BigInteger b; + protected BigInteger B; + + protected BigInteger u; + protected BigInteger S; + + public SRP6Server() + { + } + + /** + * Initialises the server to accept a new client authentication attempt + * @param N The safe prime associated with the client's verifier + * @param g The group parameter associated with the client's verifier + * @param v The client's verifier + * @param digest The digest algorithm associated with the client's verifier + * @param random For key generation + */ + public void init(BigInteger N, BigInteger g, BigInteger v, Digest digest, SecureRandom random) + { + this.N = N; + this.g = g; + this.v = v; + + this.random = random; + this.digest = digest; + } + + /** + * Generates the server's credentials that are to be sent to the client. + * @return The server's public value to the client + */ + public BigInteger generateServerCredentials() + { + BigInteger k = SRP6Util.calculateK(digest, N, g); + this.b = selectPrivateValue(); + this.B = k.multiply(v).mod(N).add(g.modPow(b, N)).mod(N); + + return B; + } + + /** + * Processes the client's credentials. If valid the shared secret is generated and returned. + * @param clientA The client's credentials + * @return A shared secret BigInteger + * @throws CryptoException If client's credentials are invalid + */ + public BigInteger calculateSecret(BigInteger clientA) throws CryptoException + { + this.A = SRP6Util.validatePublicValue(N, clientA); + this.u = SRP6Util.calculateU(digest, N, A, B); + this.S = calculateS(); + + return S; + } + + protected BigInteger selectPrivateValue() + { + return SRP6Util.generatePrivateValue(digest, N, g, random); + } + + private BigInteger calculateS() + { + return v.modPow(u, N).multiply(A).mod(N).modPow(b, N); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/agreement/srp/SRP6Util.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/agreement/srp/SRP6Util.java new file mode 100644 index 0000000..86dc1bb --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/agreement/srp/SRP6Util.java @@ -0,0 +1,91 @@ +package org.bc.crypto.agreement.srp; + +import java.math.BigInteger; +import java.security.SecureRandom; + +import org.bc.crypto.CryptoException; +import org.bc.crypto.Digest; +import org.bc.util.BigIntegers; + +public class SRP6Util +{ + private static BigInteger ZERO = BigInteger.valueOf(0); + private static BigInteger ONE = BigInteger.valueOf(1); + + public static BigInteger calculateK(Digest digest, BigInteger N, BigInteger g) + { + return hashPaddedPair(digest, N, N, g); + } + + public static BigInteger calculateU(Digest digest, BigInteger N, BigInteger A, BigInteger B) + { + return hashPaddedPair(digest, N, A, B); + } + + public static BigInteger calculateX(Digest digest, BigInteger N, byte[] salt, byte[] identity, byte[] password) + { + byte[] output = new byte[digest.getDigestSize()]; + + digest.update(identity, 0, identity.length); + digest.update((byte)':'); + digest.update(password, 0, password.length); + digest.doFinal(output, 0); + + digest.update(salt, 0, salt.length); + digest.update(output, 0, output.length); + digest.doFinal(output, 0); + + return new BigInteger(1, output); + } + + public static BigInteger generatePrivateValue(Digest digest, BigInteger N, BigInteger g, SecureRandom random) + { + int minBits = Math.min(256, N.bitLength() / 2); + BigInteger min = ONE.shiftLeft(minBits - 1); + BigInteger max = N.subtract(ONE); + + return BigIntegers.createRandomInRange(min, max, random); + } + + public static BigInteger validatePublicValue(BigInteger N, BigInteger val) + throws CryptoException + { + val = val.mod(N); + + // Check that val % N != 0 + if (val.equals(ZERO)) + { + throw new CryptoException("Invalid public value: 0"); + } + + return val; + } + + private static BigInteger hashPaddedPair(Digest digest, BigInteger N, BigInteger n1, BigInteger n2) + { + int padLength = (N.bitLength() + 7) / 8; + + byte[] n1_bytes = getPadded(n1, padLength); + byte[] n2_bytes = getPadded(n2, padLength); + + digest.update(n1_bytes, 0, n1_bytes.length); + digest.update(n2_bytes, 0, n2_bytes.length); + + byte[] output = new byte[digest.getDigestSize()]; + digest.doFinal(output, 0); + + return new BigInteger(1, output); + } + + private static byte[] getPadded(BigInteger n, int length) + { + byte[] bs = BigIntegers.asUnsignedByteArray(n); + if (bs.length < length) + { + byte[] tmp = new byte[length]; + System.arraycopy(bs, 0, tmp, length - bs.length, bs.length); + bs = tmp; + } + return bs; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/agreement/srp/SRP6VerifierGenerator.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/agreement/srp/SRP6VerifierGenerator.java new file mode 100644 index 0000000..9925aea --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/agreement/srp/SRP6VerifierGenerator.java @@ -0,0 +1,47 @@ +package org.bc.crypto.agreement.srp; + +import java.math.BigInteger; + +import org.bc.crypto.Digest; + +/** + * Generates new SRP verifier for user + */ +public class SRP6VerifierGenerator +{ + protected BigInteger N; + protected BigInteger g; + protected Digest digest; + + public SRP6VerifierGenerator() + { + } + + /** + * Initialises generator to create new verifiers + * @param N The safe prime to use (see DHParametersGenerator) + * @param g The group parameter to use (see DHParametersGenerator) + * @param digest The digest to use. The same digest type will need to be used later for the actual authentication + * attempt. Also note that the final session key size is dependent on the chosen digest. + */ + public void init(BigInteger N, BigInteger g, Digest digest) + { + this.N = N; + this.g = g; + this.digest = digest; + } + + /** + * Creates a new SRP verifier + * @param salt The salt to use, generally should be large and random + * @param identity The user's identifying information (eg. username) + * @param password The user's password + * @return A new verifier for use in future SRP authentication + */ + public BigInteger generateVerifier(byte[] salt, byte[] identity, byte[] password) + { + BigInteger x = SRP6Util.calculateX(digest, N, salt, identity, password); + + return g.modPow(x, N); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/digests/GOST3411Digest.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/digests/GOST3411Digest.java new file mode 100644 index 0000000..6a966d8 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/digests/GOST3411Digest.java @@ -0,0 +1,349 @@ +package org.bc.crypto.digests; + +import org.bc.crypto.BlockCipher; +import org.bc.crypto.ExtendedDigest; +import org.bc.crypto.engines.GOST28147Engine; +import org.bc.crypto.params.KeyParameter; +import org.bc.crypto.params.ParametersWithSBox; +import org.bc.crypto.util.Pack; +import org.bc.util.Arrays; + +/** + * implementation of GOST R 34.11-94 + */ +public class GOST3411Digest + implements ExtendedDigest +{ + private static final int DIGEST_LENGTH = 32; + + private byte[] H = new byte[32], L = new byte[32], + M = new byte[32], Sum = new byte[32]; + private byte[][] C = new byte[4][32]; + + private byte[] xBuf = new byte[32]; + private int xBufOff; + private long byteCount; + + private BlockCipher cipher = new GOST28147Engine(); + private byte[] sBox; + + /** + * Standard constructor + */ + public GOST3411Digest() + { + sBox = GOST28147Engine.getSBox("D-A"); + cipher.init(true, new ParametersWithSBox(null, sBox)); + + reset(); + } + + /** + * Constructor to allow use of a particular sbox with GOST28147 + * @see GOST28147Engine#getSBox(String) + */ + public GOST3411Digest(byte[] sBoxParam) + { + sBox = Arrays.clone(sBoxParam); + cipher.init(true, new ParametersWithSBox(null, sBox)); + + reset(); + } + + /** + * Copy constructor. This will copy the state of the provided + * message digest. + */ + public GOST3411Digest(GOST3411Digest t) + { + this.sBox = t.sBox; + cipher.init(true, new ParametersWithSBox(null, sBox)); + + reset(); + + System.arraycopy(t.H, 0, this.H, 0, t.H.length); + System.arraycopy(t.L, 0, this.L, 0, t.L.length); + System.arraycopy(t.M, 0, this.M, 0, t.M.length); + System.arraycopy(t.Sum, 0, this.Sum, 0, t.Sum.length); + System.arraycopy(t.C[1], 0, this.C[1], 0, t.C[1].length); + System.arraycopy(t.C[2], 0, this.C[2], 0, t.C[2].length); + System.arraycopy(t.C[3], 0, this.C[3], 0, t.C[3].length); + System.arraycopy(t.xBuf, 0, this.xBuf, 0, t.xBuf.length); + + this.xBufOff = t.xBufOff; + this.byteCount = t.byteCount; + } + + public String getAlgorithmName() + { + return "GOST3411"; + } + + public int getDigestSize() + { + return DIGEST_LENGTH; + } + + public void update(byte in) + { + xBuf[xBufOff++] = in; + if (xBufOff == xBuf.length) + { + sumByteArray(xBuf); // calc sum M + processBlock(xBuf, 0); + xBufOff = 0; + } + byteCount++; + } + + public void update(byte[] in, int inOff, int len) + { + while ((xBufOff != 0) && (len > 0)) + { + update(in[inOff]); + inOff++; + len--; + } + + while (len > xBuf.length) + { + System.arraycopy(in, inOff, xBuf, 0, xBuf.length); + + sumByteArray(xBuf); // calc sum M + processBlock(xBuf, 0); + inOff += xBuf.length; + len -= xBuf.length; + byteCount += xBuf.length; + } + + // load in the remainder. + while (len > 0) + { + update(in[inOff]); + inOff++; + len--; + } + } + + // (i + 1 + 4(k - 1)) = 8i + k i = 0-3, k = 1-8 + private byte[] K = new byte[32]; + + private byte[] P(byte[] in) + { + for(int k = 0; k < 8; k++) + { + K[4*k] = in[k]; + K[1 + 4*k] = in[ 8 + k]; + K[2 + 4*k] = in[16 + k]; + K[3 + 4*k] = in[24 + k]; + } + + return K; + } + + //A (x) = (x0 ^ x1) || x3 || x2 || x1 + byte[] a = new byte[8]; + private byte[] A(byte[] in) + { + for(int j=0; j<8; j++) + { + a[j]=(byte)(in[j] ^ in[j+8]); + } + + System.arraycopy(in, 8, in, 0, 24); + System.arraycopy(a, 0, in, 24, 8); + + return in; + } + + //Encrypt function, ECB mode + private void E(byte[] key, byte[] s, int sOff, byte[] in, int inOff) + { + cipher.init(true, new KeyParameter(key)); + + cipher.processBlock(in, inOff, s, sOff); + } + + // (in:) n16||..||n1 ==> (out:) n1^n2^n3^n4^n13^n16||n16||..||n2 + short[] wS = new short[16], w_S = new short[16]; + + private void fw(byte[] in) + { + cpyBytesToShort(in, wS); + w_S[15] = (short)(wS[0] ^ wS[1] ^ wS[2] ^ wS[3] ^ wS[12] ^ wS[15]); + System.arraycopy(wS, 1, w_S, 0, 15); + cpyShortToBytes(w_S, in); + } + + // block processing + byte[] S = new byte[32]; + byte[] U = new byte[32], V = new byte[32], W = new byte[32]; + + protected void processBlock(byte[] in, int inOff) + { + System.arraycopy(in, inOff, M, 0, 32); + + //key step 1 + + // H = h3 || h2 || h1 || h0 + // S = s3 || s2 || s1 || s0 + System.arraycopy(H, 0, U, 0, 32); + System.arraycopy(M, 0, V, 0, 32); + for (int j=0; j<32; j++) + { + W[j] = (byte)(U[j]^V[j]); + } + // Encrypt gost28147-ECB + E(P(W), S, 0, H, 0); // s0 = EK0 [h0] + + //keys step 2,3,4 + for (int i=1; i<4; i++) + { + byte[] tmpA = A(U); + for (int j=0; j<32; j++) + { + U[j] = (byte)(tmpA[j] ^ C[i][j]); + } + V = A(A(V)); + for (int j=0; j<32; j++) + { + W[j] = (byte)(U[j]^V[j]); + } + // Encrypt gost28147-ECB + E(P(W), S, i * 8, H, i * 8); // si = EKi [hi] + } + + // x(M, H) = y61(H^y(M^y12(S))) + for(int n = 0; n < 12; n++) + { + fw(S); + } + for(int n = 0; n < 32; n++) + { + S[n] = (byte)(S[n] ^ M[n]); + } + + fw(S); + + for(int n = 0; n < 32; n++) + { + S[n] = (byte)(H[n] ^ S[n]); + } + for(int n = 0; n < 61; n++) + { + fw(S); + } + System.arraycopy(S, 0, H, 0, H.length); + } + + private void finish() + { + Pack.longToLittleEndian(byteCount * 8, L, 0); // get length into L (byteCount * 8 = bitCount) + + while (xBufOff != 0) + { + update((byte)0); + } + + processBlock(L, 0); + processBlock(Sum, 0); + } + + public int doFinal( + byte[] out, + int outOff) + { + finish(); + + System.arraycopy(H, 0, out, outOff, H.length); + + reset(); + + return DIGEST_LENGTH; + } + + /** + * reset the chaining variables to the IV values. + */ + private static final byte[] C2 = { + 0x00,(byte)0xFF,0x00,(byte)0xFF,0x00,(byte)0xFF,0x00,(byte)0xFF, + (byte)0xFF,0x00,(byte)0xFF,0x00,(byte)0xFF,0x00,(byte)0xFF,0x00, + 0x00,(byte)0xFF,(byte)0xFF,0x00,(byte)0xFF,0x00,0x00,(byte)0xFF, + (byte)0xFF,0x00,0x00,0x00,(byte)0xFF,(byte)0xFF,0x00,(byte)0xFF}; + + public void reset() + { + byteCount = 0; + xBufOff = 0; + + for(int i=0; i
+ * NOTE: This algorithm is only included for backwards compatability + * with legacy applications, it's not secure, don't use it for anything new! + */ +public class MD4Digest + extends GeneralDigest +{ + private static final int DIGEST_LENGTH = 16; + + private int H1, H2, H3, H4; // IV's + + private int[] X = new int[16]; + private int xOff; + + /** + * Standard constructor + */ + public MD4Digest() + { + reset(); + } + + /** + * Copy constructor. This will copy the state of the provided + * message digest. + */ + public MD4Digest(MD4Digest t) + { + super(t); + + H1 = t.H1; + H2 = t.H2; + H3 = t.H3; + H4 = t.H4; + + System.arraycopy(t.X, 0, X, 0, t.X.length); + xOff = t.xOff; + } + + public String getAlgorithmName() + { + return "MD4"; + } + + public int getDigestSize() + { + return DIGEST_LENGTH; + } + + protected void processWord( + byte[] in, + int inOff) + { + X[xOff++] = (in[inOff] & 0xff) | ((in[inOff + 1] & 0xff) << 8) + | ((in[inOff + 2] & 0xff) << 16) | ((in[inOff + 3] & 0xff) << 24); + + if (xOff == 16) + { + processBlock(); + } + } + + protected void processLength( + long bitLength) + { + if (xOff > 14) + { + processBlock(); + } + + X[14] = (int)(bitLength & 0xffffffff); + X[15] = (int)(bitLength >>> 32); + } + + private void unpackWord( + int word, + byte[] out, + int outOff) + { + out[outOff] = (byte)word; + out[outOff + 1] = (byte)(word >>> 8); + out[outOff + 2] = (byte)(word >>> 16); + out[outOff + 3] = (byte)(word >>> 24); + } + + public int doFinal( + byte[] out, + int outOff) + { + finish(); + + unpackWord(H1, out, outOff); + unpackWord(H2, out, outOff + 4); + unpackWord(H3, out, outOff + 8); + unpackWord(H4, out, outOff + 12); + + reset(); + + return DIGEST_LENGTH; + } + + /** + * reset the chaining variables to the IV values. + */ + public void reset() + { + super.reset(); + + H1 = 0x67452301; + H2 = 0xefcdab89; + H3 = 0x98badcfe; + H4 = 0x10325476; + + xOff = 0; + + for (int i = 0; i != X.length; i++) + { + X[i] = 0; + } + } + + // + // round 1 left rotates + // + private static final int S11 = 3; + private static final int S12 = 7; + private static final int S13 = 11; + private static final int S14 = 19; + + // + // round 2 left rotates + // + private static final int S21 = 3; + private static final int S22 = 5; + private static final int S23 = 9; + private static final int S24 = 13; + + // + // round 3 left rotates + // + private static final int S31 = 3; + private static final int S32 = 9; + private static final int S33 = 11; + private static final int S34 = 15; + + /* + * rotate int x left n bits. + */ + private int rotateLeft( + int x, + int n) + { + return (x << n) | (x >>> (32 - n)); + } + + /* + * F, G, H and I are the basic MD4 functions. + */ + private int F( + int u, + int v, + int w) + { + return (u & v) | (~u & w); + } + + private int G( + int u, + int v, + int w) + { + return (u & v) | (u & w) | (v & w); + } + + private int H( + int u, + int v, + int w) + { + return u ^ v ^ w; + } + + protected void processBlock() + { + int a = H1; + int b = H2; + int c = H3; + int d = H4; + + // + // Round 1 - F cycle, 16 times. + // + a = rotateLeft(a + F(b, c, d) + X[ 0], S11); + d = rotateLeft(d + F(a, b, c) + X[ 1], S12); + c = rotateLeft(c + F(d, a, b) + X[ 2], S13); + b = rotateLeft(b + F(c, d, a) + X[ 3], S14); + a = rotateLeft(a + F(b, c, d) + X[ 4], S11); + d = rotateLeft(d + F(a, b, c) + X[ 5], S12); + c = rotateLeft(c + F(d, a, b) + X[ 6], S13); + b = rotateLeft(b + F(c, d, a) + X[ 7], S14); + a = rotateLeft(a + F(b, c, d) + X[ 8], S11); + d = rotateLeft(d + F(a, b, c) + X[ 9], S12); + c = rotateLeft(c + F(d, a, b) + X[10], S13); + b = rotateLeft(b + F(c, d, a) + X[11], S14); + a = rotateLeft(a + F(b, c, d) + X[12], S11); + d = rotateLeft(d + F(a, b, c) + X[13], S12); + c = rotateLeft(c + F(d, a, b) + X[14], S13); + b = rotateLeft(b + F(c, d, a) + X[15], S14); + + // + // Round 2 - G cycle, 16 times. + // + a = rotateLeft(a + G(b, c, d) + X[ 0] + 0x5a827999, S21); + d = rotateLeft(d + G(a, b, c) + X[ 4] + 0x5a827999, S22); + c = rotateLeft(c + G(d, a, b) + X[ 8] + 0x5a827999, S23); + b = rotateLeft(b + G(c, d, a) + X[12] + 0x5a827999, S24); + a = rotateLeft(a + G(b, c, d) + X[ 1] + 0x5a827999, S21); + d = rotateLeft(d + G(a, b, c) + X[ 5] + 0x5a827999, S22); + c = rotateLeft(c + G(d, a, b) + X[ 9] + 0x5a827999, S23); + b = rotateLeft(b + G(c, d, a) + X[13] + 0x5a827999, S24); + a = rotateLeft(a + G(b, c, d) + X[ 2] + 0x5a827999, S21); + d = rotateLeft(d + G(a, b, c) + X[ 6] + 0x5a827999, S22); + c = rotateLeft(c + G(d, a, b) + X[10] + 0x5a827999, S23); + b = rotateLeft(b + G(c, d, a) + X[14] + 0x5a827999, S24); + a = rotateLeft(a + G(b, c, d) + X[ 3] + 0x5a827999, S21); + d = rotateLeft(d + G(a, b, c) + X[ 7] + 0x5a827999, S22); + c = rotateLeft(c + G(d, a, b) + X[11] + 0x5a827999, S23); + b = rotateLeft(b + G(c, d, a) + X[15] + 0x5a827999, S24); + + // + // Round 3 - H cycle, 16 times. + // + a = rotateLeft(a + H(b, c, d) + X[ 0] + 0x6ed9eba1, S31); + d = rotateLeft(d + H(a, b, c) + X[ 8] + 0x6ed9eba1, S32); + c = rotateLeft(c + H(d, a, b) + X[ 4] + 0x6ed9eba1, S33); + b = rotateLeft(b + H(c, d, a) + X[12] + 0x6ed9eba1, S34); + a = rotateLeft(a + H(b, c, d) + X[ 2] + 0x6ed9eba1, S31); + d = rotateLeft(d + H(a, b, c) + X[10] + 0x6ed9eba1, S32); + c = rotateLeft(c + H(d, a, b) + X[ 6] + 0x6ed9eba1, S33); + b = rotateLeft(b + H(c, d, a) + X[14] + 0x6ed9eba1, S34); + a = rotateLeft(a + H(b, c, d) + X[ 1] + 0x6ed9eba1, S31); + d = rotateLeft(d + H(a, b, c) + X[ 9] + 0x6ed9eba1, S32); + c = rotateLeft(c + H(d, a, b) + X[ 5] + 0x6ed9eba1, S33); + b = rotateLeft(b + H(c, d, a) + X[13] + 0x6ed9eba1, S34); + a = rotateLeft(a + H(b, c, d) + X[ 3] + 0x6ed9eba1, S31); + d = rotateLeft(d + H(a, b, c) + X[11] + 0x6ed9eba1, S32); + c = rotateLeft(c + H(d, a, b) + X[ 7] + 0x6ed9eba1, S33); + b = rotateLeft(b + H(c, d, a) + X[15] + 0x6ed9eba1, S34); + + H1 += a; + H2 += b; + H3 += c; + H4 += d; + + // + // reset the offset and clean out the word buffer. + // + xOff = 0; + for (int i = 0; i != X.length; i++) + { + X[i] = 0; + } + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/digests/MD5Digest.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/digests/MD5Digest.java new file mode 100644 index 0000000..a0d5452 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/digests/MD5Digest.java @@ -0,0 +1,302 @@ +package org.bc.crypto.digests; + + +/** + * implementation of MD5 as outlined in "Handbook of Applied Cryptography", pages 346 - 347. + */ +public class MD5Digest + extends GeneralDigest +{ + private static final int DIGEST_LENGTH = 16; + + private int H1, H2, H3, H4; // IV's + + private int[] X = new int[16]; + private int xOff; + + /** + * Standard constructor + */ + public MD5Digest() + { + reset(); + } + + /** + * Copy constructor. This will copy the state of the provided + * message digest. + */ + public MD5Digest(MD5Digest t) + { + super(t); + + H1 = t.H1; + H2 = t.H2; + H3 = t.H3; + H4 = t.H4; + + System.arraycopy(t.X, 0, X, 0, t.X.length); + xOff = t.xOff; + } + + public String getAlgorithmName() + { + return "MD5"; + } + + public int getDigestSize() + { + return DIGEST_LENGTH; + } + + protected void processWord( + byte[] in, + int inOff) + { + X[xOff++] = (in[inOff] & 0xff) | ((in[inOff + 1] & 0xff) << 8) + | ((in[inOff + 2] & 0xff) << 16) | ((in[inOff + 3] & 0xff) << 24); + + if (xOff == 16) + { + processBlock(); + } + } + + protected void processLength( + long bitLength) + { + if (xOff > 14) + { + processBlock(); + } + + X[14] = (int)(bitLength & 0xffffffff); + X[15] = (int)(bitLength >>> 32); + } + + private void unpackWord( + int word, + byte[] out, + int outOff) + { + out[outOff] = (byte)word; + out[outOff + 1] = (byte)(word >>> 8); + out[outOff + 2] = (byte)(word >>> 16); + out[outOff + 3] = (byte)(word >>> 24); + } + + public int doFinal( + byte[] out, + int outOff) + { + finish(); + + unpackWord(H1, out, outOff); + unpackWord(H2, out, outOff + 4); + unpackWord(H3, out, outOff + 8); + unpackWord(H4, out, outOff + 12); + + reset(); + + return DIGEST_LENGTH; + } + + /** + * reset the chaining variables to the IV values. + */ + public void reset() + { + super.reset(); + + H1 = 0x67452301; + H2 = 0xefcdab89; + H3 = 0x98badcfe; + H4 = 0x10325476; + + xOff = 0; + + for (int i = 0; i != X.length; i++) + { + X[i] = 0; + } + } + + // + // round 1 left rotates + // + private static final int S11 = 7; + private static final int S12 = 12; + private static final int S13 = 17; + private static final int S14 = 22; + + // + // round 2 left rotates + // + private static final int S21 = 5; + private static final int S22 = 9; + private static final int S23 = 14; + private static final int S24 = 20; + + // + // round 3 left rotates + // + private static final int S31 = 4; + private static final int S32 = 11; + private static final int S33 = 16; + private static final int S34 = 23; + + // + // round 4 left rotates + // + private static final int S41 = 6; + private static final int S42 = 10; + private static final int S43 = 15; + private static final int S44 = 21; + + /* + * rotate int x left n bits. + */ + private int rotateLeft( + int x, + int n) + { + return (x << n) | (x >>> (32 - n)); + } + + /* + * F, G, H and I are the basic MD5 functions. + */ + private int F( + int u, + int v, + int w) + { + return (u & v) | (~u & w); + } + + private int G( + int u, + int v, + int w) + { + return (u & w) | (v & ~w); + } + + private int H( + int u, + int v, + int w) + { + return u ^ v ^ w; + } + + private int K( + int u, + int v, + int w) + { + return v ^ (u | ~w); + } + + protected void processBlock() + { + int a = H1; + int b = H2; + int c = H3; + int d = H4; + + // + // Round 1 - F cycle, 16 times. + // + a = rotateLeft(a + F(b, c, d) + X[ 0] + 0xd76aa478, S11) + b; + d = rotateLeft(d + F(a, b, c) + X[ 1] + 0xe8c7b756, S12) + a; + c = rotateLeft(c + F(d, a, b) + X[ 2] + 0x242070db, S13) + d; + b = rotateLeft(b + F(c, d, a) + X[ 3] + 0xc1bdceee, S14) + c; + a = rotateLeft(a + F(b, c, d) + X[ 4] + 0xf57c0faf, S11) + b; + d = rotateLeft(d + F(a, b, c) + X[ 5] + 0x4787c62a, S12) + a; + c = rotateLeft(c + F(d, a, b) + X[ 6] + 0xa8304613, S13) + d; + b = rotateLeft(b + F(c, d, a) + X[ 7] + 0xfd469501, S14) + c; + a = rotateLeft(a + F(b, c, d) + X[ 8] + 0x698098d8, S11) + b; + d = rotateLeft(d + F(a, b, c) + X[ 9] + 0x8b44f7af, S12) + a; + c = rotateLeft(c + F(d, a, b) + X[10] + 0xffff5bb1, S13) + d; + b = rotateLeft(b + F(c, d, a) + X[11] + 0x895cd7be, S14) + c; + a = rotateLeft(a + F(b, c, d) + X[12] + 0x6b901122, S11) + b; + d = rotateLeft(d + F(a, b, c) + X[13] + 0xfd987193, S12) + a; + c = rotateLeft(c + F(d, a, b) + X[14] + 0xa679438e, S13) + d; + b = rotateLeft(b + F(c, d, a) + X[15] + 0x49b40821, S14) + c; + + // + // Round 2 - G cycle, 16 times. + // + a = rotateLeft(a + G(b, c, d) + X[ 1] + 0xf61e2562, S21) + b; + d = rotateLeft(d + G(a, b, c) + X[ 6] + 0xc040b340, S22) + a; + c = rotateLeft(c + G(d, a, b) + X[11] + 0x265e5a51, S23) + d; + b = rotateLeft(b + G(c, d, a) + X[ 0] + 0xe9b6c7aa, S24) + c; + a = rotateLeft(a + G(b, c, d) + X[ 5] + 0xd62f105d, S21) + b; + d = rotateLeft(d + G(a, b, c) + X[10] + 0x02441453, S22) + a; + c = rotateLeft(c + G(d, a, b) + X[15] + 0xd8a1e681, S23) + d; + b = rotateLeft(b + G(c, d, a) + X[ 4] + 0xe7d3fbc8, S24) + c; + a = rotateLeft(a + G(b, c, d) + X[ 9] + 0x21e1cde6, S21) + b; + d = rotateLeft(d + G(a, b, c) + X[14] + 0xc33707d6, S22) + a; + c = rotateLeft(c + G(d, a, b) + X[ 3] + 0xf4d50d87, S23) + d; + b = rotateLeft(b + G(c, d, a) + X[ 8] + 0x455a14ed, S24) + c; + a = rotateLeft(a + G(b, c, d) + X[13] + 0xa9e3e905, S21) + b; + d = rotateLeft(d + G(a, b, c) + X[ 2] + 0xfcefa3f8, S22) + a; + c = rotateLeft(c + G(d, a, b) + X[ 7] + 0x676f02d9, S23) + d; + b = rotateLeft(b + G(c, d, a) + X[12] + 0x8d2a4c8a, S24) + c; + + // + // Round 3 - H cycle, 16 times. + // + a = rotateLeft(a + H(b, c, d) + X[ 5] + 0xfffa3942, S31) + b; + d = rotateLeft(d + H(a, b, c) + X[ 8] + 0x8771f681, S32) + a; + c = rotateLeft(c + H(d, a, b) + X[11] + 0x6d9d6122, S33) + d; + b = rotateLeft(b + H(c, d, a) + X[14] + 0xfde5380c, S34) + c; + a = rotateLeft(a + H(b, c, d) + X[ 1] + 0xa4beea44, S31) + b; + d = rotateLeft(d + H(a, b, c) + X[ 4] + 0x4bdecfa9, S32) + a; + c = rotateLeft(c + H(d, a, b) + X[ 7] + 0xf6bb4b60, S33) + d; + b = rotateLeft(b + H(c, d, a) + X[10] + 0xbebfbc70, S34) + c; + a = rotateLeft(a + H(b, c, d) + X[13] + 0x289b7ec6, S31) + b; + d = rotateLeft(d + H(a, b, c) + X[ 0] + 0xeaa127fa, S32) + a; + c = rotateLeft(c + H(d, a, b) + X[ 3] + 0xd4ef3085, S33) + d; + b = rotateLeft(b + H(c, d, a) + X[ 6] + 0x04881d05, S34) + c; + a = rotateLeft(a + H(b, c, d) + X[ 9] + 0xd9d4d039, S31) + b; + d = rotateLeft(d + H(a, b, c) + X[12] + 0xe6db99e5, S32) + a; + c = rotateLeft(c + H(d, a, b) + X[15] + 0x1fa27cf8, S33) + d; + b = rotateLeft(b + H(c, d, a) + X[ 2] + 0xc4ac5665, S34) + c; + + // + // Round 4 - K cycle, 16 times. + // + a = rotateLeft(a + K(b, c, d) + X[ 0] + 0xf4292244, S41) + b; + d = rotateLeft(d + K(a, b, c) + X[ 7] + 0x432aff97, S42) + a; + c = rotateLeft(c + K(d, a, b) + X[14] + 0xab9423a7, S43) + d; + b = rotateLeft(b + K(c, d, a) + X[ 5] + 0xfc93a039, S44) + c; + a = rotateLeft(a + K(b, c, d) + X[12] + 0x655b59c3, S41) + b; + d = rotateLeft(d + K(a, b, c) + X[ 3] + 0x8f0ccc92, S42) + a; + c = rotateLeft(c + K(d, a, b) + X[10] + 0xffeff47d, S43) + d; + b = rotateLeft(b + K(c, d, a) + X[ 1] + 0x85845dd1, S44) + c; + a = rotateLeft(a + K(b, c, d) + X[ 8] + 0x6fa87e4f, S41) + b; + d = rotateLeft(d + K(a, b, c) + X[15] + 0xfe2ce6e0, S42) + a; + c = rotateLeft(c + K(d, a, b) + X[ 6] + 0xa3014314, S43) + d; + b = rotateLeft(b + K(c, d, a) + X[13] + 0x4e0811a1, S44) + c; + a = rotateLeft(a + K(b, c, d) + X[ 4] + 0xf7537e82, S41) + b; + d = rotateLeft(d + K(a, b, c) + X[11] + 0xbd3af235, S42) + a; + c = rotateLeft(c + K(d, a, b) + X[ 2] + 0x2ad7d2bb, S43) + d; + b = rotateLeft(b + K(c, d, a) + X[ 9] + 0xeb86d391, S44) + c; + + H1 += a; + H2 += b; + H3 += c; + H4 += d; + + // + // reset the offset and clean out the word buffer. + // + xOff = 0; + for (int i = 0; i != X.length; i++) + { + X[i] = 0; + } + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/digests/NullDigest.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/digests/NullDigest.java new file mode 100644 index 0000000..ef88014 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/digests/NullDigest.java @@ -0,0 +1,48 @@ +package org.bc.crypto.digests; + +import java.io.ByteArrayOutputStream; + +import org.bc.crypto.Digest; + + +public class NullDigest + implements Digest +{ + private ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + public String getAlgorithmName() + { + return "NULL"; + } + + public int getDigestSize() + { + return bOut.size(); + } + + public void update(byte in) + { + bOut.write(in); + } + + public void update(byte[] in, int inOff, int len) + { + bOut.write(in, inOff, len); + } + + public int doFinal(byte[] out, int outOff) + { + byte[] res = bOut.toByteArray(); + + System.arraycopy(res, 0, out, outOff, res.length); + + reset(); + + return res.length; + } + + public void reset() + { + bOut.reset(); + } +} \ No newline at end of file diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/digests/RIPEMD128Digest.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/digests/RIPEMD128Digest.java new file mode 100644 index 0000000..02903d2 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/digests/RIPEMD128Digest.java @@ -0,0 +1,461 @@ +package org.bc.crypto.digests; + + +/** + * implementation of RIPEMD128 + */ +public class RIPEMD128Digest + extends GeneralDigest +{ + private static final int DIGEST_LENGTH = 16; + + private int H0, H1, H2, H3; // IV's + + private int[] X = new int[16]; + private int xOff; + + /** + * Standard constructor + */ + public RIPEMD128Digest() + { + reset(); + } + + /** + * Copy constructor. This will copy the state of the provided + * message digest. + */ + public RIPEMD128Digest(RIPEMD128Digest t) + { + super(t); + + H0 = t.H0; + H1 = t.H1; + H2 = t.H2; + H3 = t.H3; + + System.arraycopy(t.X, 0, X, 0, t.X.length); + xOff = t.xOff; + } + + public String getAlgorithmName() + { + return "RIPEMD128"; + } + + public int getDigestSize() + { + return DIGEST_LENGTH; + } + + protected void processWord( + byte[] in, + int inOff) + { + X[xOff++] = (in[inOff] & 0xff) | ((in[inOff + 1] & 0xff) << 8) + | ((in[inOff + 2] & 0xff) << 16) | ((in[inOff + 3] & 0xff) << 24); + + if (xOff == 16) + { + processBlock(); + } + } + + protected void processLength( + long bitLength) + { + if (xOff > 14) + { + processBlock(); + } + + X[14] = (int)(bitLength & 0xffffffff); + X[15] = (int)(bitLength >>> 32); + } + + private void unpackWord( + int word, + byte[] out, + int outOff) + { + out[outOff] = (byte)word; + out[outOff + 1] = (byte)(word >>> 8); + out[outOff + 2] = (byte)(word >>> 16); + out[outOff + 3] = (byte)(word >>> 24); + } + + public int doFinal( + byte[] out, + int outOff) + { + finish(); + + unpackWord(H0, out, outOff); + unpackWord(H1, out, outOff + 4); + unpackWord(H2, out, outOff + 8); + unpackWord(H3, out, outOff + 12); + + reset(); + + return DIGEST_LENGTH; + } + + /** + * reset the chaining variables to the IV values. + */ + public void reset() + { + super.reset(); + + H0 = 0x67452301; + H1 = 0xefcdab89; + H2 = 0x98badcfe; + H3 = 0x10325476; + + xOff = 0; + + for (int i = 0; i != X.length; i++) + { + X[i] = 0; + } + } + + /* + * rotate int x left n bits. + */ + private int RL( + int x, + int n) + { + return (x << n) | (x >>> (32 - n)); + } + + /* + * f1,f2,f3,f4 are the basic RIPEMD128 functions. + */ + + /* + * F + */ + private int f1( + int x, + int y, + int z) + { + return x ^ y ^ z; + } + + /* + * G + */ + private int f2( + int x, + int y, + int z) + { + return (x & y) | (~x & z); + } + + /* + * H + */ + private int f3( + int x, + int y, + int z) + { + return (x | ~y) ^ z; + } + + /* + * I + */ + private int f4( + int x, + int y, + int z) + { + return (x & z) | (y & ~z); + } + + private int F1( + int a, + int b, + int c, + int d, + int x, + int s) + { + return RL(a + f1(b, c, d) + x, s); + } + + private int F2( + int a, + int b, + int c, + int d, + int x, + int s) + { + return RL(a + f2(b, c, d) + x + 0x5a827999, s); + } + + private int F3( + int a, + int b, + int c, + int d, + int x, + int s) + { + return RL(a + f3(b, c, d) + x + 0x6ed9eba1, s); + } + + private int F4( + int a, + int b, + int c, + int d, + int x, + int s) + { + return RL(a + f4(b, c, d) + x + 0x8f1bbcdc, s); + } + + private int FF1( + int a, + int b, + int c, + int d, + int x, + int s) + { + return RL(a + f1(b, c, d) + x, s); + } + + private int FF2( + int a, + int b, + int c, + int d, + int x, + int s) + { + return RL(a + f2(b, c, d) + x + 0x6d703ef3, s); + } + + private int FF3( + int a, + int b, + int c, + int d, + int x, + int s) + { + return RL(a + f3(b, c, d) + x + 0x5c4dd124, s); + } + + private int FF4( + int a, + int b, + int c, + int d, + int x, + int s) + { + return RL(a + f4(b, c, d) + x + 0x50a28be6, s); + } + + protected void processBlock() + { + int a, aa; + int b, bb; + int c, cc; + int d, dd; + + a = aa = H0; + b = bb = H1; + c = cc = H2; + d = dd = H3; + + // + // Round 1 + // + a = F1(a, b, c, d, X[ 0], 11); + d = F1(d, a, b, c, X[ 1], 14); + c = F1(c, d, a, b, X[ 2], 15); + b = F1(b, c, d, a, X[ 3], 12); + a = F1(a, b, c, d, X[ 4], 5); + d = F1(d, a, b, c, X[ 5], 8); + c = F1(c, d, a, b, X[ 6], 7); + b = F1(b, c, d, a, X[ 7], 9); + a = F1(a, b, c, d, X[ 8], 11); + d = F1(d, a, b, c, X[ 9], 13); + c = F1(c, d, a, b, X[10], 14); + b = F1(b, c, d, a, X[11], 15); + a = F1(a, b, c, d, X[12], 6); + d = F1(d, a, b, c, X[13], 7); + c = F1(c, d, a, b, X[14], 9); + b = F1(b, c, d, a, X[15], 8); + + // + // Round 2 + // + a = F2(a, b, c, d, X[ 7], 7); + d = F2(d, a, b, c, X[ 4], 6); + c = F2(c, d, a, b, X[13], 8); + b = F2(b, c, d, a, X[ 1], 13); + a = F2(a, b, c, d, X[10], 11); + d = F2(d, a, b, c, X[ 6], 9); + c = F2(c, d, a, b, X[15], 7); + b = F2(b, c, d, a, X[ 3], 15); + a = F2(a, b, c, d, X[12], 7); + d = F2(d, a, b, c, X[ 0], 12); + c = F2(c, d, a, b, X[ 9], 15); + b = F2(b, c, d, a, X[ 5], 9); + a = F2(a, b, c, d, X[ 2], 11); + d = F2(d, a, b, c, X[14], 7); + c = F2(c, d, a, b, X[11], 13); + b = F2(b, c, d, a, X[ 8], 12); + + // + // Round 3 + // + a = F3(a, b, c, d, X[ 3], 11); + d = F3(d, a, b, c, X[10], 13); + c = F3(c, d, a, b, X[14], 6); + b = F3(b, c, d, a, X[ 4], 7); + a = F3(a, b, c, d, X[ 9], 14); + d = F3(d, a, b, c, X[15], 9); + c = F3(c, d, a, b, X[ 8], 13); + b = F3(b, c, d, a, X[ 1], 15); + a = F3(a, b, c, d, X[ 2], 14); + d = F3(d, a, b, c, X[ 7], 8); + c = F3(c, d, a, b, X[ 0], 13); + b = F3(b, c, d, a, X[ 6], 6); + a = F3(a, b, c, d, X[13], 5); + d = F3(d, a, b, c, X[11], 12); + c = F3(c, d, a, b, X[ 5], 7); + b = F3(b, c, d, a, X[12], 5); + + // + // Round 4 + // + a = F4(a, b, c, d, X[ 1], 11); + d = F4(d, a, b, c, X[ 9], 12); + c = F4(c, d, a, b, X[11], 14); + b = F4(b, c, d, a, X[10], 15); + a = F4(a, b, c, d, X[ 0], 14); + d = F4(d, a, b, c, X[ 8], 15); + c = F4(c, d, a, b, X[12], 9); + b = F4(b, c, d, a, X[ 4], 8); + a = F4(a, b, c, d, X[13], 9); + d = F4(d, a, b, c, X[ 3], 14); + c = F4(c, d, a, b, X[ 7], 5); + b = F4(b, c, d, a, X[15], 6); + a = F4(a, b, c, d, X[14], 8); + d = F4(d, a, b, c, X[ 5], 6); + c = F4(c, d, a, b, X[ 6], 5); + b = F4(b, c, d, a, X[ 2], 12); + + // + // Parallel round 1 + // + aa = FF4(aa, bb, cc, dd, X[ 5], 8); + dd = FF4(dd, aa, bb, cc, X[14], 9); + cc = FF4(cc, dd, aa, bb, X[ 7], 9); + bb = FF4(bb, cc, dd, aa, X[ 0], 11); + aa = FF4(aa, bb, cc, dd, X[ 9], 13); + dd = FF4(dd, aa, bb, cc, X[ 2], 15); + cc = FF4(cc, dd, aa, bb, X[11], 15); + bb = FF4(bb, cc, dd, aa, X[ 4], 5); + aa = FF4(aa, bb, cc, dd, X[13], 7); + dd = FF4(dd, aa, bb, cc, X[ 6], 7); + cc = FF4(cc, dd, aa, bb, X[15], 8); + bb = FF4(bb, cc, dd, aa, X[ 8], 11); + aa = FF4(aa, bb, cc, dd, X[ 1], 14); + dd = FF4(dd, aa, bb, cc, X[10], 14); + cc = FF4(cc, dd, aa, bb, X[ 3], 12); + bb = FF4(bb, cc, dd, aa, X[12], 6); + + // + // Parallel round 2 + // + aa = FF3(aa, bb, cc, dd, X[ 6], 9); + dd = FF3(dd, aa, bb, cc, X[11], 13); + cc = FF3(cc, dd, aa, bb, X[ 3], 15); + bb = FF3(bb, cc, dd, aa, X[ 7], 7); + aa = FF3(aa, bb, cc, dd, X[ 0], 12); + dd = FF3(dd, aa, bb, cc, X[13], 8); + cc = FF3(cc, dd, aa, bb, X[ 5], 9); + bb = FF3(bb, cc, dd, aa, X[10], 11); + aa = FF3(aa, bb, cc, dd, X[14], 7); + dd = FF3(dd, aa, bb, cc, X[15], 7); + cc = FF3(cc, dd, aa, bb, X[ 8], 12); + bb = FF3(bb, cc, dd, aa, X[12], 7); + aa = FF3(aa, bb, cc, dd, X[ 4], 6); + dd = FF3(dd, aa, bb, cc, X[ 9], 15); + cc = FF3(cc, dd, aa, bb, X[ 1], 13); + bb = FF3(bb, cc, dd, aa, X[ 2], 11); + + // + // Parallel round 3 + // + aa = FF2(aa, bb, cc, dd, X[15], 9); + dd = FF2(dd, aa, bb, cc, X[ 5], 7); + cc = FF2(cc, dd, aa, bb, X[ 1], 15); + bb = FF2(bb, cc, dd, aa, X[ 3], 11); + aa = FF2(aa, bb, cc, dd, X[ 7], 8); + dd = FF2(dd, aa, bb, cc, X[14], 6); + cc = FF2(cc, dd, aa, bb, X[ 6], 6); + bb = FF2(bb, cc, dd, aa, X[ 9], 14); + aa = FF2(aa, bb, cc, dd, X[11], 12); + dd = FF2(dd, aa, bb, cc, X[ 8], 13); + cc = FF2(cc, dd, aa, bb, X[12], 5); + bb = FF2(bb, cc, dd, aa, X[ 2], 14); + aa = FF2(aa, bb, cc, dd, X[10], 13); + dd = FF2(dd, aa, bb, cc, X[ 0], 13); + cc = FF2(cc, dd, aa, bb, X[ 4], 7); + bb = FF2(bb, cc, dd, aa, X[13], 5); + + // + // Parallel round 4 + // + aa = FF1(aa, bb, cc, dd, X[ 8], 15); + dd = FF1(dd, aa, bb, cc, X[ 6], 5); + cc = FF1(cc, dd, aa, bb, X[ 4], 8); + bb = FF1(bb, cc, dd, aa, X[ 1], 11); + aa = FF1(aa, bb, cc, dd, X[ 3], 14); + dd = FF1(dd, aa, bb, cc, X[11], 14); + cc = FF1(cc, dd, aa, bb, X[15], 6); + bb = FF1(bb, cc, dd, aa, X[ 0], 14); + aa = FF1(aa, bb, cc, dd, X[ 5], 6); + dd = FF1(dd, aa, bb, cc, X[12], 9); + cc = FF1(cc, dd, aa, bb, X[ 2], 12); + bb = FF1(bb, cc, dd, aa, X[13], 9); + aa = FF1(aa, bb, cc, dd, X[ 9], 12); + dd = FF1(dd, aa, bb, cc, X[ 7], 5); + cc = FF1(cc, dd, aa, bb, X[10], 15); + bb = FF1(bb, cc, dd, aa, X[14], 8); + + dd += c + H1; // final result for H0 + + // + // combine the results + // + H1 = H2 + d + aa; + H2 = H3 + a + bb; + H3 = H0 + b + cc; + H0 = dd; + + // + // reset the offset and clean out the word buffer. + // + xOff = 0; + for (int i = 0; i != X.length; i++) + { + X[i] = 0; + } + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/digests/RIPEMD160Digest.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/digests/RIPEMD160Digest.java new file mode 100644 index 0000000..b0a5144 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/digests/RIPEMD160Digest.java @@ -0,0 +1,422 @@ +package org.bc.crypto.digests; + + +/** + * implementation of RIPEMD see, + * http://www.esat.kuleuven.ac.be/~bosselae/ripemd160.html + */ +public class RIPEMD160Digest + extends GeneralDigest +{ + private static final int DIGEST_LENGTH = 20; + + private int H0, H1, H2, H3, H4; // IV's + + private int[] X = new int[16]; + private int xOff; + + /** + * Standard constructor + */ + public RIPEMD160Digest() + { + reset(); + } + + /** + * Copy constructor. This will copy the state of the provided + * message digest. + */ + public RIPEMD160Digest(RIPEMD160Digest t) + { + super(t); + + H0 = t.H0; + H1 = t.H1; + H2 = t.H2; + H3 = t.H3; + H4 = t.H4; + + System.arraycopy(t.X, 0, X, 0, t.X.length); + xOff = t.xOff; + } + + public String getAlgorithmName() + { + return "RIPEMD160"; + } + + public int getDigestSize() + { + return DIGEST_LENGTH; + } + + protected void processWord( + byte[] in, + int inOff) + { + X[xOff++] = (in[inOff] & 0xff) | ((in[inOff + 1] & 0xff) << 8) + | ((in[inOff + 2] & 0xff) << 16) | ((in[inOff + 3] & 0xff) << 24); + + if (xOff == 16) + { + processBlock(); + } + } + + protected void processLength( + long bitLength) + { + if (xOff > 14) + { + processBlock(); + } + + X[14] = (int)(bitLength & 0xffffffff); + X[15] = (int)(bitLength >>> 32); + } + + private void unpackWord( + int word, + byte[] out, + int outOff) + { + out[outOff] = (byte)word; + out[outOff + 1] = (byte)(word >>> 8); + out[outOff + 2] = (byte)(word >>> 16); + out[outOff + 3] = (byte)(word >>> 24); + } + + public int doFinal( + byte[] out, + int outOff) + { + finish(); + + unpackWord(H0, out, outOff); + unpackWord(H1, out, outOff + 4); + unpackWord(H2, out, outOff + 8); + unpackWord(H3, out, outOff + 12); + unpackWord(H4, out, outOff + 16); + + reset(); + + return DIGEST_LENGTH; + } + + /** + * reset the chaining variables to the IV values. + */ + public void reset() + { + super.reset(); + + H0 = 0x67452301; + H1 = 0xefcdab89; + H2 = 0x98badcfe; + H3 = 0x10325476; + H4 = 0xc3d2e1f0; + + xOff = 0; + + for (int i = 0; i != X.length; i++) + { + X[i] = 0; + } + } + + /* + * rotate int x left n bits. + */ + private int RL( + int x, + int n) + { + return (x << n) | (x >>> (32 - n)); + } + + /* + * f1,f2,f3,f4,f5 are the basic RIPEMD160 functions. + */ + + /* + * rounds 0-15 + */ + private int f1( + int x, + int y, + int z) + { + return x ^ y ^ z; + } + + /* + * rounds 16-31 + */ + private int f2( + int x, + int y, + int z) + { + return (x & y) | (~x & z); + } + + /* + * rounds 32-47 + */ + private int f3( + int x, + int y, + int z) + { + return (x | ~y) ^ z; + } + + /* + * rounds 48-63 + */ + private int f4( + int x, + int y, + int z) + { + return (x & z) | (y & ~z); + } + + /* + * rounds 64-79 + */ + private int f5( + int x, + int y, + int z) + { + return x ^ (y | ~z); + } + + protected void processBlock() + { + int a, aa; + int b, bb; + int c, cc; + int d, dd; + int e, ee; + + a = aa = H0; + b = bb = H1; + c = cc = H2; + d = dd = H3; + e = ee = H4; + + // + // Rounds 1 - 16 + // + // left + a = RL(a + f1(b,c,d) + X[ 0], 11) + e; c = RL(c, 10); + e = RL(e + f1(a,b,c) + X[ 1], 14) + d; b = RL(b, 10); + d = RL(d + f1(e,a,b) + X[ 2], 15) + c; a = RL(a, 10); + c = RL(c + f1(d,e,a) + X[ 3], 12) + b; e = RL(e, 10); + b = RL(b + f1(c,d,e) + X[ 4], 5) + a; d = RL(d, 10); + a = RL(a + f1(b,c,d) + X[ 5], 8) + e; c = RL(c, 10); + e = RL(e + f1(a,b,c) + X[ 6], 7) + d; b = RL(b, 10); + d = RL(d + f1(e,a,b) + X[ 7], 9) + c; a = RL(a, 10); + c = RL(c + f1(d,e,a) + X[ 8], 11) + b; e = RL(e, 10); + b = RL(b + f1(c,d,e) + X[ 9], 13) + a; d = RL(d, 10); + a = RL(a + f1(b,c,d) + X[10], 14) + e; c = RL(c, 10); + e = RL(e + f1(a,b,c) + X[11], 15) + d; b = RL(b, 10); + d = RL(d + f1(e,a,b) + X[12], 6) + c; a = RL(a, 10); + c = RL(c + f1(d,e,a) + X[13], 7) + b; e = RL(e, 10); + b = RL(b + f1(c,d,e) + X[14], 9) + a; d = RL(d, 10); + a = RL(a + f1(b,c,d) + X[15], 8) + e; c = RL(c, 10); + + // right + aa = RL(aa + f5(bb,cc,dd) + X[ 5] + 0x50a28be6, 8) + ee; cc = RL(cc, 10); + ee = RL(ee + f5(aa,bb,cc) + X[14] + 0x50a28be6, 9) + dd; bb = RL(bb, 10); + dd = RL(dd + f5(ee,aa,bb) + X[ 7] + 0x50a28be6, 9) + cc; aa = RL(aa, 10); + cc = RL(cc + f5(dd,ee,aa) + X[ 0] + 0x50a28be6, 11) + bb; ee = RL(ee, 10); + bb = RL(bb + f5(cc,dd,ee) + X[ 9] + 0x50a28be6, 13) + aa; dd = RL(dd, 10); + aa = RL(aa + f5(bb,cc,dd) + X[ 2] + 0x50a28be6, 15) + ee; cc = RL(cc, 10); + ee = RL(ee + f5(aa,bb,cc) + X[11] + 0x50a28be6, 15) + dd; bb = RL(bb, 10); + dd = RL(dd + f5(ee,aa,bb) + X[ 4] + 0x50a28be6, 5) + cc; aa = RL(aa, 10); + cc = RL(cc + f5(dd,ee,aa) + X[13] + 0x50a28be6, 7) + bb; ee = RL(ee, 10); + bb = RL(bb + f5(cc,dd,ee) + X[ 6] + 0x50a28be6, 7) + aa; dd = RL(dd, 10); + aa = RL(aa + f5(bb,cc,dd) + X[15] + 0x50a28be6, 8) + ee; cc = RL(cc, 10); + ee = RL(ee + f5(aa,bb,cc) + X[ 8] + 0x50a28be6, 11) + dd; bb = RL(bb, 10); + dd = RL(dd + f5(ee,aa,bb) + X[ 1] + 0x50a28be6, 14) + cc; aa = RL(aa, 10); + cc = RL(cc + f5(dd,ee,aa) + X[10] + 0x50a28be6, 14) + bb; ee = RL(ee, 10); + bb = RL(bb + f5(cc,dd,ee) + X[ 3] + 0x50a28be6, 12) + aa; dd = RL(dd, 10); + aa = RL(aa + f5(bb,cc,dd) + X[12] + 0x50a28be6, 6) + ee; cc = RL(cc, 10); + + // + // Rounds 16-31 + // + // left + e = RL(e + f2(a,b,c) + X[ 7] + 0x5a827999, 7) + d; b = RL(b, 10); + d = RL(d + f2(e,a,b) + X[ 4] + 0x5a827999, 6) + c; a = RL(a, 10); + c = RL(c + f2(d,e,a) + X[13] + 0x5a827999, 8) + b; e = RL(e, 10); + b = RL(b + f2(c,d,e) + X[ 1] + 0x5a827999, 13) + a; d = RL(d, 10); + a = RL(a + f2(b,c,d) + X[10] + 0x5a827999, 11) + e; c = RL(c, 10); + e = RL(e + f2(a,b,c) + X[ 6] + 0x5a827999, 9) + d; b = RL(b, 10); + d = RL(d + f2(e,a,b) + X[15] + 0x5a827999, 7) + c; a = RL(a, 10); + c = RL(c + f2(d,e,a) + X[ 3] + 0x5a827999, 15) + b; e = RL(e, 10); + b = RL(b + f2(c,d,e) + X[12] + 0x5a827999, 7) + a; d = RL(d, 10); + a = RL(a + f2(b,c,d) + X[ 0] + 0x5a827999, 12) + e; c = RL(c, 10); + e = RL(e + f2(a,b,c) + X[ 9] + 0x5a827999, 15) + d; b = RL(b, 10); + d = RL(d + f2(e,a,b) + X[ 5] + 0x5a827999, 9) + c; a = RL(a, 10); + c = RL(c + f2(d,e,a) + X[ 2] + 0x5a827999, 11) + b; e = RL(e, 10); + b = RL(b + f2(c,d,e) + X[14] + 0x5a827999, 7) + a; d = RL(d, 10); + a = RL(a + f2(b,c,d) + X[11] + 0x5a827999, 13) + e; c = RL(c, 10); + e = RL(e + f2(a,b,c) + X[ 8] + 0x5a827999, 12) + d; b = RL(b, 10); + + // right + ee = RL(ee + f4(aa,bb,cc) + X[ 6] + 0x5c4dd124, 9) + dd; bb = RL(bb, 10); + dd = RL(dd + f4(ee,aa,bb) + X[11] + 0x5c4dd124, 13) + cc; aa = RL(aa, 10); + cc = RL(cc + f4(dd,ee,aa) + X[ 3] + 0x5c4dd124, 15) + bb; ee = RL(ee, 10); + bb = RL(bb + f4(cc,dd,ee) + X[ 7] + 0x5c4dd124, 7) + aa; dd = RL(dd, 10); + aa = RL(aa + f4(bb,cc,dd) + X[ 0] + 0x5c4dd124, 12) + ee; cc = RL(cc, 10); + ee = RL(ee + f4(aa,bb,cc) + X[13] + 0x5c4dd124, 8) + dd; bb = RL(bb, 10); + dd = RL(dd + f4(ee,aa,bb) + X[ 5] + 0x5c4dd124, 9) + cc; aa = RL(aa, 10); + cc = RL(cc + f4(dd,ee,aa) + X[10] + 0x5c4dd124, 11) + bb; ee = RL(ee, 10); + bb = RL(bb + f4(cc,dd,ee) + X[14] + 0x5c4dd124, 7) + aa; dd = RL(dd, 10); + aa = RL(aa + f4(bb,cc,dd) + X[15] + 0x5c4dd124, 7) + ee; cc = RL(cc, 10); + ee = RL(ee + f4(aa,bb,cc) + X[ 8] + 0x5c4dd124, 12) + dd; bb = RL(bb, 10); + dd = RL(dd + f4(ee,aa,bb) + X[12] + 0x5c4dd124, 7) + cc; aa = RL(aa, 10); + cc = RL(cc + f4(dd,ee,aa) + X[ 4] + 0x5c4dd124, 6) + bb; ee = RL(ee, 10); + bb = RL(bb + f4(cc,dd,ee) + X[ 9] + 0x5c4dd124, 15) + aa; dd = RL(dd, 10); + aa = RL(aa + f4(bb,cc,dd) + X[ 1] + 0x5c4dd124, 13) + ee; cc = RL(cc, 10); + ee = RL(ee + f4(aa,bb,cc) + X[ 2] + 0x5c4dd124, 11) + dd; bb = RL(bb, 10); + + // + // Rounds 32-47 + // + // left + d = RL(d + f3(e,a,b) + X[ 3] + 0x6ed9eba1, 11) + c; a = RL(a, 10); + c = RL(c + f3(d,e,a) + X[10] + 0x6ed9eba1, 13) + b; e = RL(e, 10); + b = RL(b + f3(c,d,e) + X[14] + 0x6ed9eba1, 6) + a; d = RL(d, 10); + a = RL(a + f3(b,c,d) + X[ 4] + 0x6ed9eba1, 7) + e; c = RL(c, 10); + e = RL(e + f3(a,b,c) + X[ 9] + 0x6ed9eba1, 14) + d; b = RL(b, 10); + d = RL(d + f3(e,a,b) + X[15] + 0x6ed9eba1, 9) + c; a = RL(a, 10); + c = RL(c + f3(d,e,a) + X[ 8] + 0x6ed9eba1, 13) + b; e = RL(e, 10); + b = RL(b + f3(c,d,e) + X[ 1] + 0x6ed9eba1, 15) + a; d = RL(d, 10); + a = RL(a + f3(b,c,d) + X[ 2] + 0x6ed9eba1, 14) + e; c = RL(c, 10); + e = RL(e + f3(a,b,c) + X[ 7] + 0x6ed9eba1, 8) + d; b = RL(b, 10); + d = RL(d + f3(e,a,b) + X[ 0] + 0x6ed9eba1, 13) + c; a = RL(a, 10); + c = RL(c + f3(d,e,a) + X[ 6] + 0x6ed9eba1, 6) + b; e = RL(e, 10); + b = RL(b + f3(c,d,e) + X[13] + 0x6ed9eba1, 5) + a; d = RL(d, 10); + a = RL(a + f3(b,c,d) + X[11] + 0x6ed9eba1, 12) + e; c = RL(c, 10); + e = RL(e + f3(a,b,c) + X[ 5] + 0x6ed9eba1, 7) + d; b = RL(b, 10); + d = RL(d + f3(e,a,b) + X[12] + 0x6ed9eba1, 5) + c; a = RL(a, 10); + + // right + dd = RL(dd + f3(ee,aa,bb) + X[15] + 0x6d703ef3, 9) + cc; aa = RL(aa, 10); + cc = RL(cc + f3(dd,ee,aa) + X[ 5] + 0x6d703ef3, 7) + bb; ee = RL(ee, 10); + bb = RL(bb + f3(cc,dd,ee) + X[ 1] + 0x6d703ef3, 15) + aa; dd = RL(dd, 10); + aa = RL(aa + f3(bb,cc,dd) + X[ 3] + 0x6d703ef3, 11) + ee; cc = RL(cc, 10); + ee = RL(ee + f3(aa,bb,cc) + X[ 7] + 0x6d703ef3, 8) + dd; bb = RL(bb, 10); + dd = RL(dd + f3(ee,aa,bb) + X[14] + 0x6d703ef3, 6) + cc; aa = RL(aa, 10); + cc = RL(cc + f3(dd,ee,aa) + X[ 6] + 0x6d703ef3, 6) + bb; ee = RL(ee, 10); + bb = RL(bb + f3(cc,dd,ee) + X[ 9] + 0x6d703ef3, 14) + aa; dd = RL(dd, 10); + aa = RL(aa + f3(bb,cc,dd) + X[11] + 0x6d703ef3, 12) + ee; cc = RL(cc, 10); + ee = RL(ee + f3(aa,bb,cc) + X[ 8] + 0x6d703ef3, 13) + dd; bb = RL(bb, 10); + dd = RL(dd + f3(ee,aa,bb) + X[12] + 0x6d703ef3, 5) + cc; aa = RL(aa, 10); + cc = RL(cc + f3(dd,ee,aa) + X[ 2] + 0x6d703ef3, 14) + bb; ee = RL(ee, 10); + bb = RL(bb + f3(cc,dd,ee) + X[10] + 0x6d703ef3, 13) + aa; dd = RL(dd, 10); + aa = RL(aa + f3(bb,cc,dd) + X[ 0] + 0x6d703ef3, 13) + ee; cc = RL(cc, 10); + ee = RL(ee + f3(aa,bb,cc) + X[ 4] + 0x6d703ef3, 7) + dd; bb = RL(bb, 10); + dd = RL(dd + f3(ee,aa,bb) + X[13] + 0x6d703ef3, 5) + cc; aa = RL(aa, 10); + + // + // Rounds 48-63 + // + // left + c = RL(c + f4(d,e,a) + X[ 1] + 0x8f1bbcdc, 11) + b; e = RL(e, 10); + b = RL(b + f4(c,d,e) + X[ 9] + 0x8f1bbcdc, 12) + a; d = RL(d, 10); + a = RL(a + f4(b,c,d) + X[11] + 0x8f1bbcdc, 14) + e; c = RL(c, 10); + e = RL(e + f4(a,b,c) + X[10] + 0x8f1bbcdc, 15) + d; b = RL(b, 10); + d = RL(d + f4(e,a,b) + X[ 0] + 0x8f1bbcdc, 14) + c; a = RL(a, 10); + c = RL(c + f4(d,e,a) + X[ 8] + 0x8f1bbcdc, 15) + b; e = RL(e, 10); + b = RL(b + f4(c,d,e) + X[12] + 0x8f1bbcdc, 9) + a; d = RL(d, 10); + a = RL(a + f4(b,c,d) + X[ 4] + 0x8f1bbcdc, 8) + e; c = RL(c, 10); + e = RL(e + f4(a,b,c) + X[13] + 0x8f1bbcdc, 9) + d; b = RL(b, 10); + d = RL(d + f4(e,a,b) + X[ 3] + 0x8f1bbcdc, 14) + c; a = RL(a, 10); + c = RL(c + f4(d,e,a) + X[ 7] + 0x8f1bbcdc, 5) + b; e = RL(e, 10); + b = RL(b + f4(c,d,e) + X[15] + 0x8f1bbcdc, 6) + a; d = RL(d, 10); + a = RL(a + f4(b,c,d) + X[14] + 0x8f1bbcdc, 8) + e; c = RL(c, 10); + e = RL(e + f4(a,b,c) + X[ 5] + 0x8f1bbcdc, 6) + d; b = RL(b, 10); + d = RL(d + f4(e,a,b) + X[ 6] + 0x8f1bbcdc, 5) + c; a = RL(a, 10); + c = RL(c + f4(d,e,a) + X[ 2] + 0x8f1bbcdc, 12) + b; e = RL(e, 10); + + // right + cc = RL(cc + f2(dd,ee,aa) + X[ 8] + 0x7a6d76e9, 15) + bb; ee = RL(ee, 10); + bb = RL(bb + f2(cc,dd,ee) + X[ 6] + 0x7a6d76e9, 5) + aa; dd = RL(dd, 10); + aa = RL(aa + f2(bb,cc,dd) + X[ 4] + 0x7a6d76e9, 8) + ee; cc = RL(cc, 10); + ee = RL(ee + f2(aa,bb,cc) + X[ 1] + 0x7a6d76e9, 11) + dd; bb = RL(bb, 10); + dd = RL(dd + f2(ee,aa,bb) + X[ 3] + 0x7a6d76e9, 14) + cc; aa = RL(aa, 10); + cc = RL(cc + f2(dd,ee,aa) + X[11] + 0x7a6d76e9, 14) + bb; ee = RL(ee, 10); + bb = RL(bb + f2(cc,dd,ee) + X[15] + 0x7a6d76e9, 6) + aa; dd = RL(dd, 10); + aa = RL(aa + f2(bb,cc,dd) + X[ 0] + 0x7a6d76e9, 14) + ee; cc = RL(cc, 10); + ee = RL(ee + f2(aa,bb,cc) + X[ 5] + 0x7a6d76e9, 6) + dd; bb = RL(bb, 10); + dd = RL(dd + f2(ee,aa,bb) + X[12] + 0x7a6d76e9, 9) + cc; aa = RL(aa, 10); + cc = RL(cc + f2(dd,ee,aa) + X[ 2] + 0x7a6d76e9, 12) + bb; ee = RL(ee, 10); + bb = RL(bb + f2(cc,dd,ee) + X[13] + 0x7a6d76e9, 9) + aa; dd = RL(dd, 10); + aa = RL(aa + f2(bb,cc,dd) + X[ 9] + 0x7a6d76e9, 12) + ee; cc = RL(cc, 10); + ee = RL(ee + f2(aa,bb,cc) + X[ 7] + 0x7a6d76e9, 5) + dd; bb = RL(bb, 10); + dd = RL(dd + f2(ee,aa,bb) + X[10] + 0x7a6d76e9, 15) + cc; aa = RL(aa, 10); + cc = RL(cc + f2(dd,ee,aa) + X[14] + 0x7a6d76e9, 8) + bb; ee = RL(ee, 10); + + // + // Rounds 64-79 + // + // left + b = RL(b + f5(c,d,e) + X[ 4] + 0xa953fd4e, 9) + a; d = RL(d, 10); + a = RL(a + f5(b,c,d) + X[ 0] + 0xa953fd4e, 15) + e; c = RL(c, 10); + e = RL(e + f5(a,b,c) + X[ 5] + 0xa953fd4e, 5) + d; b = RL(b, 10); + d = RL(d + f5(e,a,b) + X[ 9] + 0xa953fd4e, 11) + c; a = RL(a, 10); + c = RL(c + f5(d,e,a) + X[ 7] + 0xa953fd4e, 6) + b; e = RL(e, 10); + b = RL(b + f5(c,d,e) + X[12] + 0xa953fd4e, 8) + a; d = RL(d, 10); + a = RL(a + f5(b,c,d) + X[ 2] + 0xa953fd4e, 13) + e; c = RL(c, 10); + e = RL(e + f5(a,b,c) + X[10] + 0xa953fd4e, 12) + d; b = RL(b, 10); + d = RL(d + f5(e,a,b) + X[14] + 0xa953fd4e, 5) + c; a = RL(a, 10); + c = RL(c + f5(d,e,a) + X[ 1] + 0xa953fd4e, 12) + b; e = RL(e, 10); + b = RL(b + f5(c,d,e) + X[ 3] + 0xa953fd4e, 13) + a; d = RL(d, 10); + a = RL(a + f5(b,c,d) + X[ 8] + 0xa953fd4e, 14) + e; c = RL(c, 10); + e = RL(e + f5(a,b,c) + X[11] + 0xa953fd4e, 11) + d; b = RL(b, 10); + d = RL(d + f5(e,a,b) + X[ 6] + 0xa953fd4e, 8) + c; a = RL(a, 10); + c = RL(c + f5(d,e,a) + X[15] + 0xa953fd4e, 5) + b; e = RL(e, 10); + b = RL(b + f5(c,d,e) + X[13] + 0xa953fd4e, 6) + a; d = RL(d, 10); + + // right + bb = RL(bb + f1(cc,dd,ee) + X[12], 8) + aa; dd = RL(dd, 10); + aa = RL(aa + f1(bb,cc,dd) + X[15], 5) + ee; cc = RL(cc, 10); + ee = RL(ee + f1(aa,bb,cc) + X[10], 12) + dd; bb = RL(bb, 10); + dd = RL(dd + f1(ee,aa,bb) + X[ 4], 9) + cc; aa = RL(aa, 10); + cc = RL(cc + f1(dd,ee,aa) + X[ 1], 12) + bb; ee = RL(ee, 10); + bb = RL(bb + f1(cc,dd,ee) + X[ 5], 5) + aa; dd = RL(dd, 10); + aa = RL(aa + f1(bb,cc,dd) + X[ 8], 14) + ee; cc = RL(cc, 10); + ee = RL(ee + f1(aa,bb,cc) + X[ 7], 6) + dd; bb = RL(bb, 10); + dd = RL(dd + f1(ee,aa,bb) + X[ 6], 8) + cc; aa = RL(aa, 10); + cc = RL(cc + f1(dd,ee,aa) + X[ 2], 13) + bb; ee = RL(ee, 10); + bb = RL(bb + f1(cc,dd,ee) + X[13], 6) + aa; dd = RL(dd, 10); + aa = RL(aa + f1(bb,cc,dd) + X[14], 5) + ee; cc = RL(cc, 10); + ee = RL(ee + f1(aa,bb,cc) + X[ 0], 15) + dd; bb = RL(bb, 10); + dd = RL(dd + f1(ee,aa,bb) + X[ 3], 13) + cc; aa = RL(aa, 10); + cc = RL(cc + f1(dd,ee,aa) + X[ 9], 11) + bb; ee = RL(ee, 10); + bb = RL(bb + f1(cc,dd,ee) + X[11], 11) + aa; dd = RL(dd, 10); + + dd += c + H1; + H1 = H2 + d + ee; + H2 = H3 + e + aa; + H3 = H4 + a + bb; + H4 = H0 + b + cc; + H0 = dd; + + // + // reset the offset and clean out the word buffer. + // + xOff = 0; + for (int i = 0; i != X.length; i++) + { + X[i] = 0; + } + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/digests/RIPEMD256Digest.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/digests/RIPEMD256Digest.java new file mode 100644 index 0000000..cf91c8b --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/digests/RIPEMD256Digest.java @@ -0,0 +1,476 @@ +package org.bc.crypto.digests; + + +/** + * implementation of RIPEMD256. + *
+ * note: this algorithm offers the same level of security as RIPEMD128. + */ +public class RIPEMD256Digest + extends GeneralDigest +{ + private static final int DIGEST_LENGTH = 32; + + private int H0, H1, H2, H3, H4, H5, H6, H7; // IV's + + private int[] X = new int[16]; + private int xOff; + + /** + * Standard constructor + */ + public RIPEMD256Digest() + { + reset(); + } + + /** + * Copy constructor. This will copy the state of the provided + * message digest. + */ + public RIPEMD256Digest(RIPEMD256Digest t) + { + super(t); + + H0 = t.H0; + H1 = t.H1; + H2 = t.H2; + H3 = t.H3; + H4 = t.H4; + H5 = t.H5; + H6 = t.H6; + H7 = t.H7; + + System.arraycopy(t.X, 0, X, 0, t.X.length); + xOff = t.xOff; + } + + public String getAlgorithmName() + { + return "RIPEMD256"; + } + + public int getDigestSize() + { + return DIGEST_LENGTH; + } + + protected void processWord( + byte[] in, + int inOff) + { + X[xOff++] = (in[inOff] & 0xff) | ((in[inOff + 1] & 0xff) << 8) + | ((in[inOff + 2] & 0xff) << 16) | ((in[inOff + 3] & 0xff) << 24); + + if (xOff == 16) + { + processBlock(); + } + } + + protected void processLength( + long bitLength) + { + if (xOff > 14) + { + processBlock(); + } + + X[14] = (int)(bitLength & 0xffffffff); + X[15] = (int)(bitLength >>> 32); + } + + private void unpackWord( + int word, + byte[] out, + int outOff) + { + out[outOff] = (byte)word; + out[outOff + 1] = (byte)(word >>> 8); + out[outOff + 2] = (byte)(word >>> 16); + out[outOff + 3] = (byte)(word >>> 24); + } + + public int doFinal( + byte[] out, + int outOff) + { + finish(); + + unpackWord(H0, out, outOff); + unpackWord(H1, out, outOff + 4); + unpackWord(H2, out, outOff + 8); + unpackWord(H3, out, outOff + 12); + unpackWord(H4, out, outOff + 16); + unpackWord(H5, out, outOff + 20); + unpackWord(H6, out, outOff + 24); + unpackWord(H7, out, outOff + 28); + + reset(); + + return DIGEST_LENGTH; + } + + /** + * reset the chaining variables to the IV values. + */ + public void reset() + { + super.reset(); + + H0 = 0x67452301; + H1 = 0xefcdab89; + H2 = 0x98badcfe; + H3 = 0x10325476; + H4 = 0x76543210; + H5 = 0xFEDCBA98; + H6 = 0x89ABCDEF; + H7 = 0x01234567; + + xOff = 0; + + for (int i = 0; i != X.length; i++) + { + X[i] = 0; + } + } + + /* + * rotate int x left n bits. + */ + private int RL( + int x, + int n) + { + return (x << n) | (x >>> (32 - n)); + } + + /* + * f1,f2,f3,f4 are the basic RIPEMD128 functions. + */ + + /* + * F + */ + private int f1( + int x, + int y, + int z) + { + return x ^ y ^ z; + } + + /* + * G + */ + private int f2( + int x, + int y, + int z) + { + return (x & y) | (~x & z); + } + + /* + * H + */ + private int f3( + int x, + int y, + int z) + { + return (x | ~y) ^ z; + } + + /* + * I + */ + private int f4( + int x, + int y, + int z) + { + return (x & z) | (y & ~z); + } + + private int F1( + int a, + int b, + int c, + int d, + int x, + int s) + { + return RL(a + f1(b, c, d) + x, s); + } + + private int F2( + int a, + int b, + int c, + int d, + int x, + int s) + { + return RL(a + f2(b, c, d) + x + 0x5a827999, s); + } + + private int F3( + int a, + int b, + int c, + int d, + int x, + int s) + { + return RL(a + f3(b, c, d) + x + 0x6ed9eba1, s); + } + + private int F4( + int a, + int b, + int c, + int d, + int x, + int s) + { + return RL(a + f4(b, c, d) + x + 0x8f1bbcdc, s); + } + + private int FF1( + int a, + int b, + int c, + int d, + int x, + int s) + { + return RL(a + f1(b, c, d) + x, s); + } + + private int FF2( + int a, + int b, + int c, + int d, + int x, + int s) + { + return RL(a + f2(b, c, d) + x + 0x6d703ef3, s); + } + + private int FF3( + int a, + int b, + int c, + int d, + int x, + int s) + { + return RL(a + f3(b, c, d) + x + 0x5c4dd124, s); + } + + private int FF4( + int a, + int b, + int c, + int d, + int x, + int s) + { + return RL(a + f4(b, c, d) + x + 0x50a28be6, s); + } + + protected void processBlock() + { + int a, aa; + int b, bb; + int c, cc; + int d, dd; + int t; + + a = H0; + b = H1; + c = H2; + d = H3; + aa = H4; + bb = H5; + cc = H6; + dd = H7; + + // + // Round 1 + // + + a = F1(a, b, c, d, X[ 0], 11); + d = F1(d, a, b, c, X[ 1], 14); + c = F1(c, d, a, b, X[ 2], 15); + b = F1(b, c, d, a, X[ 3], 12); + a = F1(a, b, c, d, X[ 4], 5); + d = F1(d, a, b, c, X[ 5], 8); + c = F1(c, d, a, b, X[ 6], 7); + b = F1(b, c, d, a, X[ 7], 9); + a = F1(a, b, c, d, X[ 8], 11); + d = F1(d, a, b, c, X[ 9], 13); + c = F1(c, d, a, b, X[10], 14); + b = F1(b, c, d, a, X[11], 15); + a = F1(a, b, c, d, X[12], 6); + d = F1(d, a, b, c, X[13], 7); + c = F1(c, d, a, b, X[14], 9); + b = F1(b, c, d, a, X[15], 8); + + aa = FF4(aa, bb, cc, dd, X[ 5], 8); + dd = FF4(dd, aa, bb, cc, X[14], 9); + cc = FF4(cc, dd, aa, bb, X[ 7], 9); + bb = FF4(bb, cc, dd, aa, X[ 0], 11); + aa = FF4(aa, bb, cc, dd, X[ 9], 13); + dd = FF4(dd, aa, bb, cc, X[ 2], 15); + cc = FF4(cc, dd, aa, bb, X[11], 15); + bb = FF4(bb, cc, dd, aa, X[ 4], 5); + aa = FF4(aa, bb, cc, dd, X[13], 7); + dd = FF4(dd, aa, bb, cc, X[ 6], 7); + cc = FF4(cc, dd, aa, bb, X[15], 8); + bb = FF4(bb, cc, dd, aa, X[ 8], 11); + aa = FF4(aa, bb, cc, dd, X[ 1], 14); + dd = FF4(dd, aa, bb, cc, X[10], 14); + cc = FF4(cc, dd, aa, bb, X[ 3], 12); + bb = FF4(bb, cc, dd, aa, X[12], 6); + + t = a; a = aa; aa = t; + + // + // Round 2 + // + a = F2(a, b, c, d, X[ 7], 7); + d = F2(d, a, b, c, X[ 4], 6); + c = F2(c, d, a, b, X[13], 8); + b = F2(b, c, d, a, X[ 1], 13); + a = F2(a, b, c, d, X[10], 11); + d = F2(d, a, b, c, X[ 6], 9); + c = F2(c, d, a, b, X[15], 7); + b = F2(b, c, d, a, X[ 3], 15); + a = F2(a, b, c, d, X[12], 7); + d = F2(d, a, b, c, X[ 0], 12); + c = F2(c, d, a, b, X[ 9], 15); + b = F2(b, c, d, a, X[ 5], 9); + a = F2(a, b, c, d, X[ 2], 11); + d = F2(d, a, b, c, X[14], 7); + c = F2(c, d, a, b, X[11], 13); + b = F2(b, c, d, a, X[ 8], 12); + + aa = FF3(aa, bb, cc, dd, X[ 6], 9); + dd = FF3(dd, aa, bb, cc, X[ 11], 13); + cc = FF3(cc, dd, aa, bb, X[3], 15); + bb = FF3(bb, cc, dd, aa, X[ 7], 7); + aa = FF3(aa, bb, cc, dd, X[0], 12); + dd = FF3(dd, aa, bb, cc, X[13], 8); + cc = FF3(cc, dd, aa, bb, X[5], 9); + bb = FF3(bb, cc, dd, aa, X[10], 11); + aa = FF3(aa, bb, cc, dd, X[14], 7); + dd = FF3(dd, aa, bb, cc, X[15], 7); + cc = FF3(cc, dd, aa, bb, X[ 8], 12); + bb = FF3(bb, cc, dd, aa, X[12], 7); + aa = FF3(aa, bb, cc, dd, X[ 4], 6); + dd = FF3(dd, aa, bb, cc, X[ 9], 15); + cc = FF3(cc, dd, aa, bb, X[ 1], 13); + bb = FF3(bb, cc, dd, aa, X[ 2], 11); + + t = b; b = bb; bb = t; + + // + // Round 3 + // + a = F3(a, b, c, d, X[ 3], 11); + d = F3(d, a, b, c, X[10], 13); + c = F3(c, d, a, b, X[14], 6); + b = F3(b, c, d, a, X[ 4], 7); + a = F3(a, b, c, d, X[ 9], 14); + d = F3(d, a, b, c, X[15], 9); + c = F3(c, d, a, b, X[ 8], 13); + b = F3(b, c, d, a, X[ 1], 15); + a = F3(a, b, c, d, X[ 2], 14); + d = F3(d, a, b, c, X[ 7], 8); + c = F3(c, d, a, b, X[ 0], 13); + b = F3(b, c, d, a, X[ 6], 6); + a = F3(a, b, c, d, X[13], 5); + d = F3(d, a, b, c, X[11], 12); + c = F3(c, d, a, b, X[ 5], 7); + b = F3(b, c, d, a, X[12], 5); + + aa = FF2(aa, bb, cc, dd, X[ 15], 9); + dd = FF2(dd, aa, bb, cc, X[5], 7); + cc = FF2(cc, dd, aa, bb, X[1], 15); + bb = FF2(bb, cc, dd, aa, X[ 3], 11); + aa = FF2(aa, bb, cc, dd, X[ 7], 8); + dd = FF2(dd, aa, bb, cc, X[14], 6); + cc = FF2(cc, dd, aa, bb, X[ 6], 6); + bb = FF2(bb, cc, dd, aa, X[ 9], 14); + aa = FF2(aa, bb, cc, dd, X[11], 12); + dd = FF2(dd, aa, bb, cc, X[ 8], 13); + cc = FF2(cc, dd, aa, bb, X[12], 5); + bb = FF2(bb, cc, dd, aa, X[ 2], 14); + aa = FF2(aa, bb, cc, dd, X[10], 13); + dd = FF2(dd, aa, bb, cc, X[ 0], 13); + cc = FF2(cc, dd, aa, bb, X[ 4], 7); + bb = FF2(bb, cc, dd, aa, X[13], 5); + + t = c; c = cc; cc = t; + + // + // Round 4 + // + a = F4(a, b, c, d, X[ 1], 11); + d = F4(d, a, b, c, X[ 9], 12); + c = F4(c, d, a, b, X[11], 14); + b = F4(b, c, d, a, X[10], 15); + a = F4(a, b, c, d, X[ 0], 14); + d = F4(d, a, b, c, X[ 8], 15); + c = F4(c, d, a, b, X[12], 9); + b = F4(b, c, d, a, X[ 4], 8); + a = F4(a, b, c, d, X[13], 9); + d = F4(d, a, b, c, X[ 3], 14); + c = F4(c, d, a, b, X[ 7], 5); + b = F4(b, c, d, a, X[15], 6); + a = F4(a, b, c, d, X[14], 8); + d = F4(d, a, b, c, X[ 5], 6); + c = F4(c, d, a, b, X[ 6], 5); + b = F4(b, c, d, a, X[ 2], 12); + + aa = FF1(aa, bb, cc, dd, X[ 8], 15); + dd = FF1(dd, aa, bb, cc, X[ 6], 5); + cc = FF1(cc, dd, aa, bb, X[ 4], 8); + bb = FF1(bb, cc, dd, aa, X[ 1], 11); + aa = FF1(aa, bb, cc, dd, X[ 3], 14); + dd = FF1(dd, aa, bb, cc, X[11], 14); + cc = FF1(cc, dd, aa, bb, X[15], 6); + bb = FF1(bb, cc, dd, aa, X[ 0], 14); + aa = FF1(aa, bb, cc, dd, X[ 5], 6); + dd = FF1(dd, aa, bb, cc, X[12], 9); + cc = FF1(cc, dd, aa, bb, X[ 2], 12); + bb = FF1(bb, cc, dd, aa, X[13], 9); + aa = FF1(aa, bb, cc, dd, X[ 9], 12); + dd = FF1(dd, aa, bb, cc, X[ 7], 5); + cc = FF1(cc, dd, aa, bb, X[10], 15); + bb = FF1(bb, cc, dd, aa, X[14], 8); + + t = d; d = dd; dd = t; + + H0 += a; + H1 += b; + H2 += c; + H3 += d; + H4 += aa; + H5 += bb; + H6 += cc; + H7 += dd; + + // + // reset the offset and clean out the word buffer. + // + xOff = 0; + for (int i = 0; i != X.length; i++) + { + X[i] = 0; + } + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/digests/RIPEMD320Digest.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/digests/RIPEMD320Digest.java new file mode 100644 index 0000000..799bb6a --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/digests/RIPEMD320Digest.java @@ -0,0 +1,461 @@ +package org.bc.crypto.digests; + + +/** + * implementation of RIPEMD 320. + *
+ * Note: this implementation offers the same level of security + * as RIPEMD 160. + */ +public class RIPEMD320Digest + extends GeneralDigest +{ + private static final int DIGEST_LENGTH = 40; + + private int H0, H1, H2, H3, H4, H5, H6, H7, H8, H9; // IV's + + private int[] X = new int[16]; + private int xOff; + + /** + * Standard constructor + */ + public RIPEMD320Digest() + { + reset(); + } + + /** + * Copy constructor. This will copy the state of the provided + * message digest. + */ + public RIPEMD320Digest(RIPEMD320Digest t) + { + super(t); + + H0 = t.H0; + H1 = t.H1; + H2 = t.H2; + H3 = t.H3; + H4 = t.H4; + H5 = t.H5; + H6 = t.H6; + H7 = t.H7; + H8 = t.H8; + H9 = t.H9; + + System.arraycopy(t.X, 0, X, 0, t.X.length); + xOff = t.xOff; + } + + public String getAlgorithmName() + { + return "RIPEMD320"; + } + + public int getDigestSize() + { + return DIGEST_LENGTH; + } + + protected void processWord( + byte[] in, + int inOff) + { + X[xOff++] = (in[inOff] & 0xff) | ((in[inOff + 1] & 0xff) << 8) + | ((in[inOff + 2] & 0xff) << 16) | ((in[inOff + 3] & 0xff) << 24); + + if (xOff == 16) + { + processBlock(); + } + } + + protected void processLength( + long bitLength) + { + if (xOff > 14) + { + processBlock(); + } + + X[14] = (int)(bitLength & 0xffffffff); + X[15] = (int)(bitLength >>> 32); + } + + private void unpackWord( + int word, + byte[] out, + int outOff) + { + out[outOff] = (byte)word; + out[outOff + 1] = (byte)(word >>> 8); + out[outOff + 2] = (byte)(word >>> 16); + out[outOff + 3] = (byte)(word >>> 24); + } + + public int doFinal( + byte[] out, + int outOff) + { + finish(); + + unpackWord(H0, out, outOff); + unpackWord(H1, out, outOff + 4); + unpackWord(H2, out, outOff + 8); + unpackWord(H3, out, outOff + 12); + unpackWord(H4, out, outOff + 16); + unpackWord(H5, out, outOff + 20); + unpackWord(H6, out, outOff + 24); + unpackWord(H7, out, outOff + 28); + unpackWord(H8, out, outOff + 32); + unpackWord(H9, out, outOff + 36); + + reset(); + + return DIGEST_LENGTH; + } + + /** + * reset the chaining variables to the IV values. + */ + public void reset() + { + super.reset(); + + H0 = 0x67452301; + H1 = 0xefcdab89; + H2 = 0x98badcfe; + H3 = 0x10325476; + H4 = 0xc3d2e1f0; + H5 = 0x76543210; + H6 = 0xFEDCBA98; + H7 = 0x89ABCDEF; + H8 = 0x01234567; + H9 = 0x3C2D1E0F; + + xOff = 0; + + for (int i = 0; i != X.length; i++) + { + X[i] = 0; + } + } + + /* + * rotate int x left n bits. + */ + private int RL( + int x, + int n) + { + return (x << n) | (x >>> (32 - n)); + } + + /* + * f1,f2,f3,f4,f5 are the basic RIPEMD160 functions. + */ + + /* + * rounds 0-15 + */ + private int f1( + int x, + int y, + int z) + { + return x ^ y ^ z; + } + + /* + * rounds 16-31 + */ + private int f2( + int x, + int y, + int z) + { + return (x & y) | (~x & z); + } + + /* + * rounds 32-47 + */ + private int f3( + int x, + int y, + int z) + { + return (x | ~y) ^ z; + } + + /* + * rounds 48-63 + */ + private int f4( + int x, + int y, + int z) + { + return (x & z) | (y & ~z); + } + + /* + * rounds 64-79 + */ + private int f5( + int x, + int y, + int z) + { + return x ^ (y | ~z); + } + + protected void processBlock() + { + int a, aa; + int b, bb; + int c, cc; + int d, dd; + int e, ee; + int t; + + a = H0; + b = H1; + c = H2; + d = H3; + e = H4; + aa = H5; + bb = H6; + cc = H7; + dd = H8; + ee = H9; + + // + // Rounds 1 - 16 + // + // left + a = RL(a + f1(b,c,d) + X[ 0], 11) + e; c = RL(c, 10); + e = RL(e + f1(a,b,c) + X[ 1], 14) + d; b = RL(b, 10); + d = RL(d + f1(e,a,b) + X[ 2], 15) + c; a = RL(a, 10); + c = RL(c + f1(d,e,a) + X[ 3], 12) + b; e = RL(e, 10); + b = RL(b + f1(c,d,e) + X[ 4], 5) + a; d = RL(d, 10); + a = RL(a + f1(b,c,d) + X[ 5], 8) + e; c = RL(c, 10); + e = RL(e + f1(a,b,c) + X[ 6], 7) + d; b = RL(b, 10); + d = RL(d + f1(e,a,b) + X[ 7], 9) + c; a = RL(a, 10); + c = RL(c + f1(d,e,a) + X[ 8], 11) + b; e = RL(e, 10); + b = RL(b + f1(c,d,e) + X[ 9], 13) + a; d = RL(d, 10); + a = RL(a + f1(b,c,d) + X[10], 14) + e; c = RL(c, 10); + e = RL(e + f1(a,b,c) + X[11], 15) + d; b = RL(b, 10); + d = RL(d + f1(e,a,b) + X[12], 6) + c; a = RL(a, 10); + c = RL(c + f1(d,e,a) + X[13], 7) + b; e = RL(e, 10); + b = RL(b + f1(c,d,e) + X[14], 9) + a; d = RL(d, 10); + a = RL(a + f1(b,c,d) + X[15], 8) + e; c = RL(c, 10); + + // right + aa = RL(aa + f5(bb,cc,dd) + X[ 5] + 0x50a28be6, 8) + ee; cc = RL(cc, 10); + ee = RL(ee + f5(aa,bb,cc) + X[14] + 0x50a28be6, 9) + dd; bb = RL(bb, 10); + dd = RL(dd + f5(ee,aa,bb) + X[ 7] + 0x50a28be6, 9) + cc; aa = RL(aa, 10); + cc = RL(cc + f5(dd,ee,aa) + X[ 0] + 0x50a28be6, 11) + bb; ee = RL(ee, 10); + bb = RL(bb + f5(cc,dd,ee) + X[ 9] + 0x50a28be6, 13) + aa; dd = RL(dd, 10); + aa = RL(aa + f5(bb,cc,dd) + X[ 2] + 0x50a28be6, 15) + ee; cc = RL(cc, 10); + ee = RL(ee + f5(aa,bb,cc) + X[11] + 0x50a28be6, 15) + dd; bb = RL(bb, 10); + dd = RL(dd + f5(ee,aa,bb) + X[ 4] + 0x50a28be6, 5) + cc; aa = RL(aa, 10); + cc = RL(cc + f5(dd,ee,aa) + X[13] + 0x50a28be6, 7) + bb; ee = RL(ee, 10); + bb = RL(bb + f5(cc,dd,ee) + X[ 6] + 0x50a28be6, 7) + aa; dd = RL(dd, 10); + aa = RL(aa + f5(bb,cc,dd) + X[15] + 0x50a28be6, 8) + ee; cc = RL(cc, 10); + ee = RL(ee + f5(aa,bb,cc) + X[ 8] + 0x50a28be6, 11) + dd; bb = RL(bb, 10); + dd = RL(dd + f5(ee,aa,bb) + X[ 1] + 0x50a28be6, 14) + cc; aa = RL(aa, 10); + cc = RL(cc + f5(dd,ee,aa) + X[10] + 0x50a28be6, 14) + bb; ee = RL(ee, 10); + bb = RL(bb + f5(cc,dd,ee) + X[ 3] + 0x50a28be6, 12) + aa; dd = RL(dd, 10); + aa = RL(aa + f5(bb,cc,dd) + X[12] + 0x50a28be6, 6) + ee; cc = RL(cc, 10); + + t = a; a = aa; aa = t; + + // + // Rounds 16-31 + // + // left + e = RL(e + f2(a,b,c) + X[ 7] + 0x5a827999, 7) + d; b = RL(b, 10); + d = RL(d + f2(e,a,b) + X[ 4] + 0x5a827999, 6) + c; a = RL(a, 10); + c = RL(c + f2(d,e,a) + X[13] + 0x5a827999, 8) + b; e = RL(e, 10); + b = RL(b + f2(c,d,e) + X[ 1] + 0x5a827999, 13) + a; d = RL(d, 10); + a = RL(a + f2(b,c,d) + X[10] + 0x5a827999, 11) + e; c = RL(c, 10); + e = RL(e + f2(a,b,c) + X[ 6] + 0x5a827999, 9) + d; b = RL(b, 10); + d = RL(d + f2(e,a,b) + X[15] + 0x5a827999, 7) + c; a = RL(a, 10); + c = RL(c + f2(d,e,a) + X[ 3] + 0x5a827999, 15) + b; e = RL(e, 10); + b = RL(b + f2(c,d,e) + X[12] + 0x5a827999, 7) + a; d = RL(d, 10); + a = RL(a + f2(b,c,d) + X[ 0] + 0x5a827999, 12) + e; c = RL(c, 10); + e = RL(e + f2(a,b,c) + X[ 9] + 0x5a827999, 15) + d; b = RL(b, 10); + d = RL(d + f2(e,a,b) + X[ 5] + 0x5a827999, 9) + c; a = RL(a, 10); + c = RL(c + f2(d,e,a) + X[ 2] + 0x5a827999, 11) + b; e = RL(e, 10); + b = RL(b + f2(c,d,e) + X[14] + 0x5a827999, 7) + a; d = RL(d, 10); + a = RL(a + f2(b,c,d) + X[11] + 0x5a827999, 13) + e; c = RL(c, 10); + e = RL(e + f2(a,b,c) + X[ 8] + 0x5a827999, 12) + d; b = RL(b, 10); + + // right + ee = RL(ee + f4(aa,bb,cc) + X[ 6] + 0x5c4dd124, 9) + dd; bb = RL(bb, 10); + dd = RL(dd + f4(ee,aa,bb) + X[11] + 0x5c4dd124, 13) + cc; aa = RL(aa, 10); + cc = RL(cc + f4(dd,ee,aa) + X[ 3] + 0x5c4dd124, 15) + bb; ee = RL(ee, 10); + bb = RL(bb + f4(cc,dd,ee) + X[ 7] + 0x5c4dd124, 7) + aa; dd = RL(dd, 10); + aa = RL(aa + f4(bb,cc,dd) + X[ 0] + 0x5c4dd124, 12) + ee; cc = RL(cc, 10); + ee = RL(ee + f4(aa,bb,cc) + X[13] + 0x5c4dd124, 8) + dd; bb = RL(bb, 10); + dd = RL(dd + f4(ee,aa,bb) + X[ 5] + 0x5c4dd124, 9) + cc; aa = RL(aa, 10); + cc = RL(cc + f4(dd,ee,aa) + X[10] + 0x5c4dd124, 11) + bb; ee = RL(ee, 10); + bb = RL(bb + f4(cc,dd,ee) + X[14] + 0x5c4dd124, 7) + aa; dd = RL(dd, 10); + aa = RL(aa + f4(bb,cc,dd) + X[15] + 0x5c4dd124, 7) + ee; cc = RL(cc, 10); + ee = RL(ee + f4(aa,bb,cc) + X[ 8] + 0x5c4dd124, 12) + dd; bb = RL(bb, 10); + dd = RL(dd + f4(ee,aa,bb) + X[12] + 0x5c4dd124, 7) + cc; aa = RL(aa, 10); + cc = RL(cc + f4(dd,ee,aa) + X[ 4] + 0x5c4dd124, 6) + bb; ee = RL(ee, 10); + bb = RL(bb + f4(cc,dd,ee) + X[ 9] + 0x5c4dd124, 15) + aa; dd = RL(dd, 10); + aa = RL(aa + f4(bb,cc,dd) + X[ 1] + 0x5c4dd124, 13) + ee; cc = RL(cc, 10); + ee = RL(ee + f4(aa,bb,cc) + X[ 2] + 0x5c4dd124, 11) + dd; bb = RL(bb, 10); + + t = b; b = bb; bb = t; + + // + // Rounds 32-47 + // + // left + d = RL(d + f3(e,a,b) + X[ 3] + 0x6ed9eba1, 11) + c; a = RL(a, 10); + c = RL(c + f3(d,e,a) + X[10] + 0x6ed9eba1, 13) + b; e = RL(e, 10); + b = RL(b + f3(c,d,e) + X[14] + 0x6ed9eba1, 6) + a; d = RL(d, 10); + a = RL(a + f3(b,c,d) + X[ 4] + 0x6ed9eba1, 7) + e; c = RL(c, 10); + e = RL(e + f3(a,b,c) + X[ 9] + 0x6ed9eba1, 14) + d; b = RL(b, 10); + d = RL(d + f3(e,a,b) + X[15] + 0x6ed9eba1, 9) + c; a = RL(a, 10); + c = RL(c + f3(d,e,a) + X[ 8] + 0x6ed9eba1, 13) + b; e = RL(e, 10); + b = RL(b + f3(c,d,e) + X[ 1] + 0x6ed9eba1, 15) + a; d = RL(d, 10); + a = RL(a + f3(b,c,d) + X[ 2] + 0x6ed9eba1, 14) + e; c = RL(c, 10); + e = RL(e + f3(a,b,c) + X[ 7] + 0x6ed9eba1, 8) + d; b = RL(b, 10); + d = RL(d + f3(e,a,b) + X[ 0] + 0x6ed9eba1, 13) + c; a = RL(a, 10); + c = RL(c + f3(d,e,a) + X[ 6] + 0x6ed9eba1, 6) + b; e = RL(e, 10); + b = RL(b + f3(c,d,e) + X[13] + 0x6ed9eba1, 5) + a; d = RL(d, 10); + a = RL(a + f3(b,c,d) + X[11] + 0x6ed9eba1, 12) + e; c = RL(c, 10); + e = RL(e + f3(a,b,c) + X[ 5] + 0x6ed9eba1, 7) + d; b = RL(b, 10); + d = RL(d + f3(e,a,b) + X[12] + 0x6ed9eba1, 5) + c; a = RL(a, 10); + + // right + dd = RL(dd + f3(ee,aa,bb) + X[15] + 0x6d703ef3, 9) + cc; aa = RL(aa, 10); + cc = RL(cc + f3(dd,ee,aa) + X[ 5] + 0x6d703ef3, 7) + bb; ee = RL(ee, 10); + bb = RL(bb + f3(cc,dd,ee) + X[ 1] + 0x6d703ef3, 15) + aa; dd = RL(dd, 10); + aa = RL(aa + f3(bb,cc,dd) + X[ 3] + 0x6d703ef3, 11) + ee; cc = RL(cc, 10); + ee = RL(ee + f3(aa,bb,cc) + X[ 7] + 0x6d703ef3, 8) + dd; bb = RL(bb, 10); + dd = RL(dd + f3(ee,aa,bb) + X[14] + 0x6d703ef3, 6) + cc; aa = RL(aa, 10); + cc = RL(cc + f3(dd,ee,aa) + X[ 6] + 0x6d703ef3, 6) + bb; ee = RL(ee, 10); + bb = RL(bb + f3(cc,dd,ee) + X[ 9] + 0x6d703ef3, 14) + aa; dd = RL(dd, 10); + aa = RL(aa + f3(bb,cc,dd) + X[11] + 0x6d703ef3, 12) + ee; cc = RL(cc, 10); + ee = RL(ee + f3(aa,bb,cc) + X[ 8] + 0x6d703ef3, 13) + dd; bb = RL(bb, 10); + dd = RL(dd + f3(ee,aa,bb) + X[12] + 0x6d703ef3, 5) + cc; aa = RL(aa, 10); + cc = RL(cc + f3(dd,ee,aa) + X[ 2] + 0x6d703ef3, 14) + bb; ee = RL(ee, 10); + bb = RL(bb + f3(cc,dd,ee) + X[10] + 0x6d703ef3, 13) + aa; dd = RL(dd, 10); + aa = RL(aa + f3(bb,cc,dd) + X[ 0] + 0x6d703ef3, 13) + ee; cc = RL(cc, 10); + ee = RL(ee + f3(aa,bb,cc) + X[ 4] + 0x6d703ef3, 7) + dd; bb = RL(bb, 10); + dd = RL(dd + f3(ee,aa,bb) + X[13] + 0x6d703ef3, 5) + cc; aa = RL(aa, 10); + + t = c; c = cc; cc = t; + + // + // Rounds 48-63 + // + // left + c = RL(c + f4(d,e,a) + X[ 1] + 0x8f1bbcdc, 11) + b; e = RL(e, 10); + b = RL(b + f4(c,d,e) + X[ 9] + 0x8f1bbcdc, 12) + a; d = RL(d, 10); + a = RL(a + f4(b,c,d) + X[11] + 0x8f1bbcdc, 14) + e; c = RL(c, 10); + e = RL(e + f4(a,b,c) + X[10] + 0x8f1bbcdc, 15) + d; b = RL(b, 10); + d = RL(d + f4(e,a,b) + X[ 0] + 0x8f1bbcdc, 14) + c; a = RL(a, 10); + c = RL(c + f4(d,e,a) + X[ 8] + 0x8f1bbcdc, 15) + b; e = RL(e, 10); + b = RL(b + f4(c,d,e) + X[12] + 0x8f1bbcdc, 9) + a; d = RL(d, 10); + a = RL(a + f4(b,c,d) + X[ 4] + 0x8f1bbcdc, 8) + e; c = RL(c, 10); + e = RL(e + f4(a,b,c) + X[13] + 0x8f1bbcdc, 9) + d; b = RL(b, 10); + d = RL(d + f4(e,a,b) + X[ 3] + 0x8f1bbcdc, 14) + c; a = RL(a, 10); + c = RL(c + f4(d,e,a) + X[ 7] + 0x8f1bbcdc, 5) + b; e = RL(e, 10); + b = RL(b + f4(c,d,e) + X[15] + 0x8f1bbcdc, 6) + a; d = RL(d, 10); + a = RL(a + f4(b,c,d) + X[14] + 0x8f1bbcdc, 8) + e; c = RL(c, 10); + e = RL(e + f4(a,b,c) + X[ 5] + 0x8f1bbcdc, 6) + d; b = RL(b, 10); + d = RL(d + f4(e,a,b) + X[ 6] + 0x8f1bbcdc, 5) + c; a = RL(a, 10); + c = RL(c + f4(d,e,a) + X[ 2] + 0x8f1bbcdc, 12) + b; e = RL(e, 10); + + // right + cc = RL(cc + f2(dd,ee,aa) + X[ 8] + 0x7a6d76e9, 15) + bb; ee = RL(ee, 10); + bb = RL(bb + f2(cc,dd,ee) + X[ 6] + 0x7a6d76e9, 5) + aa; dd = RL(dd, 10); + aa = RL(aa + f2(bb,cc,dd) + X[ 4] + 0x7a6d76e9, 8) + ee; cc = RL(cc, 10); + ee = RL(ee + f2(aa,bb,cc) + X[ 1] + 0x7a6d76e9, 11) + dd; bb = RL(bb, 10); + dd = RL(dd + f2(ee,aa,bb) + X[ 3] + 0x7a6d76e9, 14) + cc; aa = RL(aa, 10); + cc = RL(cc + f2(dd,ee,aa) + X[11] + 0x7a6d76e9, 14) + bb; ee = RL(ee, 10); + bb = RL(bb + f2(cc,dd,ee) + X[15] + 0x7a6d76e9, 6) + aa; dd = RL(dd, 10); + aa = RL(aa + f2(bb,cc,dd) + X[ 0] + 0x7a6d76e9, 14) + ee; cc = RL(cc, 10); + ee = RL(ee + f2(aa,bb,cc) + X[ 5] + 0x7a6d76e9, 6) + dd; bb = RL(bb, 10); + dd = RL(dd + f2(ee,aa,bb) + X[12] + 0x7a6d76e9, 9) + cc; aa = RL(aa, 10); + cc = RL(cc + f2(dd,ee,aa) + X[ 2] + 0x7a6d76e9, 12) + bb; ee = RL(ee, 10); + bb = RL(bb + f2(cc,dd,ee) + X[13] + 0x7a6d76e9, 9) + aa; dd = RL(dd, 10); + aa = RL(aa + f2(bb,cc,dd) + X[ 9] + 0x7a6d76e9, 12) + ee; cc = RL(cc, 10); + ee = RL(ee + f2(aa,bb,cc) + X[ 7] + 0x7a6d76e9, 5) + dd; bb = RL(bb, 10); + dd = RL(dd + f2(ee,aa,bb) + X[10] + 0x7a6d76e9, 15) + cc; aa = RL(aa, 10); + cc = RL(cc + f2(dd,ee,aa) + X[14] + 0x7a6d76e9, 8) + bb; ee = RL(ee, 10); + + t = d; d = dd; dd = t; + + // + // Rounds 64-79 + // + // left + b = RL(b + f5(c,d,e) + X[ 4] + 0xa953fd4e, 9) + a; d = RL(d, 10); + a = RL(a + f5(b,c,d) + X[ 0] + 0xa953fd4e, 15) + e; c = RL(c, 10); + e = RL(e + f5(a,b,c) + X[ 5] + 0xa953fd4e, 5) + d; b = RL(b, 10); + d = RL(d + f5(e,a,b) + X[ 9] + 0xa953fd4e, 11) + c; a = RL(a, 10); + c = RL(c + f5(d,e,a) + X[ 7] + 0xa953fd4e, 6) + b; e = RL(e, 10); + b = RL(b + f5(c,d,e) + X[12] + 0xa953fd4e, 8) + a; d = RL(d, 10); + a = RL(a + f5(b,c,d) + X[ 2] + 0xa953fd4e, 13) + e; c = RL(c, 10); + e = RL(e + f5(a,b,c) + X[10] + 0xa953fd4e, 12) + d; b = RL(b, 10); + d = RL(d + f5(e,a,b) + X[14] + 0xa953fd4e, 5) + c; a = RL(a, 10); + c = RL(c + f5(d,e,a) + X[ 1] + 0xa953fd4e, 12) + b; e = RL(e, 10); + b = RL(b + f5(c,d,e) + X[ 3] + 0xa953fd4e, 13) + a; d = RL(d, 10); + a = RL(a + f5(b,c,d) + X[ 8] + 0xa953fd4e, 14) + e; c = RL(c, 10); + e = RL(e + f5(a,b,c) + X[11] + 0xa953fd4e, 11) + d; b = RL(b, 10); + d = RL(d + f5(e,a,b) + X[ 6] + 0xa953fd4e, 8) + c; a = RL(a, 10); + c = RL(c + f5(d,e,a) + X[15] + 0xa953fd4e, 5) + b; e = RL(e, 10); + b = RL(b + f5(c,d,e) + X[13] + 0xa953fd4e, 6) + a; d = RL(d, 10); + + // right + bb = RL(bb + f1(cc,dd,ee) + X[12], 8) + aa; dd = RL(dd, 10); + aa = RL(aa + f1(bb,cc,dd) + X[15], 5) + ee; cc = RL(cc, 10); + ee = RL(ee + f1(aa,bb,cc) + X[10], 12) + dd; bb = RL(bb, 10); + dd = RL(dd + f1(ee,aa,bb) + X[ 4], 9) + cc; aa = RL(aa, 10); + cc = RL(cc + f1(dd,ee,aa) + X[ 1], 12) + bb; ee = RL(ee, 10); + bb = RL(bb + f1(cc,dd,ee) + X[ 5], 5) + aa; dd = RL(dd, 10); + aa = RL(aa + f1(bb,cc,dd) + X[ 8], 14) + ee; cc = RL(cc, 10); + ee = RL(ee + f1(aa,bb,cc) + X[ 7], 6) + dd; bb = RL(bb, 10); + dd = RL(dd + f1(ee,aa,bb) + X[ 6], 8) + cc; aa = RL(aa, 10); + cc = RL(cc + f1(dd,ee,aa) + X[ 2], 13) + bb; ee = RL(ee, 10); + bb = RL(bb + f1(cc,dd,ee) + X[13], 6) + aa; dd = RL(dd, 10); + aa = RL(aa + f1(bb,cc,dd) + X[14], 5) + ee; cc = RL(cc, 10); + ee = RL(ee + f1(aa,bb,cc) + X[ 0], 15) + dd; bb = RL(bb, 10); + dd = RL(dd + f1(ee,aa,bb) + X[ 3], 13) + cc; aa = RL(aa, 10); + cc = RL(cc + f1(dd,ee,aa) + X[ 9], 11) + bb; ee = RL(ee, 10); + bb = RL(bb + f1(cc,dd,ee) + X[11], 11) + aa; dd = RL(dd, 10); + + // + // do (e, ee) swap as part of assignment. + // + + H0 += a; + H1 += b; + H2 += c; + H3 += d; + H4 += ee; + H5 += aa; + H6 += bb; + H7 += cc; + H8 += dd; + H9 += e; + + // + // reset the offset and clean out the word buffer. + // + xOff = 0; + for (int i = 0; i != X.length; i++) + { + X[i] = 0; + } + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/digests/SHA1Digest.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/digests/SHA1Digest.java new file mode 100644 index 0000000..273e541 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/digests/SHA1Digest.java @@ -0,0 +1,290 @@ +package org.bc.crypto.digests; + +import org.bc.crypto.util.Pack; + +/** + * implementation of SHA-1 as outlined in "Handbook of Applied Cryptography", pages 346 - 349. + * + * It is interesting to ponder why the, apart from the extra IV, the other difference here from MD5 + * is the "endienness" of the word processing! + */ +public class SHA1Digest + extends GeneralDigest +{ + private static final int DIGEST_LENGTH = 20; + + private int H1, H2, H3, H4, H5; + + private int[] X = new int[80]; + private int xOff; + + /** + * Standard constructor + */ + public SHA1Digest() + { + reset(); + } + + /** + * Copy constructor. This will copy the state of the provided + * message digest. + */ + public SHA1Digest(SHA1Digest t) + { + super(t); + + H1 = t.H1; + H2 = t.H2; + H3 = t.H3; + H4 = t.H4; + H5 = t.H5; + + System.arraycopy(t.X, 0, X, 0, t.X.length); + xOff = t.xOff; + } + + public String getAlgorithmName() + { + return "SHA-1"; + } + + public int getDigestSize() + { + return DIGEST_LENGTH; + } + + protected void processWord( + byte[] in, + int inOff) + { + // Note: Inlined for performance +// X[xOff] = Pack.bigEndianToInt(in, inOff); + int n = in[ inOff] << 24; + n |= (in[++inOff] & 0xff) << 16; + n |= (in[++inOff] & 0xff) << 8; + n |= (in[++inOff] & 0xff); + X[xOff] = n; + + if (++xOff == 16) + { + processBlock(); + } + } + + protected void processLength( + long bitLength) + { + if (xOff > 14) + { + processBlock(); + } + + X[14] = (int)(bitLength >>> 32); + X[15] = (int)(bitLength & 0xffffffff); + } + + public int doFinal( + byte[] out, + int outOff) + { + finish(); + + Pack.intToBigEndian(H1, out, outOff); + Pack.intToBigEndian(H2, out, outOff + 4); + Pack.intToBigEndian(H3, out, outOff + 8); + Pack.intToBigEndian(H4, out, outOff + 12); + Pack.intToBigEndian(H5, out, outOff + 16); + + reset(); + + return DIGEST_LENGTH; + } + + /** + * reset the chaining variables + */ + public void reset() + { + super.reset(); + + H1 = 0x67452301; + H2 = 0xefcdab89; + H3 = 0x98badcfe; + H4 = 0x10325476; + H5 = 0xc3d2e1f0; + + xOff = 0; + for (int i = 0; i != X.length; i++) + { + X[i] = 0; + } + } + + // + // Additive constants + // + private static final int Y1 = 0x5a827999; + private static final int Y2 = 0x6ed9eba1; + private static final int Y3 = 0x8f1bbcdc; + private static final int Y4 = 0xca62c1d6; + + private int f( + int u, + int v, + int w) + { + return ((u & v) | ((~u) & w)); + } + + private int h( + int u, + int v, + int w) + { + return (u ^ v ^ w); + } + + private int g( + int u, + int v, + int w) + { + return ((u & v) | (u & w) | (v & w)); + } + + protected void processBlock() + { + // + // expand 16 word block into 80 word block. + // + for (int i = 16; i < 80; i++) + { + int t = X[i - 3] ^ X[i - 8] ^ X[i - 14] ^ X[i - 16]; + X[i] = t << 1 | t >>> 31; + } + + // + // set up working variables. + // + int A = H1; + int B = H2; + int C = H3; + int D = H4; + int E = H5; + + // + // round 1 + // + int idx = 0; + + for (int j = 0; j < 4; j++) + { + // E = rotateLeft(A, 5) + f(B, C, D) + E + X[idx++] + Y1 + // B = rotateLeft(B, 30) + E += (A << 5 | A >>> 27) + f(B, C, D) + X[idx++] + Y1; + B = B << 30 | B >>> 2; + + D += (E << 5 | E >>> 27) + f(A, B, C) + X[idx++] + Y1; + A = A << 30 | A >>> 2; + + C += (D << 5 | D >>> 27) + f(E, A, B) + X[idx++] + Y1; + E = E << 30 | E >>> 2; + + B += (C << 5 | C >>> 27) + f(D, E, A) + X[idx++] + Y1; + D = D << 30 | D >>> 2; + + A += (B << 5 | B >>> 27) + f(C, D, E) + X[idx++] + Y1; + C = C << 30 | C >>> 2; + } + + // + // round 2 + // + for (int j = 0; j < 4; j++) + { + // E = rotateLeft(A, 5) + h(B, C, D) + E + X[idx++] + Y2 + // B = rotateLeft(B, 30) + E += (A << 5 | A >>> 27) + h(B, C, D) + X[idx++] + Y2; + B = B << 30 | B >>> 2; + + D += (E << 5 | E >>> 27) + h(A, B, C) + X[idx++] + Y2; + A = A << 30 | A >>> 2; + + C += (D << 5 | D >>> 27) + h(E, A, B) + X[idx++] + Y2; + E = E << 30 | E >>> 2; + + B += (C << 5 | C >>> 27) + h(D, E, A) + X[idx++] + Y2; + D = D << 30 | D >>> 2; + + A += (B << 5 | B >>> 27) + h(C, D, E) + X[idx++] + Y2; + C = C << 30 | C >>> 2; + } + + // + // round 3 + // + for (int j = 0; j < 4; j++) + { + // E = rotateLeft(A, 5) + g(B, C, D) + E + X[idx++] + Y3 + // B = rotateLeft(B, 30) + E += (A << 5 | A >>> 27) + g(B, C, D) + X[idx++] + Y3; + B = B << 30 | B >>> 2; + + D += (E << 5 | E >>> 27) + g(A, B, C) + X[idx++] + Y3; + A = A << 30 | A >>> 2; + + C += (D << 5 | D >>> 27) + g(E, A, B) + X[idx++] + Y3; + E = E << 30 | E >>> 2; + + B += (C << 5 | C >>> 27) + g(D, E, A) + X[idx++] + Y3; + D = D << 30 | D >>> 2; + + A += (B << 5 | B >>> 27) + g(C, D, E) + X[idx++] + Y3; + C = C << 30 | C >>> 2; + } + + // + // round 4 + // + for (int j = 0; j <= 3; j++) + { + // E = rotateLeft(A, 5) + h(B, C, D) + E + X[idx++] + Y4 + // B = rotateLeft(B, 30) + E += (A << 5 | A >>> 27) + h(B, C, D) + X[idx++] + Y4; + B = B << 30 | B >>> 2; + + D += (E << 5 | E >>> 27) + h(A, B, C) + X[idx++] + Y4; + A = A << 30 | A >>> 2; + + C += (D << 5 | D >>> 27) + h(E, A, B) + X[idx++] + Y4; + E = E << 30 | E >>> 2; + + B += (C << 5 | C >>> 27) + h(D, E, A) + X[idx++] + Y4; + D = D << 30 | D >>> 2; + + A += (B << 5 | B >>> 27) + h(C, D, E) + X[idx++] + Y4; + C = C << 30 | C >>> 2; + } + + + H1 += A; + H2 += B; + H3 += C; + H4 += D; + H5 += E; + + // + // reset start of the buffer. + // + xOff = 0; + for (int i = 0; i < 16; i++) + { + X[i] = 0; + } + } +} + + + + diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/digests/SHA224Digest.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/digests/SHA224Digest.java new file mode 100644 index 0000000..6877f83 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/digests/SHA224Digest.java @@ -0,0 +1,292 @@ +package org.bc.crypto.digests; + + +import org.bc.crypto.digests.GeneralDigest; +import org.bc.crypto.util.Pack; + + +/** + * SHA-224 as described in RFC 3874 + *
+ * block word digest + * SHA-1 512 32 160 + * SHA-224 512 32 224 + * SHA-256 512 32 256 + * SHA-384 1024 64 384 + * SHA-512 1024 64 512 + *+ */ +public class SHA224Digest + extends GeneralDigest +{ + private static final int DIGEST_LENGTH = 28; + + private int H1, H2, H3, H4, H5, H6, H7, H8; + + private int[] X = new int[64]; + private int xOff; + + /** + * Standard constructor + */ + public SHA224Digest() + { + reset(); + } + + /** + * Copy constructor. This will copy the state of the provided + * message digest. + */ + public SHA224Digest(SHA224Digest t) + { + super(t); + + H1 = t.H1; + H2 = t.H2; + H3 = t.H3; + H4 = t.H4; + H5 = t.H5; + H6 = t.H6; + H7 = t.H7; + H8 = t.H8; + + System.arraycopy(t.X, 0, X, 0, t.X.length); + xOff = t.xOff; + } + + public String getAlgorithmName() + { + return "SHA-224"; + } + + public int getDigestSize() + { + return DIGEST_LENGTH; + } + + protected void processWord( + byte[] in, + int inOff) + { + // Note: Inlined for performance +// X[xOff] = Pack.bigEndianToInt(in, inOff); + int n = in[ inOff] << 24; + n |= (in[++inOff] & 0xff) << 16; + n |= (in[++inOff] & 0xff) << 8; + n |= (in[++inOff] & 0xff); + X[xOff] = n; + + if (++xOff == 16) + { + processBlock(); + } + } + + protected void processLength( + long bitLength) + { + if (xOff > 14) + { + processBlock(); + } + + X[14] = (int)(bitLength >>> 32); + X[15] = (int)(bitLength & 0xffffffff); + } + + public int doFinal( + byte[] out, + int outOff) + { + finish(); + + Pack.intToBigEndian(H1, out, outOff); + Pack.intToBigEndian(H2, out, outOff + 4); + Pack.intToBigEndian(H3, out, outOff + 8); + Pack.intToBigEndian(H4, out, outOff + 12); + Pack.intToBigEndian(H5, out, outOff + 16); + Pack.intToBigEndian(H6, out, outOff + 20); + Pack.intToBigEndian(H7, out, outOff + 24); + + reset(); + + return DIGEST_LENGTH; + } + + /** + * reset the chaining variables + */ + public void reset() + { + super.reset(); + + /* SHA-224 initial hash value + */ + + H1 = 0xc1059ed8; + H2 = 0x367cd507; + H3 = 0x3070dd17; + H4 = 0xf70e5939; + H5 = 0xffc00b31; + H6 = 0x68581511; + H7 = 0x64f98fa7; + H8 = 0xbefa4fa4; + + xOff = 0; + for (int i = 0; i != X.length; i++) + { + X[i] = 0; + } + } + + protected void processBlock() + { + // + // expand 16 word block into 64 word blocks. + // + for (int t = 16; t <= 63; t++) + { + X[t] = Theta1(X[t - 2]) + X[t - 7] + Theta0(X[t - 15]) + X[t - 16]; + } + + // + // set up working variables. + // + int a = H1; + int b = H2; + int c = H3; + int d = H4; + int e = H5; + int f = H6; + int g = H7; + int h = H8; + + + int t = 0; + for(int i = 0; i < 8; i ++) + { + // t = 8 * i + h += Sum1(e) + Ch(e, f, g) + K[t] + X[t]; + d += h; + h += Sum0(a) + Maj(a, b, c); + ++t; + + // t = 8 * i + 1 + g += Sum1(d) + Ch(d, e, f) + K[t] + X[t]; + c += g; + g += Sum0(h) + Maj(h, a, b); + ++t; + + // t = 8 * i + 2 + f += Sum1(c) + Ch(c, d, e) + K[t] + X[t]; + b += f; + f += Sum0(g) + Maj(g, h, a); + ++t; + + // t = 8 * i + 3 + e += Sum1(b) + Ch(b, c, d) + K[t] + X[t]; + a += e; + e += Sum0(f) + Maj(f, g, h); + ++t; + + // t = 8 * i + 4 + d += Sum1(a) + Ch(a, b, c) + K[t] + X[t]; + h += d; + d += Sum0(e) + Maj(e, f, g); + ++t; + + // t = 8 * i + 5 + c += Sum1(h) + Ch(h, a, b) + K[t] + X[t]; + g += c; + c += Sum0(d) + Maj(d, e, f); + ++t; + + // t = 8 * i + 6 + b += Sum1(g) + Ch(g, h, a) + K[t] + X[t]; + f += b; + b += Sum0(c) + Maj(c, d, e); + ++t; + + // t = 8 * i + 7 + a += Sum1(f) + Ch(f, g, h) + K[t] + X[t]; + e += a; + a += Sum0(b) + Maj(b, c, d); + ++t; + } + + H1 += a; + H2 += b; + H3 += c; + H4 += d; + H5 += e; + H6 += f; + H7 += g; + H8 += h; + + // + // reset the offset and clean out the word buffer. + // + xOff = 0; + for (int i = 0; i < 16; i++) + { + X[i] = 0; + } + } + + /* SHA-224 functions */ + private int Ch( + int x, + int y, + int z) + { + return ((x & y) ^ ((~x) & z)); + } + + private int Maj( + int x, + int y, + int z) + { + return ((x & y) ^ (x & z) ^ (y & z)); + } + + private int Sum0( + int x) + { + return ((x >>> 2) | (x << 30)) ^ ((x >>> 13) | (x << 19)) ^ ((x >>> 22) | (x << 10)); + } + + private int Sum1( + int x) + { + return ((x >>> 6) | (x << 26)) ^ ((x >>> 11) | (x << 21)) ^ ((x >>> 25) | (x << 7)); + } + + private int Theta0( + int x) + { + return ((x >>> 7) | (x << 25)) ^ ((x >>> 18) | (x << 14)) ^ (x >>> 3); + } + + private int Theta1( + int x) + { + return ((x >>> 17) | (x << 15)) ^ ((x >>> 19) | (x << 13)) ^ (x >>> 10); + } + + /* SHA-224 Constants + * (represent the first 32 bits of the fractional parts of the + * cube roots of the first sixty-four prime numbers) + */ + static final int K[] = { + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 + }; +} + diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/digests/SHA256Digest.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/digests/SHA256Digest.java new file mode 100644 index 0000000..ccf6ef3 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/digests/SHA256Digest.java @@ -0,0 +1,295 @@ +package org.bc.crypto.digests; + + +import org.bc.crypto.digests.GeneralDigest; +import org.bc.crypto.util.Pack; + + +/** + * FIPS 180-2 implementation of SHA-256. + * + *
+ * block word digest + * SHA-1 512 32 160 + * SHA-256 512 32 256 + * SHA-384 1024 64 384 + * SHA-512 1024 64 512 + *+ */ +public class SHA256Digest + extends GeneralDigest +{ + private static final int DIGEST_LENGTH = 32; + + private int H1, H2, H3, H4, H5, H6, H7, H8; + + private int[] X = new int[64]; + private int xOff; + + /** + * Standard constructor + */ + public SHA256Digest() + { + reset(); + } + + /** + * Copy constructor. This will copy the state of the provided + * message digest. + */ + public SHA256Digest(SHA256Digest t) + { + super(t); + + H1 = t.H1; + H2 = t.H2; + H3 = t.H3; + H4 = t.H4; + H5 = t.H5; + H6 = t.H6; + H7 = t.H7; + H8 = t.H8; + + System.arraycopy(t.X, 0, X, 0, t.X.length); + xOff = t.xOff; + } + + public String getAlgorithmName() + { + return "SHA-256"; + } + + public int getDigestSize() + { + return DIGEST_LENGTH; + } + + protected void processWord( + byte[] in, + int inOff) + { + // Note: Inlined for performance +// X[xOff] = Pack.bigEndianToInt(in, inOff); + int n = in[inOff] << 24; + n |= (in[++inOff] & 0xff) << 16; + n |= (in[++inOff] & 0xff) << 8; + n |= (in[++inOff] & 0xff); + X[xOff] = n; + + if (++xOff == 16) + { + processBlock(); + } + } + + protected void processLength( + long bitLength) + { + if (xOff > 14) + { + processBlock(); + } + + X[14] = (int)(bitLength >>> 32); + X[15] = (int)(bitLength & 0xffffffff); + } + + public int doFinal( + byte[] out, + int outOff) + { + finish(); + + Pack.intToBigEndian(H1, out, outOff); + Pack.intToBigEndian(H2, out, outOff + 4); + Pack.intToBigEndian(H3, out, outOff + 8); + Pack.intToBigEndian(H4, out, outOff + 12); + Pack.intToBigEndian(H5, out, outOff + 16); + Pack.intToBigEndian(H6, out, outOff + 20); + Pack.intToBigEndian(H7, out, outOff + 24); + Pack.intToBigEndian(H8, out, outOff + 28); + + reset(); + + return DIGEST_LENGTH; + } + + /** + * reset the chaining variables + */ + public void reset() + { + super.reset(); + + /* SHA-256 initial hash value + * The first 32 bits of the fractional parts of the square roots + * of the first eight prime numbers + */ + + H1 = 0x6a09e667; + H2 = 0xbb67ae85; + H3 = 0x3c6ef372; + H4 = 0xa54ff53a; + H5 = 0x510e527f; + H6 = 0x9b05688c; + H7 = 0x1f83d9ab; + H8 = 0x5be0cd19; + + xOff = 0; + for (int i = 0; i != X.length; i++) + { + X[i] = 0; + } + } + + protected void processBlock() + { + // + // expand 16 word block into 64 word blocks. + // + for (int t = 16; t <= 63; t++) + { + X[t] = Theta1(X[t - 2]) + X[t - 7] + Theta0(X[t - 15]) + X[t - 16]; + } + + // + // set up working variables. + // + int a = H1; + int b = H2; + int c = H3; + int d = H4; + int e = H5; + int f = H6; + int g = H7; + int h = H8; + + int t = 0; + for(int i = 0; i < 8; i ++) + { + // t = 8 * i + h += Sum1(e) + Ch(e, f, g) + K[t] + X[t]; + d += h; + h += Sum0(a) + Maj(a, b, c); + ++t; + + // t = 8 * i + 1 + g += Sum1(d) + Ch(d, e, f) + K[t] + X[t]; + c += g; + g += Sum0(h) + Maj(h, a, b); + ++t; + + // t = 8 * i + 2 + f += Sum1(c) + Ch(c, d, e) + K[t] + X[t]; + b += f; + f += Sum0(g) + Maj(g, h, a); + ++t; + + // t = 8 * i + 3 + e += Sum1(b) + Ch(b, c, d) + K[t] + X[t]; + a += e; + e += Sum0(f) + Maj(f, g, h); + ++t; + + // t = 8 * i + 4 + d += Sum1(a) + Ch(a, b, c) + K[t] + X[t]; + h += d; + d += Sum0(e) + Maj(e, f, g); + ++t; + + // t = 8 * i + 5 + c += Sum1(h) + Ch(h, a, b) + K[t] + X[t]; + g += c; + c += Sum0(d) + Maj(d, e, f); + ++t; + + // t = 8 * i + 6 + b += Sum1(g) + Ch(g, h, a) + K[t] + X[t]; + f += b; + b += Sum0(c) + Maj(c, d, e); + ++t; + + // t = 8 * i + 7 + a += Sum1(f) + Ch(f, g, h) + K[t] + X[t]; + e += a; + a += Sum0(b) + Maj(b, c, d); + ++t; + } + + H1 += a; + H2 += b; + H3 += c; + H4 += d; + H5 += e; + H6 += f; + H7 += g; + H8 += h; + + // + // reset the offset and clean out the word buffer. + // + xOff = 0; + for (int i = 0; i < 16; i++) + { + X[i] = 0; + } + } + + /* SHA-256 functions */ + private int Ch( + int x, + int y, + int z) + { + return (x & y) ^ ((~x) & z); + } + + private int Maj( + int x, + int y, + int z) + { + return (x & y) ^ (x & z) ^ (y & z); + } + + private int Sum0( + int x) + { + return ((x >>> 2) | (x << 30)) ^ ((x >>> 13) | (x << 19)) ^ ((x >>> 22) | (x << 10)); + } + + private int Sum1( + int x) + { + return ((x >>> 6) | (x << 26)) ^ ((x >>> 11) | (x << 21)) ^ ((x >>> 25) | (x << 7)); + } + + private int Theta0( + int x) + { + return ((x >>> 7) | (x << 25)) ^ ((x >>> 18) | (x << 14)) ^ (x >>> 3); + } + + private int Theta1( + int x) + { + return ((x >>> 17) | (x << 15)) ^ ((x >>> 19) | (x << 13)) ^ (x >>> 10); + } + + /* SHA-256 Constants + * (represent the first 32 bits of the fractional parts of the + * cube roots of the first sixty-four prime numbers) + */ + static final int K[] = { + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 + }; +} + diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/digests/SHA384Digest.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/digests/SHA384Digest.java new file mode 100644 index 0000000..9db972e --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/digests/SHA384Digest.java @@ -0,0 +1,87 @@ +package org.bc.crypto.digests; + +import org.bc.crypto.util.Pack; + + +/** + * FIPS 180-2 implementation of SHA-384. + * + *
+ * block word digest + * SHA-1 512 32 160 + * SHA-256 512 32 256 + * SHA-384 1024 64 384 + * SHA-512 1024 64 512 + *+ */ +public class SHA384Digest + extends LongDigest +{ + + private static final int DIGEST_LENGTH = 48; + + /** + * Standard constructor + */ + public SHA384Digest() + { + } + + /** + * Copy constructor. This will copy the state of the provided + * message digest. + */ + public SHA384Digest(SHA384Digest t) + { + super(t); + } + + public String getAlgorithmName() + { + return "SHA-384"; + } + + public int getDigestSize() + { + return DIGEST_LENGTH; + } + + public int doFinal( + byte[] out, + int outOff) + { + finish(); + + Pack.longToBigEndian(H1, out, outOff); + Pack.longToBigEndian(H2, out, outOff + 8); + Pack.longToBigEndian(H3, out, outOff + 16); + Pack.longToBigEndian(H4, out, outOff + 24); + Pack.longToBigEndian(H5, out, outOff + 32); + Pack.longToBigEndian(H6, out, outOff + 40); + + reset(); + + return DIGEST_LENGTH; + } + + /** + * reset the chaining variables + */ + public void reset() + { + super.reset(); + + /* SHA-384 initial hash value + * The first 64 bits of the fractional parts of the square roots + * of the 9th through 16th prime numbers + */ + H1 = 0xcbbb9d5dc1059ed8l; + H2 = 0x629a292a367cd507l; + H3 = 0x9159015a3070dd17l; + H4 = 0x152fecd8f70e5939l; + H5 = 0x67332667ffc00b31l; + H6 = 0x8eb44a8768581511l; + H7 = 0xdb0c2e0d64f98fa7l; + H8 = 0x47b5481dbefa4fa4l; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/digests/SHA3Digest.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/digests/SHA3Digest.java new file mode 100644 index 0000000..559cd59 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/digests/SHA3Digest.java @@ -0,0 +1,547 @@ +package org.bc.crypto.digests; + +import org.bc.crypto.ExtendedDigest; +import org.bc.util.Arrays; + +/** + * implementation of SHA-3 based on following KeccakNISTInterface.c from http://keccak.noekeon.org/ + * + * Following the naming conventions used in the C source code to enable easy review of the implementation. + */ +public class SHA3Digest + implements ExtendedDigest +{ + private static long[] KeccakRoundConstants = keccakInitializeRoundConstants(); + + private static int[] KeccakRhoOffsets = keccakInitializeRhoOffsets(); + + private static long[] keccakInitializeRoundConstants() + { + long[] keccakRoundConstants = new long[24]; + byte[] LFSRstate = new byte[1]; + + LFSRstate[0] = 0x01; + int i, j, bitPosition; + + for (i = 0; i < 24; i++) + { + keccakRoundConstants[i] = 0; + for (j = 0; j < 7; j++) + { + bitPosition = (1 << j) - 1; + if (LFSR86540(LFSRstate)) + { + keccakRoundConstants[i] ^= 1L << bitPosition; + } + } + } + + return keccakRoundConstants; + } + + private static boolean LFSR86540(byte[] LFSR) + { + boolean result = (((LFSR[0]) & 0x01) != 0); + if (((LFSR[0]) & 0x80) != 0) + { + LFSR[0] = (byte)(((LFSR[0]) << 1) ^ 0x71); + } + else + { + LFSR[0] <<= 1; + } + + return result; + } + + private static int[] keccakInitializeRhoOffsets() + { + int[] keccakRhoOffsets = new int[25]; + int x, y, t, newX, newY; + + keccakRhoOffsets[(((0) % 5) + 5 * ((0) % 5))] = 0; + x = 1; + y = 0; + for (t = 0; t < 24; t++) + { + keccakRhoOffsets[(((x) % 5) + 5 * ((y) % 5))] = ((t + 1) * (t + 2) / 2) % 64; + newX = (0 * x + 1 * y) % 5; + newY = (2 * x + 3 * y) % 5; + x = newX; + y = newY; + } + + return keccakRhoOffsets; + } + + private byte[] state = new byte[(1600 / 8)]; + private byte[] dataQueue = new byte[(1536 / 8)]; + private int rate; + private int bitsInQueue; + private int fixedOutputLength; + private boolean squeezing; + private int bitsAvailableForSqueezing; + private byte[] chunk; + private byte[] oneByte; + + private void clearDataQueueSection(int off, int len) + { + for (int i = off; i != off + len; i++) + { + dataQueue[i] = 0; + } + } + + public SHA3Digest() + { + init(0); + } + + public SHA3Digest(int bitLength) + { + init(bitLength); + } + + public SHA3Digest(SHA3Digest source) { + System.arraycopy(source.state, 0, this.state, 0, source.state.length); + System.arraycopy(source.dataQueue, 0, this.dataQueue, 0, source.dataQueue.length); + this.rate = source.rate; + this.bitsInQueue = source.bitsInQueue; + this.fixedOutputLength = source.fixedOutputLength; + this.squeezing = source.squeezing; + this.bitsAvailableForSqueezing = source.bitsAvailableForSqueezing; + this.chunk = Arrays.clone(source.chunk); + this.oneByte = Arrays.clone(source.oneByte); + } + + public String getAlgorithmName() + { + return "SHA3-" + fixedOutputLength; + } + + public int getDigestSize() + { + return fixedOutputLength / 8; + } + + public void update(byte in) + { + oneByte[0] = in; + + doUpdate(oneByte, 0, 8L); + } + + public void update(byte[] in, int inOff, int len) + { + doUpdate(in, inOff, len * 8L); + } + + public int doFinal(byte[] out, int outOff) + { + squeeze(out, outOff, fixedOutputLength); + + reset(); + + return getDigestSize(); + } + + public void reset() + { + init(fixedOutputLength); + } + + /** + * Return the size of block that the compression function is applied to in bytes. + * + * @return internal byte length of a block. + */ + public int getByteLength() + { + return rate / 8; + } + + private void init(int bitLength) + { + switch (bitLength) + { + case 0: + case 288: + initSponge(1024, 576); + break; + case 224: + initSponge(1152, 448); + break; + case 256: + initSponge(1088, 512); + break; + case 384: + initSponge(832, 768); + break; + case 512: + initSponge(576, 1024); + break; + default: + throw new IllegalArgumentException("bitLength must be one of 224, 256, 384, or 512."); + } + } + + private void doUpdate(byte[] data, int off, long databitlen) + { + if ((databitlen % 8) == 0) + { + absorb(data, off, databitlen); + } + else + { + absorb(data, off, databitlen - (databitlen % 8)); + + byte[] lastByte = new byte[1]; + + lastByte[0] = (byte)(data[off + (int)(databitlen / 8)] >> (8 - (databitlen % 8))); + absorb(lastByte, off, databitlen % 8); + } + } + + private void initSponge(int rate, int capacity) + { + if (rate + capacity != 1600) + { + throw new IllegalStateException("rate + capacity != 1600"); + } + if ((rate <= 0) || (rate >= 1600) || ((rate % 64) != 0)) + { + throw new IllegalStateException("invalid rate value"); + } + + this.rate = rate; + // this is never read, need to check to see why we want to save it + // this.capacity = capacity; + this.fixedOutputLength = 0; + Arrays.fill(this.state, (byte)0); + Arrays.fill(this.dataQueue, (byte)0); + this.bitsInQueue = 0; + this.squeezing = false; + this.bitsAvailableForSqueezing = 0; + this.fixedOutputLength = capacity / 2; + this.chunk = new byte[rate / 8]; + this.oneByte = new byte[1]; + } + + private void absorbQueue() + { + KeccakAbsorb(state, dataQueue, rate / 8); + + bitsInQueue = 0; + } + + private void absorb(byte[] data, int off, long databitlen) + { + long i, j, wholeBlocks; + + if ((bitsInQueue % 8) != 0) + { + throw new IllegalStateException("attempt to absorb with odd length queue."); + } + if (squeezing) + { + throw new IllegalStateException("attempt to absorb while squeezing."); + } + + i = 0; + while (i < databitlen) + { + if ((bitsInQueue == 0) && (databitlen >= rate) && (i <= (databitlen - rate))) + { + wholeBlocks = (databitlen - i) / rate; + + for (j = 0; j < wholeBlocks; j++) + { + System.arraycopy(data, (int)(off + (i / 8) + (j * chunk.length)), chunk, 0, chunk.length); + +// displayIntermediateValues.displayBytes(1, "Block to be absorbed", curData, rate / 8); + + KeccakAbsorb(state, chunk, chunk.length); + } + + i += wholeBlocks * rate; + } + else + { + int partialBlock = (int)(databitlen - i); + if (partialBlock + bitsInQueue > rate) + { + partialBlock = rate - bitsInQueue; + } + int partialByte = partialBlock % 8; + partialBlock -= partialByte; + System.arraycopy(data, off + (int)(i / 8), dataQueue, bitsInQueue / 8, partialBlock / 8); + + bitsInQueue += partialBlock; + i += partialBlock; + if (bitsInQueue == rate) + { + absorbQueue(); + } + if (partialByte > 0) + { + int mask = (1 << partialByte) - 1; + dataQueue[bitsInQueue / 8] = (byte)(data[off + ((int)(i / 8))] & mask); + bitsInQueue += partialByte; + i += partialByte; + } + } + } + } + + private void padAndSwitchToSqueezingPhase() + { + if (bitsInQueue + 1 == rate) + { + dataQueue[bitsInQueue / 8] |= 1 << (bitsInQueue % 8); + absorbQueue(); + clearDataQueueSection(0, rate / 8); + } + else + { + clearDataQueueSection((bitsInQueue + 7) / 8, rate / 8 - (bitsInQueue + 7) / 8); + dataQueue[bitsInQueue / 8] |= 1 << (bitsInQueue % 8); + } + dataQueue[(rate - 1) / 8] |= 1 << ((rate - 1) % 8); + absorbQueue(); + + +// displayIntermediateValues.displayText(1, "--- Switching to squeezing phase ---"); + + + if (rate == 1024) + { + KeccakExtract1024bits(state, dataQueue); + bitsAvailableForSqueezing = 1024; + } + else + + { + KeccakExtract(state, dataQueue, rate / 64); + bitsAvailableForSqueezing = rate; + } + +// displayIntermediateValues.displayBytes(1, "Block available for squeezing", dataQueue, bitsAvailableForSqueezing / 8); + + squeezing = true; + } + + private void squeeze(byte[] output, int offset, long outputLength) + { + long i; + int partialBlock; + + if (!squeezing) + { + padAndSwitchToSqueezingPhase(); + } + if ((outputLength % 8) != 0) + { + throw new IllegalStateException("outputLength not a multiple of 8"); + } + + i = 0; + while (i < outputLength) + { + if (bitsAvailableForSqueezing == 0) + { + keccakPermutation(state); + + if (rate == 1024) + { + KeccakExtract1024bits(state, dataQueue); + bitsAvailableForSqueezing = 1024; + } + else + + { + KeccakExtract(state, dataQueue, rate / 64); + bitsAvailableForSqueezing = rate; + } + +// displayIntermediateValues.displayBytes(1, "Block available for squeezing", dataQueue, bitsAvailableForSqueezing / 8); + + } + partialBlock = bitsAvailableForSqueezing; + if ((long)partialBlock > outputLength - i) + { + partialBlock = (int)(outputLength - i); + } + + System.arraycopy(dataQueue, (rate - bitsAvailableForSqueezing) / 8, output, offset + (int)(i / 8), partialBlock / 8); + bitsAvailableForSqueezing -= partialBlock; + i += partialBlock; + } + } + + private void fromBytesToWords(long[] stateAsWords, byte[] state) + { + for (int i = 0; i < (1600 / 64); i++) + { + stateAsWords[i] = 0; + int index = i * (64 / 8); + for (int j = 0; j < (64 / 8); j++) + { + stateAsWords[i] |= ((long)state[index + j] & 0xff) << ((8 * j)); + } + } + } + + private void fromWordsToBytes(byte[] state, long[] stateAsWords) + { + for (int i = 0; i < (1600 / 64); i++) + { + int index = i * (64 / 8); + for (int j = 0; j < (64 / 8); j++) + { + state[index + j] = (byte)((stateAsWords[i] >>> ((8 * j))) & 0xFF); + } + } + } + + private void keccakPermutation(byte[] state) + { + long[] longState = new long[state.length / 8]; + + fromBytesToWords(longState, state); + +// displayIntermediateValues.displayStateAsBytes(1, "Input of permutation", longState); + + keccakPermutationOnWords(longState); + +// displayIntermediateValues.displayStateAsBytes(1, "State after permutation", longState); + + fromWordsToBytes(state, longState); + } + + private void keccakPermutationAfterXor(byte[] state, byte[] data, int dataLengthInBytes) + { + int i; + + for (i = 0; i < dataLengthInBytes; i++) + { + state[i] ^= data[i]; + } + + keccakPermutation(state); + } + + private void keccakPermutationOnWords(long[] state) + { + int i; + +// displayIntermediateValues.displayStateAs64bitWords(3, "Same, with lanes as 64-bit words", state); + + for (i = 0; i < 24; i++) + { +// displayIntermediateValues.displayRoundNumber(3, i); + + theta(state); +// displayIntermediateValues.displayStateAs64bitWords(3, "After theta", state); + + rho(state); +// displayIntermediateValues.displayStateAs64bitWords(3, "After rho", state); + + pi(state); +// displayIntermediateValues.displayStateAs64bitWords(3, "After pi", state); + + chi(state); +// displayIntermediateValues.displayStateAs64bitWords(3, "After chi", state); + + iota(state, i); +// displayIntermediateValues.displayStateAs64bitWords(3, "After iota", state); + } + } + + long[] C = new long[5]; + + private void theta(long[] A) + { + for (int x = 0; x < 5; x++) + { + C[x] = 0; + for (int y = 0; y < 5; y++) + { + C[x] ^= A[x + 5 * y]; + } + } + for (int x = 0; x < 5; x++) + { + long dX = ((((C[(x + 1) % 5]) << 1) ^ ((C[(x + 1) % 5]) >>> (64 - 1)))) ^ C[(x + 4) % 5]; + for (int y = 0; y < 5; y++) + { + A[x + 5 * y] ^= dX; + } + } + } + + private void rho(long[] A) + { + for (int x = 0; x < 5; x++) + { + for (int y = 0; y < 5; y++) + { + int index = x + 5 * y; + A[index] = ((KeccakRhoOffsets[index] != 0) ? (((A[index]) << KeccakRhoOffsets[index]) ^ ((A[index]) >>> (64 - KeccakRhoOffsets[index]))) : A[index]); + } + } + } + + long[] tempA = new long[25]; + + private void pi(long[] A) + { + System.arraycopy(A, 0, tempA, 0, tempA.length); + + for (int x = 0; x < 5; x++) + { + for (int y = 0; y < 5; y++) + { + A[y + 5 * ((2 * x + 3 * y) % 5)] = tempA[x + 5 * y]; + } + } + } + + long[] chiC = new long[5]; + + private void chi(long[] A) + { + for (int y = 0; y < 5; y++) + { + for (int x = 0; x < 5; x++) + { + chiC[x] = A[x + 5 * y] ^ ((~A[(((x + 1) % 5) + 5 * y)]) & A[(((x + 2) % 5) + 5 * y)]); + } + for (int x = 0; x < 5; x++) + { + A[x + 5 * y] = chiC[x]; + } + } + } + + private void iota(long[] A, int indexRound) + { + A[(((0) % 5) + 5 * ((0) % 5))] ^= KeccakRoundConstants[indexRound]; + } + + private void KeccakAbsorb(byte[] byteState, byte[] data, int dataInBytes) + { + keccakPermutationAfterXor(byteState, data, dataInBytes); + } + + + private void KeccakExtract1024bits(byte[] byteState, byte[] data) + { + System.arraycopy(byteState, 0, data, 0, 128); + } + + + private void KeccakExtract(byte[] byteState, byte[] data, int laneCount) + { + System.arraycopy(byteState, 0, data, 0, laneCount * 8); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/digests/SHA512Digest.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/digests/SHA512Digest.java new file mode 100644 index 0000000..c9e2479 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/digests/SHA512Digest.java @@ -0,0 +1,89 @@ +package org.bc.crypto.digests; + +import org.bc.crypto.util.Pack; + + +/** + * FIPS 180-2 implementation of SHA-512. + * + *
+ * block word digest + * SHA-1 512 32 160 + * SHA-256 512 32 256 + * SHA-384 1024 64 384 + * SHA-512 1024 64 512 + *+ */ +public class SHA512Digest + extends LongDigest +{ + private static final int DIGEST_LENGTH = 64; + + /** + * Standard constructor + */ + public SHA512Digest() + { + } + + /** + * Copy constructor. This will copy the state of the provided + * message digest. + */ + public SHA512Digest(SHA512Digest t) + { + super(t); + } + + public String getAlgorithmName() + { + return "SHA-512"; + } + + public int getDigestSize() + { + return DIGEST_LENGTH; + } + + public int doFinal( + byte[] out, + int outOff) + { + finish(); + + Pack.longToBigEndian(H1, out, outOff); + Pack.longToBigEndian(H2, out, outOff + 8); + Pack.longToBigEndian(H3, out, outOff + 16); + Pack.longToBigEndian(H4, out, outOff + 24); + Pack.longToBigEndian(H5, out, outOff + 32); + Pack.longToBigEndian(H6, out, outOff + 40); + Pack.longToBigEndian(H7, out, outOff + 48); + Pack.longToBigEndian(H8, out, outOff + 56); + + reset(); + + return DIGEST_LENGTH; + } + + /** + * reset the chaining variables + */ + public void reset() + { + super.reset(); + + /* SHA-512 initial hash value + * The first 64 bits of the fractional parts of the square roots + * of the first eight prime numbers + */ + H1 = 0x6a09e667f3bcc908L; + H2 = 0xbb67ae8584caa73bL; + H3 = 0x3c6ef372fe94f82bL; + H4 = 0xa54ff53a5f1d36f1L; + H5 = 0x510e527fade682d1L; + H6 = 0x9b05688c2b3e6c1fL; + H7 = 0x1f83d9abfb41bd6bL; + H8 = 0x5be0cd19137e2179L; + } +} + diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/digests/ShortenedDigest.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/digests/ShortenedDigest.java new file mode 100644 index 0000000..c211244 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/digests/ShortenedDigest.java @@ -0,0 +1,80 @@ +package org.bc.crypto.digests; + +import org.bc.crypto.ExtendedDigest; + +/** + * Wrapper class that reduces the output length of a particular digest to + * only the first n bytes of the digest function. + */ +public class ShortenedDigest + implements ExtendedDigest +{ + private ExtendedDigest baseDigest; + private int length; + + /** + * Base constructor. + * + * @param baseDigest underlying digest to use. + * @param length length in bytes of the output of doFinal. + * @exception IllegalArgumentException if baseDigest is null, or length is greater than baseDigest.getDigestSize(). + */ + public ShortenedDigest( + ExtendedDigest baseDigest, + int length) + { + if (baseDigest == null) + { + throw new IllegalArgumentException("baseDigest must not be null"); + } + + if (length > baseDigest.getDigestSize()) + { + throw new IllegalArgumentException("baseDigest output not large enough to support length"); + } + + this.baseDigest = baseDigest; + this.length = length; + } + + public String getAlgorithmName() + { + return baseDigest.getAlgorithmName() + "(" + length * 8 + ")"; + } + + public int getDigestSize() + { + return length; + } + + public void update(byte in) + { + baseDigest.update(in); + } + + public void update(byte[] in, int inOff, int len) + { + baseDigest.update(in, inOff, len); + } + + public int doFinal(byte[] out, int outOff) + { + byte[] tmp = new byte[baseDigest.getDigestSize()]; + + baseDigest.doFinal(tmp, 0); + + System.arraycopy(tmp, 0, out, outOff, length); + + return length; + } + + public void reset() + { + baseDigest.reset(); + } + + public int getByteLength() + { + return baseDigest.getByteLength(); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/digests/TigerDigest.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/digests/TigerDigest.java new file mode 100644 index 0000000..247bd62 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/digests/TigerDigest.java @@ -0,0 +1,866 @@ +package org.bc.crypto.digests; + +import org.bc.crypto.ExtendedDigest; + +/** + * implementation of Tiger based on: + * + * http://www.cs.technion.ac.il/~biham/Reports/Tiger + */ +public class TigerDigest + implements ExtendedDigest +{ + private static final int BYTE_LENGTH = 64; + + /* + * S-Boxes. + */ + private static final long[] t1 = { + 0x02AAB17CF7E90C5EL /* 0 */, 0xAC424B03E243A8ECL /* 1 */, + 0x72CD5BE30DD5FCD3L /* 2 */, 0x6D019B93F6F97F3AL /* 3 */, + 0xCD9978FFD21F9193L /* 4 */, 0x7573A1C9708029E2L /* 5 */, + 0xB164326B922A83C3L /* 6 */, 0x46883EEE04915870L /* 7 */, + 0xEAACE3057103ECE6L /* 8 */, 0xC54169B808A3535CL /* 9 */, + 0x4CE754918DDEC47CL /* 10 */, 0x0AA2F4DFDC0DF40CL /* 11 */, + 0x10B76F18A74DBEFAL /* 12 */, 0xC6CCB6235AD1AB6AL /* 13 */, + 0x13726121572FE2FFL /* 14 */, 0x1A488C6F199D921EL /* 15 */, + 0x4BC9F9F4DA0007CAL /* 16 */, 0x26F5E6F6E85241C7L /* 17 */, + 0x859079DBEA5947B6L /* 18 */, 0x4F1885C5C99E8C92L /* 19 */, + 0xD78E761EA96F864BL /* 20 */, 0x8E36428C52B5C17DL /* 21 */, + 0x69CF6827373063C1L /* 22 */, 0xB607C93D9BB4C56EL /* 23 */, + 0x7D820E760E76B5EAL /* 24 */, 0x645C9CC6F07FDC42L /* 25 */, + 0xBF38A078243342E0L /* 26 */, 0x5F6B343C9D2E7D04L /* 27 */, + 0xF2C28AEB600B0EC6L /* 28 */, 0x6C0ED85F7254BCACL /* 29 */, + 0x71592281A4DB4FE5L /* 30 */, 0x1967FA69CE0FED9FL /* 31 */, + 0xFD5293F8B96545DBL /* 32 */, 0xC879E9D7F2A7600BL /* 33 */, + 0x860248920193194EL /* 34 */, 0xA4F9533B2D9CC0B3L /* 35 */, + 0x9053836C15957613L /* 36 */, 0xDB6DCF8AFC357BF1L /* 37 */, + 0x18BEEA7A7A370F57L /* 38 */, 0x037117CA50B99066L /* 39 */, + 0x6AB30A9774424A35L /* 40 */, 0xF4E92F02E325249BL /* 41 */, + 0x7739DB07061CCAE1L /* 42 */, 0xD8F3B49CECA42A05L /* 43 */, + 0xBD56BE3F51382F73L /* 44 */, 0x45FAED5843B0BB28L /* 45 */, + 0x1C813D5C11BF1F83L /* 46 */, 0x8AF0E4B6D75FA169L /* 47 */, + 0x33EE18A487AD9999L /* 48 */, 0x3C26E8EAB1C94410L /* 49 */, + 0xB510102BC0A822F9L /* 50 */, 0x141EEF310CE6123BL /* 51 */, + 0xFC65B90059DDB154L /* 52 */, 0xE0158640C5E0E607L /* 53 */, + 0x884E079826C3A3CFL /* 54 */, 0x930D0D9523C535FDL /* 55 */, + 0x35638D754E9A2B00L /* 56 */, 0x4085FCCF40469DD5L /* 57 */, + 0xC4B17AD28BE23A4CL /* 58 */, 0xCAB2F0FC6A3E6A2EL /* 59 */, + 0x2860971A6B943FCDL /* 60 */, 0x3DDE6EE212E30446L /* 61 */, + 0x6222F32AE01765AEL /* 62 */, 0x5D550BB5478308FEL /* 63 */, + 0xA9EFA98DA0EDA22AL /* 64 */, 0xC351A71686C40DA7L /* 65 */, + 0x1105586D9C867C84L /* 66 */, 0xDCFFEE85FDA22853L /* 67 */, + 0xCCFBD0262C5EEF76L /* 68 */, 0xBAF294CB8990D201L /* 69 */, + 0xE69464F52AFAD975L /* 70 */, 0x94B013AFDF133E14L /* 71 */, + 0x06A7D1A32823C958L /* 72 */, 0x6F95FE5130F61119L /* 73 */, + 0xD92AB34E462C06C0L /* 74 */, 0xED7BDE33887C71D2L /* 75 */, + 0x79746D6E6518393EL /* 76 */, 0x5BA419385D713329L /* 77 */, + 0x7C1BA6B948A97564L /* 78 */, 0x31987C197BFDAC67L /* 79 */, + 0xDE6C23C44B053D02L /* 80 */, 0x581C49FED002D64DL /* 81 */, + 0xDD474D6338261571L /* 82 */, 0xAA4546C3E473D062L /* 83 */, + 0x928FCE349455F860L /* 84 */, 0x48161BBACAAB94D9L /* 85 */, + 0x63912430770E6F68L /* 86 */, 0x6EC8A5E602C6641CL /* 87 */, + 0x87282515337DDD2BL /* 88 */, 0x2CDA6B42034B701BL /* 89 */, + 0xB03D37C181CB096DL /* 90 */, 0xE108438266C71C6FL /* 91 */, + 0x2B3180C7EB51B255L /* 92 */, 0xDF92B82F96C08BBCL /* 93 */, + 0x5C68C8C0A632F3BAL /* 94 */, 0x5504CC861C3D0556L /* 95 */, + 0xABBFA4E55FB26B8FL /* 96 */, 0x41848B0AB3BACEB4L /* 97 */, + 0xB334A273AA445D32L /* 98 */, 0xBCA696F0A85AD881L /* 99 */, + 0x24F6EC65B528D56CL /* 100 */, 0x0CE1512E90F4524AL /* 101 */, + 0x4E9DD79D5506D35AL /* 102 */, 0x258905FAC6CE9779L /* 103 */, + 0x2019295B3E109B33L /* 104 */, 0xF8A9478B73A054CCL /* 105 */, + 0x2924F2F934417EB0L /* 106 */, 0x3993357D536D1BC4L /* 107 */, + 0x38A81AC21DB6FF8BL /* 108 */, 0x47C4FBF17D6016BFL /* 109 */, + 0x1E0FAADD7667E3F5L /* 110 */, 0x7ABCFF62938BEB96L /* 111 */, + 0xA78DAD948FC179C9L /* 112 */, 0x8F1F98B72911E50DL /* 113 */, + 0x61E48EAE27121A91L /* 114 */, 0x4D62F7AD31859808L /* 115 */, + 0xECEBA345EF5CEAEBL /* 116 */, 0xF5CEB25EBC9684CEL /* 117 */, + 0xF633E20CB7F76221L /* 118 */, 0xA32CDF06AB8293E4L /* 119 */, + 0x985A202CA5EE2CA4L /* 120 */, 0xCF0B8447CC8A8FB1L /* 121 */, + 0x9F765244979859A3L /* 122 */, 0xA8D516B1A1240017L /* 123 */, + 0x0BD7BA3EBB5DC726L /* 124 */, 0xE54BCA55B86ADB39L /* 125 */, + 0x1D7A3AFD6C478063L /* 126 */, 0x519EC608E7669EDDL /* 127 */, + 0x0E5715A2D149AA23L /* 128 */, 0x177D4571848FF194L /* 129 */, + 0xEEB55F3241014C22L /* 130 */, 0x0F5E5CA13A6E2EC2L /* 131 */, + 0x8029927B75F5C361L /* 132 */, 0xAD139FABC3D6E436L /* 133 */, + 0x0D5DF1A94CCF402FL /* 134 */, 0x3E8BD948BEA5DFC8L /* 135 */, + 0xA5A0D357BD3FF77EL /* 136 */, 0xA2D12E251F74F645L /* 137 */, + 0x66FD9E525E81A082L /* 138 */, 0x2E0C90CE7F687A49L /* 139 */, + 0xC2E8BCBEBA973BC5L /* 140 */, 0x000001BCE509745FL /* 141 */, + 0x423777BBE6DAB3D6L /* 142 */, 0xD1661C7EAEF06EB5L /* 143 */, + 0xA1781F354DAACFD8L /* 144 */, 0x2D11284A2B16AFFCL /* 145 */, + 0xF1FC4F67FA891D1FL /* 146 */, 0x73ECC25DCB920ADAL /* 147 */, + 0xAE610C22C2A12651L /* 148 */, 0x96E0A810D356B78AL /* 149 */, + 0x5A9A381F2FE7870FL /* 150 */, 0xD5AD62EDE94E5530L /* 151 */, + 0xD225E5E8368D1427L /* 152 */, 0x65977B70C7AF4631L /* 153 */, + 0x99F889B2DE39D74FL /* 154 */, 0x233F30BF54E1D143L /* 155 */, + 0x9A9675D3D9A63C97L /* 156 */, 0x5470554FF334F9A8L /* 157 */, + 0x166ACB744A4F5688L /* 158 */, 0x70C74CAAB2E4AEADL /* 159 */, + 0xF0D091646F294D12L /* 160 */, 0x57B82A89684031D1L /* 161 */, + 0xEFD95A5A61BE0B6BL /* 162 */, 0x2FBD12E969F2F29AL /* 163 */, + 0x9BD37013FEFF9FE8L /* 164 */, 0x3F9B0404D6085A06L /* 165 */, + 0x4940C1F3166CFE15L /* 166 */, 0x09542C4DCDF3DEFBL /* 167 */, + 0xB4C5218385CD5CE3L /* 168 */, 0xC935B7DC4462A641L /* 169 */, + 0x3417F8A68ED3B63FL /* 170 */, 0xB80959295B215B40L /* 171 */, + 0xF99CDAEF3B8C8572L /* 172 */, 0x018C0614F8FCB95DL /* 173 */, + 0x1B14ACCD1A3ACDF3L /* 174 */, 0x84D471F200BB732DL /* 175 */, + 0xC1A3110E95E8DA16L /* 176 */, 0x430A7220BF1A82B8L /* 177 */, + 0xB77E090D39DF210EL /* 178 */, 0x5EF4BD9F3CD05E9DL /* 179 */, + 0x9D4FF6DA7E57A444L /* 180 */, 0xDA1D60E183D4A5F8L /* 181 */, + 0xB287C38417998E47L /* 182 */, 0xFE3EDC121BB31886L /* 183 */, + 0xC7FE3CCC980CCBEFL /* 184 */, 0xE46FB590189BFD03L /* 185 */, + 0x3732FD469A4C57DCL /* 186 */, 0x7EF700A07CF1AD65L /* 187 */, + 0x59C64468A31D8859L /* 188 */, 0x762FB0B4D45B61F6L /* 189 */, + 0x155BAED099047718L /* 190 */, 0x68755E4C3D50BAA6L /* 191 */, + 0xE9214E7F22D8B4DFL /* 192 */, 0x2ADDBF532EAC95F4L /* 193 */, + 0x32AE3909B4BD0109L /* 194 */, 0x834DF537B08E3450L /* 195 */, + 0xFA209DA84220728DL /* 196 */, 0x9E691D9B9EFE23F7L /* 197 */, + 0x0446D288C4AE8D7FL /* 198 */, 0x7B4CC524E169785BL /* 199 */, + 0x21D87F0135CA1385L /* 200 */, 0xCEBB400F137B8AA5L /* 201 */, + 0x272E2B66580796BEL /* 202 */, 0x3612264125C2B0DEL /* 203 */, + 0x057702BDAD1EFBB2L /* 204 */, 0xD4BABB8EACF84BE9L /* 205 */, + 0x91583139641BC67BL /* 206 */, 0x8BDC2DE08036E024L /* 207 */, + 0x603C8156F49F68EDL /* 208 */, 0xF7D236F7DBEF5111L /* 209 */, + 0x9727C4598AD21E80L /* 210 */, 0xA08A0896670A5FD7L /* 211 */, + 0xCB4A8F4309EBA9CBL /* 212 */, 0x81AF564B0F7036A1L /* 213 */, + 0xC0B99AA778199ABDL /* 214 */, 0x959F1EC83FC8E952L /* 215 */, + 0x8C505077794A81B9L /* 216 */, 0x3ACAAF8F056338F0L /* 217 */, + 0x07B43F50627A6778L /* 218 */, 0x4A44AB49F5ECCC77L /* 219 */, + 0x3BC3D6E4B679EE98L /* 220 */, 0x9CC0D4D1CF14108CL /* 221 */, + 0x4406C00B206BC8A0L /* 222 */, 0x82A18854C8D72D89L /* 223 */, + 0x67E366B35C3C432CL /* 224 */, 0xB923DD61102B37F2L /* 225 */, + 0x56AB2779D884271DL /* 226 */, 0xBE83E1B0FF1525AFL /* 227 */, + 0xFB7C65D4217E49A9L /* 228 */, 0x6BDBE0E76D48E7D4L /* 229 */, + 0x08DF828745D9179EL /* 230 */, 0x22EA6A9ADD53BD34L /* 231 */, + 0xE36E141C5622200AL /* 232 */, 0x7F805D1B8CB750EEL /* 233 */, + 0xAFE5C7A59F58E837L /* 234 */, 0xE27F996A4FB1C23CL /* 235 */, + 0xD3867DFB0775F0D0L /* 236 */, 0xD0E673DE6E88891AL /* 237 */, + 0x123AEB9EAFB86C25L /* 238 */, 0x30F1D5D5C145B895L /* 239 */, + 0xBB434A2DEE7269E7L /* 240 */, 0x78CB67ECF931FA38L /* 241 */, + 0xF33B0372323BBF9CL /* 242 */, 0x52D66336FB279C74L /* 243 */, + 0x505F33AC0AFB4EAAL /* 244 */, 0xE8A5CD99A2CCE187L /* 245 */, + 0x534974801E2D30BBL /* 246 */, 0x8D2D5711D5876D90L /* 247 */, + 0x1F1A412891BC038EL /* 248 */, 0xD6E2E71D82E56648L /* 249 */, + 0x74036C3A497732B7L /* 250 */, 0x89B67ED96361F5ABL /* 251 */, + 0xFFED95D8F1EA02A2L /* 252 */, 0xE72B3BD61464D43DL /* 253 */, + 0xA6300F170BDC4820L /* 254 */, 0xEBC18760ED78A77AL /* 255 */, + }; + + private static final long[] t2 = { + 0xE6A6BE5A05A12138L /* 256 */, 0xB5A122A5B4F87C98L /* 257 */, + 0x563C6089140B6990L /* 258 */, 0x4C46CB2E391F5DD5L /* 259 */, + 0xD932ADDBC9B79434L /* 260 */, 0x08EA70E42015AFF5L /* 261 */, + 0xD765A6673E478CF1L /* 262 */, 0xC4FB757EAB278D99L /* 263 */, + 0xDF11C6862D6E0692L /* 264 */, 0xDDEB84F10D7F3B16L /* 265 */, + 0x6F2EF604A665EA04L /* 266 */, 0x4A8E0F0FF0E0DFB3L /* 267 */, + 0xA5EDEEF83DBCBA51L /* 268 */, 0xFC4F0A2A0EA4371EL /* 269 */, + 0xE83E1DA85CB38429L /* 270 */, 0xDC8FF882BA1B1CE2L /* 271 */, + 0xCD45505E8353E80DL /* 272 */, 0x18D19A00D4DB0717L /* 273 */, + 0x34A0CFEDA5F38101L /* 274 */, 0x0BE77E518887CAF2L /* 275 */, + 0x1E341438B3C45136L /* 276 */, 0xE05797F49089CCF9L /* 277 */, + 0xFFD23F9DF2591D14L /* 278 */, 0x543DDA228595C5CDL /* 279 */, + 0x661F81FD99052A33L /* 280 */, 0x8736E641DB0F7B76L /* 281 */, + 0x15227725418E5307L /* 282 */, 0xE25F7F46162EB2FAL /* 283 */, + 0x48A8B2126C13D9FEL /* 284 */, 0xAFDC541792E76EEAL /* 285 */, + 0x03D912BFC6D1898FL /* 286 */, 0x31B1AAFA1B83F51BL /* 287 */, + 0xF1AC2796E42AB7D9L /* 288 */, 0x40A3A7D7FCD2EBACL /* 289 */, + 0x1056136D0AFBBCC5L /* 290 */, 0x7889E1DD9A6D0C85L /* 291 */, + 0xD33525782A7974AAL /* 292 */, 0xA7E25D09078AC09BL /* 293 */, + 0xBD4138B3EAC6EDD0L /* 294 */, 0x920ABFBE71EB9E70L /* 295 */, + 0xA2A5D0F54FC2625CL /* 296 */, 0xC054E36B0B1290A3L /* 297 */, + 0xF6DD59FF62FE932BL /* 298 */, 0x3537354511A8AC7DL /* 299 */, + 0xCA845E9172FADCD4L /* 300 */, 0x84F82B60329D20DCL /* 301 */, + 0x79C62CE1CD672F18L /* 302 */, 0x8B09A2ADD124642CL /* 303 */, + 0xD0C1E96A19D9E726L /* 304 */, 0x5A786A9B4BA9500CL /* 305 */, + 0x0E020336634C43F3L /* 306 */, 0xC17B474AEB66D822L /* 307 */, + 0x6A731AE3EC9BAAC2L /* 308 */, 0x8226667AE0840258L /* 309 */, + 0x67D4567691CAECA5L /* 310 */, 0x1D94155C4875ADB5L /* 311 */, + 0x6D00FD985B813FDFL /* 312 */, 0x51286EFCB774CD06L /* 313 */, + 0x5E8834471FA744AFL /* 314 */, 0xF72CA0AEE761AE2EL /* 315 */, + 0xBE40E4CDAEE8E09AL /* 316 */, 0xE9970BBB5118F665L /* 317 */, + 0x726E4BEB33DF1964L /* 318 */, 0x703B000729199762L /* 319 */, + 0x4631D816F5EF30A7L /* 320 */, 0xB880B5B51504A6BEL /* 321 */, + 0x641793C37ED84B6CL /* 322 */, 0x7B21ED77F6E97D96L /* 323 */, + 0x776306312EF96B73L /* 324 */, 0xAE528948E86FF3F4L /* 325 */, + 0x53DBD7F286A3F8F8L /* 326 */, 0x16CADCE74CFC1063L /* 327 */, + 0x005C19BDFA52C6DDL /* 328 */, 0x68868F5D64D46AD3L /* 329 */, + 0x3A9D512CCF1E186AL /* 330 */, 0x367E62C2385660AEL /* 331 */, + 0xE359E7EA77DCB1D7L /* 332 */, 0x526C0773749ABE6EL /* 333 */, + 0x735AE5F9D09F734BL /* 334 */, 0x493FC7CC8A558BA8L /* 335 */, + 0xB0B9C1533041AB45L /* 336 */, 0x321958BA470A59BDL /* 337 */, + 0x852DB00B5F46C393L /* 338 */, 0x91209B2BD336B0E5L /* 339 */, + 0x6E604F7D659EF19FL /* 340 */, 0xB99A8AE2782CCB24L /* 341 */, + 0xCCF52AB6C814C4C7L /* 342 */, 0x4727D9AFBE11727BL /* 343 */, + 0x7E950D0C0121B34DL /* 344 */, 0x756F435670AD471FL /* 345 */, + 0xF5ADD442615A6849L /* 346 */, 0x4E87E09980B9957AL /* 347 */, + 0x2ACFA1DF50AEE355L /* 348 */, 0xD898263AFD2FD556L /* 349 */, + 0xC8F4924DD80C8FD6L /* 350 */, 0xCF99CA3D754A173AL /* 351 */, + 0xFE477BACAF91BF3CL /* 352 */, 0xED5371F6D690C12DL /* 353 */, + 0x831A5C285E687094L /* 354 */, 0xC5D3C90A3708A0A4L /* 355 */, + 0x0F7F903717D06580L /* 356 */, 0x19F9BB13B8FDF27FL /* 357 */, + 0xB1BD6F1B4D502843L /* 358 */, 0x1C761BA38FFF4012L /* 359 */, + 0x0D1530C4E2E21F3BL /* 360 */, 0x8943CE69A7372C8AL /* 361 */, + 0xE5184E11FEB5CE66L /* 362 */, 0x618BDB80BD736621L /* 363 */, + 0x7D29BAD68B574D0BL /* 364 */, 0x81BB613E25E6FE5BL /* 365 */, + 0x071C9C10BC07913FL /* 366 */, 0xC7BEEB7909AC2D97L /* 367 */, + 0xC3E58D353BC5D757L /* 368 */, 0xEB017892F38F61E8L /* 369 */, + 0xD4EFFB9C9B1CC21AL /* 370 */, 0x99727D26F494F7ABL /* 371 */, + 0xA3E063A2956B3E03L /* 372 */, 0x9D4A8B9A4AA09C30L /* 373 */, + 0x3F6AB7D500090FB4L /* 374 */, 0x9CC0F2A057268AC0L /* 375 */, + 0x3DEE9D2DEDBF42D1L /* 376 */, 0x330F49C87960A972L /* 377 */, + 0xC6B2720287421B41L /* 378 */, 0x0AC59EC07C00369CL /* 379 */, + 0xEF4EAC49CB353425L /* 380 */, 0xF450244EEF0129D8L /* 381 */, + 0x8ACC46E5CAF4DEB6L /* 382 */, 0x2FFEAB63989263F7L /* 383 */, + 0x8F7CB9FE5D7A4578L /* 384 */, 0x5BD8F7644E634635L /* 385 */, + 0x427A7315BF2DC900L /* 386 */, 0x17D0C4AA2125261CL /* 387 */, + 0x3992486C93518E50L /* 388 */, 0xB4CBFEE0A2D7D4C3L /* 389 */, + 0x7C75D6202C5DDD8DL /* 390 */, 0xDBC295D8E35B6C61L /* 391 */, + 0x60B369D302032B19L /* 392 */, 0xCE42685FDCE44132L /* 393 */, + 0x06F3DDB9DDF65610L /* 394 */, 0x8EA4D21DB5E148F0L /* 395 */, + 0x20B0FCE62FCD496FL /* 396 */, 0x2C1B912358B0EE31L /* 397 */, + 0xB28317B818F5A308L /* 398 */, 0xA89C1E189CA6D2CFL /* 399 */, + 0x0C6B18576AAADBC8L /* 400 */, 0xB65DEAA91299FAE3L /* 401 */, + 0xFB2B794B7F1027E7L /* 402 */, 0x04E4317F443B5BEBL /* 403 */, + 0x4B852D325939D0A6L /* 404 */, 0xD5AE6BEEFB207FFCL /* 405 */, + 0x309682B281C7D374L /* 406 */, 0xBAE309A194C3B475L /* 407 */, + 0x8CC3F97B13B49F05L /* 408 */, 0x98A9422FF8293967L /* 409 */, + 0x244B16B01076FF7CL /* 410 */, 0xF8BF571C663D67EEL /* 411 */, + 0x1F0D6758EEE30DA1L /* 412 */, 0xC9B611D97ADEB9B7L /* 413 */, + 0xB7AFD5887B6C57A2L /* 414 */, 0x6290AE846B984FE1L /* 415 */, + 0x94DF4CDEACC1A5FDL /* 416 */, 0x058A5BD1C5483AFFL /* 417 */, + 0x63166CC142BA3C37L /* 418 */, 0x8DB8526EB2F76F40L /* 419 */, + 0xE10880036F0D6D4EL /* 420 */, 0x9E0523C9971D311DL /* 421 */, + 0x45EC2824CC7CD691L /* 422 */, 0x575B8359E62382C9L /* 423 */, + 0xFA9E400DC4889995L /* 424 */, 0xD1823ECB45721568L /* 425 */, + 0xDAFD983B8206082FL /* 426 */, 0xAA7D29082386A8CBL /* 427 */, + 0x269FCD4403B87588L /* 428 */, 0x1B91F5F728BDD1E0L /* 429 */, + 0xE4669F39040201F6L /* 430 */, 0x7A1D7C218CF04ADEL /* 431 */, + 0x65623C29D79CE5CEL /* 432 */, 0x2368449096C00BB1L /* 433 */, + 0xAB9BF1879DA503BAL /* 434 */, 0xBC23ECB1A458058EL /* 435 */, + 0x9A58DF01BB401ECCL /* 436 */, 0xA070E868A85F143DL /* 437 */, + 0x4FF188307DF2239EL /* 438 */, 0x14D565B41A641183L /* 439 */, + 0xEE13337452701602L /* 440 */, 0x950E3DCF3F285E09L /* 441 */, + 0x59930254B9C80953L /* 442 */, 0x3BF299408930DA6DL /* 443 */, + 0xA955943F53691387L /* 444 */, 0xA15EDECAA9CB8784L /* 445 */, + 0x29142127352BE9A0L /* 446 */, 0x76F0371FFF4E7AFBL /* 447 */, + 0x0239F450274F2228L /* 448 */, 0xBB073AF01D5E868BL /* 449 */, + 0xBFC80571C10E96C1L /* 450 */, 0xD267088568222E23L /* 451 */, + 0x9671A3D48E80B5B0L /* 452 */, 0x55B5D38AE193BB81L /* 453 */, + 0x693AE2D0A18B04B8L /* 454 */, 0x5C48B4ECADD5335FL /* 455 */, + 0xFD743B194916A1CAL /* 456 */, 0x2577018134BE98C4L /* 457 */, + 0xE77987E83C54A4ADL /* 458 */, 0x28E11014DA33E1B9L /* 459 */, + 0x270CC59E226AA213L /* 460 */, 0x71495F756D1A5F60L /* 461 */, + 0x9BE853FB60AFEF77L /* 462 */, 0xADC786A7F7443DBFL /* 463 */, + 0x0904456173B29A82L /* 464 */, 0x58BC7A66C232BD5EL /* 465 */, + 0xF306558C673AC8B2L /* 466 */, 0x41F639C6B6C9772AL /* 467 */, + 0x216DEFE99FDA35DAL /* 468 */, 0x11640CC71C7BE615L /* 469 */, + 0x93C43694565C5527L /* 470 */, 0xEA038E6246777839L /* 471 */, + 0xF9ABF3CE5A3E2469L /* 472 */, 0x741E768D0FD312D2L /* 473 */, + 0x0144B883CED652C6L /* 474 */, 0xC20B5A5BA33F8552L /* 475 */, + 0x1AE69633C3435A9DL /* 476 */, 0x97A28CA4088CFDECL /* 477 */, + 0x8824A43C1E96F420L /* 478 */, 0x37612FA66EEEA746L /* 479 */, + 0x6B4CB165F9CF0E5AL /* 480 */, 0x43AA1C06A0ABFB4AL /* 481 */, + 0x7F4DC26FF162796BL /* 482 */, 0x6CBACC8E54ED9B0FL /* 483 */, + 0xA6B7FFEFD2BB253EL /* 484 */, 0x2E25BC95B0A29D4FL /* 485 */, + 0x86D6A58BDEF1388CL /* 486 */, 0xDED74AC576B6F054L /* 487 */, + 0x8030BDBC2B45805DL /* 488 */, 0x3C81AF70E94D9289L /* 489 */, + 0x3EFF6DDA9E3100DBL /* 490 */, 0xB38DC39FDFCC8847L /* 491 */, + 0x123885528D17B87EL /* 492 */, 0xF2DA0ED240B1B642L /* 493 */, + 0x44CEFADCD54BF9A9L /* 494 */, 0x1312200E433C7EE6L /* 495 */, + 0x9FFCC84F3A78C748L /* 496 */, 0xF0CD1F72248576BBL /* 497 */, + 0xEC6974053638CFE4L /* 498 */, 0x2BA7B67C0CEC4E4CL /* 499 */, + 0xAC2F4DF3E5CE32EDL /* 500 */, 0xCB33D14326EA4C11L /* 501 */, + 0xA4E9044CC77E58BCL /* 502 */, 0x5F513293D934FCEFL /* 503 */, + 0x5DC9645506E55444L /* 504 */, 0x50DE418F317DE40AL /* 505 */, + 0x388CB31A69DDE259L /* 506 */, 0x2DB4A83455820A86L /* 507 */, + 0x9010A91E84711AE9L /* 508 */, 0x4DF7F0B7B1498371L /* 509 */, + 0xD62A2EABC0977179L /* 510 */, 0x22FAC097AA8D5C0EL /* 511 */, + }; + + private static final long[] t3 = { + 0xF49FCC2FF1DAF39BL /* 512 */, 0x487FD5C66FF29281L /* 513 */, + 0xE8A30667FCDCA83FL /* 514 */, 0x2C9B4BE3D2FCCE63L /* 515 */, + 0xDA3FF74B93FBBBC2L /* 516 */, 0x2FA165D2FE70BA66L /* 517 */, + 0xA103E279970E93D4L /* 518 */, 0xBECDEC77B0E45E71L /* 519 */, + 0xCFB41E723985E497L /* 520 */, 0xB70AAA025EF75017L /* 521 */, + 0xD42309F03840B8E0L /* 522 */, 0x8EFC1AD035898579L /* 523 */, + 0x96C6920BE2B2ABC5L /* 524 */, 0x66AF4163375A9172L /* 525 */, + 0x2174ABDCCA7127FBL /* 526 */, 0xB33CCEA64A72FF41L /* 527 */, + 0xF04A4933083066A5L /* 528 */, 0x8D970ACDD7289AF5L /* 529 */, + 0x8F96E8E031C8C25EL /* 530 */, 0xF3FEC02276875D47L /* 531 */, + 0xEC7BF310056190DDL /* 532 */, 0xF5ADB0AEBB0F1491L /* 533 */, + 0x9B50F8850FD58892L /* 534 */, 0x4975488358B74DE8L /* 535 */, + 0xA3354FF691531C61L /* 536 */, 0x0702BBE481D2C6EEL /* 537 */, + 0x89FB24057DEDED98L /* 538 */, 0xAC3075138596E902L /* 539 */, + 0x1D2D3580172772EDL /* 540 */, 0xEB738FC28E6BC30DL /* 541 */, + 0x5854EF8F63044326L /* 542 */, 0x9E5C52325ADD3BBEL /* 543 */, + 0x90AA53CF325C4623L /* 544 */, 0xC1D24D51349DD067L /* 545 */, + 0x2051CFEEA69EA624L /* 546 */, 0x13220F0A862E7E4FL /* 547 */, + 0xCE39399404E04864L /* 548 */, 0xD9C42CA47086FCB7L /* 549 */, + 0x685AD2238A03E7CCL /* 550 */, 0x066484B2AB2FF1DBL /* 551 */, + 0xFE9D5D70EFBF79ECL /* 552 */, 0x5B13B9DD9C481854L /* 553 */, + 0x15F0D475ED1509ADL /* 554 */, 0x0BEBCD060EC79851L /* 555 */, + 0xD58C6791183AB7F8L /* 556 */, 0xD1187C5052F3EEE4L /* 557 */, + 0xC95D1192E54E82FFL /* 558 */, 0x86EEA14CB9AC6CA2L /* 559 */, + 0x3485BEB153677D5DL /* 560 */, 0xDD191D781F8C492AL /* 561 */, + 0xF60866BAA784EBF9L /* 562 */, 0x518F643BA2D08C74L /* 563 */, + 0x8852E956E1087C22L /* 564 */, 0xA768CB8DC410AE8DL /* 565 */, + 0x38047726BFEC8E1AL /* 566 */, 0xA67738B4CD3B45AAL /* 567 */, + 0xAD16691CEC0DDE19L /* 568 */, 0xC6D4319380462E07L /* 569 */, + 0xC5A5876D0BA61938L /* 570 */, 0x16B9FA1FA58FD840L /* 571 */, + 0x188AB1173CA74F18L /* 572 */, 0xABDA2F98C99C021FL /* 573 */, + 0x3E0580AB134AE816L /* 574 */, 0x5F3B05B773645ABBL /* 575 */, + 0x2501A2BE5575F2F6L /* 576 */, 0x1B2F74004E7E8BA9L /* 577 */, + 0x1CD7580371E8D953L /* 578 */, 0x7F6ED89562764E30L /* 579 */, + 0xB15926FF596F003DL /* 580 */, 0x9F65293DA8C5D6B9L /* 581 */, + 0x6ECEF04DD690F84CL /* 582 */, 0x4782275FFF33AF88L /* 583 */, + 0xE41433083F820801L /* 584 */, 0xFD0DFE409A1AF9B5L /* 585 */, + 0x4325A3342CDB396BL /* 586 */, 0x8AE77E62B301B252L /* 587 */, + 0xC36F9E9F6655615AL /* 588 */, 0x85455A2D92D32C09L /* 589 */, + 0xF2C7DEA949477485L /* 590 */, 0x63CFB4C133A39EBAL /* 591 */, + 0x83B040CC6EBC5462L /* 592 */, 0x3B9454C8FDB326B0L /* 593 */, + 0x56F56A9E87FFD78CL /* 594 */, 0x2DC2940D99F42BC6L /* 595 */, + 0x98F7DF096B096E2DL /* 596 */, 0x19A6E01E3AD852BFL /* 597 */, + 0x42A99CCBDBD4B40BL /* 598 */, 0xA59998AF45E9C559L /* 599 */, + 0x366295E807D93186L /* 600 */, 0x6B48181BFAA1F773L /* 601 */, + 0x1FEC57E2157A0A1DL /* 602 */, 0x4667446AF6201AD5L /* 603 */, + 0xE615EBCACFB0F075L /* 604 */, 0xB8F31F4F68290778L /* 605 */, + 0x22713ED6CE22D11EL /* 606 */, 0x3057C1A72EC3C93BL /* 607 */, + 0xCB46ACC37C3F1F2FL /* 608 */, 0xDBB893FD02AAF50EL /* 609 */, + 0x331FD92E600B9FCFL /* 610 */, 0xA498F96148EA3AD6L /* 611 */, + 0xA8D8426E8B6A83EAL /* 612 */, 0xA089B274B7735CDCL /* 613 */, + 0x87F6B3731E524A11L /* 614 */, 0x118808E5CBC96749L /* 615 */, + 0x9906E4C7B19BD394L /* 616 */, 0xAFED7F7E9B24A20CL /* 617 */, + 0x6509EADEEB3644A7L /* 618 */, 0x6C1EF1D3E8EF0EDEL /* 619 */, + 0xB9C97D43E9798FB4L /* 620 */, 0xA2F2D784740C28A3L /* 621 */, + 0x7B8496476197566FL /* 622 */, 0x7A5BE3E6B65F069DL /* 623 */, + 0xF96330ED78BE6F10L /* 624 */, 0xEEE60DE77A076A15L /* 625 */, + 0x2B4BEE4AA08B9BD0L /* 626 */, 0x6A56A63EC7B8894EL /* 627 */, + 0x02121359BA34FEF4L /* 628 */, 0x4CBF99F8283703FCL /* 629 */, + 0x398071350CAF30C8L /* 630 */, 0xD0A77A89F017687AL /* 631 */, + 0xF1C1A9EB9E423569L /* 632 */, 0x8C7976282DEE8199L /* 633 */, + 0x5D1737A5DD1F7ABDL /* 634 */, 0x4F53433C09A9FA80L /* 635 */, + 0xFA8B0C53DF7CA1D9L /* 636 */, 0x3FD9DCBC886CCB77L /* 637 */, + 0xC040917CA91B4720L /* 638 */, 0x7DD00142F9D1DCDFL /* 639 */, + 0x8476FC1D4F387B58L /* 640 */, 0x23F8E7C5F3316503L /* 641 */, + 0x032A2244E7E37339L /* 642 */, 0x5C87A5D750F5A74BL /* 643 */, + 0x082B4CC43698992EL /* 644 */, 0xDF917BECB858F63CL /* 645 */, + 0x3270B8FC5BF86DDAL /* 646 */, 0x10AE72BB29B5DD76L /* 647 */, + 0x576AC94E7700362BL /* 648 */, 0x1AD112DAC61EFB8FL /* 649 */, + 0x691BC30EC5FAA427L /* 650 */, 0xFF246311CC327143L /* 651 */, + 0x3142368E30E53206L /* 652 */, 0x71380E31E02CA396L /* 653 */, + 0x958D5C960AAD76F1L /* 654 */, 0xF8D6F430C16DA536L /* 655 */, + 0xC8FFD13F1BE7E1D2L /* 656 */, 0x7578AE66004DDBE1L /* 657 */, + 0x05833F01067BE646L /* 658 */, 0xBB34B5AD3BFE586DL /* 659 */, + 0x095F34C9A12B97F0L /* 660 */, 0x247AB64525D60CA8L /* 661 */, + 0xDCDBC6F3017477D1L /* 662 */, 0x4A2E14D4DECAD24DL /* 663 */, + 0xBDB5E6D9BE0A1EEBL /* 664 */, 0x2A7E70F7794301ABL /* 665 */, + 0xDEF42D8A270540FDL /* 666 */, 0x01078EC0A34C22C1L /* 667 */, + 0xE5DE511AF4C16387L /* 668 */, 0x7EBB3A52BD9A330AL /* 669 */, + 0x77697857AA7D6435L /* 670 */, 0x004E831603AE4C32L /* 671 */, + 0xE7A21020AD78E312L /* 672 */, 0x9D41A70C6AB420F2L /* 673 */, + 0x28E06C18EA1141E6L /* 674 */, 0xD2B28CBD984F6B28L /* 675 */, + 0x26B75F6C446E9D83L /* 676 */, 0xBA47568C4D418D7FL /* 677 */, + 0xD80BADBFE6183D8EL /* 678 */, 0x0E206D7F5F166044L /* 679 */, + 0xE258A43911CBCA3EL /* 680 */, 0x723A1746B21DC0BCL /* 681 */, + 0xC7CAA854F5D7CDD3L /* 682 */, 0x7CAC32883D261D9CL /* 683 */, + 0x7690C26423BA942CL /* 684 */, 0x17E55524478042B8L /* 685 */, + 0xE0BE477656A2389FL /* 686 */, 0x4D289B5E67AB2DA0L /* 687 */, + 0x44862B9C8FBBFD31L /* 688 */, 0xB47CC8049D141365L /* 689 */, + 0x822C1B362B91C793L /* 690 */, 0x4EB14655FB13DFD8L /* 691 */, + 0x1ECBBA0714E2A97BL /* 692 */, 0x6143459D5CDE5F14L /* 693 */, + 0x53A8FBF1D5F0AC89L /* 694 */, 0x97EA04D81C5E5B00L /* 695 */, + 0x622181A8D4FDB3F3L /* 696 */, 0xE9BCD341572A1208L /* 697 */, + 0x1411258643CCE58AL /* 698 */, 0x9144C5FEA4C6E0A4L /* 699 */, + 0x0D33D06565CF620FL /* 700 */, 0x54A48D489F219CA1L /* 701 */, + 0xC43E5EAC6D63C821L /* 702 */, 0xA9728B3A72770DAFL /* 703 */, + 0xD7934E7B20DF87EFL /* 704 */, 0xE35503B61A3E86E5L /* 705 */, + 0xCAE321FBC819D504L /* 706 */, 0x129A50B3AC60BFA6L /* 707 */, + 0xCD5E68EA7E9FB6C3L /* 708 */, 0xB01C90199483B1C7L /* 709 */, + 0x3DE93CD5C295376CL /* 710 */, 0xAED52EDF2AB9AD13L /* 711 */, + 0x2E60F512C0A07884L /* 712 */, 0xBC3D86A3E36210C9L /* 713 */, + 0x35269D9B163951CEL /* 714 */, 0x0C7D6E2AD0CDB5FAL /* 715 */, + 0x59E86297D87F5733L /* 716 */, 0x298EF221898DB0E7L /* 717 */, + 0x55000029D1A5AA7EL /* 718 */, 0x8BC08AE1B5061B45L /* 719 */, + 0xC2C31C2B6C92703AL /* 720 */, 0x94CC596BAF25EF42L /* 721 */, + 0x0A1D73DB22540456L /* 722 */, 0x04B6A0F9D9C4179AL /* 723 */, + 0xEFFDAFA2AE3D3C60L /* 724 */, 0xF7C8075BB49496C4L /* 725 */, + 0x9CC5C7141D1CD4E3L /* 726 */, 0x78BD1638218E5534L /* 727 */, + 0xB2F11568F850246AL /* 728 */, 0xEDFABCFA9502BC29L /* 729 */, + 0x796CE5F2DA23051BL /* 730 */, 0xAAE128B0DC93537CL /* 731 */, + 0x3A493DA0EE4B29AEL /* 732 */, 0xB5DF6B2C416895D7L /* 733 */, + 0xFCABBD25122D7F37L /* 734 */, 0x70810B58105DC4B1L /* 735 */, + 0xE10FDD37F7882A90L /* 736 */, 0x524DCAB5518A3F5CL /* 737 */, + 0x3C9E85878451255BL /* 738 */, 0x4029828119BD34E2L /* 739 */, + 0x74A05B6F5D3CECCBL /* 740 */, 0xB610021542E13ECAL /* 741 */, + 0x0FF979D12F59E2ACL /* 742 */, 0x6037DA27E4F9CC50L /* 743 */, + 0x5E92975A0DF1847DL /* 744 */, 0xD66DE190D3E623FEL /* 745 */, + 0x5032D6B87B568048L /* 746 */, 0x9A36B7CE8235216EL /* 747 */, + 0x80272A7A24F64B4AL /* 748 */, 0x93EFED8B8C6916F7L /* 749 */, + 0x37DDBFF44CCE1555L /* 750 */, 0x4B95DB5D4B99BD25L /* 751 */, + 0x92D3FDA169812FC0L /* 752 */, 0xFB1A4A9A90660BB6L /* 753 */, + 0x730C196946A4B9B2L /* 754 */, 0x81E289AA7F49DA68L /* 755 */, + 0x64669A0F83B1A05FL /* 756 */, 0x27B3FF7D9644F48BL /* 757 */, + 0xCC6B615C8DB675B3L /* 758 */, 0x674F20B9BCEBBE95L /* 759 */, + 0x6F31238275655982L /* 760 */, 0x5AE488713E45CF05L /* 761 */, + 0xBF619F9954C21157L /* 762 */, 0xEABAC46040A8EAE9L /* 763 */, + 0x454C6FE9F2C0C1CDL /* 764 */, 0x419CF6496412691CL /* 765 */, + 0xD3DC3BEF265B0F70L /* 766 */, 0x6D0E60F5C3578A9EL /* 767 */, + }; + + private static final long[] t4 = { + 0x5B0E608526323C55L /* 768 */, 0x1A46C1A9FA1B59F5L /* 769 */, + 0xA9E245A17C4C8FFAL /* 770 */, 0x65CA5159DB2955D7L /* 771 */, + 0x05DB0A76CE35AFC2L /* 772 */, 0x81EAC77EA9113D45L /* 773 */, + 0x528EF88AB6AC0A0DL /* 774 */, 0xA09EA253597BE3FFL /* 775 */, + 0x430DDFB3AC48CD56L /* 776 */, 0xC4B3A67AF45CE46FL /* 777 */, + 0x4ECECFD8FBE2D05EL /* 778 */, 0x3EF56F10B39935F0L /* 779 */, + 0x0B22D6829CD619C6L /* 780 */, 0x17FD460A74DF2069L /* 781 */, + 0x6CF8CC8E8510ED40L /* 782 */, 0xD6C824BF3A6ECAA7L /* 783 */, + 0x61243D581A817049L /* 784 */, 0x048BACB6BBC163A2L /* 785 */, + 0xD9A38AC27D44CC32L /* 786 */, 0x7FDDFF5BAAF410ABL /* 787 */, + 0xAD6D495AA804824BL /* 788 */, 0xE1A6A74F2D8C9F94L /* 789 */, + 0xD4F7851235DEE8E3L /* 790 */, 0xFD4B7F886540D893L /* 791 */, + 0x247C20042AA4BFDAL /* 792 */, 0x096EA1C517D1327CL /* 793 */, + 0xD56966B4361A6685L /* 794 */, 0x277DA5C31221057DL /* 795 */, + 0x94D59893A43ACFF7L /* 796 */, 0x64F0C51CCDC02281L /* 797 */, + 0x3D33BCC4FF6189DBL /* 798 */, 0xE005CB184CE66AF1L /* 799 */, + 0xFF5CCD1D1DB99BEAL /* 800 */, 0xB0B854A7FE42980FL /* 801 */, + 0x7BD46A6A718D4B9FL /* 802 */, 0xD10FA8CC22A5FD8CL /* 803 */, + 0xD31484952BE4BD31L /* 804 */, 0xC7FA975FCB243847L /* 805 */, + 0x4886ED1E5846C407L /* 806 */, 0x28CDDB791EB70B04L /* 807 */, + 0xC2B00BE2F573417FL /* 808 */, 0x5C9590452180F877L /* 809 */, + 0x7A6BDDFFF370EB00L /* 810 */, 0xCE509E38D6D9D6A4L /* 811 */, + 0xEBEB0F00647FA702L /* 812 */, 0x1DCC06CF76606F06L /* 813 */, + 0xE4D9F28BA286FF0AL /* 814 */, 0xD85A305DC918C262L /* 815 */, + 0x475B1D8732225F54L /* 816 */, 0x2D4FB51668CCB5FEL /* 817 */, + 0xA679B9D9D72BBA20L /* 818 */, 0x53841C0D912D43A5L /* 819 */, + 0x3B7EAA48BF12A4E8L /* 820 */, 0x781E0E47F22F1DDFL /* 821 */, + 0xEFF20CE60AB50973L /* 822 */, 0x20D261D19DFFB742L /* 823 */, + 0x16A12B03062A2E39L /* 824 */, 0x1960EB2239650495L /* 825 */, + 0x251C16FED50EB8B8L /* 826 */, 0x9AC0C330F826016EL /* 827 */, + 0xED152665953E7671L /* 828 */, 0x02D63194A6369570L /* 829 */, + 0x5074F08394B1C987L /* 830 */, 0x70BA598C90B25CE1L /* 831 */, + 0x794A15810B9742F6L /* 832 */, 0x0D5925E9FCAF8C6CL /* 833 */, + 0x3067716CD868744EL /* 834 */, 0x910AB077E8D7731BL /* 835 */, + 0x6A61BBDB5AC42F61L /* 836 */, 0x93513EFBF0851567L /* 837 */, + 0xF494724B9E83E9D5L /* 838 */, 0xE887E1985C09648DL /* 839 */, + 0x34B1D3C675370CFDL /* 840 */, 0xDC35E433BC0D255DL /* 841 */, + 0xD0AAB84234131BE0L /* 842 */, 0x08042A50B48B7EAFL /* 843 */, + 0x9997C4EE44A3AB35L /* 844 */, 0x829A7B49201799D0L /* 845 */, + 0x263B8307B7C54441L /* 846 */, 0x752F95F4FD6A6CA6L /* 847 */, + 0x927217402C08C6E5L /* 848 */, 0x2A8AB754A795D9EEL /* 849 */, + 0xA442F7552F72943DL /* 850 */, 0x2C31334E19781208L /* 851 */, + 0x4FA98D7CEAEE6291L /* 852 */, 0x55C3862F665DB309L /* 853 */, + 0xBD0610175D53B1F3L /* 854 */, 0x46FE6CB840413F27L /* 855 */, + 0x3FE03792DF0CFA59L /* 856 */, 0xCFE700372EB85E8FL /* 857 */, + 0xA7BE29E7ADBCE118L /* 858 */, 0xE544EE5CDE8431DDL /* 859 */, + 0x8A781B1B41F1873EL /* 860 */, 0xA5C94C78A0D2F0E7L /* 861 */, + 0x39412E2877B60728L /* 862 */, 0xA1265EF3AFC9A62CL /* 863 */, + 0xBCC2770C6A2506C5L /* 864 */, 0x3AB66DD5DCE1CE12L /* 865 */, + 0xE65499D04A675B37L /* 866 */, 0x7D8F523481BFD216L /* 867 */, + 0x0F6F64FCEC15F389L /* 868 */, 0x74EFBE618B5B13C8L /* 869 */, + 0xACDC82B714273E1DL /* 870 */, 0xDD40BFE003199D17L /* 871 */, + 0x37E99257E7E061F8L /* 872 */, 0xFA52626904775AAAL /* 873 */, + 0x8BBBF63A463D56F9L /* 874 */, 0xF0013F1543A26E64L /* 875 */, + 0xA8307E9F879EC898L /* 876 */, 0xCC4C27A4150177CCL /* 877 */, + 0x1B432F2CCA1D3348L /* 878 */, 0xDE1D1F8F9F6FA013L /* 879 */, + 0x606602A047A7DDD6L /* 880 */, 0xD237AB64CC1CB2C7L /* 881 */, + 0x9B938E7225FCD1D3L /* 882 */, 0xEC4E03708E0FF476L /* 883 */, + 0xFEB2FBDA3D03C12DL /* 884 */, 0xAE0BCED2EE43889AL /* 885 */, + 0x22CB8923EBFB4F43L /* 886 */, 0x69360D013CF7396DL /* 887 */, + 0x855E3602D2D4E022L /* 888 */, 0x073805BAD01F784CL /* 889 */, + 0x33E17A133852F546L /* 890 */, 0xDF4874058AC7B638L /* 891 */, + 0xBA92B29C678AA14AL /* 892 */, 0x0CE89FC76CFAADCDL /* 893 */, + 0x5F9D4E0908339E34L /* 894 */, 0xF1AFE9291F5923B9L /* 895 */, + 0x6E3480F60F4A265FL /* 896 */, 0xEEBF3A2AB29B841CL /* 897 */, + 0xE21938A88F91B4ADL /* 898 */, 0x57DFEFF845C6D3C3L /* 899 */, + 0x2F006B0BF62CAAF2L /* 900 */, 0x62F479EF6F75EE78L /* 901 */, + 0x11A55AD41C8916A9L /* 902 */, 0xF229D29084FED453L /* 903 */, + 0x42F1C27B16B000E6L /* 904 */, 0x2B1F76749823C074L /* 905 */, + 0x4B76ECA3C2745360L /* 906 */, 0x8C98F463B91691BDL /* 907 */, + 0x14BCC93CF1ADE66AL /* 908 */, 0x8885213E6D458397L /* 909 */, + 0x8E177DF0274D4711L /* 910 */, 0xB49B73B5503F2951L /* 911 */, + 0x10168168C3F96B6BL /* 912 */, 0x0E3D963B63CAB0AEL /* 913 */, + 0x8DFC4B5655A1DB14L /* 914 */, 0xF789F1356E14DE5CL /* 915 */, + 0x683E68AF4E51DAC1L /* 916 */, 0xC9A84F9D8D4B0FD9L /* 917 */, + 0x3691E03F52A0F9D1L /* 918 */, 0x5ED86E46E1878E80L /* 919 */, + 0x3C711A0E99D07150L /* 920 */, 0x5A0865B20C4E9310L /* 921 */, + 0x56FBFC1FE4F0682EL /* 922 */, 0xEA8D5DE3105EDF9BL /* 923 */, + 0x71ABFDB12379187AL /* 924 */, 0x2EB99DE1BEE77B9CL /* 925 */, + 0x21ECC0EA33CF4523L /* 926 */, 0x59A4D7521805C7A1L /* 927 */, + 0x3896F5EB56AE7C72L /* 928 */, 0xAA638F3DB18F75DCL /* 929 */, + 0x9F39358DABE9808EL /* 930 */, 0xB7DEFA91C00B72ACL /* 931 */, + 0x6B5541FD62492D92L /* 932 */, 0x6DC6DEE8F92E4D5BL /* 933 */, + 0x353F57ABC4BEEA7EL /* 934 */, 0x735769D6DA5690CEL /* 935 */, + 0x0A234AA642391484L /* 936 */, 0xF6F9508028F80D9DL /* 937 */, + 0xB8E319A27AB3F215L /* 938 */, 0x31AD9C1151341A4DL /* 939 */, + 0x773C22A57BEF5805L /* 940 */, 0x45C7561A07968633L /* 941 */, + 0xF913DA9E249DBE36L /* 942 */, 0xDA652D9B78A64C68L /* 943 */, + 0x4C27A97F3BC334EFL /* 944 */, 0x76621220E66B17F4L /* 945 */, + 0x967743899ACD7D0BL /* 946 */, 0xF3EE5BCAE0ED6782L /* 947 */, + 0x409F753600C879FCL /* 948 */, 0x06D09A39B5926DB6L /* 949 */, + 0x6F83AEB0317AC588L /* 950 */, 0x01E6CA4A86381F21L /* 951 */, + 0x66FF3462D19F3025L /* 952 */, 0x72207C24DDFD3BFBL /* 953 */, + 0x4AF6B6D3E2ECE2EBL /* 954 */, 0x9C994DBEC7EA08DEL /* 955 */, + 0x49ACE597B09A8BC4L /* 956 */, 0xB38C4766CF0797BAL /* 957 */, + 0x131B9373C57C2A75L /* 958 */, 0xB1822CCE61931E58L /* 959 */, + 0x9D7555B909BA1C0CL /* 960 */, 0x127FAFDD937D11D2L /* 961 */, + 0x29DA3BADC66D92E4L /* 962 */, 0xA2C1D57154C2ECBCL /* 963 */, + 0x58C5134D82F6FE24L /* 964 */, 0x1C3AE3515B62274FL /* 965 */, + 0xE907C82E01CB8126L /* 966 */, 0xF8ED091913E37FCBL /* 967 */, + 0x3249D8F9C80046C9L /* 968 */, 0x80CF9BEDE388FB63L /* 969 */, + 0x1881539A116CF19EL /* 970 */, 0x5103F3F76BD52457L /* 971 */, + 0x15B7E6F5AE47F7A8L /* 972 */, 0xDBD7C6DED47E9CCFL /* 973 */, + 0x44E55C410228BB1AL /* 974 */, 0xB647D4255EDB4E99L /* 975 */, + 0x5D11882BB8AAFC30L /* 976 */, 0xF5098BBB29D3212AL /* 977 */, + 0x8FB5EA14E90296B3L /* 978 */, 0x677B942157DD025AL /* 979 */, + 0xFB58E7C0A390ACB5L /* 980 */, 0x89D3674C83BD4A01L /* 981 */, + 0x9E2DA4DF4BF3B93BL /* 982 */, 0xFCC41E328CAB4829L /* 983 */, + 0x03F38C96BA582C52L /* 984 */, 0xCAD1BDBD7FD85DB2L /* 985 */, + 0xBBB442C16082AE83L /* 986 */, 0xB95FE86BA5DA9AB0L /* 987 */, + 0xB22E04673771A93FL /* 988 */, 0x845358C9493152D8L /* 989 */, + 0xBE2A488697B4541EL /* 990 */, 0x95A2DC2DD38E6966L /* 991 */, + 0xC02C11AC923C852BL /* 992 */, 0x2388B1990DF2A87BL /* 993 */, + 0x7C8008FA1B4F37BEL /* 994 */, 0x1F70D0C84D54E503L /* 995 */, + 0x5490ADEC7ECE57D4L /* 996 */, 0x002B3C27D9063A3AL /* 997 */, + 0x7EAEA3848030A2BFL /* 998 */, 0xC602326DED2003C0L /* 999 */, + 0x83A7287D69A94086L /* 1000 */, 0xC57A5FCB30F57A8AL /* 1001 */, + 0xB56844E479EBE779L /* 1002 */, 0xA373B40F05DCBCE9L /* 1003 */, + 0xD71A786E88570EE2L /* 1004 */, 0x879CBACDBDE8F6A0L /* 1005 */, + 0x976AD1BCC164A32FL /* 1006 */, 0xAB21E25E9666D78BL /* 1007 */, + 0x901063AAE5E5C33CL /* 1008 */, 0x9818B34448698D90L /* 1009 */, + 0xE36487AE3E1E8ABBL /* 1010 */, 0xAFBDF931893BDCB4L /* 1011 */, + 0x6345A0DC5FBBD519L /* 1012 */, 0x8628FE269B9465CAL /* 1013 */, + 0x1E5D01603F9C51ECL /* 1014 */, 0x4DE44006A15049B7L /* 1015 */, + 0xBF6C70E5F776CBB1L /* 1016 */, 0x411218F2EF552BEDL /* 1017 */, + 0xCB0C0708705A36A3L /* 1018 */, 0xE74D14754F986044L /* 1019 */, + 0xCD56D9430EA8280EL /* 1020 */, 0xC12591D7535F5065L /* 1021 */, + 0xC83223F1720AEF96L /* 1022 */, 0xC3A0396F7363A51FL /* 1023 */ + }; + + private static final int DIGEST_LENGTH = 24; + + // + // registers + // + private long a, b, c; + private long byteCount; + + // + // buffers + // + private byte[] buf = new byte[8]; + private int bOff = 0; + + private long[] x = new long[8]; + private int xOff = 0; + + /** + * Standard constructor + */ + public TigerDigest() + { + reset(); + } + + /** + * Copy constructor. This will copy the state of the provided + * message digest. + */ + public TigerDigest(TigerDigest t) + { + a = t.a; + b = t.b; + c = t.c; + + System.arraycopy(t.x, 0, x, 0, t.x.length); + xOff = t.xOff; + + System.arraycopy(t.buf, 0, buf, 0, t.buf.length); + bOff = t.bOff; + + byteCount = t.byteCount; + } + + public String getAlgorithmName() + { + return "Tiger"; + } + + public int getDigestSize() + { + return DIGEST_LENGTH; + } + + private void processWord( + byte[] b, + int off) + { + x[xOff++] = ((long)(b[off + 7] & 0xff) << 56) + | ((long)(b[off + 6] & 0xff) << 48) + | ((long)(b[off + 5] & 0xff) << 40) + | ((long)(b[off + 4] & 0xff) << 32) + | ((long)(b[off + 3] & 0xff) << 24) + | ((long)(b[off + 2] & 0xff) << 16) + | ((long)(b[off + 1] & 0xff) << 8) + | ((b[off + 0] & 0xff)); + + if (xOff == x.length) + { + processBlock(); + } + + bOff = 0; + } + + public void update( + byte in) + { + buf[bOff++] = in; + + if (bOff == buf.length) + { + processWord(buf, 0); + } + + byteCount++; + } + + public void update( + byte[] in, + int inOff, + int len) + { + // + // fill the current word + // + while ((bOff != 0) && (len > 0)) + { + update(in[inOff]); + + inOff++; + len--; + } + + // + // process whole words. + // + while (len > 8) + { + processWord(in, inOff); + + inOff += 8; + len -= 8; + byteCount += 8; + } + + // + // load in the remainder. + // + while (len > 0) + { + update(in[inOff]); + + inOff++; + len--; + } + } + + private void roundABC( + long x, + long mul) + { + c ^= x ; + a -= t1[(int)c & 0xff] ^ t2[(int)(c >> 16) & 0xff] + ^ t3[(int)(c >> 32) & 0xff] ^ t4[(int)(c >> 48) & 0xff]; + b += t4[(int)(c >> 8) & 0xff] ^ t3[(int)(c >> 24) & 0xff] + ^ t2[(int)(c >> 40) & 0xff] ^ t1[(int)(c >> 56) & 0xff]; + b *= mul; + } + + private void roundBCA( + long x, + long mul) + { + a ^= x ; + b -= t1[(int)a & 0xff] ^ t2[(int)(a >> 16) & 0xff] + ^ t3[(int)(a >> 32) & 0xff] ^ t4[(int)(a >> 48) & 0xff]; + c += t4[(int)(a >> 8) & 0xff] ^ t3[(int)(a >> 24) & 0xff] + ^ t2[(int)(a >> 40) & 0xff] ^ t1[(int)(a >> 56) & 0xff]; + c *= mul; + } + + private void roundCAB( + long x, + long mul) + { + b ^= x ; + c -= t1[(int)b & 0xff] ^ t2[(int)(b >> 16) & 0xff] + ^ t3[(int)(b >> 32) & 0xff] ^ t4[(int)(b >> 48) & 0xff]; + a += t4[(int)(b >> 8) & 0xff] ^ t3[(int)(b >> 24) & 0xff] + ^ t2[(int)(b >> 40) & 0xff] ^ t1[(int)(b >> 56) & 0xff]; + a *= mul; + } + + private void keySchedule() + { + x[0] -= x[7] ^ 0xA5A5A5A5A5A5A5A5L; + x[1] ^= x[0]; + x[2] += x[1]; + x[3] -= x[2] ^ ((~x[1]) << 19); + x[4] ^= x[3]; + x[5] += x[4]; + x[6] -= x[5] ^ ((~x[4]) >>> 23); + x[7] ^= x[6]; + x[0] += x[7]; + x[1] -= x[0] ^ ((~x[7]) << 19); + x[2] ^= x[1]; + x[3] += x[2]; + x[4] -= x[3] ^ ((~x[2]) >>> 23); + x[5] ^= x[4]; + x[6] += x[5]; + x[7] -= x[6] ^ 0x0123456789ABCDEFL; + } + + private void processBlock() + { + // + // save abc + // + long aa = a; + long bb = b; + long cc = c; + + // + // rounds and schedule + // + roundABC(x[0], 5); + roundBCA(x[1], 5); + roundCAB(x[2], 5); + roundABC(x[3], 5); + roundBCA(x[4], 5); + roundCAB(x[5], 5); + roundABC(x[6], 5); + roundBCA(x[7], 5); + + keySchedule(); + + roundCAB(x[0], 7); + roundABC(x[1], 7); + roundBCA(x[2], 7); + roundCAB(x[3], 7); + roundABC(x[4], 7); + roundBCA(x[5], 7); + roundCAB(x[6], 7); + roundABC(x[7], 7); + + keySchedule(); + + roundBCA(x[0], 9); + roundCAB(x[1], 9); + roundABC(x[2], 9); + roundBCA(x[3], 9); + roundCAB(x[4], 9); + roundABC(x[5], 9); + roundBCA(x[6], 9); + roundCAB(x[7], 9); + + // + // feed forward + // + a ^= aa; + b -= bb; + c += cc; + + // + // clear the x buffer + // + xOff = 0; + for (int i = 0; i != x.length; i++) + { + x[i] = 0; + } + } + + public void unpackWord( + long r, + byte[] out, + int outOff) + { + out[outOff + 7] = (byte)(r >> 56); + out[outOff + 6] = (byte)(r >> 48); + out[outOff + 5] = (byte)(r >> 40); + out[outOff + 4] = (byte)(r >> 32); + out[outOff + 3] = (byte)(r >> 24); + out[outOff + 2] = (byte)(r >> 16); + out[outOff + 1] = (byte)(r >> 8); + out[outOff] = (byte)r; + } + + private void processLength( + long bitLength) + { + x[7] = bitLength; + } + + private void finish() + { + long bitLength = (byteCount << 3); + + update((byte)0x01); + + while (bOff != 0) + { + update((byte)0); + } + + processLength(bitLength); + + processBlock(); + } + + public int doFinal( + byte[] out, + int outOff) + { + finish(); + + unpackWord(a, out, outOff); + unpackWord(b, out, outOff + 8); + unpackWord(c, out, outOff + 16); + + reset(); + + return DIGEST_LENGTH; + } + + /** + * reset the chaining variables + */ + public void reset() + { + a = 0x0123456789ABCDEFL; + b = 0xFEDCBA9876543210L; + c = 0xF096A5B4C3B2E187L; + + xOff = 0; + for (int i = 0; i != x.length; i++) + { + x[i] = 0; + } + + bOff = 0; + for (int i = 0; i != buf.length; i++) + { + buf[i] = 0; + } + + byteCount = 0; + } + + public int getByteLength() + { + return BYTE_LENGTH; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/digests/WhirlpoolDigest.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/digests/WhirlpoolDigest.java new file mode 100644 index 0000000..2acd250 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/digests/WhirlpoolDigest.java @@ -0,0 +1,396 @@ +package org.bc.crypto.digests; + +import org.bc.crypto.ExtendedDigest; +import org.bc.util.Arrays; + + +/** + * Implementation of WhirlpoolDigest, based on Java source published by Barreto + * and Rijmen. + * + */ +public final class WhirlpoolDigest + implements ExtendedDigest +{ + private static final int BYTE_LENGTH = 64; + + private static final int DIGEST_LENGTH_BYTES = 512 / 8; + private static final int ROUNDS = 10; + private static final int REDUCTION_POLYNOMIAL = 0x011d; // 2^8 + 2^4 + 2^3 + 2 + 1; + + private static final int[] SBOX = { + 0x18, 0x23, 0xc6, 0xe8, 0x87, 0xb8, 0x01, 0x4f, 0x36, 0xa6, 0xd2, 0xf5, 0x79, 0x6f, 0x91, 0x52, + 0x60, 0xbc, 0x9b, 0x8e, 0xa3, 0x0c, 0x7b, 0x35, 0x1d, 0xe0, 0xd7, 0xc2, 0x2e, 0x4b, 0xfe, 0x57, + 0x15, 0x77, 0x37, 0xe5, 0x9f, 0xf0, 0x4a, 0xda, 0x58, 0xc9, 0x29, 0x0a, 0xb1, 0xa0, 0x6b, 0x85, + 0xbd, 0x5d, 0x10, 0xf4, 0xcb, 0x3e, 0x05, 0x67, 0xe4, 0x27, 0x41, 0x8b, 0xa7, 0x7d, 0x95, 0xd8, + 0xfb, 0xee, 0x7c, 0x66, 0xdd, 0x17, 0x47, 0x9e, 0xca, 0x2d, 0xbf, 0x07, 0xad, 0x5a, 0x83, 0x33, + 0x63, 0x02, 0xaa, 0x71, 0xc8, 0x19, 0x49, 0xd9, 0xf2, 0xe3, 0x5b, 0x88, 0x9a, 0x26, 0x32, 0xb0, + 0xe9, 0x0f, 0xd5, 0x80, 0xbe, 0xcd, 0x34, 0x48, 0xff, 0x7a, 0x90, 0x5f, 0x20, 0x68, 0x1a, 0xae, + 0xb4, 0x54, 0x93, 0x22, 0x64, 0xf1, 0x73, 0x12, 0x40, 0x08, 0xc3, 0xec, 0xdb, 0xa1, 0x8d, 0x3d, + 0x97, 0x00, 0xcf, 0x2b, 0x76, 0x82, 0xd6, 0x1b, 0xb5, 0xaf, 0x6a, 0x50, 0x45, 0xf3, 0x30, 0xef, + 0x3f, 0x55, 0xa2, 0xea, 0x65, 0xba, 0x2f, 0xc0, 0xde, 0x1c, 0xfd, 0x4d, 0x92, 0x75, 0x06, 0x8a, + 0xb2, 0xe6, 0x0e, 0x1f, 0x62, 0xd4, 0xa8, 0x96, 0xf9, 0xc5, 0x25, 0x59, 0x84, 0x72, 0x39, 0x4c, + 0x5e, 0x78, 0x38, 0x8c, 0xd1, 0xa5, 0xe2, 0x61, 0xb3, 0x21, 0x9c, 0x1e, 0x43, 0xc7, 0xfc, 0x04, + 0x51, 0x99, 0x6d, 0x0d, 0xfa, 0xdf, 0x7e, 0x24, 0x3b, 0xab, 0xce, 0x11, 0x8f, 0x4e, 0xb7, 0xeb, + 0x3c, 0x81, 0x94, 0xf7, 0xb9, 0x13, 0x2c, 0xd3, 0xe7, 0x6e, 0xc4, 0x03, 0x56, 0x44, 0x7f, 0xa9, + 0x2a, 0xbb, 0xc1, 0x53, 0xdc, 0x0b, 0x9d, 0x6c, 0x31, 0x74, 0xf6, 0x46, 0xac, 0x89, 0x14, 0xe1, + 0x16, 0x3a, 0x69, 0x09, 0x70, 0xb6, 0xd0, 0xed, 0xcc, 0x42, 0x98, 0xa4, 0x28, 0x5c, 0xf8, 0x86 + }; + + private static final long[] C0 = new long[256]; + private static final long[] C1 = new long[256]; + private static final long[] C2 = new long[256]; + private static final long[] C3 = new long[256]; + private static final long[] C4 = new long[256]; + private static final long[] C5 = new long[256]; + private static final long[] C6 = new long[256]; + private static final long[] C7 = new long[256]; + + private final long[] _rc = new long[ROUNDS + 1]; + + public WhirlpoolDigest() + { + for (int i = 0; i < 256; i++) + { + int v1 = SBOX[i]; + int v2 = maskWithReductionPolynomial(v1 << 1); + int v4 = maskWithReductionPolynomial(v2 << 1); + int v5 = v4 ^ v1; + int v8 = maskWithReductionPolynomial(v4 << 1); + int v9 = v8 ^ v1; + + C0[i] = packIntoLong(v1, v1, v4, v1, v8, v5, v2, v9); + C1[i] = packIntoLong(v9, v1, v1, v4, v1, v8, v5, v2); + C2[i] = packIntoLong(v2, v9, v1, v1, v4, v1, v8, v5); + C3[i] = packIntoLong(v5, v2, v9, v1, v1, v4, v1, v8); + C4[i] = packIntoLong(v8, v5, v2, v9, v1, v1, v4, v1); + C5[i] = packIntoLong(v1, v8, v5, v2, v9, v1, v1, v4); + C6[i] = packIntoLong(v4, v1, v8, v5, v2, v9, v1, v1); + C7[i] = packIntoLong(v1, v4, v1, v8, v5, v2, v9, v1); + + } + + _rc[0] = 0L; + for (int r = 1; r <= ROUNDS; r++) + { + int i = 8 * (r - 1); + _rc[r] = (C0[i ] & 0xff00000000000000L) ^ + (C1[i + 1] & 0x00ff000000000000L) ^ + (C2[i + 2] & 0x0000ff0000000000L) ^ + (C3[i + 3] & 0x000000ff00000000L) ^ + (C4[i + 4] & 0x00000000ff000000L) ^ + (C5[i + 5] & 0x0000000000ff0000L) ^ + (C6[i + 6] & 0x000000000000ff00L) ^ + (C7[i + 7] & 0x00000000000000ffL); + } + + } + + private long packIntoLong(int b7, int b6, int b5, int b4, int b3, int b2, int b1, int b0) + { + return + ((long)b7 << 56) ^ + ((long)b6 << 48) ^ + ((long)b5 << 40) ^ + ((long)b4 << 32) ^ + ((long)b3 << 24) ^ + ((long)b2 << 16) ^ + ((long)b1 << 8) ^ + b0; + } + + /* + * int's are used to prevent sign extension. The values that are really being used are + * actually just 0..255 + */ + private int maskWithReductionPolynomial(int input) + { + int rv = input; + if (rv >= 0x100L) // high bit set + { + rv ^= REDUCTION_POLYNOMIAL; // reduced by the polynomial + } + return rv; + } + + // --------------------------------------------------------------------------------------// + + // -- buffer information -- + private static final int BITCOUNT_ARRAY_SIZE = 32; + private byte[] _buffer = new byte[64]; + private int _bufferPos = 0; + private short[] _bitCount = new short[BITCOUNT_ARRAY_SIZE]; + + // -- internal hash state -- + private long[] _hash = new long[8]; + private long[] _K = new long[8]; // the round key + private long[] _L = new long[8]; + private long[] _block = new long[8]; // mu (buffer) + private long[] _state = new long[8]; // the current "cipher" state + + + + /** + * Copy constructor. This will copy the state of the provided message + * digest. + */ + public WhirlpoolDigest(WhirlpoolDigest originalDigest) + { + System.arraycopy(originalDigest._rc, 0, _rc, 0, _rc.length); + + System.arraycopy(originalDigest._buffer, 0, _buffer, 0, _buffer.length); + + this._bufferPos = originalDigest._bufferPos; + System.arraycopy(originalDigest._bitCount, 0, _bitCount, 0, _bitCount.length); + + // -- internal hash state -- + System.arraycopy(originalDigest._hash, 0, _hash, 0, _hash.length); + System.arraycopy(originalDigest._K, 0, _K, 0, _K.length); + System.arraycopy(originalDigest._L, 0, _L, 0, _L.length); + System.arraycopy(originalDigest._block, 0, _block, 0, _block.length); + System.arraycopy(originalDigest._state, 0, _state, 0, _state.length); + } + + public String getAlgorithmName() + { + return "Whirlpool"; + } + + public int getDigestSize() + { + return DIGEST_LENGTH_BYTES; + } + + public int doFinal(byte[] out, int outOff) + { + // sets out[outOff] .. out[outOff+DIGEST_LENGTH_BYTES] + finish(); + + for (int i = 0; i < 8; i++) + { + convertLongToByteArray(_hash[i], out, outOff + (i * 8)); + } + + reset(); + return getDigestSize(); + } + + /** + * reset the chaining variables + */ + public void reset() + { + // set variables to null, blank, whatever + _bufferPos = 0; + Arrays.fill(_bitCount, (short)0); + Arrays.fill(_buffer, (byte)0); + Arrays.fill(_hash, 0); + Arrays.fill(_K, 0); + Arrays.fill(_L, 0); + Arrays.fill(_block, 0); + Arrays.fill(_state, 0); + } + + // this takes a buffer of information and fills the block + private void processFilledBuffer(byte[] in, int inOff) + { + // copies into the block... + for (int i = 0; i < _state.length; i++) + { + _block[i] = bytesToLongFromBuffer(_buffer, i * 8); + } + processBlock(); + _bufferPos = 0; + Arrays.fill(_buffer, (byte)0); + } + + private long bytesToLongFromBuffer(byte[] buffer, int startPos) + { + long rv = (((buffer[startPos + 0] & 0xffL) << 56) | + ((buffer[startPos + 1] & 0xffL) << 48) | + ((buffer[startPos + 2] & 0xffL) << 40) | + ((buffer[startPos + 3] & 0xffL) << 32) | + ((buffer[startPos + 4] & 0xffL) << 24) | + ((buffer[startPos + 5] & 0xffL) << 16) | + ((buffer[startPos + 6] & 0xffL) << 8) | + ((buffer[startPos + 7]) & 0xffL)); + + return rv; + } + + private void convertLongToByteArray(long inputLong, byte[] outputArray, int offSet) + { + for (int i = 0; i < 8; i++) + { + outputArray[offSet + i] = (byte)((inputLong >> (56 - (i * 8))) & 0xff); + } + } + + protected void processBlock() + { + // buffer contents have been transferred to the _block[] array via + // processFilledBuffer + + // compute and apply K^0 + for (int i = 0; i < 8; i++) + { + _state[i] = _block[i] ^ (_K[i] = _hash[i]); + } + + // iterate over the rounds + for (int round = 1; round <= ROUNDS; round++) + { + for (int i = 0; i < 8; i++) + { + _L[i] = 0; + _L[i] ^= C0[(int)(_K[(i - 0) & 7] >>> 56) & 0xff]; + _L[i] ^= C1[(int)(_K[(i - 1) & 7] >>> 48) & 0xff]; + _L[i] ^= C2[(int)(_K[(i - 2) & 7] >>> 40) & 0xff]; + _L[i] ^= C3[(int)(_K[(i - 3) & 7] >>> 32) & 0xff]; + _L[i] ^= C4[(int)(_K[(i - 4) & 7] >>> 24) & 0xff]; + _L[i] ^= C5[(int)(_K[(i - 5) & 7] >>> 16) & 0xff]; + _L[i] ^= C6[(int)(_K[(i - 6) & 7] >>> 8) & 0xff]; + _L[i] ^= C7[(int)(_K[(i - 7) & 7]) & 0xff]; + } + + System.arraycopy(_L, 0, _K, 0, _K.length); + + _K[0] ^= _rc[round]; + + // apply the round transformation + for (int i = 0; i < 8; i++) + { + _L[i] = _K[i]; + + _L[i] ^= C0[(int)(_state[(i - 0) & 7] >>> 56) & 0xff]; + _L[i] ^= C1[(int)(_state[(i - 1) & 7] >>> 48) & 0xff]; + _L[i] ^= C2[(int)(_state[(i - 2) & 7] >>> 40) & 0xff]; + _L[i] ^= C3[(int)(_state[(i - 3) & 7] >>> 32) & 0xff]; + _L[i] ^= C4[(int)(_state[(i - 4) & 7] >>> 24) & 0xff]; + _L[i] ^= C5[(int)(_state[(i - 5) & 7] >>> 16) & 0xff]; + _L[i] ^= C6[(int)(_state[(i - 6) & 7] >>> 8) & 0xff]; + _L[i] ^= C7[(int)(_state[(i - 7) & 7]) & 0xff]; + } + + // save the current state + System.arraycopy(_L, 0, _state, 0, _state.length); + } + + // apply Miuaguchi-Preneel compression + for (int i = 0; i < 8; i++) + { + _hash[i] ^= _state[i] ^ _block[i]; + } + + } + + public void update(byte in) + { + _buffer[_bufferPos] = in; + + //System.out.println("adding to buffer = "+_buffer[_bufferPos]); + + ++_bufferPos; + + if (_bufferPos == _buffer.length) + { + processFilledBuffer(_buffer, 0); + } + + increment(); + } + + /* + * increment() can be implemented in this way using 2 arrays or + * by having some temporary variables that are used to set the + * value provided by EIGHT[i] and carry within the loop. + * + * not having done any timing, this seems likely to be faster + * at the slight expense of 32*(sizeof short) bytes + */ + private static final short[] EIGHT = new short[BITCOUNT_ARRAY_SIZE]; + static + { + EIGHT[BITCOUNT_ARRAY_SIZE - 1] = 8; + } + + private void increment() + { + int carry = 0; + for (int i = _bitCount.length - 1; i >= 0; i--) + { + int sum = (_bitCount[i] & 0xff) + EIGHT[i] + carry; + + carry = sum >>> 8; + _bitCount[i] = (short)(sum & 0xff); + } + } + + public void update(byte[] in, int inOff, int len) + { + while (len > 0) + { + update(in[inOff]); + ++inOff; + --len; + } + + } + + private void finish() + { + /* + * this makes a copy of the current bit length. at the expense of an + * object creation of 32 bytes rather than providing a _stopCounting + * boolean which was the alternative I could think of. + */ + byte[] bitLength = copyBitLength(); + + _buffer[_bufferPos++] |= 0x80; + + if (_bufferPos == _buffer.length) + { + processFilledBuffer(_buffer, 0); + } + + /* + * Final block contains + * [ ... data .... ][0][0][0][ length ] + * + * if [ length ] cannot fit. Need to create a new block. + */ + if (_bufferPos > 32) + { + while (_bufferPos != 0) + { + update((byte)0); + } + } + + while (_bufferPos <= 32) + { + update((byte)0); + } + + // copy the length information to the final 32 bytes of the + // 64 byte block.... + System.arraycopy(bitLength, 0, _buffer, 32, bitLength.length); + + processFilledBuffer(_buffer, 0); + } + + private byte[] copyBitLength() + { + byte[] rv = new byte[BITCOUNT_ARRAY_SIZE]; + for (int i = 0; i < rv.length; i++) + { + rv[i] = (byte)(_bitCount[i] & 0xff); + } + return rv; + } + + public int getByteLength() + { + return BYTE_LENGTH; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/encodings/ISO9796d1Encoding.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/encodings/ISO9796d1Encoding.java new file mode 100644 index 0000000..aa9131c --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/encodings/ISO9796d1Encoding.java @@ -0,0 +1,287 @@ +package org.bc.crypto.encodings; + +import java.math.BigInteger; + +import org.bc.crypto.AsymmetricBlockCipher; +import org.bc.crypto.CipherParameters; +import org.bc.crypto.InvalidCipherTextException; +import org.bc.crypto.params.ParametersWithRandom; +import org.bc.crypto.params.RSAKeyParameters; + +/** + * ISO 9796-1 padding. Note in the light of recent results you should + * only use this with RSA (rather than the "simpler" Rabin keys) and you + * should never use it with anything other than a hash (ie. even if the + * message is small don't sign the message, sign it's hash) or some "random" + * value. See your favorite search engine for details. + */ +public class ISO9796d1Encoding + implements AsymmetricBlockCipher +{ + private static final BigInteger SIXTEEN = BigInteger.valueOf(16L); + private static final BigInteger SIX = BigInteger.valueOf(6L); + + private static byte[] shadows = { 0xe, 0x3, 0x5, 0x8, 0x9, 0x4, 0x2, 0xf, + 0x0, 0xd, 0xb, 0x6, 0x7, 0xa, 0xc, 0x1 }; + private static byte[] inverse = { 0x8, 0xf, 0x6, 0x1, 0x5, 0x2, 0xb, 0xc, + 0x3, 0x4, 0xd, 0xa, 0xe, 0x9, 0x0, 0x7 }; + + private AsymmetricBlockCipher engine; + private boolean forEncryption; + private int bitSize; + private int padBits = 0; + private BigInteger modulus; + + public ISO9796d1Encoding( + AsymmetricBlockCipher cipher) + { + this.engine = cipher; + } + + public AsymmetricBlockCipher getUnderlyingCipher() + { + return engine; + } + + public void init( + boolean forEncryption, + CipherParameters param) + { + RSAKeyParameters kParam = null; + + if (param instanceof ParametersWithRandom) + { + ParametersWithRandom rParam = (ParametersWithRandom)param; + + kParam = (RSAKeyParameters)rParam.getParameters(); + } + else + { + kParam = (RSAKeyParameters)param; + } + + engine.init(forEncryption, param); + + modulus = kParam.getModulus(); + bitSize = modulus.bitLength(); + + this.forEncryption = forEncryption; + } + + /** + * return the input block size. The largest message we can process + * is (key_size_in_bits + 3)/16, which in our world comes to + * key_size_in_bytes / 2. + */ + public int getInputBlockSize() + { + int baseBlockSize = engine.getInputBlockSize(); + + if (forEncryption) + { + return (baseBlockSize + 1) / 2; + } + else + { + return baseBlockSize; + } + } + + /** + * return the maximum possible size for the output. + */ + public int getOutputBlockSize() + { + int baseBlockSize = engine.getOutputBlockSize(); + + if (forEncryption) + { + return baseBlockSize; + } + else + { + return (baseBlockSize + 1) / 2; + } + } + + /** + * set the number of bits in the next message to be treated as + * pad bits. + */ + public void setPadBits( + int padBits) + { + if (padBits > 7) + { + throw new IllegalArgumentException("padBits > 7"); + } + + this.padBits = padBits; + } + + /** + * retrieve the number of pad bits in the last decoded message. + */ + public int getPadBits() + { + return padBits; + } + + public byte[] processBlock( + byte[] in, + int inOff, + int inLen) + throws InvalidCipherTextException + { + if (forEncryption) + { + return encodeBlock(in, inOff, inLen); + } + else + { + return decodeBlock(in, inOff, inLen); + } + } + + private byte[] encodeBlock( + byte[] in, + int inOff, + int inLen) + throws InvalidCipherTextException + { + byte[] block = new byte[(bitSize + 7) / 8]; + int r = padBits + 1; + int z = inLen; + int t = (bitSize + 13) / 16; + + for (int i = 0; i < t; i += z) + { + if (i > t - z) + { + System.arraycopy(in, inOff + inLen - (t - i), + block, block.length - t, t - i); + } + else + { + System.arraycopy(in, inOff, block, block.length - (i + z), z); + } + } + + for (int i = block.length - 2 * t; i != block.length; i += 2) + { + byte val = block[block.length - t + i / 2]; + + block[i] = (byte)((shadows[(val & 0xff) >>> 4] << 4) + | shadows[val & 0x0f]); + block[i + 1] = val; + } + + block[block.length - 2 * z] ^= r; + block[block.length - 1] = (byte)((block[block.length - 1] << 4) | 0x06); + + int maxBit = (8 - (bitSize - 1) % 8); + int offSet = 0; + + if (maxBit != 8) + { + block[0] &= 0xff >>> maxBit; + block[0] |= 0x80 >>> maxBit; + } + else + { + block[0] = 0x00; + block[1] |= 0x80; + offSet = 1; + } + + return engine.processBlock(block, offSet, block.length - offSet); + } + + /** + * @exception InvalidCipherTextException if the decrypted block is not a valid ISO 9796 bit string + */ + private byte[] decodeBlock( + byte[] in, + int inOff, + int inLen) + throws InvalidCipherTextException + { + byte[] block = engine.processBlock(in, inOff, inLen); + int r = 1; + int t = (bitSize + 13) / 16; + + BigInteger iS = new BigInteger(1, block); + BigInteger iR; + if (iS.mod(SIXTEEN).equals(SIX)) + { + iR = iS; + } + else if ((modulus.subtract(iS)).mod(SIXTEEN).equals(SIX)) + { + iR = modulus.subtract(iS); + } + else + { + throw new InvalidCipherTextException("resulting integer iS or (modulus - iS) is not congruent to 6 mod 16"); + } + + block = convertOutputDecryptOnly(iR); + + if ((block[block.length - 1] & 0x0f) != 0x6 ) + { + throw new InvalidCipherTextException("invalid forcing byte in block"); + } + + block[block.length - 1] = (byte)(((block[block.length - 1] & 0xff) >>> 4) | ((inverse[(block[block.length - 2] & 0xff) >> 4]) << 4)); + block[0] = (byte)((shadows[(block[1] & 0xff) >>> 4] << 4) + | shadows[block[1] & 0x0f]); + + boolean boundaryFound = false; + int boundary = 0; + + for (int i = block.length - 1; i >= block.length - 2 * t; i -= 2) + { + int val = ((shadows[(block[i] & 0xff) >>> 4] << 4) + | shadows[block[i] & 0x0f]); + + if (((block[i - 1] ^ val) & 0xff) != 0) + { + if (!boundaryFound) + { + boundaryFound = true; + r = (block[i - 1] ^ val) & 0xff; + boundary = i - 1; + } + else + { + throw new InvalidCipherTextException("invalid tsums in block"); + } + } + } + + block[boundary] = 0; + + byte[] nblock = new byte[(block.length - boundary) / 2]; + + for (int i = 0; i < nblock.length; i++) + { + nblock[i] = block[2 * i + boundary + 1]; + } + + padBits = r - 1; + + return nblock; + } + + private static byte[] convertOutputDecryptOnly(BigInteger result) + { + byte[] output = result.toByteArray(); + if (output[0] == 0) // have ended up with an extra zero byte, copy down. + { + byte[] tmp = new byte[output.length - 1]; + System.arraycopy(output, 1, tmp, 0, tmp.length); + return tmp; + } + return output; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/encodings/OAEPEncoding.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/encodings/OAEPEncoding.java new file mode 100644 index 0000000..218a9e4 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/encodings/OAEPEncoding.java @@ -0,0 +1,348 @@ +package org.bc.crypto.encodings; + +import org.bc.crypto.AsymmetricBlockCipher; +import org.bc.crypto.CipherParameters; +import org.bc.crypto.Digest; +import org.bc.crypto.InvalidCipherTextException; +import org.bc.crypto.digests.SHA1Digest; +import org.bc.crypto.params.ParametersWithRandom; + +import java.security.SecureRandom; + +/** + * Optimal Asymmetric Encryption Padding (OAEP) - see PKCS 1 V 2. + */ +public class OAEPEncoding + implements AsymmetricBlockCipher +{ + private byte[] defHash; + private Digest hash; + private Digest mgf1Hash; + + private AsymmetricBlockCipher engine; + private SecureRandom random; + private boolean forEncryption; + + public OAEPEncoding( + AsymmetricBlockCipher cipher) + { + this(cipher, new SHA1Digest(), null); + } + + public OAEPEncoding( + AsymmetricBlockCipher cipher, + Digest hash) + { + this(cipher, hash, null); + } + + public OAEPEncoding( + AsymmetricBlockCipher cipher, + Digest hash, + byte[] encodingParams) + { + this(cipher, hash, hash, encodingParams); + } + + public OAEPEncoding( + AsymmetricBlockCipher cipher, + Digest hash, + Digest mgf1Hash, + byte[] encodingParams) + { + this.engine = cipher; + this.hash = hash; + this.mgf1Hash = mgf1Hash; + this.defHash = new byte[hash.getDigestSize()]; + + if (encodingParams != null) + { + hash.update(encodingParams, 0, encodingParams.length); + } + + hash.doFinal(defHash, 0); + } + + public AsymmetricBlockCipher getUnderlyingCipher() + { + return engine; + } + + public void init( + boolean forEncryption, + CipherParameters param) + { + if (param instanceof ParametersWithRandom) + { + ParametersWithRandom rParam = (ParametersWithRandom)param; + + this.random = rParam.getRandom(); + } + else + { + this.random = new SecureRandom(); + } + + engine.init(forEncryption, param); + + this.forEncryption = forEncryption; + } + + public int getInputBlockSize() + { + int baseBlockSize = engine.getInputBlockSize(); + + if (forEncryption) + { + return baseBlockSize - 1 - 2 * defHash.length; + } + else + { + return baseBlockSize; + } + } + + public int getOutputBlockSize() + { + int baseBlockSize = engine.getOutputBlockSize(); + + if (forEncryption) + { + return baseBlockSize; + } + else + { + return baseBlockSize - 1 - 2 * defHash.length; + } + } + + public byte[] processBlock( + byte[] in, + int inOff, + int inLen) + throws InvalidCipherTextException + { + if (forEncryption) + { + return encodeBlock(in, inOff, inLen); + } + else + { + return decodeBlock(in, inOff, inLen); + } + } + + public byte[] encodeBlock( + byte[] in, + int inOff, + int inLen) + throws InvalidCipherTextException + { + byte[] block = new byte[getInputBlockSize() + 1 + 2 * defHash.length]; + + // + // copy in the message + // + System.arraycopy(in, inOff, block, block.length - inLen, inLen); + + // + // add sentinel + // + block[block.length - inLen - 1] = 0x01; + + // + // as the block is already zeroed - there's no need to add PS (the >= 0 pad of 0) + // + + // + // add the hash of the encoding params. + // + System.arraycopy(defHash, 0, block, defHash.length, defHash.length); + + // + // generate the seed. + // + byte[] seed = new byte[defHash.length]; + + random.nextBytes(seed); + + // + // mask the message block. + // + byte[] mask = maskGeneratorFunction1(seed, 0, seed.length, block.length - defHash.length); + + for (int i = defHash.length; i != block.length; i++) + { + block[i] ^= mask[i - defHash.length]; + } + + // + // add in the seed + // + System.arraycopy(seed, 0, block, 0, defHash.length); + + // + // mask the seed. + // + mask = maskGeneratorFunction1( + block, defHash.length, block.length - defHash.length, defHash.length); + + for (int i = 0; i != defHash.length; i++) + { + block[i] ^= mask[i]; + } + + return engine.processBlock(block, 0, block.length); + } + + /** + * @exception InvalidCipherTextException if the decrypted block turns out to + * be badly formatted. + */ + public byte[] decodeBlock( + byte[] in, + int inOff, + int inLen) + throws InvalidCipherTextException + { + byte[] data = engine.processBlock(in, inOff, inLen); + byte[] block; + + // + // as we may have zeros in our leading bytes for the block we produced + // on encryption, we need to make sure our decrypted block comes back + // the same size. + // + if (data.length < engine.getOutputBlockSize()) + { + block = new byte[engine.getOutputBlockSize()]; + + System.arraycopy(data, 0, block, block.length - data.length, data.length); + } + else + { + block = data; + } + + if (block.length < (2 * defHash.length) + 1) + { + throw new InvalidCipherTextException("data too short"); + } + + // + // unmask the seed. + // + byte[] mask = maskGeneratorFunction1( + block, defHash.length, block.length - defHash.length, defHash.length); + + for (int i = 0; i != defHash.length; i++) + { + block[i] ^= mask[i]; + } + + // + // unmask the message block. + // + mask = maskGeneratorFunction1(block, 0, defHash.length, block.length - defHash.length); + + for (int i = defHash.length; i != block.length; i++) + { + block[i] ^= mask[i - defHash.length]; + } + + // + // check the hash of the encoding params. + // + for (int i = 0; i != defHash.length; i++) + { + if (defHash[i] != block[defHash.length + i]) + { + throw new InvalidCipherTextException("data hash wrong"); + } + } + + // + // find the data block + // + int start; + + for (start = 2 * defHash.length; start != block.length; start++) + { + if (block[start] != 0) + { + break; + } + } + + if (start >= (block.length - 1) || block[start] != 1) + { + throw new InvalidCipherTextException("data start wrong " + start); + } + + start++; + + // + // extract the data block + // + byte[] output = new byte[block.length - start]; + + System.arraycopy(block, start, output, 0, output.length); + + return output; + } + + /** + * int to octet string. + */ + private void ItoOSP( + int i, + byte[] sp) + { + sp[0] = (byte)(i >>> 24); + sp[1] = (byte)(i >>> 16); + sp[2] = (byte)(i >>> 8); + sp[3] = (byte)(i >>> 0); + } + + /** + * mask generator function, as described in PKCS1v2. + */ + private byte[] maskGeneratorFunction1( + byte[] Z, + int zOff, + int zLen, + int length) + { + byte[] mask = new byte[length]; + byte[] hashBuf = new byte[mgf1Hash.getDigestSize()]; + byte[] C = new byte[4]; + int counter = 0; + + hash.reset(); + + do + { + ItoOSP(counter, C); + + mgf1Hash.update(Z, zOff, zLen); + mgf1Hash.update(C, 0, C.length); + mgf1Hash.doFinal(hashBuf, 0); + + System.arraycopy(hashBuf, 0, mask, counter * hashBuf.length, hashBuf.length); + } + while (++counter < (length / hashBuf.length)); + + if ((counter * hashBuf.length) < length) + { + ItoOSP(counter, C); + + mgf1Hash.update(Z, zOff, zLen); + mgf1Hash.update(C, 0, C.length); + mgf1Hash.doFinal(hashBuf, 0); + + System.arraycopy(hashBuf, 0, mask, counter * hashBuf.length, mask.length - (counter * hashBuf.length)); + } + + return mask; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/encodings/PKCS1Encoding.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/encodings/PKCS1Encoding.java new file mode 100644 index 0000000..ce54a15 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/encodings/PKCS1Encoding.java @@ -0,0 +1,257 @@ +package org.bc.crypto.encodings; + +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.security.SecureRandom; + +import org.bc.crypto.AsymmetricBlockCipher; +import org.bc.crypto.CipherParameters; +import org.bc.crypto.InvalidCipherTextException; +import org.bc.crypto.params.AsymmetricKeyParameter; +import org.bc.crypto.params.ParametersWithRandom; + +/** + * this does your basic PKCS 1 v1.5 padding - whether or not you should be using this + * depends on your application - see PKCS1 Version 2 for details. + */ +public class PKCS1Encoding + implements AsymmetricBlockCipher +{ + /** + * some providers fail to include the leading zero in PKCS1 encoded blocks. If you need to + * work with one of these set the system property org.bouncycastle.pkcs1.strict to false. + *
+ * The system property is checked during construction of the encoding object, it is set to + * true by default. + *
+ */ + public static final String STRICT_LENGTH_ENABLED_PROPERTY = "org.bouncycastle.pkcs1.strict"; + + private static final int HEADER_LENGTH = 10; + + private SecureRandom random; + private AsymmetricBlockCipher engine; + private boolean forEncryption; + private boolean forPrivateKey; + private boolean useStrictLength; + + /** + * Basic constructor. + * @param cipher + */ + public PKCS1Encoding( + AsymmetricBlockCipher cipher) + { + this.engine = cipher; + this.useStrictLength = useStrict(); + } + + // + // for J2ME compatibility + // + private boolean useStrict() + { + // required if security manager has been installed. + String strict = (String)AccessController.doPrivileged(new PrivilegedAction() + { + public Object run() + { + return System.getProperty(STRICT_LENGTH_ENABLED_PROPERTY); + } + }); + + return strict == null || strict.equals("true"); + } + + public AsymmetricBlockCipher getUnderlyingCipher() + { + return engine; + } + + public void init( + boolean forEncryption, + CipherParameters param) + { + AsymmetricKeyParameter kParam; + + if (param instanceof ParametersWithRandom) + { + ParametersWithRandom rParam = (ParametersWithRandom)param; + + this.random = rParam.getRandom(); + kParam = (AsymmetricKeyParameter)rParam.getParameters(); + } + else + { + this.random = new SecureRandom(); + kParam = (AsymmetricKeyParameter)param; + } + + engine.init(forEncryption, param); + + this.forPrivateKey = kParam.isPrivate(); + this.forEncryption = forEncryption; + } + + public int getInputBlockSize() + { + int baseBlockSize = engine.getInputBlockSize(); + + if (forEncryption) + { + return baseBlockSize - HEADER_LENGTH; + } + else + { + return baseBlockSize; + } + } + + public int getOutputBlockSize() + { + int baseBlockSize = engine.getOutputBlockSize(); + + if (forEncryption) + { + return baseBlockSize; + } + else + { + return baseBlockSize - HEADER_LENGTH; + } + } + + public byte[] processBlock( + byte[] in, + int inOff, + int inLen) + throws InvalidCipherTextException + { + if (forEncryption) + { + return encodeBlock(in, inOff, inLen); + } + else + { + return decodeBlock(in, inOff, inLen); + } + } + + private byte[] encodeBlock( + byte[] in, + int inOff, + int inLen) + throws InvalidCipherTextException + { + if (inLen > getInputBlockSize()) + { + throw new IllegalArgumentException("input data too large"); + } + + byte[] block = new byte[engine.getInputBlockSize()]; + + if (forPrivateKey) + { + block[0] = 0x01; // type code 1 + + for (int i = 1; i != block.length - inLen - 1; i++) + { + block[i] = (byte)0xFF; + } + } + else + { + random.nextBytes(block); // random fill + + block[0] = 0x02; // type code 2 + + // + // a zero byte marks the end of the padding, so all + // the pad bytes must be non-zero. + // + for (int i = 1; i != block.length - inLen - 1; i++) + { + while (block[i] == 0) + { + block[i] = (byte)random.nextInt(); + } + } + } + + block[block.length - inLen - 1] = 0x00; // mark the end of the padding + System.arraycopy(in, inOff, block, block.length - inLen, inLen); + + return engine.processBlock(block, 0, block.length); + } + + /** + * @exception InvalidCipherTextException if the decrypted block is not in PKCS1 format. + */ + private byte[] decodeBlock( + byte[] in, + int inOff, + int inLen) + throws InvalidCipherTextException + { + byte[] block = engine.processBlock(in, inOff, inLen); + + if (block.length < getOutputBlockSize()) + { + throw new InvalidCipherTextException("block truncated"); + } + + byte type = block[0]; + + if (forPrivateKey) + { + if (type != 2) + { + throw new InvalidCipherTextException("unknown block type"); + } + } + else + { + if (type != 1) + { + throw new InvalidCipherTextException("unknown block type"); + } + } + + if (useStrictLength && block.length != engine.getOutputBlockSize()) + { + throw new InvalidCipherTextException("block incorrect size"); + } + + // + // find and extract the message block. + // + int start; + + for (start = 1; start != block.length; start++) + { + byte pad = block[start]; + + if (pad == 0) + { + break; + } + if (type == 1 && pad != (byte)0xff) + { + throw new InvalidCipherTextException("block padding incorrect"); + } + } + + start++; // data should start at the next byte + + if (start > block.length || start < HEADER_LENGTH) + { + throw new InvalidCipherTextException("no data in block"); + } + + byte[] result = new byte[block.length - start]; + + System.arraycopy(block, start, result, 0, result.length); + + return result; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/AESEngine.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/AESEngine.java new file mode 100644 index 0000000..f9fa7f4 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/AESEngine.java @@ -0,0 +1,545 @@ +package org.bc.crypto.engines; + +import org.bc.crypto.BlockCipher; +import org.bc.crypto.CipherParameters; +import org.bc.crypto.DataLengthException; +import org.bc.crypto.params.KeyParameter; + +/** + * an implementation of the AES (Rijndael), from FIPS-197. + *+ * For further details see: http://csrc.nist.gov/encryption/aes/. + * + * This implementation is based on optimizations from Dr. Brian Gladman's paper and C code at + * http://fp.gladman.plus.com/cryptography_technology/rijndael/ + * + * There are three levels of tradeoff of speed vs memory + * Because java has no preprocessor, they are written as three separate classes from which to choose + * + * The fastest uses 8Kbytes of static tables to precompute round calculations, 4 256 word tables for encryption + * and 4 for decryption. + * + * The middle performance version uses only one 256 word table for each, for a total of 2Kbytes, + * adding 12 rotate operations per round to compute the values contained in the other tables from + * the contents of the first. + * + * The slowest version uses no static tables at all and computes the values in each round. + *
+ * This file contains the middle performance version with 2Kbytes of static tables for round precomputation. + * + */ +public class AESEngine + implements BlockCipher +{ + // The S box + private static final byte[] S = { + (byte)99, (byte)124, (byte)119, (byte)123, (byte)242, (byte)107, (byte)111, (byte)197, + (byte)48, (byte)1, (byte)103, (byte)43, (byte)254, (byte)215, (byte)171, (byte)118, + (byte)202, (byte)130, (byte)201, (byte)125, (byte)250, (byte)89, (byte)71, (byte)240, + (byte)173, (byte)212, (byte)162, (byte)175, (byte)156, (byte)164, (byte)114, (byte)192, + (byte)183, (byte)253, (byte)147, (byte)38, (byte)54, (byte)63, (byte)247, (byte)204, + (byte)52, (byte)165, (byte)229, (byte)241, (byte)113, (byte)216, (byte)49, (byte)21, + (byte)4, (byte)199, (byte)35, (byte)195, (byte)24, (byte)150, (byte)5, (byte)154, + (byte)7, (byte)18, (byte)128, (byte)226, (byte)235, (byte)39, (byte)178, (byte)117, + (byte)9, (byte)131, (byte)44, (byte)26, (byte)27, (byte)110, (byte)90, (byte)160, + (byte)82, (byte)59, (byte)214, (byte)179, (byte)41, (byte)227, (byte)47, (byte)132, + (byte)83, (byte)209, (byte)0, (byte)237, (byte)32, (byte)252, (byte)177, (byte)91, + (byte)106, (byte)203, (byte)190, (byte)57, (byte)74, (byte)76, (byte)88, (byte)207, + (byte)208, (byte)239, (byte)170, (byte)251, (byte)67, (byte)77, (byte)51, (byte)133, + (byte)69, (byte)249, (byte)2, (byte)127, (byte)80, (byte)60, (byte)159, (byte)168, + (byte)81, (byte)163, (byte)64, (byte)143, (byte)146, (byte)157, (byte)56, (byte)245, + (byte)188, (byte)182, (byte)218, (byte)33, (byte)16, (byte)255, (byte)243, (byte)210, + (byte)205, (byte)12, (byte)19, (byte)236, (byte)95, (byte)151, (byte)68, (byte)23, + (byte)196, (byte)167, (byte)126, (byte)61, (byte)100, (byte)93, (byte)25, (byte)115, + (byte)96, (byte)129, (byte)79, (byte)220, (byte)34, (byte)42, (byte)144, (byte)136, + (byte)70, (byte)238, (byte)184, (byte)20, (byte)222, (byte)94, (byte)11, (byte)219, + (byte)224, (byte)50, (byte)58, (byte)10, (byte)73, (byte)6, (byte)36, (byte)92, + (byte)194, (byte)211, (byte)172, (byte)98, (byte)145, (byte)149, (byte)228, (byte)121, + (byte)231, (byte)200, (byte)55, (byte)109, (byte)141, (byte)213, (byte)78, (byte)169, + (byte)108, (byte)86, (byte)244, (byte)234, (byte)101, (byte)122, (byte)174, (byte)8, + (byte)186, (byte)120, (byte)37, (byte)46, (byte)28, (byte)166, (byte)180, (byte)198, + (byte)232, (byte)221, (byte)116, (byte)31, (byte)75, (byte)189, (byte)139, (byte)138, + (byte)112, (byte)62, (byte)181, (byte)102, (byte)72, (byte)3, (byte)246, (byte)14, + (byte)97, (byte)53, (byte)87, (byte)185, (byte)134, (byte)193, (byte)29, (byte)158, + (byte)225, (byte)248, (byte)152, (byte)17, (byte)105, (byte)217, (byte)142, (byte)148, + (byte)155, (byte)30, (byte)135, (byte)233, (byte)206, (byte)85, (byte)40, (byte)223, + (byte)140, (byte)161, (byte)137, (byte)13, (byte)191, (byte)230, (byte)66, (byte)104, + (byte)65, (byte)153, (byte)45, (byte)15, (byte)176, (byte)84, (byte)187, (byte)22, + }; + + // The inverse S-box + private static final byte[] Si = { + (byte)82, (byte)9, (byte)106, (byte)213, (byte)48, (byte)54, (byte)165, (byte)56, + (byte)191, (byte)64, (byte)163, (byte)158, (byte)129, (byte)243, (byte)215, (byte)251, + (byte)124, (byte)227, (byte)57, (byte)130, (byte)155, (byte)47, (byte)255, (byte)135, + (byte)52, (byte)142, (byte)67, (byte)68, (byte)196, (byte)222, (byte)233, (byte)203, + (byte)84, (byte)123, (byte)148, (byte)50, (byte)166, (byte)194, (byte)35, (byte)61, + (byte)238, (byte)76, (byte)149, (byte)11, (byte)66, (byte)250, (byte)195, (byte)78, + (byte)8, (byte)46, (byte)161, (byte)102, (byte)40, (byte)217, (byte)36, (byte)178, + (byte)118, (byte)91, (byte)162, (byte)73, (byte)109, (byte)139, (byte)209, (byte)37, + (byte)114, (byte)248, (byte)246, (byte)100, (byte)134, (byte)104, (byte)152, (byte)22, + (byte)212, (byte)164, (byte)92, (byte)204, (byte)93, (byte)101, (byte)182, (byte)146, + (byte)108, (byte)112, (byte)72, (byte)80, (byte)253, (byte)237, (byte)185, (byte)218, + (byte)94, (byte)21, (byte)70, (byte)87, (byte)167, (byte)141, (byte)157, (byte)132, + (byte)144, (byte)216, (byte)171, (byte)0, (byte)140, (byte)188, (byte)211, (byte)10, + (byte)247, (byte)228, (byte)88, (byte)5, (byte)184, (byte)179, (byte)69, (byte)6, + (byte)208, (byte)44, (byte)30, (byte)143, (byte)202, (byte)63, (byte)15, (byte)2, + (byte)193, (byte)175, (byte)189, (byte)3, (byte)1, (byte)19, (byte)138, (byte)107, + (byte)58, (byte)145, (byte)17, (byte)65, (byte)79, (byte)103, (byte)220, (byte)234, + (byte)151, (byte)242, (byte)207, (byte)206, (byte)240, (byte)180, (byte)230, (byte)115, + (byte)150, (byte)172, (byte)116, (byte)34, (byte)231, (byte)173, (byte)53, (byte)133, + (byte)226, (byte)249, (byte)55, (byte)232, (byte)28, (byte)117, (byte)223, (byte)110, + (byte)71, (byte)241, (byte)26, (byte)113, (byte)29, (byte)41, (byte)197, (byte)137, + (byte)111, (byte)183, (byte)98, (byte)14, (byte)170, (byte)24, (byte)190, (byte)27, + (byte)252, (byte)86, (byte)62, (byte)75, (byte)198, (byte)210, (byte)121, (byte)32, + (byte)154, (byte)219, (byte)192, (byte)254, (byte)120, (byte)205, (byte)90, (byte)244, + (byte)31, (byte)221, (byte)168, (byte)51, (byte)136, (byte)7, (byte)199, (byte)49, + (byte)177, (byte)18, (byte)16, (byte)89, (byte)39, (byte)128, (byte)236, (byte)95, + (byte)96, (byte)81, (byte)127, (byte)169, (byte)25, (byte)181, (byte)74, (byte)13, + (byte)45, (byte)229, (byte)122, (byte)159, (byte)147, (byte)201, (byte)156, (byte)239, + (byte)160, (byte)224, (byte)59, (byte)77, (byte)174, (byte)42, (byte)245, (byte)176, + (byte)200, (byte)235, (byte)187, (byte)60, (byte)131, (byte)83, (byte)153, (byte)97, + (byte)23, (byte)43, (byte)4, (byte)126, (byte)186, (byte)119, (byte)214, (byte)38, + (byte)225, (byte)105, (byte)20, (byte)99, (byte)85, (byte)33, (byte)12, (byte)125, + }; + + // vector used in calculating key schedule (powers of x in GF(256)) + private static final int[] rcon = { + 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, + 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91 }; + + // precomputation tables of calculations for rounds + private static final int[] T0 = + { + 0xa56363c6, 0x847c7cf8, 0x997777ee, 0x8d7b7bf6, 0x0df2f2ff, + 0xbd6b6bd6, 0xb16f6fde, 0x54c5c591, 0x50303060, 0x03010102, + 0xa96767ce, 0x7d2b2b56, 0x19fefee7, 0x62d7d7b5, 0xe6abab4d, + 0x9a7676ec, 0x45caca8f, 0x9d82821f, 0x40c9c989, 0x877d7dfa, + 0x15fafaef, 0xeb5959b2, 0xc947478e, 0x0bf0f0fb, 0xecadad41, + 0x67d4d4b3, 0xfda2a25f, 0xeaafaf45, 0xbf9c9c23, 0xf7a4a453, + 0x967272e4, 0x5bc0c09b, 0xc2b7b775, 0x1cfdfde1, 0xae93933d, + 0x6a26264c, 0x5a36366c, 0x413f3f7e, 0x02f7f7f5, 0x4fcccc83, + 0x5c343468, 0xf4a5a551, 0x34e5e5d1, 0x08f1f1f9, 0x937171e2, + 0x73d8d8ab, 0x53313162, 0x3f15152a, 0x0c040408, 0x52c7c795, + 0x65232346, 0x5ec3c39d, 0x28181830, 0xa1969637, 0x0f05050a, + 0xb59a9a2f, 0x0907070e, 0x36121224, 0x9b80801b, 0x3de2e2df, + 0x26ebebcd, 0x6927274e, 0xcdb2b27f, 0x9f7575ea, 0x1b090912, + 0x9e83831d, 0x742c2c58, 0x2e1a1a34, 0x2d1b1b36, 0xb26e6edc, + 0xee5a5ab4, 0xfba0a05b, 0xf65252a4, 0x4d3b3b76, 0x61d6d6b7, + 0xceb3b37d, 0x7b292952, 0x3ee3e3dd, 0x712f2f5e, 0x97848413, + 0xf55353a6, 0x68d1d1b9, 0x00000000, 0x2cededc1, 0x60202040, + 0x1ffcfce3, 0xc8b1b179, 0xed5b5bb6, 0xbe6a6ad4, 0x46cbcb8d, + 0xd9bebe67, 0x4b393972, 0xde4a4a94, 0xd44c4c98, 0xe85858b0, + 0x4acfcf85, 0x6bd0d0bb, 0x2aefefc5, 0xe5aaaa4f, 0x16fbfbed, + 0xc5434386, 0xd74d4d9a, 0x55333366, 0x94858511, 0xcf45458a, + 0x10f9f9e9, 0x06020204, 0x817f7ffe, 0xf05050a0, 0x443c3c78, + 0xba9f9f25, 0xe3a8a84b, 0xf35151a2, 0xfea3a35d, 0xc0404080, + 0x8a8f8f05, 0xad92923f, 0xbc9d9d21, 0x48383870, 0x04f5f5f1, + 0xdfbcbc63, 0xc1b6b677, 0x75dadaaf, 0x63212142, 0x30101020, + 0x1affffe5, 0x0ef3f3fd, 0x6dd2d2bf, 0x4ccdcd81, 0x140c0c18, + 0x35131326, 0x2fececc3, 0xe15f5fbe, 0xa2979735, 0xcc444488, + 0x3917172e, 0x57c4c493, 0xf2a7a755, 0x827e7efc, 0x473d3d7a, + 0xac6464c8, 0xe75d5dba, 0x2b191932, 0x957373e6, 0xa06060c0, + 0x98818119, 0xd14f4f9e, 0x7fdcdca3, 0x66222244, 0x7e2a2a54, + 0xab90903b, 0x8388880b, 0xca46468c, 0x29eeeec7, 0xd3b8b86b, + 0x3c141428, 0x79dedea7, 0xe25e5ebc, 0x1d0b0b16, 0x76dbdbad, + 0x3be0e0db, 0x56323264, 0x4e3a3a74, 0x1e0a0a14, 0xdb494992, + 0x0a06060c, 0x6c242448, 0xe45c5cb8, 0x5dc2c29f, 0x6ed3d3bd, + 0xefacac43, 0xa66262c4, 0xa8919139, 0xa4959531, 0x37e4e4d3, + 0x8b7979f2, 0x32e7e7d5, 0x43c8c88b, 0x5937376e, 0xb76d6dda, + 0x8c8d8d01, 0x64d5d5b1, 0xd24e4e9c, 0xe0a9a949, 0xb46c6cd8, + 0xfa5656ac, 0x07f4f4f3, 0x25eaeacf, 0xaf6565ca, 0x8e7a7af4, + 0xe9aeae47, 0x18080810, 0xd5baba6f, 0x887878f0, 0x6f25254a, + 0x722e2e5c, 0x241c1c38, 0xf1a6a657, 0xc7b4b473, 0x51c6c697, + 0x23e8e8cb, 0x7cdddda1, 0x9c7474e8, 0x211f1f3e, 0xdd4b4b96, + 0xdcbdbd61, 0x868b8b0d, 0x858a8a0f, 0x907070e0, 0x423e3e7c, + 0xc4b5b571, 0xaa6666cc, 0xd8484890, 0x05030306, 0x01f6f6f7, + 0x120e0e1c, 0xa36161c2, 0x5f35356a, 0xf95757ae, 0xd0b9b969, + 0x91868617, 0x58c1c199, 0x271d1d3a, 0xb99e9e27, 0x38e1e1d9, + 0x13f8f8eb, 0xb398982b, 0x33111122, 0xbb6969d2, 0x70d9d9a9, + 0x898e8e07, 0xa7949433, 0xb69b9b2d, 0x221e1e3c, 0x92878715, + 0x20e9e9c9, 0x49cece87, 0xff5555aa, 0x78282850, 0x7adfdfa5, + 0x8f8c8c03, 0xf8a1a159, 0x80898909, 0x170d0d1a, 0xdabfbf65, + 0x31e6e6d7, 0xc6424284, 0xb86868d0, 0xc3414182, 0xb0999929, + 0x772d2d5a, 0x110f0f1e, 0xcbb0b07b, 0xfc5454a8, 0xd6bbbb6d, + 0x3a16162c}; + +private static final int[] Tinv0 = + { + 0x50a7f451, 0x5365417e, 0xc3a4171a, 0x965e273a, 0xcb6bab3b, + 0xf1459d1f, 0xab58faac, 0x9303e34b, 0x55fa3020, 0xf66d76ad, + 0x9176cc88, 0x254c02f5, 0xfcd7e54f, 0xd7cb2ac5, 0x80443526, + 0x8fa362b5, 0x495ab1de, 0x671bba25, 0x980eea45, 0xe1c0fe5d, + 0x02752fc3, 0x12f04c81, 0xa397468d, 0xc6f9d36b, 0xe75f8f03, + 0x959c9215, 0xeb7a6dbf, 0xda595295, 0x2d83bed4, 0xd3217458, + 0x2969e049, 0x44c8c98e, 0x6a89c275, 0x78798ef4, 0x6b3e5899, + 0xdd71b927, 0xb64fe1be, 0x17ad88f0, 0x66ac20c9, 0xb43ace7d, + 0x184adf63, 0x82311ae5, 0x60335197, 0x457f5362, 0xe07764b1, + 0x84ae6bbb, 0x1ca081fe, 0x942b08f9, 0x58684870, 0x19fd458f, + 0x876cde94, 0xb7f87b52, 0x23d373ab, 0xe2024b72, 0x578f1fe3, + 0x2aab5566, 0x0728ebb2, 0x03c2b52f, 0x9a7bc586, 0xa50837d3, + 0xf2872830, 0xb2a5bf23, 0xba6a0302, 0x5c8216ed, 0x2b1ccf8a, + 0x92b479a7, 0xf0f207f3, 0xa1e2694e, 0xcdf4da65, 0xd5be0506, + 0x1f6234d1, 0x8afea6c4, 0x9d532e34, 0xa055f3a2, 0x32e18a05, + 0x75ebf6a4, 0x39ec830b, 0xaaef6040, 0x069f715e, 0x51106ebd, + 0xf98a213e, 0x3d06dd96, 0xae053edd, 0x46bde64d, 0xb58d5491, + 0x055dc471, 0x6fd40604, 0xff155060, 0x24fb9819, 0x97e9bdd6, + 0xcc434089, 0x779ed967, 0xbd42e8b0, 0x888b8907, 0x385b19e7, + 0xdbeec879, 0x470a7ca1, 0xe90f427c, 0xc91e84f8, 0x00000000, + 0x83868009, 0x48ed2b32, 0xac70111e, 0x4e725a6c, 0xfbff0efd, + 0x5638850f, 0x1ed5ae3d, 0x27392d36, 0x64d90f0a, 0x21a65c68, + 0xd1545b9b, 0x3a2e3624, 0xb1670a0c, 0x0fe75793, 0xd296eeb4, + 0x9e919b1b, 0x4fc5c080, 0xa220dc61, 0x694b775a, 0x161a121c, + 0x0aba93e2, 0xe52aa0c0, 0x43e0223c, 0x1d171b12, 0x0b0d090e, + 0xadc78bf2, 0xb9a8b62d, 0xc8a91e14, 0x8519f157, 0x4c0775af, + 0xbbdd99ee, 0xfd607fa3, 0x9f2601f7, 0xbcf5725c, 0xc53b6644, + 0x347efb5b, 0x7629438b, 0xdcc623cb, 0x68fcedb6, 0x63f1e4b8, + 0xcadc31d7, 0x10856342, 0x40229713, 0x2011c684, 0x7d244a85, + 0xf83dbbd2, 0x1132f9ae, 0x6da129c7, 0x4b2f9e1d, 0xf330b2dc, + 0xec52860d, 0xd0e3c177, 0x6c16b32b, 0x99b970a9, 0xfa489411, + 0x2264e947, 0xc48cfca8, 0x1a3ff0a0, 0xd82c7d56, 0xef903322, + 0xc74e4987, 0xc1d138d9, 0xfea2ca8c, 0x360bd498, 0xcf81f5a6, + 0x28de7aa5, 0x268eb7da, 0xa4bfad3f, 0xe49d3a2c, 0x0d927850, + 0x9bcc5f6a, 0x62467e54, 0xc2138df6, 0xe8b8d890, 0x5ef7392e, + 0xf5afc382, 0xbe805d9f, 0x7c93d069, 0xa92dd56f, 0xb31225cf, + 0x3b99acc8, 0xa77d1810, 0x6e639ce8, 0x7bbb3bdb, 0x097826cd, + 0xf418596e, 0x01b79aec, 0xa89a4f83, 0x656e95e6, 0x7ee6ffaa, + 0x08cfbc21, 0xe6e815ef, 0xd99be7ba, 0xce366f4a, 0xd4099fea, + 0xd67cb029, 0xafb2a431, 0x31233f2a, 0x3094a5c6, 0xc066a235, + 0x37bc4e74, 0xa6ca82fc, 0xb0d090e0, 0x15d8a733, 0x4a9804f1, + 0xf7daec41, 0x0e50cd7f, 0x2ff69117, 0x8dd64d76, 0x4db0ef43, + 0x544daacc, 0xdf0496e4, 0xe3b5d19e, 0x1b886a4c, 0xb81f2cc1, + 0x7f516546, 0x04ea5e9d, 0x5d358c01, 0x737487fa, 0x2e410bfb, + 0x5a1d67b3, 0x52d2db92, 0x335610e9, 0x1347d66d, 0x8c61d79a, + 0x7a0ca137, 0x8e14f859, 0x893c13eb, 0xee27a9ce, 0x35c961b7, + 0xede51ce1, 0x3cb1477a, 0x59dfd29c, 0x3f73f255, 0x79ce1418, + 0xbf37c773, 0xeacdf753, 0x5baafd5f, 0x146f3ddf, 0x86db4478, + 0x81f3afca, 0x3ec468b9, 0x2c342438, 0x5f40a3c2, 0x72c31d16, + 0x0c25e2bc, 0x8b493c28, 0x41950dff, 0x7101a839, 0xdeb30c08, + 0x9ce4b4d8, 0x90c15664, 0x6184cb7b, 0x70b632d5, 0x745c6c48, + 0x4257b8d0}; + + private static int shift(int r, int shift) + { + return (r >>> shift) | (r << -shift); + } + + /* multiply four bytes in GF(2^8) by 'x' {02} in parallel */ + + private static final int m1 = 0x80808080; + private static final int m2 = 0x7f7f7f7f; + private static final int m3 = 0x0000001b; + + private static int FFmulX(int x) + { + return (((x & m2) << 1) ^ (((x & m1) >>> 7) * m3)); + } + + /* + The following defines provide alternative definitions of FFmulX that might + give improved performance if a fast 32-bit multiply is not available. + + private int FFmulX(int x) { int u = x & m1; u |= (u >> 1); return ((x & m2) << 1) ^ ((u >>> 3) | (u >>> 6)); } + private static final int m4 = 0x1b1b1b1b; + private int FFmulX(int x) { int u = x & m1; return ((x & m2) << 1) ^ ((u - (u >>> 7)) & m4); } + + */ + + private static int inv_mcol(int x) + { + int f2 = FFmulX(x); + int f4 = FFmulX(f2); + int f8 = FFmulX(f4); + int f9 = x ^ f8; + + return f2 ^ f4 ^ f8 ^ shift(f2 ^ f9, 8) ^ shift(f4 ^ f9, 16) ^ shift(f9, 24); + } + + private static int subWord(int x) + { + return (S[x&255]&255 | ((S[(x>>8)&255]&255)<<8) | ((S[(x>>16)&255]&255)<<16) | S[(x>>24)&255]<<24); + } + + /** + * Calculate the necessary round keys + * The number of calculations depends on key size and block size + * AES specified a fixed block size of 128 bits and key sizes 128/192/256 bits + * This code is written assuming those are the only possible values + */ + private int[][] generateWorkingKey( + byte[] key, + boolean forEncryption) + { + int KC = key.length / 4; // key length in words + int t; + + if (((KC != 4) && (KC != 6) && (KC != 8)) || ((KC * 4) != key.length)) + { + throw new IllegalArgumentException("Key length not 128/192/256 bits."); + } + + ROUNDS = KC + 6; // This is not always true for the generalized Rijndael that allows larger block sizes + int[][] W = new int[ROUNDS+1][4]; // 4 words in a block + + // + // copy the key into the round key array + // + + t = 0; + int i = 0; + while (i < key.length) + { + W[t >> 2][t & 3] = (key[i]&0xff) | ((key[i+1]&0xff) << 8) | ((key[i+2]&0xff) << 16) | (key[i+3] << 24); + i+=4; + t++; + } + + // + // while not enough round key material calculated + // calculate new values + // + int k = (ROUNDS + 1) << 2; + for (i = KC; (i < k); i++) + { + int temp = W[(i-1)>>2][(i-1)&3]; + if ((i % KC) == 0) + { + temp = subWord(shift(temp, 8)) ^ rcon[(i / KC)-1]; + } + else if ((KC > 6) && ((i % KC) == 4)) + { + temp = subWord(temp); + } + + W[i>>2][i&3] = W[(i - KC)>>2][(i-KC)&3] ^ temp; + } + + if (!forEncryption) + { + for (int j = 1; j < ROUNDS; j++) + { + for (i = 0; i < 4; i++) + { + W[j][i] = inv_mcol(W[j][i]); + } + } + } + + return W; + } + + private int ROUNDS; + private int[][] WorkingKey = null; + private int C0, C1, C2, C3; + private boolean forEncryption; + + private static final int BLOCK_SIZE = 16; + + /** + * default constructor - 128 bit block size. + */ + public AESEngine() + { + } + + /** + * initialise an AES cipher. + * + * @param forEncryption whether or not we are for encryption. + * @param params the parameters required to set up the cipher. + * @exception IllegalArgumentException if the params argument is + * inappropriate. + */ + public void init( + boolean forEncryption, + CipherParameters params) + { + if (params instanceof KeyParameter) + { + WorkingKey = generateWorkingKey(((KeyParameter)params).getKey(), forEncryption); + this.forEncryption = forEncryption; + return; + } + + throw new IllegalArgumentException("invalid parameter passed to AES init - " + params.getClass().getName()); + } + + public String getAlgorithmName() + { + return "AES"; + } + + public int getBlockSize() + { + return BLOCK_SIZE; + } + + public int processBlock( + byte[] in, + int inOff, + byte[] out, + int outOff) + { + if (WorkingKey == null) + { + throw new IllegalStateException("AES engine not initialised"); + } + + if ((inOff + (32 / 2)) > in.length) + { + throw new DataLengthException("input buffer too short"); + } + + if ((outOff + (32 / 2)) > out.length) + { + throw new DataLengthException("output buffer too short"); + } + + if (forEncryption) + { + unpackBlock(in, inOff); + encryptBlock(WorkingKey); + packBlock(out, outOff); + } + else + { + unpackBlock(in, inOff); + decryptBlock(WorkingKey); + packBlock(out, outOff); + } + + return BLOCK_SIZE; + } + + public void reset() + { + } + + private void unpackBlock( + byte[] bytes, + int off) + { + int index = off; + + C0 = (bytes[index++] & 0xff); + C0 |= (bytes[index++] & 0xff) << 8; + C0 |= (bytes[index++] & 0xff) << 16; + C0 |= bytes[index++] << 24; + + C1 = (bytes[index++] & 0xff); + C1 |= (bytes[index++] & 0xff) << 8; + C1 |= (bytes[index++] & 0xff) << 16; + C1 |= bytes[index++] << 24; + + C2 = (bytes[index++] & 0xff); + C2 |= (bytes[index++] & 0xff) << 8; + C2 |= (bytes[index++] & 0xff) << 16; + C2 |= bytes[index++] << 24; + + C3 = (bytes[index++] & 0xff); + C3 |= (bytes[index++] & 0xff) << 8; + C3 |= (bytes[index++] & 0xff) << 16; + C3 |= bytes[index++] << 24; + } + + private void packBlock( + byte[] bytes, + int off) + { + int index = off; + + bytes[index++] = (byte)C0; + bytes[index++] = (byte)(C0 >> 8); + bytes[index++] = (byte)(C0 >> 16); + bytes[index++] = (byte)(C0 >> 24); + + bytes[index++] = (byte)C1; + bytes[index++] = (byte)(C1 >> 8); + bytes[index++] = (byte)(C1 >> 16); + bytes[index++] = (byte)(C1 >> 24); + + bytes[index++] = (byte)C2; + bytes[index++] = (byte)(C2 >> 8); + bytes[index++] = (byte)(C2 >> 16); + bytes[index++] = (byte)(C2 >> 24); + + bytes[index++] = (byte)C3; + bytes[index++] = (byte)(C3 >> 8); + bytes[index++] = (byte)(C3 >> 16); + bytes[index++] = (byte)(C3 >> 24); + } + + + private void encryptBlock(int[][] KW) + { + int r, r0, r1, r2, r3; + + C0 ^= KW[0][0]; + C1 ^= KW[0][1]; + C2 ^= KW[0][2]; + C3 ^= KW[0][3]; + + r = 1; + + while (r < ROUNDS - 1) + { + r0 = T0[C0&255] ^ shift(T0[(C1>>8)&255], 24) ^ shift(T0[(C2>>16)&255],16) ^ shift(T0[(C3>>24)&255],8) ^ KW[r][0]; + r1 = T0[C1&255] ^ shift(T0[(C2>>8)&255], 24) ^ shift(T0[(C3>>16)&255], 16) ^ shift(T0[(C0>>24)&255], 8) ^ KW[r][1]; + r2 = T0[C2&255] ^ shift(T0[(C3>>8)&255], 24) ^ shift(T0[(C0>>16)&255], 16) ^ shift(T0[(C1>>24)&255], 8) ^ KW[r][2]; + r3 = T0[C3&255] ^ shift(T0[(C0>>8)&255], 24) ^ shift(T0[(C1>>16)&255], 16) ^ shift(T0[(C2>>24)&255], 8) ^ KW[r++][3]; + C0 = T0[r0&255] ^ shift(T0[(r1>>8)&255], 24) ^ shift(T0[(r2>>16)&255], 16) ^ shift(T0[(r3>>24)&255], 8) ^ KW[r][0]; + C1 = T0[r1&255] ^ shift(T0[(r2>>8)&255], 24) ^ shift(T0[(r3>>16)&255], 16) ^ shift(T0[(r0>>24)&255], 8) ^ KW[r][1]; + C2 = T0[r2&255] ^ shift(T0[(r3>>8)&255], 24) ^ shift(T0[(r0>>16)&255], 16) ^ shift(T0[(r1>>24)&255], 8) ^ KW[r][2]; + C3 = T0[r3&255] ^ shift(T0[(r0>>8)&255], 24) ^ shift(T0[(r1>>16)&255], 16) ^ shift(T0[(r2>>24)&255], 8) ^ KW[r++][3]; + } + + r0 = T0[C0&255] ^ shift(T0[(C1>>8)&255], 24) ^ shift(T0[(C2>>16)&255], 16) ^ shift(T0[(C3>>24)&255], 8) ^ KW[r][0]; + r1 = T0[C1&255] ^ shift(T0[(C2>>8)&255], 24) ^ shift(T0[(C3>>16)&255], 16) ^ shift(T0[(C0>>24)&255], 8) ^ KW[r][1]; + r2 = T0[C2&255] ^ shift(T0[(C3>>8)&255], 24) ^ shift(T0[(C0>>16)&255], 16) ^ shift(T0[(C1>>24)&255], 8) ^ KW[r][2]; + r3 = T0[C3&255] ^ shift(T0[(C0>>8)&255], 24) ^ shift(T0[(C1>>16)&255], 16) ^ shift(T0[(C2>>24)&255], 8) ^ KW[r++][3]; + + // the final round's table is a simple function of S so we don't use a whole other four tables for it + + C0 = (S[r0&255]&255) ^ ((S[(r1>>8)&255]&255)<<8) ^ ((S[(r2>>16)&255]&255)<<16) ^ (S[(r3>>24)&255]<<24) ^ KW[r][0]; + C1 = (S[r1&255]&255) ^ ((S[(r2>>8)&255]&255)<<8) ^ ((S[(r3>>16)&255]&255)<<16) ^ (S[(r0>>24)&255]<<24) ^ KW[r][1]; + C2 = (S[r2&255]&255) ^ ((S[(r3>>8)&255]&255)<<8) ^ ((S[(r0>>16)&255]&255)<<16) ^ (S[(r1>>24)&255]<<24) ^ KW[r][2]; + C3 = (S[r3&255]&255) ^ ((S[(r0>>8)&255]&255)<<8) ^ ((S[(r1>>16)&255]&255)<<16) ^ (S[(r2>>24)&255]<<24) ^ KW[r][3]; + + } + + private void decryptBlock(int[][] KW) + { + int r, r0, r1, r2, r3; + + C0 ^= KW[ROUNDS][0]; + C1 ^= KW[ROUNDS][1]; + C2 ^= KW[ROUNDS][2]; + C3 ^= KW[ROUNDS][3]; + + r = ROUNDS-1; + + while (r>1) + { + r0 = Tinv0[C0&255] ^ shift(Tinv0[(C3>>8)&255], 24) ^ shift(Tinv0[(C2>>16)&255], 16) ^ shift(Tinv0[(C1>>24)&255], 8) ^ KW[r][0]; + r1 = Tinv0[C1&255] ^ shift(Tinv0[(C0>>8)&255], 24) ^ shift(Tinv0[(C3>>16)&255], 16) ^ shift(Tinv0[(C2>>24)&255], 8) ^ KW[r][1]; + r2 = Tinv0[C2&255] ^ shift(Tinv0[(C1>>8)&255], 24) ^ shift(Tinv0[(C0>>16)&255], 16) ^ shift(Tinv0[(C3>>24)&255], 8) ^ KW[r][2]; + r3 = Tinv0[C3&255] ^ shift(Tinv0[(C2>>8)&255], 24) ^ shift(Tinv0[(C1>>16)&255], 16) ^ shift(Tinv0[(C0>>24)&255], 8) ^ KW[r--][3]; + C0 = Tinv0[r0&255] ^ shift(Tinv0[(r3>>8)&255], 24) ^ shift(Tinv0[(r2>>16)&255], 16) ^ shift(Tinv0[(r1>>24)&255], 8) ^ KW[r][0]; + C1 = Tinv0[r1&255] ^ shift(Tinv0[(r0>>8)&255], 24) ^ shift(Tinv0[(r3>>16)&255], 16) ^ shift(Tinv0[(r2>>24)&255], 8) ^ KW[r][1]; + C2 = Tinv0[r2&255] ^ shift(Tinv0[(r1>>8)&255], 24) ^ shift(Tinv0[(r0>>16)&255], 16) ^ shift(Tinv0[(r3>>24)&255], 8) ^ KW[r][2]; + C3 = Tinv0[r3&255] ^ shift(Tinv0[(r2>>8)&255], 24) ^ shift(Tinv0[(r1>>16)&255], 16) ^ shift(Tinv0[(r0>>24)&255], 8) ^ KW[r--][3]; + } + + r0 = Tinv0[C0&255] ^ shift(Tinv0[(C3>>8)&255], 24) ^ shift(Tinv0[(C2>>16)&255], 16) ^ shift(Tinv0[(C1>>24)&255], 8) ^ KW[r][0]; + r1 = Tinv0[C1&255] ^ shift(Tinv0[(C0>>8)&255], 24) ^ shift(Tinv0[(C3>>16)&255], 16) ^ shift(Tinv0[(C2>>24)&255], 8) ^ KW[r][1]; + r2 = Tinv0[C2&255] ^ shift(Tinv0[(C1>>8)&255], 24) ^ shift(Tinv0[(C0>>16)&255], 16) ^ shift(Tinv0[(C3>>24)&255], 8) ^ KW[r][2]; + r3 = Tinv0[C3&255] ^ shift(Tinv0[(C2>>8)&255], 24) ^ shift(Tinv0[(C1>>16)&255], 16) ^ shift(Tinv0[(C0>>24)&255], 8) ^ KW[r][3]; + + // the final round's table is a simple function of Si so we don't use a whole other four tables for it + + C0 = (Si[r0&255]&255) ^ ((Si[(r3>>8)&255]&255)<<8) ^ ((Si[(r2>>16)&255]&255)<<16) ^ (Si[(r1>>24)&255]<<24) ^ KW[0][0]; + C1 = (Si[r1&255]&255) ^ ((Si[(r0>>8)&255]&255)<<8) ^ ((Si[(r3>>16)&255]&255)<<16) ^ (Si[(r2>>24)&255]<<24) ^ KW[0][1]; + C2 = (Si[r2&255]&255) ^ ((Si[(r1>>8)&255]&255)<<8) ^ ((Si[(r0>>16)&255]&255)<<16) ^ (Si[(r3>>24)&255]<<24) ^ KW[0][2]; + C3 = (Si[r3&255]&255) ^ ((Si[(r2>>8)&255]&255)<<8) ^ ((Si[(r1>>16)&255]&255)<<16) ^ (Si[(r0>>24)&255]<<24) ^ KW[0][3]; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/AESFastEngine.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/AESFastEngine.java new file mode 100644 index 0000000..d2547de --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/AESFastEngine.java @@ -0,0 +1,874 @@ +package org.bc.crypto.engines; + +import org.bc.crypto.BlockCipher; +import org.bc.crypto.CipherParameters; +import org.bc.crypto.DataLengthException; +import org.bc.crypto.params.KeyParameter; + +/** + * an implementation of the AES (Rijndael), from FIPS-197. + *
+ * For further details see: http://csrc.nist.gov/encryption/aes/. + * + * This implementation is based on optimizations from Dr. Brian Gladman's paper and C code at + * http://fp.gladman.plus.com/cryptography_technology/rijndael/ + * + * There are three levels of tradeoff of speed vs memory + * Because java has no preprocessor, they are written as three separate classes from which to choose + * + * The fastest uses 8Kbytes of static tables to precompute round calculations, 4 256 word tables for encryption + * and 4 for decryption. + * + * The middle performance version uses only one 256 word table for each, for a total of 2Kbytes, + * adding 12 rotate operations per round to compute the values contained in the other tables from + * the contents of the first + * + * The slowest version uses no static tables at all and computes the values in each round + *
+ * This file contains the fast version with 8Kbytes of static tables for round precomputation + * + */ +public class AESFastEngine + implements BlockCipher +{ + // The S box + private static final byte[] S = { + (byte)99, (byte)124, (byte)119, (byte)123, (byte)242, (byte)107, (byte)111, (byte)197, + (byte)48, (byte)1, (byte)103, (byte)43, (byte)254, (byte)215, (byte)171, (byte)118, + (byte)202, (byte)130, (byte)201, (byte)125, (byte)250, (byte)89, (byte)71, (byte)240, + (byte)173, (byte)212, (byte)162, (byte)175, (byte)156, (byte)164, (byte)114, (byte)192, + (byte)183, (byte)253, (byte)147, (byte)38, (byte)54, (byte)63, (byte)247, (byte)204, + (byte)52, (byte)165, (byte)229, (byte)241, (byte)113, (byte)216, (byte)49, (byte)21, + (byte)4, (byte)199, (byte)35, (byte)195, (byte)24, (byte)150, (byte)5, (byte)154, + (byte)7, (byte)18, (byte)128, (byte)226, (byte)235, (byte)39, (byte)178, (byte)117, + (byte)9, (byte)131, (byte)44, (byte)26, (byte)27, (byte)110, (byte)90, (byte)160, + (byte)82, (byte)59, (byte)214, (byte)179, (byte)41, (byte)227, (byte)47, (byte)132, + (byte)83, (byte)209, (byte)0, (byte)237, (byte)32, (byte)252, (byte)177, (byte)91, + (byte)106, (byte)203, (byte)190, (byte)57, (byte)74, (byte)76, (byte)88, (byte)207, + (byte)208, (byte)239, (byte)170, (byte)251, (byte)67, (byte)77, (byte)51, (byte)133, + (byte)69, (byte)249, (byte)2, (byte)127, (byte)80, (byte)60, (byte)159, (byte)168, + (byte)81, (byte)163, (byte)64, (byte)143, (byte)146, (byte)157, (byte)56, (byte)245, + (byte)188, (byte)182, (byte)218, (byte)33, (byte)16, (byte)255, (byte)243, (byte)210, + (byte)205, (byte)12, (byte)19, (byte)236, (byte)95, (byte)151, (byte)68, (byte)23, + (byte)196, (byte)167, (byte)126, (byte)61, (byte)100, (byte)93, (byte)25, (byte)115, + (byte)96, (byte)129, (byte)79, (byte)220, (byte)34, (byte)42, (byte)144, (byte)136, + (byte)70, (byte)238, (byte)184, (byte)20, (byte)222, (byte)94, (byte)11, (byte)219, + (byte)224, (byte)50, (byte)58, (byte)10, (byte)73, (byte)6, (byte)36, (byte)92, + (byte)194, (byte)211, (byte)172, (byte)98, (byte)145, (byte)149, (byte)228, (byte)121, + (byte)231, (byte)200, (byte)55, (byte)109, (byte)141, (byte)213, (byte)78, (byte)169, + (byte)108, (byte)86, (byte)244, (byte)234, (byte)101, (byte)122, (byte)174, (byte)8, + (byte)186, (byte)120, (byte)37, (byte)46, (byte)28, (byte)166, (byte)180, (byte)198, + (byte)232, (byte)221, (byte)116, (byte)31, (byte)75, (byte)189, (byte)139, (byte)138, + (byte)112, (byte)62, (byte)181, (byte)102, (byte)72, (byte)3, (byte)246, (byte)14, + (byte)97, (byte)53, (byte)87, (byte)185, (byte)134, (byte)193, (byte)29, (byte)158, + (byte)225, (byte)248, (byte)152, (byte)17, (byte)105, (byte)217, (byte)142, (byte)148, + (byte)155, (byte)30, (byte)135, (byte)233, (byte)206, (byte)85, (byte)40, (byte)223, + (byte)140, (byte)161, (byte)137, (byte)13, (byte)191, (byte)230, (byte)66, (byte)104, + (byte)65, (byte)153, (byte)45, (byte)15, (byte)176, (byte)84, (byte)187, (byte)22, + }; + + // The inverse S-box + private static final byte[] Si = { + (byte)82, (byte)9, (byte)106, (byte)213, (byte)48, (byte)54, (byte)165, (byte)56, + (byte)191, (byte)64, (byte)163, (byte)158, (byte)129, (byte)243, (byte)215, (byte)251, + (byte)124, (byte)227, (byte)57, (byte)130, (byte)155, (byte)47, (byte)255, (byte)135, + (byte)52, (byte)142, (byte)67, (byte)68, (byte)196, (byte)222, (byte)233, (byte)203, + (byte)84, (byte)123, (byte)148, (byte)50, (byte)166, (byte)194, (byte)35, (byte)61, + (byte)238, (byte)76, (byte)149, (byte)11, (byte)66, (byte)250, (byte)195, (byte)78, + (byte)8, (byte)46, (byte)161, (byte)102, (byte)40, (byte)217, (byte)36, (byte)178, + (byte)118, (byte)91, (byte)162, (byte)73, (byte)109, (byte)139, (byte)209, (byte)37, + (byte)114, (byte)248, (byte)246, (byte)100, (byte)134, (byte)104, (byte)152, (byte)22, + (byte)212, (byte)164, (byte)92, (byte)204, (byte)93, (byte)101, (byte)182, (byte)146, + (byte)108, (byte)112, (byte)72, (byte)80, (byte)253, (byte)237, (byte)185, (byte)218, + (byte)94, (byte)21, (byte)70, (byte)87, (byte)167, (byte)141, (byte)157, (byte)132, + (byte)144, (byte)216, (byte)171, (byte)0, (byte)140, (byte)188, (byte)211, (byte)10, + (byte)247, (byte)228, (byte)88, (byte)5, (byte)184, (byte)179, (byte)69, (byte)6, + (byte)208, (byte)44, (byte)30, (byte)143, (byte)202, (byte)63, (byte)15, (byte)2, + (byte)193, (byte)175, (byte)189, (byte)3, (byte)1, (byte)19, (byte)138, (byte)107, + (byte)58, (byte)145, (byte)17, (byte)65, (byte)79, (byte)103, (byte)220, (byte)234, + (byte)151, (byte)242, (byte)207, (byte)206, (byte)240, (byte)180, (byte)230, (byte)115, + (byte)150, (byte)172, (byte)116, (byte)34, (byte)231, (byte)173, (byte)53, (byte)133, + (byte)226, (byte)249, (byte)55, (byte)232, (byte)28, (byte)117, (byte)223, (byte)110, + (byte)71, (byte)241, (byte)26, (byte)113, (byte)29, (byte)41, (byte)197, (byte)137, + (byte)111, (byte)183, (byte)98, (byte)14, (byte)170, (byte)24, (byte)190, (byte)27, + (byte)252, (byte)86, (byte)62, (byte)75, (byte)198, (byte)210, (byte)121, (byte)32, + (byte)154, (byte)219, (byte)192, (byte)254, (byte)120, (byte)205, (byte)90, (byte)244, + (byte)31, (byte)221, (byte)168, (byte)51, (byte)136, (byte)7, (byte)199, (byte)49, + (byte)177, (byte)18, (byte)16, (byte)89, (byte)39, (byte)128, (byte)236, (byte)95, + (byte)96, (byte)81, (byte)127, (byte)169, (byte)25, (byte)181, (byte)74, (byte)13, + (byte)45, (byte)229, (byte)122, (byte)159, (byte)147, (byte)201, (byte)156, (byte)239, + (byte)160, (byte)224, (byte)59, (byte)77, (byte)174, (byte)42, (byte)245, (byte)176, + (byte)200, (byte)235, (byte)187, (byte)60, (byte)131, (byte)83, (byte)153, (byte)97, + (byte)23, (byte)43, (byte)4, (byte)126, (byte)186, (byte)119, (byte)214, (byte)38, + (byte)225, (byte)105, (byte)20, (byte)99, (byte)85, (byte)33, (byte)12, (byte)125, + }; + + // vector used in calculating key schedule (powers of x in GF(256)) + private static final int[] rcon = { + 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, + 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91 }; + + // precomputation tables of calculations for rounds + private static final int[] T0 = + { + 0xa56363c6, 0x847c7cf8, 0x997777ee, 0x8d7b7bf6, 0x0df2f2ff, + 0xbd6b6bd6, 0xb16f6fde, 0x54c5c591, 0x50303060, 0x03010102, + 0xa96767ce, 0x7d2b2b56, 0x19fefee7, 0x62d7d7b5, 0xe6abab4d, + 0x9a7676ec, 0x45caca8f, 0x9d82821f, 0x40c9c989, 0x877d7dfa, + 0x15fafaef, 0xeb5959b2, 0xc947478e, 0x0bf0f0fb, 0xecadad41, + 0x67d4d4b3, 0xfda2a25f, 0xeaafaf45, 0xbf9c9c23, 0xf7a4a453, + 0x967272e4, 0x5bc0c09b, 0xc2b7b775, 0x1cfdfde1, 0xae93933d, + 0x6a26264c, 0x5a36366c, 0x413f3f7e, 0x02f7f7f5, 0x4fcccc83, + 0x5c343468, 0xf4a5a551, 0x34e5e5d1, 0x08f1f1f9, 0x937171e2, + 0x73d8d8ab, 0x53313162, 0x3f15152a, 0x0c040408, 0x52c7c795, + 0x65232346, 0x5ec3c39d, 0x28181830, 0xa1969637, 0x0f05050a, + 0xb59a9a2f, 0x0907070e, 0x36121224, 0x9b80801b, 0x3de2e2df, + 0x26ebebcd, 0x6927274e, 0xcdb2b27f, 0x9f7575ea, 0x1b090912, + 0x9e83831d, 0x742c2c58, 0x2e1a1a34, 0x2d1b1b36, 0xb26e6edc, + 0xee5a5ab4, 0xfba0a05b, 0xf65252a4, 0x4d3b3b76, 0x61d6d6b7, + 0xceb3b37d, 0x7b292952, 0x3ee3e3dd, 0x712f2f5e, 0x97848413, + 0xf55353a6, 0x68d1d1b9, 0x00000000, 0x2cededc1, 0x60202040, + 0x1ffcfce3, 0xc8b1b179, 0xed5b5bb6, 0xbe6a6ad4, 0x46cbcb8d, + 0xd9bebe67, 0x4b393972, 0xde4a4a94, 0xd44c4c98, 0xe85858b0, + 0x4acfcf85, 0x6bd0d0bb, 0x2aefefc5, 0xe5aaaa4f, 0x16fbfbed, + 0xc5434386, 0xd74d4d9a, 0x55333366, 0x94858511, 0xcf45458a, + 0x10f9f9e9, 0x06020204, 0x817f7ffe, 0xf05050a0, 0x443c3c78, + 0xba9f9f25, 0xe3a8a84b, 0xf35151a2, 0xfea3a35d, 0xc0404080, + 0x8a8f8f05, 0xad92923f, 0xbc9d9d21, 0x48383870, 0x04f5f5f1, + 0xdfbcbc63, 0xc1b6b677, 0x75dadaaf, 0x63212142, 0x30101020, + 0x1affffe5, 0x0ef3f3fd, 0x6dd2d2bf, 0x4ccdcd81, 0x140c0c18, + 0x35131326, 0x2fececc3, 0xe15f5fbe, 0xa2979735, 0xcc444488, + 0x3917172e, 0x57c4c493, 0xf2a7a755, 0x827e7efc, 0x473d3d7a, + 0xac6464c8, 0xe75d5dba, 0x2b191932, 0x957373e6, 0xa06060c0, + 0x98818119, 0xd14f4f9e, 0x7fdcdca3, 0x66222244, 0x7e2a2a54, + 0xab90903b, 0x8388880b, 0xca46468c, 0x29eeeec7, 0xd3b8b86b, + 0x3c141428, 0x79dedea7, 0xe25e5ebc, 0x1d0b0b16, 0x76dbdbad, + 0x3be0e0db, 0x56323264, 0x4e3a3a74, 0x1e0a0a14, 0xdb494992, + 0x0a06060c, 0x6c242448, 0xe45c5cb8, 0x5dc2c29f, 0x6ed3d3bd, + 0xefacac43, 0xa66262c4, 0xa8919139, 0xa4959531, 0x37e4e4d3, + 0x8b7979f2, 0x32e7e7d5, 0x43c8c88b, 0x5937376e, 0xb76d6dda, + 0x8c8d8d01, 0x64d5d5b1, 0xd24e4e9c, 0xe0a9a949, 0xb46c6cd8, + 0xfa5656ac, 0x07f4f4f3, 0x25eaeacf, 0xaf6565ca, 0x8e7a7af4, + 0xe9aeae47, 0x18080810, 0xd5baba6f, 0x887878f0, 0x6f25254a, + 0x722e2e5c, 0x241c1c38, 0xf1a6a657, 0xc7b4b473, 0x51c6c697, + 0x23e8e8cb, 0x7cdddda1, 0x9c7474e8, 0x211f1f3e, 0xdd4b4b96, + 0xdcbdbd61, 0x868b8b0d, 0x858a8a0f, 0x907070e0, 0x423e3e7c, + 0xc4b5b571, 0xaa6666cc, 0xd8484890, 0x05030306, 0x01f6f6f7, + 0x120e0e1c, 0xa36161c2, 0x5f35356a, 0xf95757ae, 0xd0b9b969, + 0x91868617, 0x58c1c199, 0x271d1d3a, 0xb99e9e27, 0x38e1e1d9, + 0x13f8f8eb, 0xb398982b, 0x33111122, 0xbb6969d2, 0x70d9d9a9, + 0x898e8e07, 0xa7949433, 0xb69b9b2d, 0x221e1e3c, 0x92878715, + 0x20e9e9c9, 0x49cece87, 0xff5555aa, 0x78282850, 0x7adfdfa5, + 0x8f8c8c03, 0xf8a1a159, 0x80898909, 0x170d0d1a, 0xdabfbf65, + 0x31e6e6d7, 0xc6424284, 0xb86868d0, 0xc3414182, 0xb0999929, + 0x772d2d5a, 0x110f0f1e, 0xcbb0b07b, 0xfc5454a8, 0xd6bbbb6d, + 0x3a16162c}; + + private static final int[] T1 = + { + 0x6363c6a5, 0x7c7cf884, 0x7777ee99, 0x7b7bf68d, 0xf2f2ff0d, + 0x6b6bd6bd, 0x6f6fdeb1, 0xc5c59154, 0x30306050, 0x01010203, + 0x6767cea9, 0x2b2b567d, 0xfefee719, 0xd7d7b562, 0xabab4de6, + 0x7676ec9a, 0xcaca8f45, 0x82821f9d, 0xc9c98940, 0x7d7dfa87, + 0xfafaef15, 0x5959b2eb, 0x47478ec9, 0xf0f0fb0b, 0xadad41ec, + 0xd4d4b367, 0xa2a25ffd, 0xafaf45ea, 0x9c9c23bf, 0xa4a453f7, + 0x7272e496, 0xc0c09b5b, 0xb7b775c2, 0xfdfde11c, 0x93933dae, + 0x26264c6a, 0x36366c5a, 0x3f3f7e41, 0xf7f7f502, 0xcccc834f, + 0x3434685c, 0xa5a551f4, 0xe5e5d134, 0xf1f1f908, 0x7171e293, + 0xd8d8ab73, 0x31316253, 0x15152a3f, 0x0404080c, 0xc7c79552, + 0x23234665, 0xc3c39d5e, 0x18183028, 0x969637a1, 0x05050a0f, + 0x9a9a2fb5, 0x07070e09, 0x12122436, 0x80801b9b, 0xe2e2df3d, + 0xebebcd26, 0x27274e69, 0xb2b27fcd, 0x7575ea9f, 0x0909121b, + 0x83831d9e, 0x2c2c5874, 0x1a1a342e, 0x1b1b362d, 0x6e6edcb2, + 0x5a5ab4ee, 0xa0a05bfb, 0x5252a4f6, 0x3b3b764d, 0xd6d6b761, + 0xb3b37dce, 0x2929527b, 0xe3e3dd3e, 0x2f2f5e71, 0x84841397, + 0x5353a6f5, 0xd1d1b968, 0x00000000, 0xededc12c, 0x20204060, + 0xfcfce31f, 0xb1b179c8, 0x5b5bb6ed, 0x6a6ad4be, 0xcbcb8d46, + 0xbebe67d9, 0x3939724b, 0x4a4a94de, 0x4c4c98d4, 0x5858b0e8, + 0xcfcf854a, 0xd0d0bb6b, 0xefefc52a, 0xaaaa4fe5, 0xfbfbed16, + 0x434386c5, 0x4d4d9ad7, 0x33336655, 0x85851194, 0x45458acf, + 0xf9f9e910, 0x02020406, 0x7f7ffe81, 0x5050a0f0, 0x3c3c7844, + 0x9f9f25ba, 0xa8a84be3, 0x5151a2f3, 0xa3a35dfe, 0x404080c0, + 0x8f8f058a, 0x92923fad, 0x9d9d21bc, 0x38387048, 0xf5f5f104, + 0xbcbc63df, 0xb6b677c1, 0xdadaaf75, 0x21214263, 0x10102030, + 0xffffe51a, 0xf3f3fd0e, 0xd2d2bf6d, 0xcdcd814c, 0x0c0c1814, + 0x13132635, 0xececc32f, 0x5f5fbee1, 0x979735a2, 0x444488cc, + 0x17172e39, 0xc4c49357, 0xa7a755f2, 0x7e7efc82, 0x3d3d7a47, + 0x6464c8ac, 0x5d5dbae7, 0x1919322b, 0x7373e695, 0x6060c0a0, + 0x81811998, 0x4f4f9ed1, 0xdcdca37f, 0x22224466, 0x2a2a547e, + 0x90903bab, 0x88880b83, 0x46468cca, 0xeeeec729, 0xb8b86bd3, + 0x1414283c, 0xdedea779, 0x5e5ebce2, 0x0b0b161d, 0xdbdbad76, + 0xe0e0db3b, 0x32326456, 0x3a3a744e, 0x0a0a141e, 0x494992db, + 0x06060c0a, 0x2424486c, 0x5c5cb8e4, 0xc2c29f5d, 0xd3d3bd6e, + 0xacac43ef, 0x6262c4a6, 0x919139a8, 0x959531a4, 0xe4e4d337, + 0x7979f28b, 0xe7e7d532, 0xc8c88b43, 0x37376e59, 0x6d6ddab7, + 0x8d8d018c, 0xd5d5b164, 0x4e4e9cd2, 0xa9a949e0, 0x6c6cd8b4, + 0x5656acfa, 0xf4f4f307, 0xeaeacf25, 0x6565caaf, 0x7a7af48e, + 0xaeae47e9, 0x08081018, 0xbaba6fd5, 0x7878f088, 0x25254a6f, + 0x2e2e5c72, 0x1c1c3824, 0xa6a657f1, 0xb4b473c7, 0xc6c69751, + 0xe8e8cb23, 0xdddda17c, 0x7474e89c, 0x1f1f3e21, 0x4b4b96dd, + 0xbdbd61dc, 0x8b8b0d86, 0x8a8a0f85, 0x7070e090, 0x3e3e7c42, + 0xb5b571c4, 0x6666ccaa, 0x484890d8, 0x03030605, 0xf6f6f701, + 0x0e0e1c12, 0x6161c2a3, 0x35356a5f, 0x5757aef9, 0xb9b969d0, + 0x86861791, 0xc1c19958, 0x1d1d3a27, 0x9e9e27b9, 0xe1e1d938, + 0xf8f8eb13, 0x98982bb3, 0x11112233, 0x6969d2bb, 0xd9d9a970, + 0x8e8e0789, 0x949433a7, 0x9b9b2db6, 0x1e1e3c22, 0x87871592, + 0xe9e9c920, 0xcece8749, 0x5555aaff, 0x28285078, 0xdfdfa57a, + 0x8c8c038f, 0xa1a159f8, 0x89890980, 0x0d0d1a17, 0xbfbf65da, + 0xe6e6d731, 0x424284c6, 0x6868d0b8, 0x414182c3, 0x999929b0, + 0x2d2d5a77, 0x0f0f1e11, 0xb0b07bcb, 0x5454a8fc, 0xbbbb6dd6, + 0x16162c3a}; + + private static final int[] T2 = + { + 0x63c6a563, 0x7cf8847c, 0x77ee9977, 0x7bf68d7b, 0xf2ff0df2, + 0x6bd6bd6b, 0x6fdeb16f, 0xc59154c5, 0x30605030, 0x01020301, + 0x67cea967, 0x2b567d2b, 0xfee719fe, 0xd7b562d7, 0xab4de6ab, + 0x76ec9a76, 0xca8f45ca, 0x821f9d82, 0xc98940c9, 0x7dfa877d, + 0xfaef15fa, 0x59b2eb59, 0x478ec947, 0xf0fb0bf0, 0xad41ecad, + 0xd4b367d4, 0xa25ffda2, 0xaf45eaaf, 0x9c23bf9c, 0xa453f7a4, + 0x72e49672, 0xc09b5bc0, 0xb775c2b7, 0xfde11cfd, 0x933dae93, + 0x264c6a26, 0x366c5a36, 0x3f7e413f, 0xf7f502f7, 0xcc834fcc, + 0x34685c34, 0xa551f4a5, 0xe5d134e5, 0xf1f908f1, 0x71e29371, + 0xd8ab73d8, 0x31625331, 0x152a3f15, 0x04080c04, 0xc79552c7, + 0x23466523, 0xc39d5ec3, 0x18302818, 0x9637a196, 0x050a0f05, + 0x9a2fb59a, 0x070e0907, 0x12243612, 0x801b9b80, 0xe2df3de2, + 0xebcd26eb, 0x274e6927, 0xb27fcdb2, 0x75ea9f75, 0x09121b09, + 0x831d9e83, 0x2c58742c, 0x1a342e1a, 0x1b362d1b, 0x6edcb26e, + 0x5ab4ee5a, 0xa05bfba0, 0x52a4f652, 0x3b764d3b, 0xd6b761d6, + 0xb37dceb3, 0x29527b29, 0xe3dd3ee3, 0x2f5e712f, 0x84139784, + 0x53a6f553, 0xd1b968d1, 0x00000000, 0xedc12ced, 0x20406020, + 0xfce31ffc, 0xb179c8b1, 0x5bb6ed5b, 0x6ad4be6a, 0xcb8d46cb, + 0xbe67d9be, 0x39724b39, 0x4a94de4a, 0x4c98d44c, 0x58b0e858, + 0xcf854acf, 0xd0bb6bd0, 0xefc52aef, 0xaa4fe5aa, 0xfbed16fb, + 0x4386c543, 0x4d9ad74d, 0x33665533, 0x85119485, 0x458acf45, + 0xf9e910f9, 0x02040602, 0x7ffe817f, 0x50a0f050, 0x3c78443c, + 0x9f25ba9f, 0xa84be3a8, 0x51a2f351, 0xa35dfea3, 0x4080c040, + 0x8f058a8f, 0x923fad92, 0x9d21bc9d, 0x38704838, 0xf5f104f5, + 0xbc63dfbc, 0xb677c1b6, 0xdaaf75da, 0x21426321, 0x10203010, + 0xffe51aff, 0xf3fd0ef3, 0xd2bf6dd2, 0xcd814ccd, 0x0c18140c, + 0x13263513, 0xecc32fec, 0x5fbee15f, 0x9735a297, 0x4488cc44, + 0x172e3917, 0xc49357c4, 0xa755f2a7, 0x7efc827e, 0x3d7a473d, + 0x64c8ac64, 0x5dbae75d, 0x19322b19, 0x73e69573, 0x60c0a060, + 0x81199881, 0x4f9ed14f, 0xdca37fdc, 0x22446622, 0x2a547e2a, + 0x903bab90, 0x880b8388, 0x468cca46, 0xeec729ee, 0xb86bd3b8, + 0x14283c14, 0xdea779de, 0x5ebce25e, 0x0b161d0b, 0xdbad76db, + 0xe0db3be0, 0x32645632, 0x3a744e3a, 0x0a141e0a, 0x4992db49, + 0x060c0a06, 0x24486c24, 0x5cb8e45c, 0xc29f5dc2, 0xd3bd6ed3, + 0xac43efac, 0x62c4a662, 0x9139a891, 0x9531a495, 0xe4d337e4, + 0x79f28b79, 0xe7d532e7, 0xc88b43c8, 0x376e5937, 0x6ddab76d, + 0x8d018c8d, 0xd5b164d5, 0x4e9cd24e, 0xa949e0a9, 0x6cd8b46c, + 0x56acfa56, 0xf4f307f4, 0xeacf25ea, 0x65caaf65, 0x7af48e7a, + 0xae47e9ae, 0x08101808, 0xba6fd5ba, 0x78f08878, 0x254a6f25, + 0x2e5c722e, 0x1c38241c, 0xa657f1a6, 0xb473c7b4, 0xc69751c6, + 0xe8cb23e8, 0xdda17cdd, 0x74e89c74, 0x1f3e211f, 0x4b96dd4b, + 0xbd61dcbd, 0x8b0d868b, 0x8a0f858a, 0x70e09070, 0x3e7c423e, + 0xb571c4b5, 0x66ccaa66, 0x4890d848, 0x03060503, 0xf6f701f6, + 0x0e1c120e, 0x61c2a361, 0x356a5f35, 0x57aef957, 0xb969d0b9, + 0x86179186, 0xc19958c1, 0x1d3a271d, 0x9e27b99e, 0xe1d938e1, + 0xf8eb13f8, 0x982bb398, 0x11223311, 0x69d2bb69, 0xd9a970d9, + 0x8e07898e, 0x9433a794, 0x9b2db69b, 0x1e3c221e, 0x87159287, + 0xe9c920e9, 0xce8749ce, 0x55aaff55, 0x28507828, 0xdfa57adf, + 0x8c038f8c, 0xa159f8a1, 0x89098089, 0x0d1a170d, 0xbf65dabf, + 0xe6d731e6, 0x4284c642, 0x68d0b868, 0x4182c341, 0x9929b099, + 0x2d5a772d, 0x0f1e110f, 0xb07bcbb0, 0x54a8fc54, 0xbb6dd6bb, + 0x162c3a16}; + + private static final int[] T3 = + { + 0xc6a56363, 0xf8847c7c, 0xee997777, 0xf68d7b7b, 0xff0df2f2, + 0xd6bd6b6b, 0xdeb16f6f, 0x9154c5c5, 0x60503030, 0x02030101, + 0xcea96767, 0x567d2b2b, 0xe719fefe, 0xb562d7d7, 0x4de6abab, + 0xec9a7676, 0x8f45caca, 0x1f9d8282, 0x8940c9c9, 0xfa877d7d, + 0xef15fafa, 0xb2eb5959, 0x8ec94747, 0xfb0bf0f0, 0x41ecadad, + 0xb367d4d4, 0x5ffda2a2, 0x45eaafaf, 0x23bf9c9c, 0x53f7a4a4, + 0xe4967272, 0x9b5bc0c0, 0x75c2b7b7, 0xe11cfdfd, 0x3dae9393, + 0x4c6a2626, 0x6c5a3636, 0x7e413f3f, 0xf502f7f7, 0x834fcccc, + 0x685c3434, 0x51f4a5a5, 0xd134e5e5, 0xf908f1f1, 0xe2937171, + 0xab73d8d8, 0x62533131, 0x2a3f1515, 0x080c0404, 0x9552c7c7, + 0x46652323, 0x9d5ec3c3, 0x30281818, 0x37a19696, 0x0a0f0505, + 0x2fb59a9a, 0x0e090707, 0x24361212, 0x1b9b8080, 0xdf3de2e2, + 0xcd26ebeb, 0x4e692727, 0x7fcdb2b2, 0xea9f7575, 0x121b0909, + 0x1d9e8383, 0x58742c2c, 0x342e1a1a, 0x362d1b1b, 0xdcb26e6e, + 0xb4ee5a5a, 0x5bfba0a0, 0xa4f65252, 0x764d3b3b, 0xb761d6d6, + 0x7dceb3b3, 0x527b2929, 0xdd3ee3e3, 0x5e712f2f, 0x13978484, + 0xa6f55353, 0xb968d1d1, 0x00000000, 0xc12ceded, 0x40602020, + 0xe31ffcfc, 0x79c8b1b1, 0xb6ed5b5b, 0xd4be6a6a, 0x8d46cbcb, + 0x67d9bebe, 0x724b3939, 0x94de4a4a, 0x98d44c4c, 0xb0e85858, + 0x854acfcf, 0xbb6bd0d0, 0xc52aefef, 0x4fe5aaaa, 0xed16fbfb, + 0x86c54343, 0x9ad74d4d, 0x66553333, 0x11948585, 0x8acf4545, + 0xe910f9f9, 0x04060202, 0xfe817f7f, 0xa0f05050, 0x78443c3c, + 0x25ba9f9f, 0x4be3a8a8, 0xa2f35151, 0x5dfea3a3, 0x80c04040, + 0x058a8f8f, 0x3fad9292, 0x21bc9d9d, 0x70483838, 0xf104f5f5, + 0x63dfbcbc, 0x77c1b6b6, 0xaf75dada, 0x42632121, 0x20301010, + 0xe51affff, 0xfd0ef3f3, 0xbf6dd2d2, 0x814ccdcd, 0x18140c0c, + 0x26351313, 0xc32fecec, 0xbee15f5f, 0x35a29797, 0x88cc4444, + 0x2e391717, 0x9357c4c4, 0x55f2a7a7, 0xfc827e7e, 0x7a473d3d, + 0xc8ac6464, 0xbae75d5d, 0x322b1919, 0xe6957373, 0xc0a06060, + 0x19988181, 0x9ed14f4f, 0xa37fdcdc, 0x44662222, 0x547e2a2a, + 0x3bab9090, 0x0b838888, 0x8cca4646, 0xc729eeee, 0x6bd3b8b8, + 0x283c1414, 0xa779dede, 0xbce25e5e, 0x161d0b0b, 0xad76dbdb, + 0xdb3be0e0, 0x64563232, 0x744e3a3a, 0x141e0a0a, 0x92db4949, + 0x0c0a0606, 0x486c2424, 0xb8e45c5c, 0x9f5dc2c2, 0xbd6ed3d3, + 0x43efacac, 0xc4a66262, 0x39a89191, 0x31a49595, 0xd337e4e4, + 0xf28b7979, 0xd532e7e7, 0x8b43c8c8, 0x6e593737, 0xdab76d6d, + 0x018c8d8d, 0xb164d5d5, 0x9cd24e4e, 0x49e0a9a9, 0xd8b46c6c, + 0xacfa5656, 0xf307f4f4, 0xcf25eaea, 0xcaaf6565, 0xf48e7a7a, + 0x47e9aeae, 0x10180808, 0x6fd5baba, 0xf0887878, 0x4a6f2525, + 0x5c722e2e, 0x38241c1c, 0x57f1a6a6, 0x73c7b4b4, 0x9751c6c6, + 0xcb23e8e8, 0xa17cdddd, 0xe89c7474, 0x3e211f1f, 0x96dd4b4b, + 0x61dcbdbd, 0x0d868b8b, 0x0f858a8a, 0xe0907070, 0x7c423e3e, + 0x71c4b5b5, 0xccaa6666, 0x90d84848, 0x06050303, 0xf701f6f6, + 0x1c120e0e, 0xc2a36161, 0x6a5f3535, 0xaef95757, 0x69d0b9b9, + 0x17918686, 0x9958c1c1, 0x3a271d1d, 0x27b99e9e, 0xd938e1e1, + 0xeb13f8f8, 0x2bb39898, 0x22331111, 0xd2bb6969, 0xa970d9d9, + 0x07898e8e, 0x33a79494, 0x2db69b9b, 0x3c221e1e, 0x15928787, + 0xc920e9e9, 0x8749cece, 0xaaff5555, 0x50782828, 0xa57adfdf, + 0x038f8c8c, 0x59f8a1a1, 0x09808989, 0x1a170d0d, 0x65dabfbf, + 0xd731e6e6, 0x84c64242, 0xd0b86868, 0x82c34141, 0x29b09999, + 0x5a772d2d, 0x1e110f0f, 0x7bcbb0b0, 0xa8fc5454, 0x6dd6bbbb, + 0x2c3a1616}; + + private static final int[] Tinv0 = + { + 0x50a7f451, 0x5365417e, 0xc3a4171a, 0x965e273a, 0xcb6bab3b, + 0xf1459d1f, 0xab58faac, 0x9303e34b, 0x55fa3020, 0xf66d76ad, + 0x9176cc88, 0x254c02f5, 0xfcd7e54f, 0xd7cb2ac5, 0x80443526, + 0x8fa362b5, 0x495ab1de, 0x671bba25, 0x980eea45, 0xe1c0fe5d, + 0x02752fc3, 0x12f04c81, 0xa397468d, 0xc6f9d36b, 0xe75f8f03, + 0x959c9215, 0xeb7a6dbf, 0xda595295, 0x2d83bed4, 0xd3217458, + 0x2969e049, 0x44c8c98e, 0x6a89c275, 0x78798ef4, 0x6b3e5899, + 0xdd71b927, 0xb64fe1be, 0x17ad88f0, 0x66ac20c9, 0xb43ace7d, + 0x184adf63, 0x82311ae5, 0x60335197, 0x457f5362, 0xe07764b1, + 0x84ae6bbb, 0x1ca081fe, 0x942b08f9, 0x58684870, 0x19fd458f, + 0x876cde94, 0xb7f87b52, 0x23d373ab, 0xe2024b72, 0x578f1fe3, + 0x2aab5566, 0x0728ebb2, 0x03c2b52f, 0x9a7bc586, 0xa50837d3, + 0xf2872830, 0xb2a5bf23, 0xba6a0302, 0x5c8216ed, 0x2b1ccf8a, + 0x92b479a7, 0xf0f207f3, 0xa1e2694e, 0xcdf4da65, 0xd5be0506, + 0x1f6234d1, 0x8afea6c4, 0x9d532e34, 0xa055f3a2, 0x32e18a05, + 0x75ebf6a4, 0x39ec830b, 0xaaef6040, 0x069f715e, 0x51106ebd, + 0xf98a213e, 0x3d06dd96, 0xae053edd, 0x46bde64d, 0xb58d5491, + 0x055dc471, 0x6fd40604, 0xff155060, 0x24fb9819, 0x97e9bdd6, + 0xcc434089, 0x779ed967, 0xbd42e8b0, 0x888b8907, 0x385b19e7, + 0xdbeec879, 0x470a7ca1, 0xe90f427c, 0xc91e84f8, 0x00000000, + 0x83868009, 0x48ed2b32, 0xac70111e, 0x4e725a6c, 0xfbff0efd, + 0x5638850f, 0x1ed5ae3d, 0x27392d36, 0x64d90f0a, 0x21a65c68, + 0xd1545b9b, 0x3a2e3624, 0xb1670a0c, 0x0fe75793, 0xd296eeb4, + 0x9e919b1b, 0x4fc5c080, 0xa220dc61, 0x694b775a, 0x161a121c, + 0x0aba93e2, 0xe52aa0c0, 0x43e0223c, 0x1d171b12, 0x0b0d090e, + 0xadc78bf2, 0xb9a8b62d, 0xc8a91e14, 0x8519f157, 0x4c0775af, + 0xbbdd99ee, 0xfd607fa3, 0x9f2601f7, 0xbcf5725c, 0xc53b6644, + 0x347efb5b, 0x7629438b, 0xdcc623cb, 0x68fcedb6, 0x63f1e4b8, + 0xcadc31d7, 0x10856342, 0x40229713, 0x2011c684, 0x7d244a85, + 0xf83dbbd2, 0x1132f9ae, 0x6da129c7, 0x4b2f9e1d, 0xf330b2dc, + 0xec52860d, 0xd0e3c177, 0x6c16b32b, 0x99b970a9, 0xfa489411, + 0x2264e947, 0xc48cfca8, 0x1a3ff0a0, 0xd82c7d56, 0xef903322, + 0xc74e4987, 0xc1d138d9, 0xfea2ca8c, 0x360bd498, 0xcf81f5a6, + 0x28de7aa5, 0x268eb7da, 0xa4bfad3f, 0xe49d3a2c, 0x0d927850, + 0x9bcc5f6a, 0x62467e54, 0xc2138df6, 0xe8b8d890, 0x5ef7392e, + 0xf5afc382, 0xbe805d9f, 0x7c93d069, 0xa92dd56f, 0xb31225cf, + 0x3b99acc8, 0xa77d1810, 0x6e639ce8, 0x7bbb3bdb, 0x097826cd, + 0xf418596e, 0x01b79aec, 0xa89a4f83, 0x656e95e6, 0x7ee6ffaa, + 0x08cfbc21, 0xe6e815ef, 0xd99be7ba, 0xce366f4a, 0xd4099fea, + 0xd67cb029, 0xafb2a431, 0x31233f2a, 0x3094a5c6, 0xc066a235, + 0x37bc4e74, 0xa6ca82fc, 0xb0d090e0, 0x15d8a733, 0x4a9804f1, + 0xf7daec41, 0x0e50cd7f, 0x2ff69117, 0x8dd64d76, 0x4db0ef43, + 0x544daacc, 0xdf0496e4, 0xe3b5d19e, 0x1b886a4c, 0xb81f2cc1, + 0x7f516546, 0x04ea5e9d, 0x5d358c01, 0x737487fa, 0x2e410bfb, + 0x5a1d67b3, 0x52d2db92, 0x335610e9, 0x1347d66d, 0x8c61d79a, + 0x7a0ca137, 0x8e14f859, 0x893c13eb, 0xee27a9ce, 0x35c961b7, + 0xede51ce1, 0x3cb1477a, 0x59dfd29c, 0x3f73f255, 0x79ce1418, + 0xbf37c773, 0xeacdf753, 0x5baafd5f, 0x146f3ddf, 0x86db4478, + 0x81f3afca, 0x3ec468b9, 0x2c342438, 0x5f40a3c2, 0x72c31d16, + 0x0c25e2bc, 0x8b493c28, 0x41950dff, 0x7101a839, 0xdeb30c08, + 0x9ce4b4d8, 0x90c15664, 0x6184cb7b, 0x70b632d5, 0x745c6c48, + 0x4257b8d0}; + + private static final int[] Tinv1 = + { + 0xa7f45150, 0x65417e53, 0xa4171ac3, 0x5e273a96, 0x6bab3bcb, + 0x459d1ff1, 0x58faacab, 0x03e34b93, 0xfa302055, 0x6d76adf6, + 0x76cc8891, 0x4c02f525, 0xd7e54ffc, 0xcb2ac5d7, 0x44352680, + 0xa362b58f, 0x5ab1de49, 0x1bba2567, 0x0eea4598, 0xc0fe5de1, + 0x752fc302, 0xf04c8112, 0x97468da3, 0xf9d36bc6, 0x5f8f03e7, + 0x9c921595, 0x7a6dbfeb, 0x595295da, 0x83bed42d, 0x217458d3, + 0x69e04929, 0xc8c98e44, 0x89c2756a, 0x798ef478, 0x3e58996b, + 0x71b927dd, 0x4fe1beb6, 0xad88f017, 0xac20c966, 0x3ace7db4, + 0x4adf6318, 0x311ae582, 0x33519760, 0x7f536245, 0x7764b1e0, + 0xae6bbb84, 0xa081fe1c, 0x2b08f994, 0x68487058, 0xfd458f19, + 0x6cde9487, 0xf87b52b7, 0xd373ab23, 0x024b72e2, 0x8f1fe357, + 0xab55662a, 0x28ebb207, 0xc2b52f03, 0x7bc5869a, 0x0837d3a5, + 0x872830f2, 0xa5bf23b2, 0x6a0302ba, 0x8216ed5c, 0x1ccf8a2b, + 0xb479a792, 0xf207f3f0, 0xe2694ea1, 0xf4da65cd, 0xbe0506d5, + 0x6234d11f, 0xfea6c48a, 0x532e349d, 0x55f3a2a0, 0xe18a0532, + 0xebf6a475, 0xec830b39, 0xef6040aa, 0x9f715e06, 0x106ebd51, + 0x8a213ef9, 0x06dd963d, 0x053eddae, 0xbde64d46, 0x8d5491b5, + 0x5dc47105, 0xd406046f, 0x155060ff, 0xfb981924, 0xe9bdd697, + 0x434089cc, 0x9ed96777, 0x42e8b0bd, 0x8b890788, 0x5b19e738, + 0xeec879db, 0x0a7ca147, 0x0f427ce9, 0x1e84f8c9, 0x00000000, + 0x86800983, 0xed2b3248, 0x70111eac, 0x725a6c4e, 0xff0efdfb, + 0x38850f56, 0xd5ae3d1e, 0x392d3627, 0xd90f0a64, 0xa65c6821, + 0x545b9bd1, 0x2e36243a, 0x670a0cb1, 0xe757930f, 0x96eeb4d2, + 0x919b1b9e, 0xc5c0804f, 0x20dc61a2, 0x4b775a69, 0x1a121c16, + 0xba93e20a, 0x2aa0c0e5, 0xe0223c43, 0x171b121d, 0x0d090e0b, + 0xc78bf2ad, 0xa8b62db9, 0xa91e14c8, 0x19f15785, 0x0775af4c, + 0xdd99eebb, 0x607fa3fd, 0x2601f79f, 0xf5725cbc, 0x3b6644c5, + 0x7efb5b34, 0x29438b76, 0xc623cbdc, 0xfcedb668, 0xf1e4b863, + 0xdc31d7ca, 0x85634210, 0x22971340, 0x11c68420, 0x244a857d, + 0x3dbbd2f8, 0x32f9ae11, 0xa129c76d, 0x2f9e1d4b, 0x30b2dcf3, + 0x52860dec, 0xe3c177d0, 0x16b32b6c, 0xb970a999, 0x489411fa, + 0x64e94722, 0x8cfca8c4, 0x3ff0a01a, 0x2c7d56d8, 0x903322ef, + 0x4e4987c7, 0xd138d9c1, 0xa2ca8cfe, 0x0bd49836, 0x81f5a6cf, + 0xde7aa528, 0x8eb7da26, 0xbfad3fa4, 0x9d3a2ce4, 0x9278500d, + 0xcc5f6a9b, 0x467e5462, 0x138df6c2, 0xb8d890e8, 0xf7392e5e, + 0xafc382f5, 0x805d9fbe, 0x93d0697c, 0x2dd56fa9, 0x1225cfb3, + 0x99acc83b, 0x7d1810a7, 0x639ce86e, 0xbb3bdb7b, 0x7826cd09, + 0x18596ef4, 0xb79aec01, 0x9a4f83a8, 0x6e95e665, 0xe6ffaa7e, + 0xcfbc2108, 0xe815efe6, 0x9be7bad9, 0x366f4ace, 0x099fead4, + 0x7cb029d6, 0xb2a431af, 0x233f2a31, 0x94a5c630, 0x66a235c0, + 0xbc4e7437, 0xca82fca6, 0xd090e0b0, 0xd8a73315, 0x9804f14a, + 0xdaec41f7, 0x50cd7f0e, 0xf691172f, 0xd64d768d, 0xb0ef434d, + 0x4daacc54, 0x0496e4df, 0xb5d19ee3, 0x886a4c1b, 0x1f2cc1b8, + 0x5165467f, 0xea5e9d04, 0x358c015d, 0x7487fa73, 0x410bfb2e, + 0x1d67b35a, 0xd2db9252, 0x5610e933, 0x47d66d13, 0x61d79a8c, + 0x0ca1377a, 0x14f8598e, 0x3c13eb89, 0x27a9ceee, 0xc961b735, + 0xe51ce1ed, 0xb1477a3c, 0xdfd29c59, 0x73f2553f, 0xce141879, + 0x37c773bf, 0xcdf753ea, 0xaafd5f5b, 0x6f3ddf14, 0xdb447886, + 0xf3afca81, 0xc468b93e, 0x3424382c, 0x40a3c25f, 0xc31d1672, + 0x25e2bc0c, 0x493c288b, 0x950dff41, 0x01a83971, 0xb30c08de, + 0xe4b4d89c, 0xc1566490, 0x84cb7b61, 0xb632d570, 0x5c6c4874, + 0x57b8d042}; + + private static final int[] Tinv2 = + { + 0xf45150a7, 0x417e5365, 0x171ac3a4, 0x273a965e, 0xab3bcb6b, + 0x9d1ff145, 0xfaacab58, 0xe34b9303, 0x302055fa, 0x76adf66d, + 0xcc889176, 0x02f5254c, 0xe54ffcd7, 0x2ac5d7cb, 0x35268044, + 0x62b58fa3, 0xb1de495a, 0xba25671b, 0xea45980e, 0xfe5de1c0, + 0x2fc30275, 0x4c8112f0, 0x468da397, 0xd36bc6f9, 0x8f03e75f, + 0x9215959c, 0x6dbfeb7a, 0x5295da59, 0xbed42d83, 0x7458d321, + 0xe0492969, 0xc98e44c8, 0xc2756a89, 0x8ef47879, 0x58996b3e, + 0xb927dd71, 0xe1beb64f, 0x88f017ad, 0x20c966ac, 0xce7db43a, + 0xdf63184a, 0x1ae58231, 0x51976033, 0x5362457f, 0x64b1e077, + 0x6bbb84ae, 0x81fe1ca0, 0x08f9942b, 0x48705868, 0x458f19fd, + 0xde94876c, 0x7b52b7f8, 0x73ab23d3, 0x4b72e202, 0x1fe3578f, + 0x55662aab, 0xebb20728, 0xb52f03c2, 0xc5869a7b, 0x37d3a508, + 0x2830f287, 0xbf23b2a5, 0x0302ba6a, 0x16ed5c82, 0xcf8a2b1c, + 0x79a792b4, 0x07f3f0f2, 0x694ea1e2, 0xda65cdf4, 0x0506d5be, + 0x34d11f62, 0xa6c48afe, 0x2e349d53, 0xf3a2a055, 0x8a0532e1, + 0xf6a475eb, 0x830b39ec, 0x6040aaef, 0x715e069f, 0x6ebd5110, + 0x213ef98a, 0xdd963d06, 0x3eddae05, 0xe64d46bd, 0x5491b58d, + 0xc471055d, 0x06046fd4, 0x5060ff15, 0x981924fb, 0xbdd697e9, + 0x4089cc43, 0xd967779e, 0xe8b0bd42, 0x8907888b, 0x19e7385b, + 0xc879dbee, 0x7ca1470a, 0x427ce90f, 0x84f8c91e, 0x00000000, + 0x80098386, 0x2b3248ed, 0x111eac70, 0x5a6c4e72, 0x0efdfbff, + 0x850f5638, 0xae3d1ed5, 0x2d362739, 0x0f0a64d9, 0x5c6821a6, + 0x5b9bd154, 0x36243a2e, 0x0a0cb167, 0x57930fe7, 0xeeb4d296, + 0x9b1b9e91, 0xc0804fc5, 0xdc61a220, 0x775a694b, 0x121c161a, + 0x93e20aba, 0xa0c0e52a, 0x223c43e0, 0x1b121d17, 0x090e0b0d, + 0x8bf2adc7, 0xb62db9a8, 0x1e14c8a9, 0xf1578519, 0x75af4c07, + 0x99eebbdd, 0x7fa3fd60, 0x01f79f26, 0x725cbcf5, 0x6644c53b, + 0xfb5b347e, 0x438b7629, 0x23cbdcc6, 0xedb668fc, 0xe4b863f1, + 0x31d7cadc, 0x63421085, 0x97134022, 0xc6842011, 0x4a857d24, + 0xbbd2f83d, 0xf9ae1132, 0x29c76da1, 0x9e1d4b2f, 0xb2dcf330, + 0x860dec52, 0xc177d0e3, 0xb32b6c16, 0x70a999b9, 0x9411fa48, + 0xe9472264, 0xfca8c48c, 0xf0a01a3f, 0x7d56d82c, 0x3322ef90, + 0x4987c74e, 0x38d9c1d1, 0xca8cfea2, 0xd498360b, 0xf5a6cf81, + 0x7aa528de, 0xb7da268e, 0xad3fa4bf, 0x3a2ce49d, 0x78500d92, + 0x5f6a9bcc, 0x7e546246, 0x8df6c213, 0xd890e8b8, 0x392e5ef7, + 0xc382f5af, 0x5d9fbe80, 0xd0697c93, 0xd56fa92d, 0x25cfb312, + 0xacc83b99, 0x1810a77d, 0x9ce86e63, 0x3bdb7bbb, 0x26cd0978, + 0x596ef418, 0x9aec01b7, 0x4f83a89a, 0x95e6656e, 0xffaa7ee6, + 0xbc2108cf, 0x15efe6e8, 0xe7bad99b, 0x6f4ace36, 0x9fead409, + 0xb029d67c, 0xa431afb2, 0x3f2a3123, 0xa5c63094, 0xa235c066, + 0x4e7437bc, 0x82fca6ca, 0x90e0b0d0, 0xa73315d8, 0x04f14a98, + 0xec41f7da, 0xcd7f0e50, 0x91172ff6, 0x4d768dd6, 0xef434db0, + 0xaacc544d, 0x96e4df04, 0xd19ee3b5, 0x6a4c1b88, 0x2cc1b81f, + 0x65467f51, 0x5e9d04ea, 0x8c015d35, 0x87fa7374, 0x0bfb2e41, + 0x67b35a1d, 0xdb9252d2, 0x10e93356, 0xd66d1347, 0xd79a8c61, + 0xa1377a0c, 0xf8598e14, 0x13eb893c, 0xa9ceee27, 0x61b735c9, + 0x1ce1ede5, 0x477a3cb1, 0xd29c59df, 0xf2553f73, 0x141879ce, + 0xc773bf37, 0xf753eacd, 0xfd5f5baa, 0x3ddf146f, 0x447886db, + 0xafca81f3, 0x68b93ec4, 0x24382c34, 0xa3c25f40, 0x1d1672c3, + 0xe2bc0c25, 0x3c288b49, 0x0dff4195, 0xa8397101, 0x0c08deb3, + 0xb4d89ce4, 0x566490c1, 0xcb7b6184, 0x32d570b6, 0x6c48745c, + 0xb8d04257}; + + private static final int[] Tinv3 = + { + 0x5150a7f4, 0x7e536541, 0x1ac3a417, 0x3a965e27, 0x3bcb6bab, + 0x1ff1459d, 0xacab58fa, 0x4b9303e3, 0x2055fa30, 0xadf66d76, + 0x889176cc, 0xf5254c02, 0x4ffcd7e5, 0xc5d7cb2a, 0x26804435, + 0xb58fa362, 0xde495ab1, 0x25671bba, 0x45980eea, 0x5de1c0fe, + 0xc302752f, 0x8112f04c, 0x8da39746, 0x6bc6f9d3, 0x03e75f8f, + 0x15959c92, 0xbfeb7a6d, 0x95da5952, 0xd42d83be, 0x58d32174, + 0x492969e0, 0x8e44c8c9, 0x756a89c2, 0xf478798e, 0x996b3e58, + 0x27dd71b9, 0xbeb64fe1, 0xf017ad88, 0xc966ac20, 0x7db43ace, + 0x63184adf, 0xe582311a, 0x97603351, 0x62457f53, 0xb1e07764, + 0xbb84ae6b, 0xfe1ca081, 0xf9942b08, 0x70586848, 0x8f19fd45, + 0x94876cde, 0x52b7f87b, 0xab23d373, 0x72e2024b, 0xe3578f1f, + 0x662aab55, 0xb20728eb, 0x2f03c2b5, 0x869a7bc5, 0xd3a50837, + 0x30f28728, 0x23b2a5bf, 0x02ba6a03, 0xed5c8216, 0x8a2b1ccf, + 0xa792b479, 0xf3f0f207, 0x4ea1e269, 0x65cdf4da, 0x06d5be05, + 0xd11f6234, 0xc48afea6, 0x349d532e, 0xa2a055f3, 0x0532e18a, + 0xa475ebf6, 0x0b39ec83, 0x40aaef60, 0x5e069f71, 0xbd51106e, + 0x3ef98a21, 0x963d06dd, 0xddae053e, 0x4d46bde6, 0x91b58d54, + 0x71055dc4, 0x046fd406, 0x60ff1550, 0x1924fb98, 0xd697e9bd, + 0x89cc4340, 0x67779ed9, 0xb0bd42e8, 0x07888b89, 0xe7385b19, + 0x79dbeec8, 0xa1470a7c, 0x7ce90f42, 0xf8c91e84, 0x00000000, + 0x09838680, 0x3248ed2b, 0x1eac7011, 0x6c4e725a, 0xfdfbff0e, + 0x0f563885, 0x3d1ed5ae, 0x3627392d, 0x0a64d90f, 0x6821a65c, + 0x9bd1545b, 0x243a2e36, 0x0cb1670a, 0x930fe757, 0xb4d296ee, + 0x1b9e919b, 0x804fc5c0, 0x61a220dc, 0x5a694b77, 0x1c161a12, + 0xe20aba93, 0xc0e52aa0, 0x3c43e022, 0x121d171b, 0x0e0b0d09, + 0xf2adc78b, 0x2db9a8b6, 0x14c8a91e, 0x578519f1, 0xaf4c0775, + 0xeebbdd99, 0xa3fd607f, 0xf79f2601, 0x5cbcf572, 0x44c53b66, + 0x5b347efb, 0x8b762943, 0xcbdcc623, 0xb668fced, 0xb863f1e4, + 0xd7cadc31, 0x42108563, 0x13402297, 0x842011c6, 0x857d244a, + 0xd2f83dbb, 0xae1132f9, 0xc76da129, 0x1d4b2f9e, 0xdcf330b2, + 0x0dec5286, 0x77d0e3c1, 0x2b6c16b3, 0xa999b970, 0x11fa4894, + 0x472264e9, 0xa8c48cfc, 0xa01a3ff0, 0x56d82c7d, 0x22ef9033, + 0x87c74e49, 0xd9c1d138, 0x8cfea2ca, 0x98360bd4, 0xa6cf81f5, + 0xa528de7a, 0xda268eb7, 0x3fa4bfad, 0x2ce49d3a, 0x500d9278, + 0x6a9bcc5f, 0x5462467e, 0xf6c2138d, 0x90e8b8d8, 0x2e5ef739, + 0x82f5afc3, 0x9fbe805d, 0x697c93d0, 0x6fa92dd5, 0xcfb31225, + 0xc83b99ac, 0x10a77d18, 0xe86e639c, 0xdb7bbb3b, 0xcd097826, + 0x6ef41859, 0xec01b79a, 0x83a89a4f, 0xe6656e95, 0xaa7ee6ff, + 0x2108cfbc, 0xefe6e815, 0xbad99be7, 0x4ace366f, 0xead4099f, + 0x29d67cb0, 0x31afb2a4, 0x2a31233f, 0xc63094a5, 0x35c066a2, + 0x7437bc4e, 0xfca6ca82, 0xe0b0d090, 0x3315d8a7, 0xf14a9804, + 0x41f7daec, 0x7f0e50cd, 0x172ff691, 0x768dd64d, 0x434db0ef, + 0xcc544daa, 0xe4df0496, 0x9ee3b5d1, 0x4c1b886a, 0xc1b81f2c, + 0x467f5165, 0x9d04ea5e, 0x015d358c, 0xfa737487, 0xfb2e410b, + 0xb35a1d67, 0x9252d2db, 0xe9335610, 0x6d1347d6, 0x9a8c61d7, + 0x377a0ca1, 0x598e14f8, 0xeb893c13, 0xceee27a9, 0xb735c961, + 0xe1ede51c, 0x7a3cb147, 0x9c59dfd2, 0x553f73f2, 0x1879ce14, + 0x73bf37c7, 0x53eacdf7, 0x5f5baafd, 0xdf146f3d, 0x7886db44, + 0xca81f3af, 0xb93ec468, 0x382c3424, 0xc25f40a3, 0x1672c31d, + 0xbc0c25e2, 0x288b493c, 0xff41950d, 0x397101a8, 0x08deb30c, + 0xd89ce4b4, 0x6490c156, 0x7b6184cb, 0xd570b632, 0x48745c6c, + 0xd04257b8}; + + private static int shift(int r, int shift) + { + return (r >>> shift) | (r << -shift); + } + + /* multiply four bytes in GF(2^8) by 'x' {02} in parallel */ + + private static final int m1 = 0x80808080; + private static final int m2 = 0x7f7f7f7f; + private static final int m3 = 0x0000001b; + + private static int FFmulX(int x) + { + return (((x & m2) << 1) ^ (((x & m1) >>> 7) * m3)); + } + + /* + The following defines provide alternative definitions of FFmulX that might + give improved performance if a fast 32-bit multiply is not available. + + private int FFmulX(int x) { int u = x & m1; u |= (u >> 1); return ((x & m2) << 1) ^ ((u >>> 3) | (u >>> 6)); } + private static final int m4 = 0x1b1b1b1b; + private int FFmulX(int x) { int u = x & m1; return ((x & m2) << 1) ^ ((u - (u >>> 7)) & m4); } + + */ + + private static int inv_mcol(int x) + { + int f2 = FFmulX(x); + int f4 = FFmulX(f2); + int f8 = FFmulX(f4); + int f9 = x ^ f8; + + return f2 ^ f4 ^ f8 ^ shift(f2 ^ f9, 8) ^ shift(f4 ^ f9, 16) ^ shift(f9, 24); + } + + + private static int subWord(int x) + { + return (S[x&255]&255 | ((S[(x>>8)&255]&255)<<8) | ((S[(x>>16)&255]&255)<<16) | S[(x>>24)&255]<<24); + } + + /** + * Calculate the necessary round keys + * The number of calculations depends on key size and block size + * AES specified a fixed block size of 128 bits and key sizes 128/192/256 bits + * This code is written assuming those are the only possible values + */ + private int[][] generateWorkingKey( + byte[] key, + boolean forEncryption) + { + int KC = key.length / 4; // key length in words + int t; + + if (((KC != 4) && (KC != 6) && (KC != 8)) || ((KC * 4) != key.length)) + { + throw new IllegalArgumentException("Key length not 128/192/256 bits."); + } + + ROUNDS = KC + 6; // This is not always true for the generalized Rijndael that allows larger block sizes + int[][] W = new int[ROUNDS+1][4]; // 4 words in a block + + // + // copy the key into the round key array + // + + t = 0; + int i = 0; + while (i < key.length) + { + W[t >> 2][t & 3] = (key[i]&0xff) | ((key[i+1]&0xff) << 8) | ((key[i+2]&0xff) << 16) | (key[i+3] << 24); + i+=4; + t++; + } + + // + // while not enough round key material calculated + // calculate new values + // + int k = (ROUNDS + 1) << 2; + for (i = KC; (i < k); i++) + { + int temp = W[(i - 1) >> 2][(i - 1) & 3]; + if ((i % KC) == 0) + { + temp = subWord(shift(temp, 8)) ^ rcon[(i / KC) - 1]; + } + else if ((KC > 6) && ((i % KC) == 4)) + { + temp = subWord(temp); + } + + W[i >> 2][i & 3] = W[(i - KC) >> 2][(i - KC) & 3] ^ temp; + } + + if (!forEncryption) + { + for (int j = 1; j < ROUNDS; j++) + { + for (i = 0; i < 4; i++) + { + W[j][i] = inv_mcol(W[j][i]); + } + } + } + + return W; + } + + private int ROUNDS; + private int[][] WorkingKey = null; + private int C0, C1, C2, C3; + private boolean forEncryption; + + private static final int BLOCK_SIZE = 16; + + /** + * default constructor - 128 bit block size. + */ + public AESFastEngine() + { + } + + /** + * initialise an AES cipher. + * + * @param forEncryption whether or not we are for encryption. + * @param params the parameters required to set up the cipher. + * @exception IllegalArgumentException if the params argument is + * inappropriate. + */ + public void init( + boolean forEncryption, + CipherParameters params) + { + if (params instanceof KeyParameter) + { + WorkingKey = generateWorkingKey(((KeyParameter)params).getKey(), forEncryption); + this.forEncryption = forEncryption; + return; + } + + throw new IllegalArgumentException("invalid parameter passed to AES init - " + params.getClass().getName()); + } + + public String getAlgorithmName() + { + return "AES"; + } + + public int getBlockSize() + { + return BLOCK_SIZE; + } + + public int processBlock( + byte[] in, + int inOff, + byte[] out, + int outOff) + { + if (WorkingKey == null) + { + throw new IllegalStateException("AES engine not initialised"); + } + + if ((inOff + (32 / 2)) > in.length) + { + throw new DataLengthException("input buffer too short"); + } + + if ((outOff + (32 / 2)) > out.length) + { + throw new DataLengthException("output buffer too short"); + } + + if (forEncryption) + { + unpackBlock(in, inOff); + encryptBlock(WorkingKey); + packBlock(out, outOff); + } + else + { + unpackBlock(in, inOff); + decryptBlock(WorkingKey); + packBlock(out, outOff); + } + + return BLOCK_SIZE; + } + + public void reset() + { + } + + private void unpackBlock( + byte[] bytes, + int off) + { + int index = off; + + C0 = (bytes[index++] & 0xff); + C0 |= (bytes[index++] & 0xff) << 8; + C0 |= (bytes[index++] & 0xff) << 16; + C0 |= bytes[index++] << 24; + + C1 = (bytes[index++] & 0xff); + C1 |= (bytes[index++] & 0xff) << 8; + C1 |= (bytes[index++] & 0xff) << 16; + C1 |= bytes[index++] << 24; + + C2 = (bytes[index++] & 0xff); + C2 |= (bytes[index++] & 0xff) << 8; + C2 |= (bytes[index++] & 0xff) << 16; + C2 |= bytes[index++] << 24; + + C3 = (bytes[index++] & 0xff); + C3 |= (bytes[index++] & 0xff) << 8; + C3 |= (bytes[index++] & 0xff) << 16; + C3 |= bytes[index++] << 24; + } + + private void packBlock( + byte[] bytes, + int off) + { + int index = off; + + bytes[index++] = (byte)C0; + bytes[index++] = (byte)(C0 >> 8); + bytes[index++] = (byte)(C0 >> 16); + bytes[index++] = (byte)(C0 >> 24); + + bytes[index++] = (byte)C1; + bytes[index++] = (byte)(C1 >> 8); + bytes[index++] = (byte)(C1 >> 16); + bytes[index++] = (byte)(C1 >> 24); + + bytes[index++] = (byte)C2; + bytes[index++] = (byte)(C2 >> 8); + bytes[index++] = (byte)(C2 >> 16); + bytes[index++] = (byte)(C2 >> 24); + + bytes[index++] = (byte)C3; + bytes[index++] = (byte)(C3 >> 8); + bytes[index++] = (byte)(C3 >> 16); + bytes[index++] = (byte)(C3 >> 24); + } + + private void encryptBlock(int[][] KW) + { + int r, r0, r1, r2, r3; + + C0 ^= KW[0][0]; + C1 ^= KW[0][1]; + C2 ^= KW[0][2]; + C3 ^= KW[0][3]; + + r = 1; + while (r < ROUNDS - 1) + { + r0 = T0[C0&255] ^ T1[(C1>>8)&255] ^ T2[(C2>>16)&255] ^ T3[(C3>>24)&255] ^ KW[r][0]; + r1 = T0[C1&255] ^ T1[(C2>>8)&255] ^ T2[(C3>>16)&255] ^ T3[(C0>>24)&255] ^ KW[r][1]; + r2 = T0[C2&255] ^ T1[(C3>>8)&255] ^ T2[(C0>>16)&255] ^ T3[(C1>>24)&255] ^ KW[r][2]; + r3 = T0[C3&255] ^ T1[(C0>>8)&255] ^ T2[(C1>>16)&255] ^ T3[(C2>>24)&255] ^ KW[r++][3]; + C0 = T0[r0&255] ^ T1[(r1>>8)&255] ^ T2[(r2>>16)&255] ^ T3[(r3>>24)&255] ^ KW[r][0]; + C1 = T0[r1&255] ^ T1[(r2>>8)&255] ^ T2[(r3>>16)&255] ^ T3[(r0>>24)&255] ^ KW[r][1]; + C2 = T0[r2&255] ^ T1[(r3>>8)&255] ^ T2[(r0>>16)&255] ^ T3[(r1>>24)&255] ^ KW[r][2]; + C3 = T0[r3&255] ^ T1[(r0>>8)&255] ^ T2[(r1>>16)&255] ^ T3[(r2>>24)&255] ^ KW[r++][3]; + } + + r0 = T0[C0&255] ^ T1[(C1>>8)&255] ^ T2[(C2>>16)&255] ^ T3[(C3>>24)&255] ^ KW[r][0]; + r1 = T0[C1&255] ^ T1[(C2>>8)&255] ^ T2[(C3>>16)&255] ^ T3[(C0>>24)&255] ^ KW[r][1]; + r2 = T0[C2&255] ^ T1[(C3>>8)&255] ^ T2[(C0>>16)&255] ^ T3[(C1>>24)&255] ^ KW[r][2]; + r3 = T0[C3&255] ^ T1[(C0>>8)&255] ^ T2[(C1>>16)&255] ^ T3[(C2>>24)&255] ^ KW[r++][3]; + + // the final round's table is a simple function of S so we don't use a whole other four tables for it + + C0 = (S[r0&255]&255) ^ ((S[(r1>>8)&255]&255)<<8) ^ ((S[(r2>>16)&255]&255)<<16) ^ (S[(r3>>24)&255]<<24) ^ KW[r][0]; + C1 = (S[r1&255]&255) ^ ((S[(r2>>8)&255]&255)<<8) ^ ((S[(r3>>16)&255]&255)<<16) ^ (S[(r0>>24)&255]<<24) ^ KW[r][1]; + C2 = (S[r2&255]&255) ^ ((S[(r3>>8)&255]&255)<<8) ^ ((S[(r0>>16)&255]&255)<<16) ^ (S[(r1>>24)&255]<<24) ^ KW[r][2]; + C3 = (S[r3&255]&255) ^ ((S[(r0>>8)&255]&255)<<8) ^ ((S[(r1>>16)&255]&255)<<16) ^ (S[(r2>>24)&255]<<24) ^ KW[r][3]; + + } + + private void decryptBlock(int[][] KW) + { + int r0, r1, r2, r3; + + C0 ^= KW[ROUNDS][0]; + C1 ^= KW[ROUNDS][1]; + C2 ^= KW[ROUNDS][2]; + C3 ^= KW[ROUNDS][3]; + + int r = ROUNDS-1; + + while (r>1) + { + r0 = Tinv0[C0&255] ^ Tinv1[(C3>>8)&255] ^ Tinv2[(C2>>16)&255] ^ Tinv3[(C1>>24)&255] ^ KW[r][0]; + r1 = Tinv0[C1&255] ^ Tinv1[(C0>>8)&255] ^ Tinv2[(C3>>16)&255] ^ Tinv3[(C2>>24)&255] ^ KW[r][1]; + r2 = Tinv0[C2&255] ^ Tinv1[(C1>>8)&255] ^ Tinv2[(C0>>16)&255] ^ Tinv3[(C3>>24)&255] ^ KW[r][2]; + r3 = Tinv0[C3&255] ^ Tinv1[(C2>>8)&255] ^ Tinv2[(C1>>16)&255] ^ Tinv3[(C0>>24)&255] ^ KW[r--][3]; + C0 = Tinv0[r0&255] ^ Tinv1[(r3>>8)&255] ^ Tinv2[(r2>>16)&255] ^ Tinv3[(r1>>24)&255] ^ KW[r][0]; + C1 = Tinv0[r1&255] ^ Tinv1[(r0>>8)&255] ^ Tinv2[(r3>>16)&255] ^ Tinv3[(r2>>24)&255] ^ KW[r][1]; + C2 = Tinv0[r2&255] ^ Tinv1[(r1>>8)&255] ^ Tinv2[(r0>>16)&255] ^ Tinv3[(r3>>24)&255] ^ KW[r][2]; + C3 = Tinv0[r3&255] ^ Tinv1[(r2>>8)&255] ^ Tinv2[(r1>>16)&255] ^ Tinv3[(r0>>24)&255] ^ KW[r--][3]; + } + + r0 = Tinv0[C0&255] ^ Tinv1[(C3>>8)&255] ^ Tinv2[(C2>>16)&255] ^ Tinv3[(C1>>24)&255] ^ KW[r][0]; + r1 = Tinv0[C1&255] ^ Tinv1[(C0>>8)&255] ^ Tinv2[(C3>>16)&255] ^ Tinv3[(C2>>24)&255] ^ KW[r][1]; + r2 = Tinv0[C2&255] ^ Tinv1[(C1>>8)&255] ^ Tinv2[(C0>>16)&255] ^ Tinv3[(C3>>24)&255] ^ KW[r][2]; + r3 = Tinv0[C3&255] ^ Tinv1[(C2>>8)&255] ^ Tinv2[(C1>>16)&255] ^ Tinv3[(C0>>24)&255] ^ KW[r][3]; + + // the final round's table is a simple function of Si so we don't use a whole other four tables for it + + C0 = (Si[r0&255]&255) ^ ((Si[(r3>>8)&255]&255)<<8) ^ ((Si[(r2>>16)&255]&255)<<16) ^ (Si[(r1>>24)&255]<<24) ^ KW[0][0]; + C1 = (Si[r1&255]&255) ^ ((Si[(r0>>8)&255]&255)<<8) ^ ((Si[(r3>>16)&255]&255)<<16) ^ (Si[(r2>>24)&255]<<24) ^ KW[0][1]; + C2 = (Si[r2&255]&255) ^ ((Si[(r1>>8)&255]&255)<<8) ^ ((Si[(r0>>16)&255]&255)<<16) ^ (Si[(r3>>24)&255]<<24) ^ KW[0][2]; + C3 = (Si[r3&255]&255) ^ ((Si[(r2>>8)&255]&255)<<8) ^ ((Si[(r1>>16)&255]&255)<<16) ^ (Si[(r0>>24)&255]<<24) ^ KW[0][3]; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/AESLightEngine.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/AESLightEngine.java new file mode 100644 index 0000000..9b43a81 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/AESLightEngine.java @@ -0,0 +1,438 @@ +package org.bc.crypto.engines; + +import org.bc.crypto.BlockCipher; +import org.bc.crypto.CipherParameters; +import org.bc.crypto.DataLengthException; +import org.bc.crypto.params.KeyParameter; + +/** + * an implementation of the AES (Rijndael), from FIPS-197. + *
+ * For further details see: http://csrc.nist.gov/encryption/aes/. + * + * This implementation is based on optimizations from Dr. Brian Gladman's paper and C code at + * http://fp.gladman.plus.com/cryptography_technology/rijndael/ + * + * There are three levels of tradeoff of speed vs memory + * Because java has no preprocessor, they are written as three separate classes from which to choose + * + * The fastest uses 8Kbytes of static tables to precompute round calculations, 4 256 word tables for encryption + * and 4 for decryption. + * + * The middle performance version uses only one 256 word table for each, for a total of 2Kbytes, + * adding 12 rotate operations per round to compute the values contained in the other tables from + * the contents of the first + * + * The slowest version uses no static tables at all and computes the values + * in each round. + *
+ * This file contains the slowest performance version with no static tables + * for round precomputation, but it has the smallest foot print. + * + */ +public class AESLightEngine + implements BlockCipher +{ + // The S box + private static final byte[] S = { + (byte)99, (byte)124, (byte)119, (byte)123, (byte)242, (byte)107, (byte)111, (byte)197, + (byte)48, (byte)1, (byte)103, (byte)43, (byte)254, (byte)215, (byte)171, (byte)118, + (byte)202, (byte)130, (byte)201, (byte)125, (byte)250, (byte)89, (byte)71, (byte)240, + (byte)173, (byte)212, (byte)162, (byte)175, (byte)156, (byte)164, (byte)114, (byte)192, + (byte)183, (byte)253, (byte)147, (byte)38, (byte)54, (byte)63, (byte)247, (byte)204, + (byte)52, (byte)165, (byte)229, (byte)241, (byte)113, (byte)216, (byte)49, (byte)21, + (byte)4, (byte)199, (byte)35, (byte)195, (byte)24, (byte)150, (byte)5, (byte)154, + (byte)7, (byte)18, (byte)128, (byte)226, (byte)235, (byte)39, (byte)178, (byte)117, + (byte)9, (byte)131, (byte)44, (byte)26, (byte)27, (byte)110, (byte)90, (byte)160, + (byte)82, (byte)59, (byte)214, (byte)179, (byte)41, (byte)227, (byte)47, (byte)132, + (byte)83, (byte)209, (byte)0, (byte)237, (byte)32, (byte)252, (byte)177, (byte)91, + (byte)106, (byte)203, (byte)190, (byte)57, (byte)74, (byte)76, (byte)88, (byte)207, + (byte)208, (byte)239, (byte)170, (byte)251, (byte)67, (byte)77, (byte)51, (byte)133, + (byte)69, (byte)249, (byte)2, (byte)127, (byte)80, (byte)60, (byte)159, (byte)168, + (byte)81, (byte)163, (byte)64, (byte)143, (byte)146, (byte)157, (byte)56, (byte)245, + (byte)188, (byte)182, (byte)218, (byte)33, (byte)16, (byte)255, (byte)243, (byte)210, + (byte)205, (byte)12, (byte)19, (byte)236, (byte)95, (byte)151, (byte)68, (byte)23, + (byte)196, (byte)167, (byte)126, (byte)61, (byte)100, (byte)93, (byte)25, (byte)115, + (byte)96, (byte)129, (byte)79, (byte)220, (byte)34, (byte)42, (byte)144, (byte)136, + (byte)70, (byte)238, (byte)184, (byte)20, (byte)222, (byte)94, (byte)11, (byte)219, + (byte)224, (byte)50, (byte)58, (byte)10, (byte)73, (byte)6, (byte)36, (byte)92, + (byte)194, (byte)211, (byte)172, (byte)98, (byte)145, (byte)149, (byte)228, (byte)121, + (byte)231, (byte)200, (byte)55, (byte)109, (byte)141, (byte)213, (byte)78, (byte)169, + (byte)108, (byte)86, (byte)244, (byte)234, (byte)101, (byte)122, (byte)174, (byte)8, + (byte)186, (byte)120, (byte)37, (byte)46, (byte)28, (byte)166, (byte)180, (byte)198, + (byte)232, (byte)221, (byte)116, (byte)31, (byte)75, (byte)189, (byte)139, (byte)138, + (byte)112, (byte)62, (byte)181, (byte)102, (byte)72, (byte)3, (byte)246, (byte)14, + (byte)97, (byte)53, (byte)87, (byte)185, (byte)134, (byte)193, (byte)29, (byte)158, + (byte)225, (byte)248, (byte)152, (byte)17, (byte)105, (byte)217, (byte)142, (byte)148, + (byte)155, (byte)30, (byte)135, (byte)233, (byte)206, (byte)85, (byte)40, (byte)223, + (byte)140, (byte)161, (byte)137, (byte)13, (byte)191, (byte)230, (byte)66, (byte)104, + (byte)65, (byte)153, (byte)45, (byte)15, (byte)176, (byte)84, (byte)187, (byte)22, + }; + + // The inverse S-box + private static final byte[] Si = { + (byte)82, (byte)9, (byte)106, (byte)213, (byte)48, (byte)54, (byte)165, (byte)56, + (byte)191, (byte)64, (byte)163, (byte)158, (byte)129, (byte)243, (byte)215, (byte)251, + (byte)124, (byte)227, (byte)57, (byte)130, (byte)155, (byte)47, (byte)255, (byte)135, + (byte)52, (byte)142, (byte)67, (byte)68, (byte)196, (byte)222, (byte)233, (byte)203, + (byte)84, (byte)123, (byte)148, (byte)50, (byte)166, (byte)194, (byte)35, (byte)61, + (byte)238, (byte)76, (byte)149, (byte)11, (byte)66, (byte)250, (byte)195, (byte)78, + (byte)8, (byte)46, (byte)161, (byte)102, (byte)40, (byte)217, (byte)36, (byte)178, + (byte)118, (byte)91, (byte)162, (byte)73, (byte)109, (byte)139, (byte)209, (byte)37, + (byte)114, (byte)248, (byte)246, (byte)100, (byte)134, (byte)104, (byte)152, (byte)22, + (byte)212, (byte)164, (byte)92, (byte)204, (byte)93, (byte)101, (byte)182, (byte)146, + (byte)108, (byte)112, (byte)72, (byte)80, (byte)253, (byte)237, (byte)185, (byte)218, + (byte)94, (byte)21, (byte)70, (byte)87, (byte)167, (byte)141, (byte)157, (byte)132, + (byte)144, (byte)216, (byte)171, (byte)0, (byte)140, (byte)188, (byte)211, (byte)10, + (byte)247, (byte)228, (byte)88, (byte)5, (byte)184, (byte)179, (byte)69, (byte)6, + (byte)208, (byte)44, (byte)30, (byte)143, (byte)202, (byte)63, (byte)15, (byte)2, + (byte)193, (byte)175, (byte)189, (byte)3, (byte)1, (byte)19, (byte)138, (byte)107, + (byte)58, (byte)145, (byte)17, (byte)65, (byte)79, (byte)103, (byte)220, (byte)234, + (byte)151, (byte)242, (byte)207, (byte)206, (byte)240, (byte)180, (byte)230, (byte)115, + (byte)150, (byte)172, (byte)116, (byte)34, (byte)231, (byte)173, (byte)53, (byte)133, + (byte)226, (byte)249, (byte)55, (byte)232, (byte)28, (byte)117, (byte)223, (byte)110, + (byte)71, (byte)241, (byte)26, (byte)113, (byte)29, (byte)41, (byte)197, (byte)137, + (byte)111, (byte)183, (byte)98, (byte)14, (byte)170, (byte)24, (byte)190, (byte)27, + (byte)252, (byte)86, (byte)62, (byte)75, (byte)198, (byte)210, (byte)121, (byte)32, + (byte)154, (byte)219, (byte)192, (byte)254, (byte)120, (byte)205, (byte)90, (byte)244, + (byte)31, (byte)221, (byte)168, (byte)51, (byte)136, (byte)7, (byte)199, (byte)49, + (byte)177, (byte)18, (byte)16, (byte)89, (byte)39, (byte)128, (byte)236, (byte)95, + (byte)96, (byte)81, (byte)127, (byte)169, (byte)25, (byte)181, (byte)74, (byte)13, + (byte)45, (byte)229, (byte)122, (byte)159, (byte)147, (byte)201, (byte)156, (byte)239, + (byte)160, (byte)224, (byte)59, (byte)77, (byte)174, (byte)42, (byte)245, (byte)176, + (byte)200, (byte)235, (byte)187, (byte)60, (byte)131, (byte)83, (byte)153, (byte)97, + (byte)23, (byte)43, (byte)4, (byte)126, (byte)186, (byte)119, (byte)214, (byte)38, + (byte)225, (byte)105, (byte)20, (byte)99, (byte)85, (byte)33, (byte)12, (byte)125, + }; + + // vector used in calculating key schedule (powers of x in GF(256)) + private static final int[] rcon = { + 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, + 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91 }; + + private static int shift(int r, int shift) + { + return (r >>> shift) | (r << -shift); + } + + /* multiply four bytes in GF(2^8) by 'x' {02} in parallel */ + + private static final int m1 = 0x80808080; + private static final int m2 = 0x7f7f7f7f; + private static final int m3 = 0x0000001b; + + private static int FFmulX(int x) + { + return (((x & m2) << 1) ^ (((x & m1) >>> 7) * m3)); + } + + /* + The following defines provide alternative definitions of FFmulX that might + give improved performance if a fast 32-bit multiply is not available. + + private int FFmulX(int x) { int u = x & m1; u |= (u >> 1); return ((x & m2) << 1) ^ ((u >>> 3) | (u >>> 6)); } + private static final int m4 = 0x1b1b1b1b; + private int FFmulX(int x) { int u = x & m1; return ((x & m2) << 1) ^ ((u - (u >>> 7)) & m4); } + + */ + + private static int mcol(int x) + { + int f2 = FFmulX(x); + return f2 ^ shift(x ^ f2, 8) ^ shift(x, 16) ^ shift(x, 24); + } + + private static int inv_mcol(int x) + { + int f2 = FFmulX(x); + int f4 = FFmulX(f2); + int f8 = FFmulX(f4); + int f9 = x ^ f8; + + return f2 ^ f4 ^ f8 ^ shift(f2 ^ f9, 8) ^ shift(f4 ^ f9, 16) ^ shift(f9, 24); + } + + + private static int subWord(int x) + { + return (S[x&255]&255 | ((S[(x>>8)&255]&255)<<8) | ((S[(x>>16)&255]&255)<<16) | S[(x>>24)&255]<<24); + } + + /** + * Calculate the necessary round keys + * The number of calculations depends on key size and block size + * AES specified a fixed block size of 128 bits and key sizes 128/192/256 bits + * This code is written assuming those are the only possible values + */ + private int[][] generateWorkingKey( + byte[] key, + boolean forEncryption) + { + int KC = key.length / 4; // key length in words + int t; + + if (((KC != 4) && (KC != 6) && (KC != 8)) || ((KC * 4) != key.length)) + { + throw new IllegalArgumentException("Key length not 128/192/256 bits."); + } + + ROUNDS = KC + 6; // This is not always true for the generalized Rijndael that allows larger block sizes + int[][] W = new int[ROUNDS+1][4]; // 4 words in a block + + // + // copy the key into the round key array + // + + t = 0; + int i = 0; + while (i < key.length) + { + W[t >> 2][t & 3] = (key[i]&0xff) | ((key[i+1]&0xff) << 8) | ((key[i+2]&0xff) << 16) | (key[i+3] << 24); + i+=4; + t++; + } + + // + // while not enough round key material calculated + // calculate new values + // + int k = (ROUNDS + 1) << 2; + for (i = KC; (i < k); i++) + { + int temp = W[(i-1)>>2][(i-1)&3]; + if ((i % KC) == 0) + { + temp = subWord(shift(temp, 8)) ^ rcon[(i / KC)-1]; + } + else if ((KC > 6) && ((i % KC) == 4)) + { + temp = subWord(temp); + } + + W[i>>2][i&3] = W[(i - KC)>>2][(i-KC)&3] ^ temp; + } + + if (!forEncryption) + { + for (int j = 1; j < ROUNDS; j++) + { + for (i = 0; i < 4; i++) + { + W[j][i] = inv_mcol(W[j][i]); + } + } + } + + return W; + } + + private int ROUNDS; + private int[][] WorkingKey = null; + private int C0, C1, C2, C3; + private boolean forEncryption; + + private static final int BLOCK_SIZE = 16; + + /** + * default constructor - 128 bit block size. + */ + public AESLightEngine() + { + } + + /** + * initialise an AES cipher. + * + * @param forEncryption whether or not we are for encryption. + * @param params the parameters required to set up the cipher. + * @exception IllegalArgumentException if the params argument is + * inappropriate. + */ + public void init( + boolean forEncryption, + CipherParameters params) + { + if (params instanceof KeyParameter) + { + WorkingKey = generateWorkingKey(((KeyParameter)params).getKey(), forEncryption); + this.forEncryption = forEncryption; + return; + } + + throw new IllegalArgumentException("invalid parameter passed to AES init - " + params.getClass().getName()); + } + + public String getAlgorithmName() + { + return "AES"; + } + + public int getBlockSize() + { + return BLOCK_SIZE; + } + + public int processBlock( + byte[] in, + int inOff, + byte[] out, + int outOff) + { + if (WorkingKey == null) + { + throw new IllegalStateException("AES engine not initialised"); + } + + if ((inOff + (32 / 2)) > in.length) + { + throw new DataLengthException("input buffer too short"); + } + + if ((outOff + (32 / 2)) > out.length) + { + throw new DataLengthException("output buffer too short"); + } + + if (forEncryption) + { + unpackBlock(in, inOff); + encryptBlock(WorkingKey); + packBlock(out, outOff); + } + else + { + unpackBlock(in, inOff); + decryptBlock(WorkingKey); + packBlock(out, outOff); + } + + return BLOCK_SIZE; + } + + public void reset() + { + } + + private void unpackBlock( + byte[] bytes, + int off) + { + int index = off; + + C0 = (bytes[index++] & 0xff); + C0 |= (bytes[index++] & 0xff) << 8; + C0 |= (bytes[index++] & 0xff) << 16; + C0 |= bytes[index++] << 24; + + C1 = (bytes[index++] & 0xff); + C1 |= (bytes[index++] & 0xff) << 8; + C1 |= (bytes[index++] & 0xff) << 16; + C1 |= bytes[index++] << 24; + + C2 = (bytes[index++] & 0xff); + C2 |= (bytes[index++] & 0xff) << 8; + C2 |= (bytes[index++] & 0xff) << 16; + C2 |= bytes[index++] << 24; + + C3 = (bytes[index++] & 0xff); + C3 |= (bytes[index++] & 0xff) << 8; + C3 |= (bytes[index++] & 0xff) << 16; + C3 |= bytes[index++] << 24; + } + + private void packBlock( + byte[] bytes, + int off) + { + int index = off; + + bytes[index++] = (byte)C0; + bytes[index++] = (byte)(C0 >> 8); + bytes[index++] = (byte)(C0 >> 16); + bytes[index++] = (byte)(C0 >> 24); + + bytes[index++] = (byte)C1; + bytes[index++] = (byte)(C1 >> 8); + bytes[index++] = (byte)(C1 >> 16); + bytes[index++] = (byte)(C1 >> 24); + + bytes[index++] = (byte)C2; + bytes[index++] = (byte)(C2 >> 8); + bytes[index++] = (byte)(C2 >> 16); + bytes[index++] = (byte)(C2 >> 24); + + bytes[index++] = (byte)C3; + bytes[index++] = (byte)(C3 >> 8); + bytes[index++] = (byte)(C3 >> 16); + bytes[index++] = (byte)(C3 >> 24); + } + + private void encryptBlock(int[][] KW) + { + int r, r0, r1, r2, r3; + + C0 ^= KW[0][0]; + C1 ^= KW[0][1]; + C2 ^= KW[0][2]; + C3 ^= KW[0][3]; + + for (r = 1; r < ROUNDS - 1;) + { + r0 = mcol((S[C0&255]&255) ^ ((S[(C1>>8)&255]&255)<<8) ^ ((S[(C2>>16)&255]&255)<<16) ^ (S[(C3>>24)&255]<<24)) ^ KW[r][0]; + r1 = mcol((S[C1&255]&255) ^ ((S[(C2>>8)&255]&255)<<8) ^ ((S[(C3>>16)&255]&255)<<16) ^ (S[(C0>>24)&255]<<24)) ^ KW[r][1]; + r2 = mcol((S[C2&255]&255) ^ ((S[(C3>>8)&255]&255)<<8) ^ ((S[(C0>>16)&255]&255)<<16) ^ (S[(C1>>24)&255]<<24)) ^ KW[r][2]; + r3 = mcol((S[C3&255]&255) ^ ((S[(C0>>8)&255]&255)<<8) ^ ((S[(C1>>16)&255]&255)<<16) ^ (S[(C2>>24)&255]<<24)) ^ KW[r++][3]; + C0 = mcol((S[r0&255]&255) ^ ((S[(r1>>8)&255]&255)<<8) ^ ((S[(r2>>16)&255]&255)<<16) ^ (S[(r3>>24)&255]<<24)) ^ KW[r][0]; + C1 = mcol((S[r1&255]&255) ^ ((S[(r2>>8)&255]&255)<<8) ^ ((S[(r3>>16)&255]&255)<<16) ^ (S[(r0>>24)&255]<<24)) ^ KW[r][1]; + C2 = mcol((S[r2&255]&255) ^ ((S[(r3>>8)&255]&255)<<8) ^ ((S[(r0>>16)&255]&255)<<16) ^ (S[(r1>>24)&255]<<24)) ^ KW[r][2]; + C3 = mcol((S[r3&255]&255) ^ ((S[(r0>>8)&255]&255)<<8) ^ ((S[(r1>>16)&255]&255)<<16) ^ (S[(r2>>24)&255]<<24)) ^ KW[r++][3]; + } + + r0 = mcol((S[C0&255]&255) ^ ((S[(C1>>8)&255]&255)<<8) ^ ((S[(C2>>16)&255]&255)<<16) ^ (S[(C3>>24)&255]<<24)) ^ KW[r][0]; + r1 = mcol((S[C1&255]&255) ^ ((S[(C2>>8)&255]&255)<<8) ^ ((S[(C3>>16)&255]&255)<<16) ^ (S[(C0>>24)&255]<<24)) ^ KW[r][1]; + r2 = mcol((S[C2&255]&255) ^ ((S[(C3>>8)&255]&255)<<8) ^ ((S[(C0>>16)&255]&255)<<16) ^ (S[(C1>>24)&255]<<24)) ^ KW[r][2]; + r3 = mcol((S[C3&255]&255) ^ ((S[(C0>>8)&255]&255)<<8) ^ ((S[(C1>>16)&255]&255)<<16) ^ (S[(C2>>24)&255]<<24)) ^ KW[r++][3]; + + // the final round is a simple function of S + + C0 = (S[r0&255]&255) ^ ((S[(r1>>8)&255]&255)<<8) ^ ((S[(r2>>16)&255]&255)<<16) ^ (S[(r3>>24)&255]<<24) ^ KW[r][0]; + C1 = (S[r1&255]&255) ^ ((S[(r2>>8)&255]&255)<<8) ^ ((S[(r3>>16)&255]&255)<<16) ^ (S[(r0>>24)&255]<<24) ^ KW[r][1]; + C2 = (S[r2&255]&255) ^ ((S[(r3>>8)&255]&255)<<8) ^ ((S[(r0>>16)&255]&255)<<16) ^ (S[(r1>>24)&255]<<24) ^ KW[r][2]; + C3 = (S[r3&255]&255) ^ ((S[(r0>>8)&255]&255)<<8) ^ ((S[(r1>>16)&255]&255)<<16) ^ (S[(r2>>24)&255]<<24) ^ KW[r][3]; + + } + + private void decryptBlock(int[][] KW) + { + int r, r0, r1, r2, r3; + + C0 ^= KW[ROUNDS][0]; + C1 ^= KW[ROUNDS][1]; + C2 ^= KW[ROUNDS][2]; + C3 ^= KW[ROUNDS][3]; + + for (r = ROUNDS-1; r>1;) + { + r0 = inv_mcol((Si[C0&255]&255) ^ ((Si[(C3>>8)&255]&255)<<8) ^ ((Si[(C2>>16)&255]&255)<<16) ^ (Si[(C1>>24)&255]<<24)) ^ KW[r][0]; + r1 = inv_mcol((Si[C1&255]&255) ^ ((Si[(C0>>8)&255]&255)<<8) ^ ((Si[(C3>>16)&255]&255)<<16) ^ (Si[(C2>>24)&255]<<24)) ^ KW[r][1]; + r2 = inv_mcol((Si[C2&255]&255) ^ ((Si[(C1>>8)&255]&255)<<8) ^ ((Si[(C0>>16)&255]&255)<<16) ^ (Si[(C3>>24)&255]<<24)) ^ KW[r][2]; + r3 = inv_mcol((Si[C3&255]&255) ^ ((Si[(C2>>8)&255]&255)<<8) ^ ((Si[(C1>>16)&255]&255)<<16) ^ (Si[(C0>>24)&255]<<24)) ^ KW[r--][3]; + C0 = inv_mcol((Si[r0&255]&255) ^ ((Si[(r3>>8)&255]&255)<<8) ^ ((Si[(r2>>16)&255]&255)<<16) ^ (Si[(r1>>24)&255]<<24)) ^ KW[r][0]; + C1 = inv_mcol((Si[r1&255]&255) ^ ((Si[(r0>>8)&255]&255)<<8) ^ ((Si[(r3>>16)&255]&255)<<16) ^ (Si[(r2>>24)&255]<<24)) ^ KW[r][1]; + C2 = inv_mcol((Si[r2&255]&255) ^ ((Si[(r1>>8)&255]&255)<<8) ^ ((Si[(r0>>16)&255]&255)<<16) ^ (Si[(r3>>24)&255]<<24)) ^ KW[r][2]; + C3 = inv_mcol((Si[r3&255]&255) ^ ((Si[(r2>>8)&255]&255)<<8) ^ ((Si[(r1>>16)&255]&255)<<16) ^ (Si[(r0>>24)&255]<<24)) ^ KW[r--][3]; + } + + r0 = inv_mcol((Si[C0&255]&255) ^ ((Si[(C3>>8)&255]&255)<<8) ^ ((Si[(C2>>16)&255]&255)<<16) ^ (Si[(C1>>24)&255]<<24)) ^ KW[r][0]; + r1 = inv_mcol((Si[C1&255]&255) ^ ((Si[(C0>>8)&255]&255)<<8) ^ ((Si[(C3>>16)&255]&255)<<16) ^ (Si[(C2>>24)&255]<<24)) ^ KW[r][1]; + r2 = inv_mcol((Si[C2&255]&255) ^ ((Si[(C1>>8)&255]&255)<<8) ^ ((Si[(C0>>16)&255]&255)<<16) ^ (Si[(C3>>24)&255]<<24)) ^ KW[r][2]; + r3 = inv_mcol((Si[C3&255]&255) ^ ((Si[(C2>>8)&255]&255)<<8) ^ ((Si[(C1>>16)&255]&255)<<16) ^ (Si[(C0>>24)&255]<<24)) ^ KW[r][3]; + + // the final round's table is a simple function of Si + + C0 = (Si[r0&255]&255) ^ ((Si[(r3>>8)&255]&255)<<8) ^ ((Si[(r2>>16)&255]&255)<<16) ^ (Si[(r1>>24)&255]<<24) ^ KW[0][0]; + C1 = (Si[r1&255]&255) ^ ((Si[(r0>>8)&255]&255)<<8) ^ ((Si[(r3>>16)&255]&255)<<16) ^ (Si[(r2>>24)&255]<<24) ^ KW[0][1]; + C2 = (Si[r2&255]&255) ^ ((Si[(r1>>8)&255]&255)<<8) ^ ((Si[(r0>>16)&255]&255)<<16) ^ (Si[(r3>>24)&255]<<24) ^ KW[0][2]; + C3 = (Si[r3&255]&255) ^ ((Si[(r2>>8)&255]&255)<<8) ^ ((Si[(r1>>16)&255]&255)<<16) ^ (Si[(r0>>24)&255]<<24) ^ KW[0][3]; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/AESWrapEngine.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/AESWrapEngine.java new file mode 100644 index 0000000..f4cd8ee --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/AESWrapEngine.java @@ -0,0 +1,16 @@ +package org.bc.crypto.engines; + +/** + * an implementation of the AES Key Wrapper from the NIST Key Wrap + * Specification. + *
+ * For further details see: http://csrc.nist.gov/encryption/kms/key-wrap.pdf. + */ +public class AESWrapEngine + extends RFC3394WrapEngine +{ + public AESWrapEngine() + { + super(new AESEngine()); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/BlowfishEngine.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/BlowfishEngine.java new file mode 100644 index 0000000..4018a38 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/BlowfishEngine.java @@ -0,0 +1,576 @@ +package org.bc.crypto.engines; + +import org.bc.crypto.BlockCipher; +import org.bc.crypto.CipherParameters; +import org.bc.crypto.DataLengthException; +import org.bc.crypto.params.KeyParameter; + +/** + * A class that provides Blowfish key encryption operations, + * such as encoding data and generating keys. + * All the algorithms herein are from Applied Cryptography + * and implement a simplified cryptography interface. + */ +public final class BlowfishEngine +implements BlockCipher +{ + private final static int[] + KP = { + 0x243F6A88, 0x85A308D3, 0x13198A2E, 0x03707344, + 0xA4093822, 0x299F31D0, 0x082EFA98, 0xEC4E6C89, + 0x452821E6, 0x38D01377, 0xBE5466CF, 0x34E90C6C, + 0xC0AC29B7, 0xC97C50DD, 0x3F84D5B5, 0xB5470917, + 0x9216D5D9, 0x8979FB1B + }, + + KS0 = { + 0xD1310BA6, 0x98DFB5AC, 0x2FFD72DB, 0xD01ADFB7, + 0xB8E1AFED, 0x6A267E96, 0xBA7C9045, 0xF12C7F99, + 0x24A19947, 0xB3916CF7, 0x0801F2E2, 0x858EFC16, + 0x636920D8, 0x71574E69, 0xA458FEA3, 0xF4933D7E, + 0x0D95748F, 0x728EB658, 0x718BCD58, 0x82154AEE, + 0x7B54A41D, 0xC25A59B5, 0x9C30D539, 0x2AF26013, + 0xC5D1B023, 0x286085F0, 0xCA417918, 0xB8DB38EF, + 0x8E79DCB0, 0x603A180E, 0x6C9E0E8B, 0xB01E8A3E, + 0xD71577C1, 0xBD314B27, 0x78AF2FDA, 0x55605C60, + 0xE65525F3, 0xAA55AB94, 0x57489862, 0x63E81440, + 0x55CA396A, 0x2AAB10B6, 0xB4CC5C34, 0x1141E8CE, + 0xA15486AF, 0x7C72E993, 0xB3EE1411, 0x636FBC2A, + 0x2BA9C55D, 0x741831F6, 0xCE5C3E16, 0x9B87931E, + 0xAFD6BA33, 0x6C24CF5C, 0x7A325381, 0x28958677, + 0x3B8F4898, 0x6B4BB9AF, 0xC4BFE81B, 0x66282193, + 0x61D809CC, 0xFB21A991, 0x487CAC60, 0x5DEC8032, + 0xEF845D5D, 0xE98575B1, 0xDC262302, 0xEB651B88, + 0x23893E81, 0xD396ACC5, 0x0F6D6FF3, 0x83F44239, + 0x2E0B4482, 0xA4842004, 0x69C8F04A, 0x9E1F9B5E, + 0x21C66842, 0xF6E96C9A, 0x670C9C61, 0xABD388F0, + 0x6A51A0D2, 0xD8542F68, 0x960FA728, 0xAB5133A3, + 0x6EEF0B6C, 0x137A3BE4, 0xBA3BF050, 0x7EFB2A98, + 0xA1F1651D, 0x39AF0176, 0x66CA593E, 0x82430E88, + 0x8CEE8619, 0x456F9FB4, 0x7D84A5C3, 0x3B8B5EBE, + 0xE06F75D8, 0x85C12073, 0x401A449F, 0x56C16AA6, + 0x4ED3AA62, 0x363F7706, 0x1BFEDF72, 0x429B023D, + 0x37D0D724, 0xD00A1248, 0xDB0FEAD3, 0x49F1C09B, + 0x075372C9, 0x80991B7B, 0x25D479D8, 0xF6E8DEF7, + 0xE3FE501A, 0xB6794C3B, 0x976CE0BD, 0x04C006BA, + 0xC1A94FB6, 0x409F60C4, 0x5E5C9EC2, 0x196A2463, + 0x68FB6FAF, 0x3E6C53B5, 0x1339B2EB, 0x3B52EC6F, + 0x6DFC511F, 0x9B30952C, 0xCC814544, 0xAF5EBD09, + 0xBEE3D004, 0xDE334AFD, 0x660F2807, 0x192E4BB3, + 0xC0CBA857, 0x45C8740F, 0xD20B5F39, 0xB9D3FBDB, + 0x5579C0BD, 0x1A60320A, 0xD6A100C6, 0x402C7279, + 0x679F25FE, 0xFB1FA3CC, 0x8EA5E9F8, 0xDB3222F8, + 0x3C7516DF, 0xFD616B15, 0x2F501EC8, 0xAD0552AB, + 0x323DB5FA, 0xFD238760, 0x53317B48, 0x3E00DF82, + 0x9E5C57BB, 0xCA6F8CA0, 0x1A87562E, 0xDF1769DB, + 0xD542A8F6, 0x287EFFC3, 0xAC6732C6, 0x8C4F5573, + 0x695B27B0, 0xBBCA58C8, 0xE1FFA35D, 0xB8F011A0, + 0x10FA3D98, 0xFD2183B8, 0x4AFCB56C, 0x2DD1D35B, + 0x9A53E479, 0xB6F84565, 0xD28E49BC, 0x4BFB9790, + 0xE1DDF2DA, 0xA4CB7E33, 0x62FB1341, 0xCEE4C6E8, + 0xEF20CADA, 0x36774C01, 0xD07E9EFE, 0x2BF11FB4, + 0x95DBDA4D, 0xAE909198, 0xEAAD8E71, 0x6B93D5A0, + 0xD08ED1D0, 0xAFC725E0, 0x8E3C5B2F, 0x8E7594B7, + 0x8FF6E2FB, 0xF2122B64, 0x8888B812, 0x900DF01C, + 0x4FAD5EA0, 0x688FC31C, 0xD1CFF191, 0xB3A8C1AD, + 0x2F2F2218, 0xBE0E1777, 0xEA752DFE, 0x8B021FA1, + 0xE5A0CC0F, 0xB56F74E8, 0x18ACF3D6, 0xCE89E299, + 0xB4A84FE0, 0xFD13E0B7, 0x7CC43B81, 0xD2ADA8D9, + 0x165FA266, 0x80957705, 0x93CC7314, 0x211A1477, + 0xE6AD2065, 0x77B5FA86, 0xC75442F5, 0xFB9D35CF, + 0xEBCDAF0C, 0x7B3E89A0, 0xD6411BD3, 0xAE1E7E49, + 0x00250E2D, 0x2071B35E, 0x226800BB, 0x57B8E0AF, + 0x2464369B, 0xF009B91E, 0x5563911D, 0x59DFA6AA, + 0x78C14389, 0xD95A537F, 0x207D5BA2, 0x02E5B9C5, + 0x83260376, 0x6295CFA9, 0x11C81968, 0x4E734A41, + 0xB3472DCA, 0x7B14A94A, 0x1B510052, 0x9A532915, + 0xD60F573F, 0xBC9BC6E4, 0x2B60A476, 0x81E67400, + 0x08BA6FB5, 0x571BE91F, 0xF296EC6B, 0x2A0DD915, + 0xB6636521, 0xE7B9F9B6, 0xFF34052E, 0xC5855664, + 0x53B02D5D, 0xA99F8FA1, 0x08BA4799, 0x6E85076A + }, + + KS1 = { + 0x4B7A70E9, 0xB5B32944, 0xDB75092E, 0xC4192623, + 0xAD6EA6B0, 0x49A7DF7D, 0x9CEE60B8, 0x8FEDB266, + 0xECAA8C71, 0x699A17FF, 0x5664526C, 0xC2B19EE1, + 0x193602A5, 0x75094C29, 0xA0591340, 0xE4183A3E, + 0x3F54989A, 0x5B429D65, 0x6B8FE4D6, 0x99F73FD6, + 0xA1D29C07, 0xEFE830F5, 0x4D2D38E6, 0xF0255DC1, + 0x4CDD2086, 0x8470EB26, 0x6382E9C6, 0x021ECC5E, + 0x09686B3F, 0x3EBAEFC9, 0x3C971814, 0x6B6A70A1, + 0x687F3584, 0x52A0E286, 0xB79C5305, 0xAA500737, + 0x3E07841C, 0x7FDEAE5C, 0x8E7D44EC, 0x5716F2B8, + 0xB03ADA37, 0xF0500C0D, 0xF01C1F04, 0x0200B3FF, + 0xAE0CF51A, 0x3CB574B2, 0x25837A58, 0xDC0921BD, + 0xD19113F9, 0x7CA92FF6, 0x94324773, 0x22F54701, + 0x3AE5E581, 0x37C2DADC, 0xC8B57634, 0x9AF3DDA7, + 0xA9446146, 0x0FD0030E, 0xECC8C73E, 0xA4751E41, + 0xE238CD99, 0x3BEA0E2F, 0x3280BBA1, 0x183EB331, + 0x4E548B38, 0x4F6DB908, 0x6F420D03, 0xF60A04BF, + 0x2CB81290, 0x24977C79, 0x5679B072, 0xBCAF89AF, + 0xDE9A771F, 0xD9930810, 0xB38BAE12, 0xDCCF3F2E, + 0x5512721F, 0x2E6B7124, 0x501ADDE6, 0x9F84CD87, + 0x7A584718, 0x7408DA17, 0xBC9F9ABC, 0xE94B7D8C, + 0xEC7AEC3A, 0xDB851DFA, 0x63094366, 0xC464C3D2, + 0xEF1C1847, 0x3215D908, 0xDD433B37, 0x24C2BA16, + 0x12A14D43, 0x2A65C451, 0x50940002, 0x133AE4DD, + 0x71DFF89E, 0x10314E55, 0x81AC77D6, 0x5F11199B, + 0x043556F1, 0xD7A3C76B, 0x3C11183B, 0x5924A509, + 0xF28FE6ED, 0x97F1FBFA, 0x9EBABF2C, 0x1E153C6E, + 0x86E34570, 0xEAE96FB1, 0x860E5E0A, 0x5A3E2AB3, + 0x771FE71C, 0x4E3D06FA, 0x2965DCB9, 0x99E71D0F, + 0x803E89D6, 0x5266C825, 0x2E4CC978, 0x9C10B36A, + 0xC6150EBA, 0x94E2EA78, 0xA5FC3C53, 0x1E0A2DF4, + 0xF2F74EA7, 0x361D2B3D, 0x1939260F, 0x19C27960, + 0x5223A708, 0xF71312B6, 0xEBADFE6E, 0xEAC31F66, + 0xE3BC4595, 0xA67BC883, 0xB17F37D1, 0x018CFF28, + 0xC332DDEF, 0xBE6C5AA5, 0x65582185, 0x68AB9802, + 0xEECEA50F, 0xDB2F953B, 0x2AEF7DAD, 0x5B6E2F84, + 0x1521B628, 0x29076170, 0xECDD4775, 0x619F1510, + 0x13CCA830, 0xEB61BD96, 0x0334FE1E, 0xAA0363CF, + 0xB5735C90, 0x4C70A239, 0xD59E9E0B, 0xCBAADE14, + 0xEECC86BC, 0x60622CA7, 0x9CAB5CAB, 0xB2F3846E, + 0x648B1EAF, 0x19BDF0CA, 0xA02369B9, 0x655ABB50, + 0x40685A32, 0x3C2AB4B3, 0x319EE9D5, 0xC021B8F7, + 0x9B540B19, 0x875FA099, 0x95F7997E, 0x623D7DA8, + 0xF837889A, 0x97E32D77, 0x11ED935F, 0x16681281, + 0x0E358829, 0xC7E61FD6, 0x96DEDFA1, 0x7858BA99, + 0x57F584A5, 0x1B227263, 0x9B83C3FF, 0x1AC24696, + 0xCDB30AEB, 0x532E3054, 0x8FD948E4, 0x6DBC3128, + 0x58EBF2EF, 0x34C6FFEA, 0xFE28ED61, 0xEE7C3C73, + 0x5D4A14D9, 0xE864B7E3, 0x42105D14, 0x203E13E0, + 0x45EEE2B6, 0xA3AAABEA, 0xDB6C4F15, 0xFACB4FD0, + 0xC742F442, 0xEF6ABBB5, 0x654F3B1D, 0x41CD2105, + 0xD81E799E, 0x86854DC7, 0xE44B476A, 0x3D816250, + 0xCF62A1F2, 0x5B8D2646, 0xFC8883A0, 0xC1C7B6A3, + 0x7F1524C3, 0x69CB7492, 0x47848A0B, 0x5692B285, + 0x095BBF00, 0xAD19489D, 0x1462B174, 0x23820E00, + 0x58428D2A, 0x0C55F5EA, 0x1DADF43E, 0x233F7061, + 0x3372F092, 0x8D937E41, 0xD65FECF1, 0x6C223BDB, + 0x7CDE3759, 0xCBEE7460, 0x4085F2A7, 0xCE77326E, + 0xA6078084, 0x19F8509E, 0xE8EFD855, 0x61D99735, + 0xA969A7AA, 0xC50C06C2, 0x5A04ABFC, 0x800BCADC, + 0x9E447A2E, 0xC3453484, 0xFDD56705, 0x0E1E9EC9, + 0xDB73DBD3, 0x105588CD, 0x675FDA79, 0xE3674340, + 0xC5C43465, 0x713E38D8, 0x3D28F89E, 0xF16DFF20, + 0x153E21E7, 0x8FB03D4A, 0xE6E39F2B, 0xDB83ADF7 + }, + + KS2 = { + 0xE93D5A68, 0x948140F7, 0xF64C261C, 0x94692934, + 0x411520F7, 0x7602D4F7, 0xBCF46B2E, 0xD4A20068, + 0xD4082471, 0x3320F46A, 0x43B7D4B7, 0x500061AF, + 0x1E39F62E, 0x97244546, 0x14214F74, 0xBF8B8840, + 0x4D95FC1D, 0x96B591AF, 0x70F4DDD3, 0x66A02F45, + 0xBFBC09EC, 0x03BD9785, 0x7FAC6DD0, 0x31CB8504, + 0x96EB27B3, 0x55FD3941, 0xDA2547E6, 0xABCA0A9A, + 0x28507825, 0x530429F4, 0x0A2C86DA, 0xE9B66DFB, + 0x68DC1462, 0xD7486900, 0x680EC0A4, 0x27A18DEE, + 0x4F3FFEA2, 0xE887AD8C, 0xB58CE006, 0x7AF4D6B6, + 0xAACE1E7C, 0xD3375FEC, 0xCE78A399, 0x406B2A42, + 0x20FE9E35, 0xD9F385B9, 0xEE39D7AB, 0x3B124E8B, + 0x1DC9FAF7, 0x4B6D1856, 0x26A36631, 0xEAE397B2, + 0x3A6EFA74, 0xDD5B4332, 0x6841E7F7, 0xCA7820FB, + 0xFB0AF54E, 0xD8FEB397, 0x454056AC, 0xBA489527, + 0x55533A3A, 0x20838D87, 0xFE6BA9B7, 0xD096954B, + 0x55A867BC, 0xA1159A58, 0xCCA92963, 0x99E1DB33, + 0xA62A4A56, 0x3F3125F9, 0x5EF47E1C, 0x9029317C, + 0xFDF8E802, 0x04272F70, 0x80BB155C, 0x05282CE3, + 0x95C11548, 0xE4C66D22, 0x48C1133F, 0xC70F86DC, + 0x07F9C9EE, 0x41041F0F, 0x404779A4, 0x5D886E17, + 0x325F51EB, 0xD59BC0D1, 0xF2BCC18F, 0x41113564, + 0x257B7834, 0x602A9C60, 0xDFF8E8A3, 0x1F636C1B, + 0x0E12B4C2, 0x02E1329E, 0xAF664FD1, 0xCAD18115, + 0x6B2395E0, 0x333E92E1, 0x3B240B62, 0xEEBEB922, + 0x85B2A20E, 0xE6BA0D99, 0xDE720C8C, 0x2DA2F728, + 0xD0127845, 0x95B794FD, 0x647D0862, 0xE7CCF5F0, + 0x5449A36F, 0x877D48FA, 0xC39DFD27, 0xF33E8D1E, + 0x0A476341, 0x992EFF74, 0x3A6F6EAB, 0xF4F8FD37, + 0xA812DC60, 0xA1EBDDF8, 0x991BE14C, 0xDB6E6B0D, + 0xC67B5510, 0x6D672C37, 0x2765D43B, 0xDCD0E804, + 0xF1290DC7, 0xCC00FFA3, 0xB5390F92, 0x690FED0B, + 0x667B9FFB, 0xCEDB7D9C, 0xA091CF0B, 0xD9155EA3, + 0xBB132F88, 0x515BAD24, 0x7B9479BF, 0x763BD6EB, + 0x37392EB3, 0xCC115979, 0x8026E297, 0xF42E312D, + 0x6842ADA7, 0xC66A2B3B, 0x12754CCC, 0x782EF11C, + 0x6A124237, 0xB79251E7, 0x06A1BBE6, 0x4BFB6350, + 0x1A6B1018, 0x11CAEDFA, 0x3D25BDD8, 0xE2E1C3C9, + 0x44421659, 0x0A121386, 0xD90CEC6E, 0xD5ABEA2A, + 0x64AF674E, 0xDA86A85F, 0xBEBFE988, 0x64E4C3FE, + 0x9DBC8057, 0xF0F7C086, 0x60787BF8, 0x6003604D, + 0xD1FD8346, 0xF6381FB0, 0x7745AE04, 0xD736FCCC, + 0x83426B33, 0xF01EAB71, 0xB0804187, 0x3C005E5F, + 0x77A057BE, 0xBDE8AE24, 0x55464299, 0xBF582E61, + 0x4E58F48F, 0xF2DDFDA2, 0xF474EF38, 0x8789BDC2, + 0x5366F9C3, 0xC8B38E74, 0xB475F255, 0x46FCD9B9, + 0x7AEB2661, 0x8B1DDF84, 0x846A0E79, 0x915F95E2, + 0x466E598E, 0x20B45770, 0x8CD55591, 0xC902DE4C, + 0xB90BACE1, 0xBB8205D0, 0x11A86248, 0x7574A99E, + 0xB77F19B6, 0xE0A9DC09, 0x662D09A1, 0xC4324633, + 0xE85A1F02, 0x09F0BE8C, 0x4A99A025, 0x1D6EFE10, + 0x1AB93D1D, 0x0BA5A4DF, 0xA186F20F, 0x2868F169, + 0xDCB7DA83, 0x573906FE, 0xA1E2CE9B, 0x4FCD7F52, + 0x50115E01, 0xA70683FA, 0xA002B5C4, 0x0DE6D027, + 0x9AF88C27, 0x773F8641, 0xC3604C06, 0x61A806B5, + 0xF0177A28, 0xC0F586E0, 0x006058AA, 0x30DC7D62, + 0x11E69ED7, 0x2338EA63, 0x53C2DD94, 0xC2C21634, + 0xBBCBEE56, 0x90BCB6DE, 0xEBFC7DA1, 0xCE591D76, + 0x6F05E409, 0x4B7C0188, 0x39720A3D, 0x7C927C24, + 0x86E3725F, 0x724D9DB9, 0x1AC15BB4, 0xD39EB8FC, + 0xED545578, 0x08FCA5B5, 0xD83D7CD3, 0x4DAD0FC4, + 0x1E50EF5E, 0xB161E6F8, 0xA28514D9, 0x6C51133C, + 0x6FD5C7E7, 0x56E14EC4, 0x362ABFCE, 0xDDC6C837, + 0xD79A3234, 0x92638212, 0x670EFA8E, 0x406000E0 + }, + + KS3 = { + 0x3A39CE37, 0xD3FAF5CF, 0xABC27737, 0x5AC52D1B, + 0x5CB0679E, 0x4FA33742, 0xD3822740, 0x99BC9BBE, + 0xD5118E9D, 0xBF0F7315, 0xD62D1C7E, 0xC700C47B, + 0xB78C1B6B, 0x21A19045, 0xB26EB1BE, 0x6A366EB4, + 0x5748AB2F, 0xBC946E79, 0xC6A376D2, 0x6549C2C8, + 0x530FF8EE, 0x468DDE7D, 0xD5730A1D, 0x4CD04DC6, + 0x2939BBDB, 0xA9BA4650, 0xAC9526E8, 0xBE5EE304, + 0xA1FAD5F0, 0x6A2D519A, 0x63EF8CE2, 0x9A86EE22, + 0xC089C2B8, 0x43242EF6, 0xA51E03AA, 0x9CF2D0A4, + 0x83C061BA, 0x9BE96A4D, 0x8FE51550, 0xBA645BD6, + 0x2826A2F9, 0xA73A3AE1, 0x4BA99586, 0xEF5562E9, + 0xC72FEFD3, 0xF752F7DA, 0x3F046F69, 0x77FA0A59, + 0x80E4A915, 0x87B08601, 0x9B09E6AD, 0x3B3EE593, + 0xE990FD5A, 0x9E34D797, 0x2CF0B7D9, 0x022B8B51, + 0x96D5AC3A, 0x017DA67D, 0xD1CF3ED6, 0x7C7D2D28, + 0x1F9F25CF, 0xADF2B89B, 0x5AD6B472, 0x5A88F54C, + 0xE029AC71, 0xE019A5E6, 0x47B0ACFD, 0xED93FA9B, + 0xE8D3C48D, 0x283B57CC, 0xF8D56629, 0x79132E28, + 0x785F0191, 0xED756055, 0xF7960E44, 0xE3D35E8C, + 0x15056DD4, 0x88F46DBA, 0x03A16125, 0x0564F0BD, + 0xC3EB9E15, 0x3C9057A2, 0x97271AEC, 0xA93A072A, + 0x1B3F6D9B, 0x1E6321F5, 0xF59C66FB, 0x26DCF319, + 0x7533D928, 0xB155FDF5, 0x03563482, 0x8ABA3CBB, + 0x28517711, 0xC20AD9F8, 0xABCC5167, 0xCCAD925F, + 0x4DE81751, 0x3830DC8E, 0x379D5862, 0x9320F991, + 0xEA7A90C2, 0xFB3E7BCE, 0x5121CE64, 0x774FBE32, + 0xA8B6E37E, 0xC3293D46, 0x48DE5369, 0x6413E680, + 0xA2AE0810, 0xDD6DB224, 0x69852DFD, 0x09072166, + 0xB39A460A, 0x6445C0DD, 0x586CDECF, 0x1C20C8AE, + 0x5BBEF7DD, 0x1B588D40, 0xCCD2017F, 0x6BB4E3BB, + 0xDDA26A7E, 0x3A59FF45, 0x3E350A44, 0xBCB4CDD5, + 0x72EACEA8, 0xFA6484BB, 0x8D6612AE, 0xBF3C6F47, + 0xD29BE463, 0x542F5D9E, 0xAEC2771B, 0xF64E6370, + 0x740E0D8D, 0xE75B1357, 0xF8721671, 0xAF537D5D, + 0x4040CB08, 0x4EB4E2CC, 0x34D2466A, 0x0115AF84, + 0xE1B00428, 0x95983A1D, 0x06B89FB4, 0xCE6EA048, + 0x6F3F3B82, 0x3520AB82, 0x011A1D4B, 0x277227F8, + 0x611560B1, 0xE7933FDC, 0xBB3A792B, 0x344525BD, + 0xA08839E1, 0x51CE794B, 0x2F32C9B7, 0xA01FBAC9, + 0xE01CC87E, 0xBCC7D1F6, 0xCF0111C3, 0xA1E8AAC7, + 0x1A908749, 0xD44FBD9A, 0xD0DADECB, 0xD50ADA38, + 0x0339C32A, 0xC6913667, 0x8DF9317C, 0xE0B12B4F, + 0xF79E59B7, 0x43F5BB3A, 0xF2D519FF, 0x27D9459C, + 0xBF97222C, 0x15E6FC2A, 0x0F91FC71, 0x9B941525, + 0xFAE59361, 0xCEB69CEB, 0xC2A86459, 0x12BAA8D1, + 0xB6C1075E, 0xE3056A0C, 0x10D25065, 0xCB03A442, + 0xE0EC6E0E, 0x1698DB3B, 0x4C98A0BE, 0x3278E964, + 0x9F1F9532, 0xE0D392DF, 0xD3A0342B, 0x8971F21E, + 0x1B0A7441, 0x4BA3348C, 0xC5BE7120, 0xC37632D8, + 0xDF359F8D, 0x9B992F2E, 0xE60B6F47, 0x0FE3F11D, + 0xE54CDA54, 0x1EDAD891, 0xCE6279CF, 0xCD3E7E6F, + 0x1618B166, 0xFD2C1D05, 0x848FD2C5, 0xF6FB2299, + 0xF523F357, 0xA6327623, 0x93A83531, 0x56CCCD02, + 0xACF08162, 0x5A75EBB5, 0x6E163697, 0x88D273CC, + 0xDE966292, 0x81B949D0, 0x4C50901B, 0x71C65614, + 0xE6C6C7BD, 0x327A140A, 0x45E1D006, 0xC3F27B9A, + 0xC9AA53FD, 0x62A80F00, 0xBB25BFE2, 0x35BDD2F6, + 0x71126905, 0xB2040222, 0xB6CBCF7C, 0xCD769C2B, + 0x53113EC0, 0x1640E3D3, 0x38ABBD60, 0x2547ADF0, + 0xBA38209C, 0xF746CE76, 0x77AFA1C5, 0x20756060, + 0x85CBFE4E, 0x8AE88DD8, 0x7AAAF9B0, 0x4CF9AA7E, + 0x1948C25C, 0x02FB8A8C, 0x01C36AE4, 0xD6EBE1F9, + 0x90D4F869, 0xA65CDEA0, 0x3F09252D, 0xC208E69F, + 0xB74E6132, 0xCE77E25B, 0x578FDFE3, 0x3AC372E6 + }; + + //==================================== + // Useful constants + //==================================== + + private static final int ROUNDS = 16; + private static final int BLOCK_SIZE = 8; // bytes = 64 bits + private static final int SBOX_SK = 256; + private static final int P_SZ = ROUNDS+2; + + private final int[] S0, S1, S2, S3; // the s-boxes + private final int[] P; // the p-array + + private boolean encrypting = false; + + private byte[] workingKey = null; + + public BlowfishEngine() + { + S0 = new int[SBOX_SK]; + S1 = new int[SBOX_SK]; + S2 = new int[SBOX_SK]; + S3 = new int[SBOX_SK]; + P = new int[P_SZ]; + } + + /** + * initialise a Blowfish cipher. + * + * @param encrypting whether or not we are for encryption. + * @param params the parameters required to set up the cipher. + * @exception IllegalArgumentException if the params argument is + * inappropriate. + */ + public void init( + boolean encrypting, + CipherParameters params) + { + if (params instanceof KeyParameter) + { + this.encrypting = encrypting; + this.workingKey = ((KeyParameter)params).getKey(); + setKey(this.workingKey); + + return; + } + + throw new IllegalArgumentException("invalid parameter passed to Blowfish init - " + params.getClass().getName()); + } + + public String getAlgorithmName() + { + return "Blowfish"; + } + + public final int processBlock( + byte[] in, + int inOff, + byte[] out, + int outOff) + { + if (workingKey == null) + { + throw new IllegalStateException("Blowfish not initialised"); + } + + if ((inOff + BLOCK_SIZE) > in.length) + { + throw new DataLengthException("input buffer too short"); + } + + if ((outOff + BLOCK_SIZE) > out.length) + { + throw new DataLengthException("output buffer too short"); + } + + if (encrypting) + { + encryptBlock(in, inOff, out, outOff); + } + else + { + decryptBlock(in, inOff, out, outOff); + } + + return BLOCK_SIZE; + } + + public void reset() + { + } + + public int getBlockSize() + { + return BLOCK_SIZE; + } + + //================================== + // Private Implementation + //================================== + + private int F(int x) + { + return (((S0[(x >>> 24)] + S1[(x >>> 16) & 0xff]) + ^ S2[(x >>> 8) & 0xff]) + S3[x & 0xff]); + } + + /** + * apply the encryption cycle to each value pair in the table. + */ + private void processTable( + int xl, + int xr, + int[] table) + { + int size = table.length; + + for (int s = 0; s < size; s += 2) + { + xl ^= P[0]; + + for (int i = 1; i < ROUNDS; i += 2) + { + xr ^= F(xl) ^ P[i]; + xl ^= F(xr) ^ P[i + 1]; + } + + xr ^= P[ROUNDS + 1]; + + table[s] = xr; + table[s + 1] = xl; + + xr = xl; // end of cycle swap + xl = table[s]; + } + } + + private void setKey(byte[] key) + { + /* + * - comments are from _Applied Crypto_, Schneier, p338 + * please be careful comparing the two, AC numbers the + * arrays from 1, the enclosed code from 0. + * + * (1) + * Initialise the S-boxes and the P-array, with a fixed string + * This string contains the hexadecimal digits of pi (3.141...) + */ + System.arraycopy(KS0, 0, S0, 0, SBOX_SK); + System.arraycopy(KS1, 0, S1, 0, SBOX_SK); + System.arraycopy(KS2, 0, S2, 0, SBOX_SK); + System.arraycopy(KS3, 0, S3, 0, SBOX_SK); + + System.arraycopy(KP, 0, P, 0, P_SZ); + + /* + * (2) + * Now, XOR P[0] with the first 32 bits of the key, XOR P[1] with the + * second 32-bits of the key, and so on for all bits of the key + * (up to P[17]). Repeatedly cycle through the key bits until the + * entire P-array has been XOR-ed with the key bits + */ + int keyLength = key.length; + int keyIndex = 0; + + for (int i=0; i < P_SZ; i++) + { + // get the 32 bits of the key, in 4 * 8 bit chunks + int data = 0x0000000; + for (int j=0; j < 4; j++) + { + // create a 32 bit block + data = (data << 8) | (key[keyIndex++] & 0xff); + + // wrap when we get to the end of the key + if (keyIndex >= keyLength) + { + keyIndex = 0; + } + } + // XOR the newly created 32 bit chunk onto the P-array + P[i] ^= data; + } + + /* + * (3) + * Encrypt the all-zero string with the Blowfish algorithm, using + * the subkeys described in (1) and (2) + * + * (4) + * Replace P1 and P2 with the output of step (3) + * + * (5) + * Encrypt the output of step(3) using the Blowfish algorithm, + * with the modified subkeys. + * + * (6) + * Replace P3 and P4 with the output of step (5) + * + * (7) + * Continue the process, replacing all elements of the P-array + * and then all four S-boxes in order, with the output of the + * continuously changing Blowfish algorithm + */ + + processTable(0, 0, P); + processTable(P[P_SZ - 2], P[P_SZ - 1], S0); + processTable(S0[SBOX_SK - 2], S0[SBOX_SK - 1], S1); + processTable(S1[SBOX_SK - 2], S1[SBOX_SK - 1], S2); + processTable(S2[SBOX_SK - 2], S2[SBOX_SK - 1], S3); + } + + /** + * Encrypt the given input starting at the given offset and place + * the result in the provided buffer starting at the given offset. + * The input will be an exact multiple of our blocksize. + */ + private void encryptBlock( + byte[] src, + int srcIndex, + byte[] dst, + int dstIndex) + { + int xl = BytesTo32bits(src, srcIndex); + int xr = BytesTo32bits(src, srcIndex+4); + + xl ^= P[0]; + + for (int i = 1; i < ROUNDS; i += 2) + { + xr ^= F(xl) ^ P[i]; + xl ^= F(xr) ^ P[i + 1]; + } + + xr ^= P[ROUNDS + 1]; + + Bits32ToBytes(xr, dst, dstIndex); + Bits32ToBytes(xl, dst, dstIndex + 4); + } + + /** + * Decrypt the given input starting at the given offset and place + * the result in the provided buffer starting at the given offset. + * The input will be an exact multiple of our blocksize. + */ + private void decryptBlock( + byte[] src, + int srcIndex, + byte[] dst, + int dstIndex) + { + int xl = BytesTo32bits(src, srcIndex); + int xr = BytesTo32bits(src, srcIndex + 4); + + xl ^= P[ROUNDS + 1]; + + for (int i = ROUNDS; i > 0 ; i -= 2) + { + xr ^= F(xl) ^ P[i]; + xl ^= F(xr) ^ P[i - 1]; + } + + xr ^= P[0]; + + Bits32ToBytes(xr, dst, dstIndex); + Bits32ToBytes(xl, dst, dstIndex+4); + } + + private int BytesTo32bits(byte[] b, int i) + { + return ((b[i] & 0xff) << 24) | + ((b[i+1] & 0xff) << 16) | + ((b[i+2] & 0xff) << 8) | + ((b[i+3] & 0xff)); + } + + private void Bits32ToBytes(int in, byte[] b, int offset) + { + b[offset + 3] = (byte)in; + b[offset + 2] = (byte)(in >> 8); + b[offset + 1] = (byte)(in >> 16); + b[offset] = (byte)(in >> 24); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/CAST5Engine.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/CAST5Engine.java new file mode 100644 index 0000000..d37a712 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/CAST5Engine.java @@ -0,0 +1,830 @@ +package org.bc.crypto.engines; + +import org.bc.crypto.BlockCipher; +import org.bc.crypto.CipherParameters; +import org.bc.crypto.DataLengthException; +import org.bc.crypto.params.KeyParameter; + +/** + * A class that provides CAST key encryption operations, + * such as encoding data and generating keys. + * + * All the algorithms herein are from the Internet RFC's + * + * RFC2144 - CAST5 (64bit block, 40-128bit key) + * RFC2612 - CAST6 (128bit block, 128-256bit key) + * + * and implement a simplified cryptography interface. + */ +public class CAST5Engine + implements BlockCipher +{ + protected final static int M32 = 0xffffffff; + + protected final static int[] + S1 = { +0x30fb40d4, 0x9fa0ff0b, 0x6beccd2f, 0x3f258c7a, 0x1e213f2f, 0x9c004dd3, 0x6003e540, 0xcf9fc949, +0xbfd4af27, 0x88bbbdb5, 0xe2034090, 0x98d09675, 0x6e63a0e0, 0x15c361d2, 0xc2e7661d, 0x22d4ff8e, +0x28683b6f, 0xc07fd059, 0xff2379c8, 0x775f50e2, 0x43c340d3, 0xdf2f8656, 0x887ca41a, 0xa2d2bd2d, +0xa1c9e0d6, 0x346c4819, 0x61b76d87, 0x22540f2f, 0x2abe32e1, 0xaa54166b, 0x22568e3a, 0xa2d341d0, +0x66db40c8, 0xa784392f, 0x004dff2f, 0x2db9d2de, 0x97943fac, 0x4a97c1d8, 0x527644b7, 0xb5f437a7, +0xb82cbaef, 0xd751d159, 0x6ff7f0ed, 0x5a097a1f, 0x827b68d0, 0x90ecf52e, 0x22b0c054, 0xbc8e5935, +0x4b6d2f7f, 0x50bb64a2, 0xd2664910, 0xbee5812d, 0xb7332290, 0xe93b159f, 0xb48ee411, 0x4bff345d, +0xfd45c240, 0xad31973f, 0xc4f6d02e, 0x55fc8165, 0xd5b1caad, 0xa1ac2dae, 0xa2d4b76d, 0xc19b0c50, +0x882240f2, 0x0c6e4f38, 0xa4e4bfd7, 0x4f5ba272, 0x564c1d2f, 0xc59c5319, 0xb949e354, 0xb04669fe, +0xb1b6ab8a, 0xc71358dd, 0x6385c545, 0x110f935d, 0x57538ad5, 0x6a390493, 0xe63d37e0, 0x2a54f6b3, +0x3a787d5f, 0x6276a0b5, 0x19a6fcdf, 0x7a42206a, 0x29f9d4d5, 0xf61b1891, 0xbb72275e, 0xaa508167, +0x38901091, 0xc6b505eb, 0x84c7cb8c, 0x2ad75a0f, 0x874a1427, 0xa2d1936b, 0x2ad286af, 0xaa56d291, +0xd7894360, 0x425c750d, 0x93b39e26, 0x187184c9, 0x6c00b32d, 0x73e2bb14, 0xa0bebc3c, 0x54623779, +0x64459eab, 0x3f328b82, 0x7718cf82, 0x59a2cea6, 0x04ee002e, 0x89fe78e6, 0x3fab0950, 0x325ff6c2, +0x81383f05, 0x6963c5c8, 0x76cb5ad6, 0xd49974c9, 0xca180dcf, 0x380782d5, 0xc7fa5cf6, 0x8ac31511, +0x35e79e13, 0x47da91d0, 0xf40f9086, 0xa7e2419e, 0x31366241, 0x051ef495, 0xaa573b04, 0x4a805d8d, +0x548300d0, 0x00322a3c, 0xbf64cddf, 0xba57a68e, 0x75c6372b, 0x50afd341, 0xa7c13275, 0x915a0bf5, +0x6b54bfab, 0x2b0b1426, 0xab4cc9d7, 0x449ccd82, 0xf7fbf265, 0xab85c5f3, 0x1b55db94, 0xaad4e324, +0xcfa4bd3f, 0x2deaa3e2, 0x9e204d02, 0xc8bd25ac, 0xeadf55b3, 0xd5bd9e98, 0xe31231b2, 0x2ad5ad6c, +0x954329de, 0xadbe4528, 0xd8710f69, 0xaa51c90f, 0xaa786bf6, 0x22513f1e, 0xaa51a79b, 0x2ad344cc, +0x7b5a41f0, 0xd37cfbad, 0x1b069505, 0x41ece491, 0xb4c332e6, 0x032268d4, 0xc9600acc, 0xce387e6d, +0xbf6bb16c, 0x6a70fb78, 0x0d03d9c9, 0xd4df39de, 0xe01063da, 0x4736f464, 0x5ad328d8, 0xb347cc96, +0x75bb0fc3, 0x98511bfb, 0x4ffbcc35, 0xb58bcf6a, 0xe11f0abc, 0xbfc5fe4a, 0xa70aec10, 0xac39570a, +0x3f04442f, 0x6188b153, 0xe0397a2e, 0x5727cb79, 0x9ceb418f, 0x1cacd68d, 0x2ad37c96, 0x0175cb9d, +0xc69dff09, 0xc75b65f0, 0xd9db40d8, 0xec0e7779, 0x4744ead4, 0xb11c3274, 0xdd24cb9e, 0x7e1c54bd, +0xf01144f9, 0xd2240eb1, 0x9675b3fd, 0xa3ac3755, 0xd47c27af, 0x51c85f4d, 0x56907596, 0xa5bb15e6, +0x580304f0, 0xca042cf1, 0x011a37ea, 0x8dbfaadb, 0x35ba3e4a, 0x3526ffa0, 0xc37b4d09, 0xbc306ed9, +0x98a52666, 0x5648f725, 0xff5e569d, 0x0ced63d0, 0x7c63b2cf, 0x700b45e1, 0xd5ea50f1, 0x85a92872, +0xaf1fbda7, 0xd4234870, 0xa7870bf3, 0x2d3b4d79, 0x42e04198, 0x0cd0ede7, 0x26470db8, 0xf881814c, +0x474d6ad7, 0x7c0c5e5c, 0xd1231959, 0x381b7298, 0xf5d2f4db, 0xab838653, 0x6e2f1e23, 0x83719c9e, +0xbd91e046, 0x9a56456e, 0xdc39200c, 0x20c8c571, 0x962bda1c, 0xe1e696ff, 0xb141ab08, 0x7cca89b9, +0x1a69e783, 0x02cc4843, 0xa2f7c579, 0x429ef47d, 0x427b169c, 0x5ac9f049, 0xdd8f0f00, 0x5c8165bf + }, + S2 = { +0x1f201094, 0xef0ba75b, 0x69e3cf7e, 0x393f4380, 0xfe61cf7a, 0xeec5207a, 0x55889c94, 0x72fc0651, +0xada7ef79, 0x4e1d7235, 0xd55a63ce, 0xde0436ba, 0x99c430ef, 0x5f0c0794, 0x18dcdb7d, 0xa1d6eff3, +0xa0b52f7b, 0x59e83605, 0xee15b094, 0xe9ffd909, 0xdc440086, 0xef944459, 0xba83ccb3, 0xe0c3cdfb, +0xd1da4181, 0x3b092ab1, 0xf997f1c1, 0xa5e6cf7b, 0x01420ddb, 0xe4e7ef5b, 0x25a1ff41, 0xe180f806, +0x1fc41080, 0x179bee7a, 0xd37ac6a9, 0xfe5830a4, 0x98de8b7f, 0x77e83f4e, 0x79929269, 0x24fa9f7b, +0xe113c85b, 0xacc40083, 0xd7503525, 0xf7ea615f, 0x62143154, 0x0d554b63, 0x5d681121, 0xc866c359, +0x3d63cf73, 0xcee234c0, 0xd4d87e87, 0x5c672b21, 0x071f6181, 0x39f7627f, 0x361e3084, 0xe4eb573b, +0x602f64a4, 0xd63acd9c, 0x1bbc4635, 0x9e81032d, 0x2701f50c, 0x99847ab4, 0xa0e3df79, 0xba6cf38c, +0x10843094, 0x2537a95e, 0xf46f6ffe, 0xa1ff3b1f, 0x208cfb6a, 0x8f458c74, 0xd9e0a227, 0x4ec73a34, +0xfc884f69, 0x3e4de8df, 0xef0e0088, 0x3559648d, 0x8a45388c, 0x1d804366, 0x721d9bfd, 0xa58684bb, +0xe8256333, 0x844e8212, 0x128d8098, 0xfed33fb4, 0xce280ae1, 0x27e19ba5, 0xd5a6c252, 0xe49754bd, +0xc5d655dd, 0xeb667064, 0x77840b4d, 0xa1b6a801, 0x84db26a9, 0xe0b56714, 0x21f043b7, 0xe5d05860, +0x54f03084, 0x066ff472, 0xa31aa153, 0xdadc4755, 0xb5625dbf, 0x68561be6, 0x83ca6b94, 0x2d6ed23b, +0xeccf01db, 0xa6d3d0ba, 0xb6803d5c, 0xaf77a709, 0x33b4a34c, 0x397bc8d6, 0x5ee22b95, 0x5f0e5304, +0x81ed6f61, 0x20e74364, 0xb45e1378, 0xde18639b, 0x881ca122, 0xb96726d1, 0x8049a7e8, 0x22b7da7b, +0x5e552d25, 0x5272d237, 0x79d2951c, 0xc60d894c, 0x488cb402, 0x1ba4fe5b, 0xa4b09f6b, 0x1ca815cf, +0xa20c3005, 0x8871df63, 0xb9de2fcb, 0x0cc6c9e9, 0x0beeff53, 0xe3214517, 0xb4542835, 0x9f63293c, +0xee41e729, 0x6e1d2d7c, 0x50045286, 0x1e6685f3, 0xf33401c6, 0x30a22c95, 0x31a70850, 0x60930f13, +0x73f98417, 0xa1269859, 0xec645c44, 0x52c877a9, 0xcdff33a6, 0xa02b1741, 0x7cbad9a2, 0x2180036f, +0x50d99c08, 0xcb3f4861, 0xc26bd765, 0x64a3f6ab, 0x80342676, 0x25a75e7b, 0xe4e6d1fc, 0x20c710e6, +0xcdf0b680, 0x17844d3b, 0x31eef84d, 0x7e0824e4, 0x2ccb49eb, 0x846a3bae, 0x8ff77888, 0xee5d60f6, +0x7af75673, 0x2fdd5cdb, 0xa11631c1, 0x30f66f43, 0xb3faec54, 0x157fd7fa, 0xef8579cc, 0xd152de58, +0xdb2ffd5e, 0x8f32ce19, 0x306af97a, 0x02f03ef8, 0x99319ad5, 0xc242fa0f, 0xa7e3ebb0, 0xc68e4906, +0xb8da230c, 0x80823028, 0xdcdef3c8, 0xd35fb171, 0x088a1bc8, 0xbec0c560, 0x61a3c9e8, 0xbca8f54d, +0xc72feffa, 0x22822e99, 0x82c570b4, 0xd8d94e89, 0x8b1c34bc, 0x301e16e6, 0x273be979, 0xb0ffeaa6, +0x61d9b8c6, 0x00b24869, 0xb7ffce3f, 0x08dc283b, 0x43daf65a, 0xf7e19798, 0x7619b72f, 0x8f1c9ba4, +0xdc8637a0, 0x16a7d3b1, 0x9fc393b7, 0xa7136eeb, 0xc6bcc63e, 0x1a513742, 0xef6828bc, 0x520365d6, +0x2d6a77ab, 0x3527ed4b, 0x821fd216, 0x095c6e2e, 0xdb92f2fb, 0x5eea29cb, 0x145892f5, 0x91584f7f, +0x5483697b, 0x2667a8cc, 0x85196048, 0x8c4bacea, 0x833860d4, 0x0d23e0f9, 0x6c387e8a, 0x0ae6d249, +0xb284600c, 0xd835731d, 0xdcb1c647, 0xac4c56ea, 0x3ebd81b3, 0x230eabb0, 0x6438bc87, 0xf0b5b1fa, +0x8f5ea2b3, 0xfc184642, 0x0a036b7a, 0x4fb089bd, 0x649da589, 0xa345415e, 0x5c038323, 0x3e5d3bb9, +0x43d79572, 0x7e6dd07c, 0x06dfdf1e, 0x6c6cc4ef, 0x7160a539, 0x73bfbe70, 0x83877605, 0x4523ecf1 + }, + S3 = { +0x8defc240, 0x25fa5d9f, 0xeb903dbf, 0xe810c907, 0x47607fff, 0x369fe44b, 0x8c1fc644, 0xaececa90, +0xbeb1f9bf, 0xeefbcaea, 0xe8cf1950, 0x51df07ae, 0x920e8806, 0xf0ad0548, 0xe13c8d83, 0x927010d5, +0x11107d9f, 0x07647db9, 0xb2e3e4d4, 0x3d4f285e, 0xb9afa820, 0xfade82e0, 0xa067268b, 0x8272792e, +0x553fb2c0, 0x489ae22b, 0xd4ef9794, 0x125e3fbc, 0x21fffcee, 0x825b1bfd, 0x9255c5ed, 0x1257a240, +0x4e1a8302, 0xbae07fff, 0x528246e7, 0x8e57140e, 0x3373f7bf, 0x8c9f8188, 0xa6fc4ee8, 0xc982b5a5, +0xa8c01db7, 0x579fc264, 0x67094f31, 0xf2bd3f5f, 0x40fff7c1, 0x1fb78dfc, 0x8e6bd2c1, 0x437be59b, +0x99b03dbf, 0xb5dbc64b, 0x638dc0e6, 0x55819d99, 0xa197c81c, 0x4a012d6e, 0xc5884a28, 0xccc36f71, +0xb843c213, 0x6c0743f1, 0x8309893c, 0x0feddd5f, 0x2f7fe850, 0xd7c07f7e, 0x02507fbf, 0x5afb9a04, +0xa747d2d0, 0x1651192e, 0xaf70bf3e, 0x58c31380, 0x5f98302e, 0x727cc3c4, 0x0a0fb402, 0x0f7fef82, +0x8c96fdad, 0x5d2c2aae, 0x8ee99a49, 0x50da88b8, 0x8427f4a0, 0x1eac5790, 0x796fb449, 0x8252dc15, +0xefbd7d9b, 0xa672597d, 0xada840d8, 0x45f54504, 0xfa5d7403, 0xe83ec305, 0x4f91751a, 0x925669c2, +0x23efe941, 0xa903f12e, 0x60270df2, 0x0276e4b6, 0x94fd6574, 0x927985b2, 0x8276dbcb, 0x02778176, +0xf8af918d, 0x4e48f79e, 0x8f616ddf, 0xe29d840e, 0x842f7d83, 0x340ce5c8, 0x96bbb682, 0x93b4b148, +0xef303cab, 0x984faf28, 0x779faf9b, 0x92dc560d, 0x224d1e20, 0x8437aa88, 0x7d29dc96, 0x2756d3dc, +0x8b907cee, 0xb51fd240, 0xe7c07ce3, 0xe566b4a1, 0xc3e9615e, 0x3cf8209d, 0x6094d1e3, 0xcd9ca341, +0x5c76460e, 0x00ea983b, 0xd4d67881, 0xfd47572c, 0xf76cedd9, 0xbda8229c, 0x127dadaa, 0x438a074e, +0x1f97c090, 0x081bdb8a, 0x93a07ebe, 0xb938ca15, 0x97b03cff, 0x3dc2c0f8, 0x8d1ab2ec, 0x64380e51, +0x68cc7bfb, 0xd90f2788, 0x12490181, 0x5de5ffd4, 0xdd7ef86a, 0x76a2e214, 0xb9a40368, 0x925d958f, +0x4b39fffa, 0xba39aee9, 0xa4ffd30b, 0xfaf7933b, 0x6d498623, 0x193cbcfa, 0x27627545, 0x825cf47a, +0x61bd8ba0, 0xd11e42d1, 0xcead04f4, 0x127ea392, 0x10428db7, 0x8272a972, 0x9270c4a8, 0x127de50b, +0x285ba1c8, 0x3c62f44f, 0x35c0eaa5, 0xe805d231, 0x428929fb, 0xb4fcdf82, 0x4fb66a53, 0x0e7dc15b, +0x1f081fab, 0x108618ae, 0xfcfd086d, 0xf9ff2889, 0x694bcc11, 0x236a5cae, 0x12deca4d, 0x2c3f8cc5, +0xd2d02dfe, 0xf8ef5896, 0xe4cf52da, 0x95155b67, 0x494a488c, 0xb9b6a80c, 0x5c8f82bc, 0x89d36b45, +0x3a609437, 0xec00c9a9, 0x44715253, 0x0a874b49, 0xd773bc40, 0x7c34671c, 0x02717ef6, 0x4feb5536, +0xa2d02fff, 0xd2bf60c4, 0xd43f03c0, 0x50b4ef6d, 0x07478cd1, 0x006e1888, 0xa2e53f55, 0xb9e6d4bc, +0xa2048016, 0x97573833, 0xd7207d67, 0xde0f8f3d, 0x72f87b33, 0xabcc4f33, 0x7688c55d, 0x7b00a6b0, +0x947b0001, 0x570075d2, 0xf9bb88f8, 0x8942019e, 0x4264a5ff, 0x856302e0, 0x72dbd92b, 0xee971b69, +0x6ea22fde, 0x5f08ae2b, 0xaf7a616d, 0xe5c98767, 0xcf1febd2, 0x61efc8c2, 0xf1ac2571, 0xcc8239c2, +0x67214cb8, 0xb1e583d1, 0xb7dc3e62, 0x7f10bdce, 0xf90a5c38, 0x0ff0443d, 0x606e6dc6, 0x60543a49, +0x5727c148, 0x2be98a1d, 0x8ab41738, 0x20e1be24, 0xaf96da0f, 0x68458425, 0x99833be5, 0x600d457d, +0x282f9350, 0x8334b362, 0xd91d1120, 0x2b6d8da0, 0x642b1e31, 0x9c305a00, 0x52bce688, 0x1b03588a, +0xf7baefd5, 0x4142ed9c, 0xa4315c11, 0x83323ec5, 0xdfef4636, 0xa133c501, 0xe9d3531c, 0xee353783 + }, + S4 = { +0x9db30420, 0x1fb6e9de, 0xa7be7bef, 0xd273a298, 0x4a4f7bdb, 0x64ad8c57, 0x85510443, 0xfa020ed1, +0x7e287aff, 0xe60fb663, 0x095f35a1, 0x79ebf120, 0xfd059d43, 0x6497b7b1, 0xf3641f63, 0x241e4adf, +0x28147f5f, 0x4fa2b8cd, 0xc9430040, 0x0cc32220, 0xfdd30b30, 0xc0a5374f, 0x1d2d00d9, 0x24147b15, +0xee4d111a, 0x0fca5167, 0x71ff904c, 0x2d195ffe, 0x1a05645f, 0x0c13fefe, 0x081b08ca, 0x05170121, +0x80530100, 0xe83e5efe, 0xac9af4f8, 0x7fe72701, 0xd2b8ee5f, 0x06df4261, 0xbb9e9b8a, 0x7293ea25, +0xce84ffdf, 0xf5718801, 0x3dd64b04, 0xa26f263b, 0x7ed48400, 0x547eebe6, 0x446d4ca0, 0x6cf3d6f5, +0x2649abdf, 0xaea0c7f5, 0x36338cc1, 0x503f7e93, 0xd3772061, 0x11b638e1, 0x72500e03, 0xf80eb2bb, +0xabe0502e, 0xec8d77de, 0x57971e81, 0xe14f6746, 0xc9335400, 0x6920318f, 0x081dbb99, 0xffc304a5, +0x4d351805, 0x7f3d5ce3, 0xa6c866c6, 0x5d5bcca9, 0xdaec6fea, 0x9f926f91, 0x9f46222f, 0x3991467d, +0xa5bf6d8e, 0x1143c44f, 0x43958302, 0xd0214eeb, 0x022083b8, 0x3fb6180c, 0x18f8931e, 0x281658e6, +0x26486e3e, 0x8bd78a70, 0x7477e4c1, 0xb506e07c, 0xf32d0a25, 0x79098b02, 0xe4eabb81, 0x28123b23, +0x69dead38, 0x1574ca16, 0xdf871b62, 0x211c40b7, 0xa51a9ef9, 0x0014377b, 0x041e8ac8, 0x09114003, +0xbd59e4d2, 0xe3d156d5, 0x4fe876d5, 0x2f91a340, 0x557be8de, 0x00eae4a7, 0x0ce5c2ec, 0x4db4bba6, +0xe756bdff, 0xdd3369ac, 0xec17b035, 0x06572327, 0x99afc8b0, 0x56c8c391, 0x6b65811c, 0x5e146119, +0x6e85cb75, 0xbe07c002, 0xc2325577, 0x893ff4ec, 0x5bbfc92d, 0xd0ec3b25, 0xb7801ab7, 0x8d6d3b24, +0x20c763ef, 0xc366a5fc, 0x9c382880, 0x0ace3205, 0xaac9548a, 0xeca1d7c7, 0x041afa32, 0x1d16625a, +0x6701902c, 0x9b757a54, 0x31d477f7, 0x9126b031, 0x36cc6fdb, 0xc70b8b46, 0xd9e66a48, 0x56e55a79, +0x026a4ceb, 0x52437eff, 0x2f8f76b4, 0x0df980a5, 0x8674cde3, 0xedda04eb, 0x17a9be04, 0x2c18f4df, +0xb7747f9d, 0xab2af7b4, 0xefc34d20, 0x2e096b7c, 0x1741a254, 0xe5b6a035, 0x213d42f6, 0x2c1c7c26, +0x61c2f50f, 0x6552daf9, 0xd2c231f8, 0x25130f69, 0xd8167fa2, 0x0418f2c8, 0x001a96a6, 0x0d1526ab, +0x63315c21, 0x5e0a72ec, 0x49bafefd, 0x187908d9, 0x8d0dbd86, 0x311170a7, 0x3e9b640c, 0xcc3e10d7, +0xd5cad3b6, 0x0caec388, 0xf73001e1, 0x6c728aff, 0x71eae2a1, 0x1f9af36e, 0xcfcbd12f, 0xc1de8417, +0xac07be6b, 0xcb44a1d8, 0x8b9b0f56, 0x013988c3, 0xb1c52fca, 0xb4be31cd, 0xd8782806, 0x12a3a4e2, +0x6f7de532, 0x58fd7eb6, 0xd01ee900, 0x24adffc2, 0xf4990fc5, 0x9711aac5, 0x001d7b95, 0x82e5e7d2, +0x109873f6, 0x00613096, 0xc32d9521, 0xada121ff, 0x29908415, 0x7fbb977f, 0xaf9eb3db, 0x29c9ed2a, +0x5ce2a465, 0xa730f32c, 0xd0aa3fe8, 0x8a5cc091, 0xd49e2ce7, 0x0ce454a9, 0xd60acd86, 0x015f1919, +0x77079103, 0xdea03af6, 0x78a8565e, 0xdee356df, 0x21f05cbe, 0x8b75e387, 0xb3c50651, 0xb8a5c3ef, +0xd8eeb6d2, 0xe523be77, 0xc2154529, 0x2f69efdf, 0xafe67afb, 0xf470c4b2, 0xf3e0eb5b, 0xd6cc9876, +0x39e4460c, 0x1fda8538, 0x1987832f, 0xca007367, 0xa99144f8, 0x296b299e, 0x492fc295, 0x9266beab, +0xb5676e69, 0x9bd3ddda, 0xdf7e052f, 0xdb25701c, 0x1b5e51ee, 0xf65324e6, 0x6afce36c, 0x0316cc04, +0x8644213e, 0xb7dc59d0, 0x7965291f, 0xccd6fd43, 0x41823979, 0x932bcdf6, 0xb657c34d, 0x4edfd282, +0x7ae5290c, 0x3cb9536b, 0x851e20fe, 0x9833557e, 0x13ecf0b0, 0xd3ffb372, 0x3f85c5c1, 0x0aef7ed2 + }, + S5 = { +0x7ec90c04, 0x2c6e74b9, 0x9b0e66df, 0xa6337911, 0xb86a7fff, 0x1dd358f5, 0x44dd9d44, 0x1731167f, +0x08fbf1fa, 0xe7f511cc, 0xd2051b00, 0x735aba00, 0x2ab722d8, 0x386381cb, 0xacf6243a, 0x69befd7a, +0xe6a2e77f, 0xf0c720cd, 0xc4494816, 0xccf5c180, 0x38851640, 0x15b0a848, 0xe68b18cb, 0x4caadeff, +0x5f480a01, 0x0412b2aa, 0x259814fc, 0x41d0efe2, 0x4e40b48d, 0x248eb6fb, 0x8dba1cfe, 0x41a99b02, +0x1a550a04, 0xba8f65cb, 0x7251f4e7, 0x95a51725, 0xc106ecd7, 0x97a5980a, 0xc539b9aa, 0x4d79fe6a, +0xf2f3f763, 0x68af8040, 0xed0c9e56, 0x11b4958b, 0xe1eb5a88, 0x8709e6b0, 0xd7e07156, 0x4e29fea7, +0x6366e52d, 0x02d1c000, 0xc4ac8e05, 0x9377f571, 0x0c05372a, 0x578535f2, 0x2261be02, 0xd642a0c9, +0xdf13a280, 0x74b55bd2, 0x682199c0, 0xd421e5ec, 0x53fb3ce8, 0xc8adedb3, 0x28a87fc9, 0x3d959981, +0x5c1ff900, 0xfe38d399, 0x0c4eff0b, 0x062407ea, 0xaa2f4fb1, 0x4fb96976, 0x90c79505, 0xb0a8a774, +0xef55a1ff, 0xe59ca2c2, 0xa6b62d27, 0xe66a4263, 0xdf65001f, 0x0ec50966, 0xdfdd55bc, 0x29de0655, +0x911e739a, 0x17af8975, 0x32c7911c, 0x89f89468, 0x0d01e980, 0x524755f4, 0x03b63cc9, 0x0cc844b2, +0xbcf3f0aa, 0x87ac36e9, 0xe53a7426, 0x01b3d82b, 0x1a9e7449, 0x64ee2d7e, 0xcddbb1da, 0x01c94910, +0xb868bf80, 0x0d26f3fd, 0x9342ede7, 0x04a5c284, 0x636737b6, 0x50f5b616, 0xf24766e3, 0x8eca36c1, +0x136e05db, 0xfef18391, 0xfb887a37, 0xd6e7f7d4, 0xc7fb7dc9, 0x3063fcdf, 0xb6f589de, 0xec2941da, +0x26e46695, 0xb7566419, 0xf654efc5, 0xd08d58b7, 0x48925401, 0xc1bacb7f, 0xe5ff550f, 0xb6083049, +0x5bb5d0e8, 0x87d72e5a, 0xab6a6ee1, 0x223a66ce, 0xc62bf3cd, 0x9e0885f9, 0x68cb3e47, 0x086c010f, +0xa21de820, 0xd18b69de, 0xf3f65777, 0xfa02c3f6, 0x407edac3, 0xcbb3d550, 0x1793084d, 0xb0d70eba, +0x0ab378d5, 0xd951fb0c, 0xded7da56, 0x4124bbe4, 0x94ca0b56, 0x0f5755d1, 0xe0e1e56e, 0x6184b5be, +0x580a249f, 0x94f74bc0, 0xe327888e, 0x9f7b5561, 0xc3dc0280, 0x05687715, 0x646c6bd7, 0x44904db3, +0x66b4f0a3, 0xc0f1648a, 0x697ed5af, 0x49e92ff6, 0x309e374f, 0x2cb6356a, 0x85808573, 0x4991f840, +0x76f0ae02, 0x083be84d, 0x28421c9a, 0x44489406, 0x736e4cb8, 0xc1092910, 0x8bc95fc6, 0x7d869cf4, +0x134f616f, 0x2e77118d, 0xb31b2be1, 0xaa90b472, 0x3ca5d717, 0x7d161bba, 0x9cad9010, 0xaf462ba2, +0x9fe459d2, 0x45d34559, 0xd9f2da13, 0xdbc65487, 0xf3e4f94e, 0x176d486f, 0x097c13ea, 0x631da5c7, +0x445f7382, 0x175683f4, 0xcdc66a97, 0x70be0288, 0xb3cdcf72, 0x6e5dd2f3, 0x20936079, 0x459b80a5, +0xbe60e2db, 0xa9c23101, 0xeba5315c, 0x224e42f2, 0x1c5c1572, 0xf6721b2c, 0x1ad2fff3, 0x8c25404e, +0x324ed72f, 0x4067b7fd, 0x0523138e, 0x5ca3bc78, 0xdc0fd66e, 0x75922283, 0x784d6b17, 0x58ebb16e, +0x44094f85, 0x3f481d87, 0xfcfeae7b, 0x77b5ff76, 0x8c2302bf, 0xaaf47556, 0x5f46b02a, 0x2b092801, +0x3d38f5f7, 0x0ca81f36, 0x52af4a8a, 0x66d5e7c0, 0xdf3b0874, 0x95055110, 0x1b5ad7a8, 0xf61ed5ad, +0x6cf6e479, 0x20758184, 0xd0cefa65, 0x88f7be58, 0x4a046826, 0x0ff6f8f3, 0xa09c7f70, 0x5346aba0, +0x5ce96c28, 0xe176eda3, 0x6bac307f, 0x376829d2, 0x85360fa9, 0x17e3fe2a, 0x24b79767, 0xf5a96b20, +0xd6cd2595, 0x68ff1ebf, 0x7555442c, 0xf19f06be, 0xf9e0659a, 0xeeb9491d, 0x34010718, 0xbb30cab8, +0xe822fe15, 0x88570983, 0x750e6249, 0xda627e55, 0x5e76ffa8, 0xb1534546, 0x6d47de08, 0xefe9e7d4 + }, + S6 = { +0xf6fa8f9d, 0x2cac6ce1, 0x4ca34867, 0xe2337f7c, 0x95db08e7, 0x016843b4, 0xeced5cbc, 0x325553ac, +0xbf9f0960, 0xdfa1e2ed, 0x83f0579d, 0x63ed86b9, 0x1ab6a6b8, 0xde5ebe39, 0xf38ff732, 0x8989b138, +0x33f14961, 0xc01937bd, 0xf506c6da, 0xe4625e7e, 0xa308ea99, 0x4e23e33c, 0x79cbd7cc, 0x48a14367, +0xa3149619, 0xfec94bd5, 0xa114174a, 0xeaa01866, 0xa084db2d, 0x09a8486f, 0xa888614a, 0x2900af98, +0x01665991, 0xe1992863, 0xc8f30c60, 0x2e78ef3c, 0xd0d51932, 0xcf0fec14, 0xf7ca07d2, 0xd0a82072, +0xfd41197e, 0x9305a6b0, 0xe86be3da, 0x74bed3cd, 0x372da53c, 0x4c7f4448, 0xdab5d440, 0x6dba0ec3, +0x083919a7, 0x9fbaeed9, 0x49dbcfb0, 0x4e670c53, 0x5c3d9c01, 0x64bdb941, 0x2c0e636a, 0xba7dd9cd, +0xea6f7388, 0xe70bc762, 0x35f29adb, 0x5c4cdd8d, 0xf0d48d8c, 0xb88153e2, 0x08a19866, 0x1ae2eac8, +0x284caf89, 0xaa928223, 0x9334be53, 0x3b3a21bf, 0x16434be3, 0x9aea3906, 0xefe8c36e, 0xf890cdd9, +0x80226dae, 0xc340a4a3, 0xdf7e9c09, 0xa694a807, 0x5b7c5ecc, 0x221db3a6, 0x9a69a02f, 0x68818a54, +0xceb2296f, 0x53c0843a, 0xfe893655, 0x25bfe68a, 0xb4628abc, 0xcf222ebf, 0x25ac6f48, 0xa9a99387, +0x53bddb65, 0xe76ffbe7, 0xe967fd78, 0x0ba93563, 0x8e342bc1, 0xe8a11be9, 0x4980740d, 0xc8087dfc, +0x8de4bf99, 0xa11101a0, 0x7fd37975, 0xda5a26c0, 0xe81f994f, 0x9528cd89, 0xfd339fed, 0xb87834bf, +0x5f04456d, 0x22258698, 0xc9c4c83b, 0x2dc156be, 0x4f628daa, 0x57f55ec5, 0xe2220abe, 0xd2916ebf, +0x4ec75b95, 0x24f2c3c0, 0x42d15d99, 0xcd0d7fa0, 0x7b6e27ff, 0xa8dc8af0, 0x7345c106, 0xf41e232f, +0x35162386, 0xe6ea8926, 0x3333b094, 0x157ec6f2, 0x372b74af, 0x692573e4, 0xe9a9d848, 0xf3160289, +0x3a62ef1d, 0xa787e238, 0xf3a5f676, 0x74364853, 0x20951063, 0x4576698d, 0xb6fad407, 0x592af950, +0x36f73523, 0x4cfb6e87, 0x7da4cec0, 0x6c152daa, 0xcb0396a8, 0xc50dfe5d, 0xfcd707ab, 0x0921c42f, +0x89dff0bb, 0x5fe2be78, 0x448f4f33, 0x754613c9, 0x2b05d08d, 0x48b9d585, 0xdc049441, 0xc8098f9b, +0x7dede786, 0xc39a3373, 0x42410005, 0x6a091751, 0x0ef3c8a6, 0x890072d6, 0x28207682, 0xa9a9f7be, +0xbf32679d, 0xd45b5b75, 0xb353fd00, 0xcbb0e358, 0x830f220a, 0x1f8fb214, 0xd372cf08, 0xcc3c4a13, +0x8cf63166, 0x061c87be, 0x88c98f88, 0x6062e397, 0x47cf8e7a, 0xb6c85283, 0x3cc2acfb, 0x3fc06976, +0x4e8f0252, 0x64d8314d, 0xda3870e3, 0x1e665459, 0xc10908f0, 0x513021a5, 0x6c5b68b7, 0x822f8aa0, +0x3007cd3e, 0x74719eef, 0xdc872681, 0x073340d4, 0x7e432fd9, 0x0c5ec241, 0x8809286c, 0xf592d891, +0x08a930f6, 0x957ef305, 0xb7fbffbd, 0xc266e96f, 0x6fe4ac98, 0xb173ecc0, 0xbc60b42a, 0x953498da, +0xfba1ae12, 0x2d4bd736, 0x0f25faab, 0xa4f3fceb, 0xe2969123, 0x257f0c3d, 0x9348af49, 0x361400bc, +0xe8816f4a, 0x3814f200, 0xa3f94043, 0x9c7a54c2, 0xbc704f57, 0xda41e7f9, 0xc25ad33a, 0x54f4a084, +0xb17f5505, 0x59357cbe, 0xedbd15c8, 0x7f97c5ab, 0xba5ac7b5, 0xb6f6deaf, 0x3a479c3a, 0x5302da25, +0x653d7e6a, 0x54268d49, 0x51a477ea, 0x5017d55b, 0xd7d25d88, 0x44136c76, 0x0404a8c8, 0xb8e5a121, +0xb81a928a, 0x60ed5869, 0x97c55b96, 0xeaec991b, 0x29935913, 0x01fdb7f1, 0x088e8dfa, 0x9ab6f6f5, +0x3b4cbf9f, 0x4a5de3ab, 0xe6051d35, 0xa0e1d855, 0xd36b4cf1, 0xf544edeb, 0xb0e93524, 0xbebb8fbd, +0xa2d762cf, 0x49c92f54, 0x38b5f331, 0x7128a454, 0x48392905, 0xa65b1db8, 0x851c97bd, 0xd675cf2f + }, + S7 = { +0x85e04019, 0x332bf567, 0x662dbfff, 0xcfc65693, 0x2a8d7f6f, 0xab9bc912, 0xde6008a1, 0x2028da1f, +0x0227bce7, 0x4d642916, 0x18fac300, 0x50f18b82, 0x2cb2cb11, 0xb232e75c, 0x4b3695f2, 0xb28707de, +0xa05fbcf6, 0xcd4181e9, 0xe150210c, 0xe24ef1bd, 0xb168c381, 0xfde4e789, 0x5c79b0d8, 0x1e8bfd43, +0x4d495001, 0x38be4341, 0x913cee1d, 0x92a79c3f, 0x089766be, 0xbaeeadf4, 0x1286becf, 0xb6eacb19, +0x2660c200, 0x7565bde4, 0x64241f7a, 0x8248dca9, 0xc3b3ad66, 0x28136086, 0x0bd8dfa8, 0x356d1cf2, +0x107789be, 0xb3b2e9ce, 0x0502aa8f, 0x0bc0351e, 0x166bf52a, 0xeb12ff82, 0xe3486911, 0xd34d7516, +0x4e7b3aff, 0x5f43671b, 0x9cf6e037, 0x4981ac83, 0x334266ce, 0x8c9341b7, 0xd0d854c0, 0xcb3a6c88, +0x47bc2829, 0x4725ba37, 0xa66ad22b, 0x7ad61f1e, 0x0c5cbafa, 0x4437f107, 0xb6e79962, 0x42d2d816, +0x0a961288, 0xe1a5c06e, 0x13749e67, 0x72fc081a, 0xb1d139f7, 0xf9583745, 0xcf19df58, 0xbec3f756, +0xc06eba30, 0x07211b24, 0x45c28829, 0xc95e317f, 0xbc8ec511, 0x38bc46e9, 0xc6e6fa14, 0xbae8584a, +0xad4ebc46, 0x468f508b, 0x7829435f, 0xf124183b, 0x821dba9f, 0xaff60ff4, 0xea2c4e6d, 0x16e39264, +0x92544a8b, 0x009b4fc3, 0xaba68ced, 0x9ac96f78, 0x06a5b79a, 0xb2856e6e, 0x1aec3ca9, 0xbe838688, +0x0e0804e9, 0x55f1be56, 0xe7e5363b, 0xb3a1f25d, 0xf7debb85, 0x61fe033c, 0x16746233, 0x3c034c28, +0xda6d0c74, 0x79aac56c, 0x3ce4e1ad, 0x51f0c802, 0x98f8f35a, 0x1626a49f, 0xeed82b29, 0x1d382fe3, +0x0c4fb99a, 0xbb325778, 0x3ec6d97b, 0x6e77a6a9, 0xcb658b5c, 0xd45230c7, 0x2bd1408b, 0x60c03eb7, +0xb9068d78, 0xa33754f4, 0xf430c87d, 0xc8a71302, 0xb96d8c32, 0xebd4e7be, 0xbe8b9d2d, 0x7979fb06, +0xe7225308, 0x8b75cf77, 0x11ef8da4, 0xe083c858, 0x8d6b786f, 0x5a6317a6, 0xfa5cf7a0, 0x5dda0033, +0xf28ebfb0, 0xf5b9c310, 0xa0eac280, 0x08b9767a, 0xa3d9d2b0, 0x79d34217, 0x021a718d, 0x9ac6336a, +0x2711fd60, 0x438050e3, 0x069908a8, 0x3d7fedc4, 0x826d2bef, 0x4eeb8476, 0x488dcf25, 0x36c9d566, +0x28e74e41, 0xc2610aca, 0x3d49a9cf, 0xbae3b9df, 0xb65f8de6, 0x92aeaf64, 0x3ac7d5e6, 0x9ea80509, +0xf22b017d, 0xa4173f70, 0xdd1e16c3, 0x15e0d7f9, 0x50b1b887, 0x2b9f4fd5, 0x625aba82, 0x6a017962, +0x2ec01b9c, 0x15488aa9, 0xd716e740, 0x40055a2c, 0x93d29a22, 0xe32dbf9a, 0x058745b9, 0x3453dc1e, +0xd699296e, 0x496cff6f, 0x1c9f4986, 0xdfe2ed07, 0xb87242d1, 0x19de7eae, 0x053e561a, 0x15ad6f8c, +0x66626c1c, 0x7154c24c, 0xea082b2a, 0x93eb2939, 0x17dcb0f0, 0x58d4f2ae, 0x9ea294fb, 0x52cf564c, +0x9883fe66, 0x2ec40581, 0x763953c3, 0x01d6692e, 0xd3a0c108, 0xa1e7160e, 0xe4f2dfa6, 0x693ed285, +0x74904698, 0x4c2b0edd, 0x4f757656, 0x5d393378, 0xa132234f, 0x3d321c5d, 0xc3f5e194, 0x4b269301, +0xc79f022f, 0x3c997e7e, 0x5e4f9504, 0x3ffafbbd, 0x76f7ad0e, 0x296693f4, 0x3d1fce6f, 0xc61e45be, +0xd3b5ab34, 0xf72bf9b7, 0x1b0434c0, 0x4e72b567, 0x5592a33d, 0xb5229301, 0xcfd2a87f, 0x60aeb767, +0x1814386b, 0x30bcc33d, 0x38a0c07d, 0xfd1606f2, 0xc363519b, 0x589dd390, 0x5479f8e6, 0x1cb8d647, +0x97fd61a9, 0xea7759f4, 0x2d57539d, 0x569a58cf, 0xe84e63ad, 0x462e1b78, 0x6580f87e, 0xf3817914, +0x91da55f4, 0x40a230f3, 0xd1988f35, 0xb6e318d2, 0x3ffa50bc, 0x3d40f021, 0xc3c0bdae, 0x4958c24c, +0x518f36b2, 0x84b1d370, 0x0fedce83, 0x878ddada, 0xf2a279c7, 0x94e01be8, 0x90716f4b, 0x954b8aa3 + }, + S8 = { +0xe216300d, 0xbbddfffc, 0xa7ebdabd, 0x35648095, 0x7789f8b7, 0xe6c1121b, 0x0e241600, 0x052ce8b5, +0x11a9cfb0, 0xe5952f11, 0xece7990a, 0x9386d174, 0x2a42931c, 0x76e38111, 0xb12def3a, 0x37ddddfc, +0xde9adeb1, 0x0a0cc32c, 0xbe197029, 0x84a00940, 0xbb243a0f, 0xb4d137cf, 0xb44e79f0, 0x049eedfd, +0x0b15a15d, 0x480d3168, 0x8bbbde5a, 0x669ded42, 0xc7ece831, 0x3f8f95e7, 0x72df191b, 0x7580330d, +0x94074251, 0x5c7dcdfa, 0xabbe6d63, 0xaa402164, 0xb301d40a, 0x02e7d1ca, 0x53571dae, 0x7a3182a2, +0x12a8ddec, 0xfdaa335d, 0x176f43e8, 0x71fb46d4, 0x38129022, 0xce949ad4, 0xb84769ad, 0x965bd862, +0x82f3d055, 0x66fb9767, 0x15b80b4e, 0x1d5b47a0, 0x4cfde06f, 0xc28ec4b8, 0x57e8726e, 0x647a78fc, +0x99865d44, 0x608bd593, 0x6c200e03, 0x39dc5ff6, 0x5d0b00a3, 0xae63aff2, 0x7e8bd632, 0x70108c0c, +0xbbd35049, 0x2998df04, 0x980cf42a, 0x9b6df491, 0x9e7edd53, 0x06918548, 0x58cb7e07, 0x3b74ef2e, +0x522fffb1, 0xd24708cc, 0x1c7e27cd, 0xa4eb215b, 0x3cf1d2e2, 0x19b47a38, 0x424f7618, 0x35856039, +0x9d17dee7, 0x27eb35e6, 0xc9aff67b, 0x36baf5b8, 0x09c467cd, 0xc18910b1, 0xe11dbf7b, 0x06cd1af8, +0x7170c608, 0x2d5e3354, 0xd4de495a, 0x64c6d006, 0xbcc0c62c, 0x3dd00db3, 0x708f8f34, 0x77d51b42, +0x264f620f, 0x24b8d2bf, 0x15c1b79e, 0x46a52564, 0xf8d7e54e, 0x3e378160, 0x7895cda5, 0x859c15a5, +0xe6459788, 0xc37bc75f, 0xdb07ba0c, 0x0676a3ab, 0x7f229b1e, 0x31842e7b, 0x24259fd7, 0xf8bef472, +0x835ffcb8, 0x6df4c1f2, 0x96f5b195, 0xfd0af0fc, 0xb0fe134c, 0xe2506d3d, 0x4f9b12ea, 0xf215f225, +0xa223736f, 0x9fb4c428, 0x25d04979, 0x34c713f8, 0xc4618187, 0xea7a6e98, 0x7cd16efc, 0x1436876c, +0xf1544107, 0xbedeee14, 0x56e9af27, 0xa04aa441, 0x3cf7c899, 0x92ecbae6, 0xdd67016d, 0x151682eb, +0xa842eedf, 0xfdba60b4, 0xf1907b75, 0x20e3030f, 0x24d8c29e, 0xe139673b, 0xefa63fb8, 0x71873054, +0xb6f2cf3b, 0x9f326442, 0xcb15a4cc, 0xb01a4504, 0xf1e47d8d, 0x844a1be5, 0xbae7dfdc, 0x42cbda70, +0xcd7dae0a, 0x57e85b7a, 0xd53f5af6, 0x20cf4d8c, 0xcea4d428, 0x79d130a4, 0x3486ebfb, 0x33d3cddc, +0x77853b53, 0x37effcb5, 0xc5068778, 0xe580b3e6, 0x4e68b8f4, 0xc5c8b37e, 0x0d809ea2, 0x398feb7c, +0x132a4f94, 0x43b7950e, 0x2fee7d1c, 0x223613bd, 0xdd06caa2, 0x37df932b, 0xc4248289, 0xacf3ebc3, +0x5715f6b7, 0xef3478dd, 0xf267616f, 0xc148cbe4, 0x9052815e, 0x5e410fab, 0xb48a2465, 0x2eda7fa4, +0xe87b40e4, 0xe98ea084, 0x5889e9e1, 0xefd390fc, 0xdd07d35b, 0xdb485694, 0x38d7e5b2, 0x57720101, +0x730edebc, 0x5b643113, 0x94917e4f, 0x503c2fba, 0x646f1282, 0x7523d24a, 0xe0779695, 0xf9c17a8f, +0x7a5b2121, 0xd187b896, 0x29263a4d, 0xba510cdf, 0x81f47c9f, 0xad1163ed, 0xea7b5965, 0x1a00726e, +0x11403092, 0x00da6d77, 0x4a0cdd61, 0xad1f4603, 0x605bdfb0, 0x9eedc364, 0x22ebe6a8, 0xcee7d28a, +0xa0e736a0, 0x5564a6b9, 0x10853209, 0xc7eb8f37, 0x2de705ca, 0x8951570f, 0xdf09822b, 0xbd691a6c, +0xaa12e4f2, 0x87451c0f, 0xe0f6a27a, 0x3ada4819, 0x4cf1764f, 0x0d771c2b, 0x67cdb156, 0x350d8384, +0x5938fa0f, 0x42399ef3, 0x36997b07, 0x0e84093d, 0x4aa93e61, 0x8360d87b, 0x1fa98b0c, 0x1149382c, +0xe97625a5, 0x0614d1b7, 0x0e25244b, 0x0c768347, 0x589e8d82, 0x0d2059d1, 0xa466bb1e, 0xf8da0a82, +0x04f19130, 0xba6e4ec0, 0x99265164, 0x1ee7230d, 0x50b2ad80, 0xeaee6801, 0x8db2a283, 0xea8bf59e + }; + + //==================================== + // Useful constants + //==================================== + + protected static final int MAX_ROUNDS = 16; + protected static final int RED_ROUNDS = 12; + + protected static final int BLOCK_SIZE = 8; // bytes = 64 bits + + protected int _Kr[] = new int[17]; // the rotating round key + protected int _Km[] = new int[17]; // the masking round key + + private boolean _encrypting = false; + + private byte[] _workingKey = null; + private int _rounds = MAX_ROUNDS; + + public CAST5Engine() + { + } + + /** + * initialise a CAST cipher. + * + * @param encrypting whether or not we are for encryption. + * @param params the parameters required to set up the cipher. + * @exception IllegalArgumentException if the params argument is + * inappropriate. + */ + public void init( + boolean encrypting, + CipherParameters params) + { + if (params instanceof KeyParameter) + { + _encrypting = encrypting; + _workingKey = ((KeyParameter)params).getKey(); + + setKey(_workingKey); + + return; + } + + throw new IllegalArgumentException("Invalid parameter passed to "+getAlgorithmName()+" init - " + params.getClass().getName()); + } + + public String getAlgorithmName() + { + return "CAST5"; + } + + public int processBlock( + byte[] in, + int inOff, + byte[] out, + int outOff) + { + if (_workingKey == null) + { + throw new IllegalStateException(getAlgorithmName()+" not initialised"); + } + + int blockSize = getBlockSize(); + if ((inOff + blockSize) > in.length) + { + throw new DataLengthException("Input buffer too short"); + } + + if ((outOff + blockSize) > out.length) + { + throw new DataLengthException("Output buffer too short"); + } + + if (_encrypting) + { + return encryptBlock(in, inOff, out, outOff); + } + else + { + return decryptBlock(in, inOff, out, outOff); + } + } + + public void reset() + { + } + + public int getBlockSize() + { + return BLOCK_SIZE; + } + + //================================== + // Private Implementation + //================================== + + /* + * Creates the subkeys using the same nomenclature + * as described in RFC2144. + * + * See section 2.4 + */ + protected void setKey(byte[] key) + { + /* + * Determine the key size here, if required + * + * if keysize <= 80bits, use 12 rounds instead of 16 + * if keysize < 128bits, pad with 0 + * + * Typical key sizes => 40, 64, 80, 128 + */ + + if (key.length < 11) + { + _rounds = RED_ROUNDS; + } + + int z[] = new int[16]; + int x[] = new int[16]; + + int z03, z47, z8B, zCF; + int x03, x47, x8B, xCF; + + /* copy the key into x */ + for (int i=0; i< key.length; i++) + { + x[i] = key[i] & 0xff; + } + + /* + * This will look different because the selection of + * bytes from the input key I've already chosen the + * correct int. + */ + x03 = IntsTo32bits(x, 0x0); + x47 = IntsTo32bits(x, 0x4); + x8B = IntsTo32bits(x, 0x8); + xCF = IntsTo32bits(x, 0xC); + + z03 = x03 ^S5[x[0xD]] ^S6[x[0xF]] ^S7[x[0xC]] ^S8[x[0xE]] ^S7[x[0x8]]; + + Bits32ToInts(z03, z, 0x0); + z47 = x8B ^S5[z[0x0]] ^S6[z[0x2]] ^S7[z[0x1]] ^S8[z[0x3]] ^S8[x[0xA]]; + Bits32ToInts(z47, z, 0x4); + z8B = xCF ^S5[z[0x7]] ^S6[z[0x6]] ^S7[z[0x5]] ^S8[z[0x4]] ^S5[x[0x9]]; + Bits32ToInts(z8B, z, 0x8); + zCF = x47 ^S5[z[0xA]] ^S6[z[0x9]] ^S7[z[0xB]] ^S8[z[0x8]] ^S6[x[0xB]]; + Bits32ToInts(zCF, z, 0xC); + _Km[ 1]= S5[z[0x8]] ^ S6[z[0x9]] ^ S7[z[0x7]] ^ S8[z[0x6]] ^ S5[z[0x2]]; + _Km[ 2]= S5[z[0xA]] ^ S6[z[0xB]] ^ S7[z[0x5]] ^ S8[z[0x4]] ^ S6[z[0x6]]; + _Km[ 3]= S5[z[0xC]] ^ S6[z[0xD]] ^ S7[z[0x3]] ^ S8[z[0x2]] ^ S7[z[0x9]]; + _Km[ 4]= S5[z[0xE]] ^ S6[z[0xF]] ^ S7[z[0x1]] ^ S8[z[0x0]] ^ S8[z[0xC]]; + + z03 = IntsTo32bits(z, 0x0); + z47 = IntsTo32bits(z, 0x4); + z8B = IntsTo32bits(z, 0x8); + zCF = IntsTo32bits(z, 0xC); + x03 = z8B ^S5[z[0x5]] ^S6[z[0x7]] ^S7[z[0x4]] ^S8[z[0x6]] ^S7[z[0x0]]; + Bits32ToInts(x03, x, 0x0); + x47 = z03 ^S5[x[0x0]] ^S6[x[0x2]] ^S7[x[0x1]] ^S8[x[0x3]] ^S8[z[0x2]]; + Bits32ToInts(x47, x, 0x4); + x8B = z47 ^S5[x[0x7]] ^S6[x[0x6]] ^S7[x[0x5]] ^S8[x[0x4]] ^S5[z[0x1]]; + Bits32ToInts(x8B, x, 0x8); + xCF = zCF ^S5[x[0xA]] ^S6[x[0x9]] ^S7[x[0xB]] ^S8[x[0x8]] ^S6[z[0x3]]; + Bits32ToInts(xCF, x, 0xC); + _Km[ 5]= S5[x[0x3]] ^ S6[x[0x2]] ^ S7[x[0xC]] ^ S8[x[0xD]] ^ S5[x[0x8]]; + _Km[ 6]= S5[x[0x1]] ^ S6[x[0x0]] ^ S7[x[0xE]] ^ S8[x[0xF]] ^ S6[x[0xD]]; + _Km[ 7]= S5[x[0x7]] ^ S6[x[0x6]] ^ S7[x[0x8]] ^ S8[x[0x9]] ^ S7[x[0x3]]; + _Km[ 8]= S5[x[0x5]] ^ S6[x[0x4]] ^ S7[x[0xA]] ^ S8[x[0xB]] ^ S8[x[0x7]]; + + x03 = IntsTo32bits(x, 0x0); + x47 = IntsTo32bits(x, 0x4); + x8B = IntsTo32bits(x, 0x8); + xCF = IntsTo32bits(x, 0xC); + z03 = x03 ^S5[x[0xD]] ^S6[x[0xF]] ^S7[x[0xC]] ^S8[x[0xE]] ^S7[x[0x8]]; + Bits32ToInts(z03, z, 0x0); + z47 = x8B ^S5[z[0x0]] ^S6[z[0x2]] ^S7[z[0x1]] ^S8[z[0x3]] ^S8[x[0xA]]; + Bits32ToInts(z47, z, 0x4); + z8B = xCF ^S5[z[0x7]] ^S6[z[0x6]] ^S7[z[0x5]] ^S8[z[0x4]] ^S5[x[0x9]]; + Bits32ToInts(z8B, z, 0x8); + zCF = x47 ^S5[z[0xA]] ^S6[z[0x9]] ^S7[z[0xB]] ^S8[z[0x8]] ^S6[x[0xB]]; + Bits32ToInts(zCF, z, 0xC); + _Km[ 9]= S5[z[0x3]] ^ S6[z[0x2]] ^ S7[z[0xC]] ^ S8[z[0xD]] ^ S5[z[0x9]]; + _Km[10]= S5[z[0x1]] ^ S6[z[0x0]] ^ S7[z[0xE]] ^ S8[z[0xF]] ^ S6[z[0xc]]; + _Km[11]= S5[z[0x7]] ^ S6[z[0x6]] ^ S7[z[0x8]] ^ S8[z[0x9]] ^ S7[z[0x2]]; + _Km[12]= S5[z[0x5]] ^ S6[z[0x4]] ^ S7[z[0xA]] ^ S8[z[0xB]] ^ S8[z[0x6]]; + + z03 = IntsTo32bits(z, 0x0); + z47 = IntsTo32bits(z, 0x4); + z8B = IntsTo32bits(z, 0x8); + zCF = IntsTo32bits(z, 0xC); + x03 = z8B ^S5[z[0x5]] ^S6[z[0x7]] ^S7[z[0x4]] ^S8[z[0x6]] ^S7[z[0x0]]; + Bits32ToInts(x03, x, 0x0); + x47 = z03 ^S5[x[0x0]] ^S6[x[0x2]] ^S7[x[0x1]] ^S8[x[0x3]] ^S8[z[0x2]]; + Bits32ToInts(x47, x, 0x4); + x8B = z47 ^S5[x[0x7]] ^S6[x[0x6]] ^S7[x[0x5]] ^S8[x[0x4]] ^S5[z[0x1]]; + Bits32ToInts(x8B, x, 0x8); + xCF = zCF ^S5[x[0xA]] ^S6[x[0x9]] ^S7[x[0xB]] ^S8[x[0x8]] ^S6[z[0x3]]; + Bits32ToInts(xCF, x, 0xC); + _Km[13]= S5[x[0x8]] ^ S6[x[0x9]] ^ S7[x[0x7]] ^ S8[x[0x6]] ^ S5[x[0x3]]; + _Km[14]= S5[x[0xA]] ^ S6[x[0xB]] ^ S7[x[0x5]] ^ S8[x[0x4]] ^ S6[x[0x7]]; + _Km[15]= S5[x[0xC]] ^ S6[x[0xD]] ^ S7[x[0x3]] ^ S8[x[0x2]] ^ S7[x[0x8]]; + _Km[16]= S5[x[0xE]] ^ S6[x[0xF]] ^ S7[x[0x1]] ^ S8[x[0x0]] ^ S8[x[0xD]]; + + x03 = IntsTo32bits(x, 0x0); + x47 = IntsTo32bits(x, 0x4); + x8B = IntsTo32bits(x, 0x8); + xCF = IntsTo32bits(x, 0xC); + z03 = x03 ^S5[x[0xD]] ^S6[x[0xF]] ^S7[x[0xC]] ^S8[x[0xE]] ^S7[x[0x8]]; + Bits32ToInts(z03, z, 0x0); + z47 = x8B ^S5[z[0x0]] ^S6[z[0x2]] ^S7[z[0x1]] ^S8[z[0x3]] ^S8[x[0xA]]; + Bits32ToInts(z47, z, 0x4); + z8B = xCF ^S5[z[0x7]] ^S6[z[0x6]] ^S7[z[0x5]] ^S8[z[0x4]] ^S5[x[0x9]]; + Bits32ToInts(z8B, z, 0x8); + zCF = x47 ^S5[z[0xA]] ^S6[z[0x9]] ^S7[z[0xB]] ^S8[z[0x8]] ^S6[x[0xB]]; + Bits32ToInts(zCF, z, 0xC); + _Kr[ 1]=(S5[z[0x8]]^S6[z[0x9]]^S7[z[0x7]]^S8[z[0x6]] ^ S5[z[0x2]])&0x1f; + _Kr[ 2]=(S5[z[0xA]]^S6[z[0xB]]^S7[z[0x5]]^S8[z[0x4]] ^ S6[z[0x6]])&0x1f; + _Kr[ 3]=(S5[z[0xC]]^S6[z[0xD]]^S7[z[0x3]]^S8[z[0x2]] ^ S7[z[0x9]])&0x1f; + _Kr[ 4]=(S5[z[0xE]]^S6[z[0xF]]^S7[z[0x1]]^S8[z[0x0]] ^ S8[z[0xC]])&0x1f; + + z03 = IntsTo32bits(z, 0x0); + z47 = IntsTo32bits(z, 0x4); + z8B = IntsTo32bits(z, 0x8); + zCF = IntsTo32bits(z, 0xC); + x03 = z8B ^S5[z[0x5]] ^S6[z[0x7]] ^S7[z[0x4]] ^S8[z[0x6]] ^S7[z[0x0]]; + Bits32ToInts(x03, x, 0x0); + x47 = z03 ^S5[x[0x0]] ^S6[x[0x2]] ^S7[x[0x1]] ^S8[x[0x3]] ^S8[z[0x2]]; + Bits32ToInts(x47, x, 0x4); + x8B = z47 ^S5[x[0x7]] ^S6[x[0x6]] ^S7[x[0x5]] ^S8[x[0x4]] ^S5[z[0x1]]; + Bits32ToInts(x8B, x, 0x8); + xCF = zCF ^S5[x[0xA]] ^S6[x[0x9]] ^S7[x[0xB]] ^S8[x[0x8]] ^S6[z[0x3]]; + Bits32ToInts(xCF, x, 0xC); + _Kr[ 5]=(S5[x[0x3]]^S6[x[0x2]]^S7[x[0xC]]^S8[x[0xD]]^S5[x[0x8]])&0x1f; + _Kr[ 6]=(S5[x[0x1]]^S6[x[0x0]]^S7[x[0xE]]^S8[x[0xF]]^S6[x[0xD]])&0x1f; + _Kr[ 7]=(S5[x[0x7]]^S6[x[0x6]]^S7[x[0x8]]^S8[x[0x9]]^S7[x[0x3]])&0x1f; + _Kr[ 8]=(S5[x[0x5]]^S6[x[0x4]]^S7[x[0xA]]^S8[x[0xB]]^S8[x[0x7]])&0x1f; + + x03 = IntsTo32bits(x, 0x0); + x47 = IntsTo32bits(x, 0x4); + x8B = IntsTo32bits(x, 0x8); + xCF = IntsTo32bits(x, 0xC); + z03 = x03 ^S5[x[0xD]] ^S6[x[0xF]] ^S7[x[0xC]] ^S8[x[0xE]] ^S7[x[0x8]]; + Bits32ToInts(z03, z, 0x0); + z47 = x8B ^S5[z[0x0]] ^S6[z[0x2]] ^S7[z[0x1]] ^S8[z[0x3]] ^S8[x[0xA]]; + Bits32ToInts(z47, z, 0x4); + z8B = xCF ^S5[z[0x7]] ^S6[z[0x6]] ^S7[z[0x5]] ^S8[z[0x4]] ^S5[x[0x9]]; + Bits32ToInts(z8B, z, 0x8); + zCF = x47 ^S5[z[0xA]] ^S6[z[0x9]] ^S7[z[0xB]] ^S8[z[0x8]] ^S6[x[0xB]]; + Bits32ToInts(zCF, z, 0xC); + _Kr[ 9]=(S5[z[0x3]]^S6[z[0x2]]^S7[z[0xC]]^S8[z[0xD]]^S5[z[0x9]])&0x1f; + _Kr[10]=(S5[z[0x1]]^S6[z[0x0]]^S7[z[0xE]]^S8[z[0xF]]^S6[z[0xc]])&0x1f; + _Kr[11]=(S5[z[0x7]]^S6[z[0x6]]^S7[z[0x8]]^S8[z[0x9]]^S7[z[0x2]])&0x1f; + _Kr[12]=(S5[z[0x5]]^S6[z[0x4]]^S7[z[0xA]]^S8[z[0xB]]^S8[z[0x6]])&0x1f; + + z03 = IntsTo32bits(z, 0x0); + z47 = IntsTo32bits(z, 0x4); + z8B = IntsTo32bits(z, 0x8); + zCF = IntsTo32bits(z, 0xC); + x03 = z8B ^S5[z[0x5]] ^S6[z[0x7]] ^S7[z[0x4]] ^S8[z[0x6]] ^S7[z[0x0]]; + Bits32ToInts(x03, x, 0x0); + x47 = z03 ^S5[x[0x0]] ^S6[x[0x2]] ^S7[x[0x1]] ^S8[x[0x3]] ^S8[z[0x2]]; + Bits32ToInts(x47, x, 0x4); + x8B = z47 ^S5[x[0x7]] ^S6[x[0x6]] ^S7[x[0x5]] ^S8[x[0x4]] ^S5[z[0x1]]; + Bits32ToInts(x8B, x, 0x8); + xCF = zCF ^S5[x[0xA]] ^S6[x[0x9]] ^S7[x[0xB]] ^S8[x[0x8]] ^S6[z[0x3]]; + Bits32ToInts(xCF, x, 0xC); + _Kr[13]=(S5[x[0x8]]^S6[x[0x9]]^S7[x[0x7]]^S8[x[0x6]]^S5[x[0x3]])&0x1f; + _Kr[14]=(S5[x[0xA]]^S6[x[0xB]]^S7[x[0x5]]^S8[x[0x4]]^S6[x[0x7]])&0x1f; + _Kr[15]=(S5[x[0xC]]^S6[x[0xD]]^S7[x[0x3]]^S8[x[0x2]]^S7[x[0x8]])&0x1f; + _Kr[16]=(S5[x[0xE]]^S6[x[0xF]]^S7[x[0x1]]^S8[x[0x0]]^S8[x[0xD]])&0x1f; + } + + /** + * Encrypt the given input starting at the given offset and place + * the result in the provided buffer starting at the given offset. + * + * @param src The plaintext buffer + * @param srcIndex An offset into src + * @param dst The ciphertext buffer + * @param dstIndex An offset into dst + */ + protected int encryptBlock( + byte[] src, + int srcIndex, + byte[] dst, + int dstIndex) + { + + int result[] = new int[2]; + + // process the input block + // batch the units up into a 32 bit chunk and go for it + // the array is in bytes, the increment is 8x8 bits = 64 + + int L0 = BytesTo32bits(src, srcIndex); + int R0 = BytesTo32bits(src, srcIndex + 4); + + CAST_Encipher(L0, R0, result); + + // now stuff them into the destination block + Bits32ToBytes(result[0], dst, dstIndex); + Bits32ToBytes(result[1], dst, dstIndex + 4); + + return BLOCK_SIZE; + } + + /** + * Decrypt the given input starting at the given offset and place + * the result in the provided buffer starting at the given offset. + * + * @param src The plaintext buffer + * @param srcIndex An offset into src + * @param dst The ciphertext buffer + * @param dstIndex An offset into dst + */ + protected int decryptBlock( + byte[] src, + int srcIndex, + byte[] dst, + int dstIndex) + { + int result[] = new int[2]; + + // process the input block + // batch the units up into a 32 bit chunk and go for it + // the array is in bytes, the increment is 8x8 bits = 64 + int L16 = BytesTo32bits(src, srcIndex); + int R16 = BytesTo32bits(src, srcIndex+4); + + CAST_Decipher(L16, R16, result); + + // now stuff them into the destination block + Bits32ToBytes(result[0], dst, dstIndex); + Bits32ToBytes(result[1], dst, dstIndex+4); + + return BLOCK_SIZE; + } + + /** + * The first of the three processing functions for the + * encryption and decryption. + * + * @param D the input to be processed + * @param Kmi the mask to be used from Km[n] + * @param Kri the rotation value to be used + * + */ + protected final int F1(int D, int Kmi, int Kri) + { + int I = Kmi + D; + I = I << Kri | I >>> (32-Kri); + return ((S1[(I>>>24)&0xff]^S2[(I>>>16)&0xff])-S3[(I>>> 8)&0xff])+ + S4[I & 0xff]; + } + + /** + * The second of the three processing functions for the + * encryption and decryption. + * + * @param D the input to be processed + * @param Kmi the mask to be used from Km[n] + * @param Kri the rotation value to be used + * + */ + protected final int F2(int D, int Kmi, int Kri) + { + int I = Kmi ^ D; + I = I << Kri | I >>> (32-Kri); + return ((S1[(I>>>24)&0xff]-S2[(I>>>16)&0xff])+S3[(I>>> 8)&0xff])^ + S4[I & 0xff]; + } + + /** + * The third of the three processing functions for the + * encryption and decryption. + * + * @param D the input to be processed + * @param Kmi the mask to be used from Km[n] + * @param Kri the rotation value to be used + * + */ + protected final int F3(int D, int Kmi, int Kri) + { + int I = Kmi - D; + I = I << Kri | I >>> (32-Kri); + return ((S1[(I>>>24)&0xff]+S2[(I>>>16)&0xff])^S3[(I>>> 8)&0xff])- + S4[I & 0xff]; + } + + /** + * Does the 16 rounds to encrypt the block. + * + * @param L0 the LH-32bits of the plaintext block + * @param R0 the RH-32bits of the plaintext block + */ + protected final void CAST_Encipher(int L0, int R0, int result[]) + { + int Lp = L0; // the previous value, equiv to L[i-1] + int Rp = R0; // equivalent to R[i-1] + + /* + * numbering consistent with paper to make + * checking and validating easier + */ + int Li = L0, Ri = R0; + + for (int i = 1; i<=_rounds ; i++) + { + Lp = Li; + Rp = Ri; + + Li = Rp; + switch (i) + { + case 1: + case 4: + case 7: + case 10: + case 13: + case 16: + Ri = Lp ^ F1(Rp, _Km[i], _Kr[i]); + break; + case 2: + case 5: + case 8: + case 11: + case 14: + Ri = Lp ^ F2(Rp, _Km[i], _Kr[i]); + break; + case 3: + case 6: + case 9: + case 12: + case 15: + Ri = Lp ^ F3(Rp, _Km[i], _Kr[i]); + break; + } + } + + result[0] = Ri; + result[1] = Li; + + return; + } + + protected final void CAST_Decipher(int L16, int R16, int result[]) + { + int Lp = L16; // the previous value, equiv to L[i-1] + int Rp = R16; // equivalent to R[i-1] + + /* + * numbering consistent with paper to make + * checking and validating easier + */ + int Li = L16, Ri = R16; + + for (int i = _rounds; i > 0; i--) + { + Lp = Li; + Rp = Ri; + + Li = Rp; + switch (i) + { + case 1: + case 4: + case 7: + case 10: + case 13: + case 16: + Ri = Lp ^ F1(Rp, _Km[i], _Kr[i]); + break; + case 2: + case 5: + case 8: + case 11: + case 14: + Ri = Lp ^ F2(Rp, _Km[i], _Kr[i]); + break; + case 3: + case 6: + case 9: + case 12: + case 15: + Ri = Lp ^ F3(Rp, _Km[i], _Kr[i]); + break; + } + } + + result[0] = Ri; + result[1] = Li; + + return; + } + + protected final void Bits32ToInts(int in, int[] b, int offset) + { + b[offset + 3] = (in & 0xff); + b[offset + 2] = ((in >>> 8) & 0xff); + b[offset + 1] = ((in >>> 16) & 0xff); + b[offset] = ((in >>> 24) & 0xff); + } + + protected final int IntsTo32bits(int[] b, int i) + { + int rv = 0; + + rv = ((b[i] & 0xff) << 24) | + ((b[i+1] & 0xff) << 16) | + ((b[i+2] & 0xff) << 8) | + ((b[i+3] & 0xff)); + + return rv; + } + + protected final void Bits32ToBytes(int in, byte[] b, int offset) + { + b[offset + 3] = (byte)in; + b[offset + 2] = (byte)(in >>> 8); + b[offset + 1] = (byte)(in >>> 16); + b[offset] = (byte)(in >>> 24); + } + + protected final int BytesTo32bits(byte[] b, int i) + { + return ((b[i] & 0xff) << 24) | + ((b[i+1] & 0xff) << 16) | + ((b[i+2] & 0xff) << 8) | + ((b[i+3] & 0xff)); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/CAST6Engine.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/CAST6Engine.java new file mode 100644 index 0000000..2a3773e --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/CAST6Engine.java @@ -0,0 +1,296 @@ +package org.bc.crypto.engines; + + +/** + * A class that provides CAST6 key encryption operations, + * such as encoding data and generating keys. + * + * All the algorithms herein are from the Internet RFC + * + * RFC2612 - CAST6 (128bit block, 128-256bit key) + * + * and implement a simplified cryptography interface. + */ +public final class CAST6Engine extends CAST5Engine +{ + //==================================== + // Useful constants + //==================================== + + protected static final int ROUNDS = 12; + + protected static final int BLOCK_SIZE = 16; // bytes = 128 bits + + /* + * Put the round and mask keys into an array. + * Kr0[i] => _Kr[i*4 + 0] + */ + protected int _Kr[] = new int[ROUNDS*4]; // the rotating round key(s) + protected int _Km[] = new int[ROUNDS*4]; // the masking round key(s) + + /* + * Key setup + */ + protected int _Tr[] = new int[24 * 8]; + protected int _Tm[] = new int[24 * 8]; + + private int[] _workingKey = new int[8]; + + public CAST6Engine() + { + } + + public String getAlgorithmName() + { + return "CAST6"; + } + + public void reset() + { + } + + public int getBlockSize() + { + return BLOCK_SIZE; + } + + //================================== + // Private Implementation + //================================== + + /* + * Creates the subkeys using the same nomenclature + * as described in RFC2612. + * + * See section 2.4 + */ + protected void setKey(byte[] key) + { + int Cm = 0x5a827999; + int Mm = 0x6ed9eba1; + int Cr = 19; + int Mr = 17; + + /* + * Determine the key size here, if required + * + * if keysize < 256 bytes, pad with 0 + * + * Typical key sizes => 128, 160, 192, 224, 256 + */ + for (int i=0; i< 24; i++) + { + for (int j=0; j< 8; j++) + { + _Tm[i*8 + j] = Cm; + Cm = (Cm + Mm); // mod 2^32; + + _Tr[i*8 + j] = Cr; + Cr = (Cr + Mr) & 0x1f; // mod 32 + } + } + + byte[] tmpKey = new byte[64]; + int length = key.length; + System.arraycopy(key, 0, tmpKey, 0, length); + + // now create ABCDEFGH + for (int i=0; i< 8; i++) + { + _workingKey[i] = BytesTo32bits(tmpKey, i*4); + } + + // Generate the key schedule + for (int i=0; i< 12; i++) + { + // KAPPA <- W2i(KAPPA) + int i2 = i*2 *8; + _workingKey[6] ^= F1(_workingKey[7], _Tm[i2 ], _Tr[i2 ]); + _workingKey[5] ^= F2(_workingKey[6], _Tm[i2+1], _Tr[i2+1]); + _workingKey[4] ^= F3(_workingKey[5], _Tm[i2+2], _Tr[i2+2]); + _workingKey[3] ^= F1(_workingKey[4], _Tm[i2+3], _Tr[i2+3]); + _workingKey[2] ^= F2(_workingKey[3], _Tm[i2+4], _Tr[i2+4]); + _workingKey[1] ^= F3(_workingKey[2], _Tm[i2+5], _Tr[i2+5]); + _workingKey[0] ^= F1(_workingKey[1], _Tm[i2+6], _Tr[i2+6]); + _workingKey[7] ^= F2(_workingKey[0], _Tm[i2+7], _Tr[i2+7]); + + // KAPPA <- W2i+1(KAPPA) + i2 = (i*2 + 1)*8; + _workingKey[6] ^= F1(_workingKey[7], _Tm[i2 ], _Tr[i2 ]); + _workingKey[5] ^= F2(_workingKey[6], _Tm[i2+1], _Tr[i2+1]); + _workingKey[4] ^= F3(_workingKey[5], _Tm[i2+2], _Tr[i2+2]); + _workingKey[3] ^= F1(_workingKey[4], _Tm[i2+3], _Tr[i2+3]); + _workingKey[2] ^= F2(_workingKey[3], _Tm[i2+4], _Tr[i2+4]); + _workingKey[1] ^= F3(_workingKey[2], _Tm[i2+5], _Tr[i2+5]); + _workingKey[0] ^= F1(_workingKey[1], _Tm[i2+6], _Tr[i2+6]); + _workingKey[7] ^= F2(_workingKey[0], _Tm[i2+7], _Tr[i2+7]); + + // Kr_(i) <- KAPPA + _Kr[i*4 ] = _workingKey[0] & 0x1f; + _Kr[i*4 + 1] = _workingKey[2] & 0x1f; + _Kr[i*4 + 2] = _workingKey[4] & 0x1f; + _Kr[i*4 + 3] = _workingKey[6] & 0x1f; + + + // Km_(i) <- KAPPA + _Km[i*4 ] = _workingKey[7]; + _Km[i*4 + 1] = _workingKey[5]; + _Km[i*4 + 2] = _workingKey[3]; + _Km[i*4 + 3] = _workingKey[1]; + } + + } + + /** + * Encrypt the given input starting at the given offset and place + * the result in the provided buffer starting at the given offset. + * + * @param src The plaintext buffer + * @param srcIndex An offset into src + * @param dst The ciphertext buffer + * @param dstIndex An offset into dst + */ + protected int encryptBlock( + byte[] src, + int srcIndex, + byte[] dst, + int dstIndex) + { + + int result[] = new int[4]; + + // process the input block + // batch the units up into 4x32 bit chunks and go for it + + int A = BytesTo32bits(src, srcIndex); + int B = BytesTo32bits(src, srcIndex + 4); + int C = BytesTo32bits(src, srcIndex + 8); + int D = BytesTo32bits(src, srcIndex + 12); + + CAST_Encipher(A, B, C, D, result); + + // now stuff them into the destination block + Bits32ToBytes(result[0], dst, dstIndex); + Bits32ToBytes(result[1], dst, dstIndex + 4); + Bits32ToBytes(result[2], dst, dstIndex + 8); + Bits32ToBytes(result[3], dst, dstIndex + 12); + + return BLOCK_SIZE; + } + + /** + * Decrypt the given input starting at the given offset and place + * the result in the provided buffer starting at the given offset. + * + * @param src The plaintext buffer + * @param srcIndex An offset into src + * @param dst The ciphertext buffer + * @param dstIndex An offset into dst + */ + protected int decryptBlock( + byte[] src, + int srcIndex, + byte[] dst, + int dstIndex) + { + int result[] = new int[4]; + + // process the input block + // batch the units up into 4x32 bit chunks and go for it + int A = BytesTo32bits(src, srcIndex); + int B = BytesTo32bits(src, srcIndex + 4); + int C = BytesTo32bits(src, srcIndex + 8); + int D = BytesTo32bits(src, srcIndex + 12); + + CAST_Decipher(A, B, C, D, result); + + // now stuff them into the destination block + Bits32ToBytes(result[0], dst, dstIndex); + Bits32ToBytes(result[1], dst, dstIndex + 4); + Bits32ToBytes(result[2], dst, dstIndex + 8); + Bits32ToBytes(result[3], dst, dstIndex + 12); + + return BLOCK_SIZE; + } + + /** + * Does the 12 quad rounds rounds to encrypt the block. + * + * @param A the 00-31 bits of the plaintext block + * @param B the 32-63 bits of the plaintext block + * @param C the 64-95 bits of the plaintext block + * @param D the 96-127 bits of the plaintext block + * @param result the resulting ciphertext + */ + protected final void CAST_Encipher(int A, int B, int C, int D,int result[]) + { + int x; + for (int i=0; i< 6; i++) + { + x = i*4; + // BETA <- Qi(BETA) + C ^= F1(D, _Km[x], _Kr[x]); + B ^= F2(C, _Km[x + 1], _Kr[x + 1]); + A ^= F3(B, _Km[x + 2], _Kr[x + 2]); + D ^= F1(A, _Km[x + 3], _Kr[x + 3]); + + } + + for (int i=6; i<12; i++) + { + x = i*4; + // BETA <- QBARi(BETA) + D ^= F1(A, _Km[x + 3], _Kr[x + 3]); + A ^= F3(B, _Km[x + 2], _Kr[x + 2]); + B ^= F2(C, _Km[x + 1], _Kr[x + 1]); + C ^= F1(D, _Km[x], _Kr[x]); + + } + + result[0] = A; + result[1] = B; + result[2] = C; + result[3] = D; + } + + /** + * Does the 12 quad rounds rounds to decrypt the block. + * + * @param A the 00-31 bits of the ciphertext block + * @param B the 32-63 bits of the ciphertext block + * @param C the 64-95 bits of the ciphertext block + * @param D the 96-127 bits of the ciphertext block + * @param result the resulting plaintext + */ + protected final void CAST_Decipher(int A, int B, int C, int D,int result[]) + { + int x; + for (int i=0; i< 6; i++) + { + x = (11-i)*4; + // BETA <- Qi(BETA) + C ^= F1(D, _Km[x], _Kr[x]); + B ^= F2(C, _Km[x + 1], _Kr[x + 1]); + A ^= F3(B, _Km[x + 2], _Kr[x + 2]); + D ^= F1(A, _Km[x + 3], _Kr[x + 3]); + + } + + for (int i=6; i<12; i++) + { + x = (11-i)*4; + // BETA <- QBARi(BETA) + D ^= F1(A, _Km[x + 3], _Kr[x + 3]); + A ^= F3(B, _Km[x + 2], _Kr[x + 2]); + B ^= F2(C, _Km[x + 1], _Kr[x + 1]); + C ^= F1(D, _Km[x], _Kr[x]); + + } + + result[0] = A; + result[1] = B; + result[2] = C; + result[3] = D; + } + +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/CamelliaEngine.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/CamelliaEngine.java new file mode 100644 index 0000000..abc063c --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/CamelliaEngine.java @@ -0,0 +1,683 @@ +package org.bc.crypto.engines; + +import org.bc.crypto.BlockCipher; +import org.bc.crypto.CipherParameters; +import org.bc.crypto.DataLengthException; +import org.bc.crypto.params.KeyParameter; + +/** + * Camellia - based on RFC 3713. + */ +public class CamelliaEngine + implements BlockCipher +{ + private boolean initialised = false; + private boolean _keyIs128; + + private static final int BLOCK_SIZE = 16; + private static final int MASK8 = 0xff; + + private int[] subkey = new int[24 * 4]; + private int[] kw = new int[4 * 2]; // for whitening + private int[] ke = new int[6 * 2]; // for FL and FL^(-1) + private int[] state = new int[4]; // for encryption and decryption + + private static final int SIGMA[] = { + 0xa09e667f, 0x3bcc908b, + 0xb67ae858, 0x4caa73b2, + 0xc6ef372f, 0xe94f82be, + 0x54ff53a5, 0xf1d36f1c, + 0x10e527fa, 0xde682d1d, + 0xb05688c2, 0xb3e6c1fd + }; + + /* + * + * S-box data + * + */ + private static final int SBOX1_1110[] = { + 0x70707000, 0x82828200, 0x2c2c2c00, 0xececec00, 0xb3b3b300, 0x27272700, + 0xc0c0c000, 0xe5e5e500, 0xe4e4e400, 0x85858500, 0x57575700, 0x35353500, + 0xeaeaea00, 0x0c0c0c00, 0xaeaeae00, 0x41414100, 0x23232300, 0xefefef00, + 0x6b6b6b00, 0x93939300, 0x45454500, 0x19191900, 0xa5a5a500, 0x21212100, + 0xededed00, 0x0e0e0e00, 0x4f4f4f00, 0x4e4e4e00, 0x1d1d1d00, 0x65656500, + 0x92929200, 0xbdbdbd00, 0x86868600, 0xb8b8b800, 0xafafaf00, 0x8f8f8f00, + 0x7c7c7c00, 0xebebeb00, 0x1f1f1f00, 0xcecece00, 0x3e3e3e00, 0x30303000, + 0xdcdcdc00, 0x5f5f5f00, 0x5e5e5e00, 0xc5c5c500, 0x0b0b0b00, 0x1a1a1a00, + 0xa6a6a600, 0xe1e1e100, 0x39393900, 0xcacaca00, 0xd5d5d500, 0x47474700, + 0x5d5d5d00, 0x3d3d3d00, 0xd9d9d900, 0x01010100, 0x5a5a5a00, 0xd6d6d600, + 0x51515100, 0x56565600, 0x6c6c6c00, 0x4d4d4d00, 0x8b8b8b00, 0x0d0d0d00, + 0x9a9a9a00, 0x66666600, 0xfbfbfb00, 0xcccccc00, 0xb0b0b000, 0x2d2d2d00, + 0x74747400, 0x12121200, 0x2b2b2b00, 0x20202000, 0xf0f0f000, 0xb1b1b100, + 0x84848400, 0x99999900, 0xdfdfdf00, 0x4c4c4c00, 0xcbcbcb00, 0xc2c2c200, + 0x34343400, 0x7e7e7e00, 0x76767600, 0x05050500, 0x6d6d6d00, 0xb7b7b700, + 0xa9a9a900, 0x31313100, 0xd1d1d100, 0x17171700, 0x04040400, 0xd7d7d700, + 0x14141400, 0x58585800, 0x3a3a3a00, 0x61616100, 0xdedede00, 0x1b1b1b00, + 0x11111100, 0x1c1c1c00, 0x32323200, 0x0f0f0f00, 0x9c9c9c00, 0x16161600, + 0x53535300, 0x18181800, 0xf2f2f200, 0x22222200, 0xfefefe00, 0x44444400, + 0xcfcfcf00, 0xb2b2b200, 0xc3c3c300, 0xb5b5b500, 0x7a7a7a00, 0x91919100, + 0x24242400, 0x08080800, 0xe8e8e800, 0xa8a8a800, 0x60606000, 0xfcfcfc00, + 0x69696900, 0x50505000, 0xaaaaaa00, 0xd0d0d000, 0xa0a0a000, 0x7d7d7d00, + 0xa1a1a100, 0x89898900, 0x62626200, 0x97979700, 0x54545400, 0x5b5b5b00, + 0x1e1e1e00, 0x95959500, 0xe0e0e000, 0xffffff00, 0x64646400, 0xd2d2d200, + 0x10101000, 0xc4c4c400, 0x00000000, 0x48484800, 0xa3a3a300, 0xf7f7f700, + 0x75757500, 0xdbdbdb00, 0x8a8a8a00, 0x03030300, 0xe6e6e600, 0xdadada00, + 0x09090900, 0x3f3f3f00, 0xdddddd00, 0x94949400, 0x87878700, 0x5c5c5c00, + 0x83838300, 0x02020200, 0xcdcdcd00, 0x4a4a4a00, 0x90909000, 0x33333300, + 0x73737300, 0x67676700, 0xf6f6f600, 0xf3f3f300, 0x9d9d9d00, 0x7f7f7f00, + 0xbfbfbf00, 0xe2e2e200, 0x52525200, 0x9b9b9b00, 0xd8d8d800, 0x26262600, + 0xc8c8c800, 0x37373700, 0xc6c6c600, 0x3b3b3b00, 0x81818100, 0x96969600, + 0x6f6f6f00, 0x4b4b4b00, 0x13131300, 0xbebebe00, 0x63636300, 0x2e2e2e00, + 0xe9e9e900, 0x79797900, 0xa7a7a700, 0x8c8c8c00, 0x9f9f9f00, 0x6e6e6e00, + 0xbcbcbc00, 0x8e8e8e00, 0x29292900, 0xf5f5f500, 0xf9f9f900, 0xb6b6b600, + 0x2f2f2f00, 0xfdfdfd00, 0xb4b4b400, 0x59595900, 0x78787800, 0x98989800, + 0x06060600, 0x6a6a6a00, 0xe7e7e700, 0x46464600, 0x71717100, 0xbababa00, + 0xd4d4d400, 0x25252500, 0xababab00, 0x42424200, 0x88888800, 0xa2a2a200, + 0x8d8d8d00, 0xfafafa00, 0x72727200, 0x07070700, 0xb9b9b900, 0x55555500, + 0xf8f8f800, 0xeeeeee00, 0xacacac00, 0x0a0a0a00, 0x36363600, 0x49494900, + 0x2a2a2a00, 0x68686800, 0x3c3c3c00, 0x38383800, 0xf1f1f100, 0xa4a4a400, + 0x40404000, 0x28282800, 0xd3d3d300, 0x7b7b7b00, 0xbbbbbb00, 0xc9c9c900, + 0x43434300, 0xc1c1c100, 0x15151500, 0xe3e3e300, 0xadadad00, 0xf4f4f400, + 0x77777700, 0xc7c7c700, 0x80808000, 0x9e9e9e00 + }; + + private static final int SBOX4_4404[] = { + 0x70700070, 0x2c2c002c, 0xb3b300b3, 0xc0c000c0, 0xe4e400e4, 0x57570057, + 0xeaea00ea, 0xaeae00ae, 0x23230023, 0x6b6b006b, 0x45450045, 0xa5a500a5, + 0xeded00ed, 0x4f4f004f, 0x1d1d001d, 0x92920092, 0x86860086, 0xafaf00af, + 0x7c7c007c, 0x1f1f001f, 0x3e3e003e, 0xdcdc00dc, 0x5e5e005e, 0x0b0b000b, + 0xa6a600a6, 0x39390039, 0xd5d500d5, 0x5d5d005d, 0xd9d900d9, 0x5a5a005a, + 0x51510051, 0x6c6c006c, 0x8b8b008b, 0x9a9a009a, 0xfbfb00fb, 0xb0b000b0, + 0x74740074, 0x2b2b002b, 0xf0f000f0, 0x84840084, 0xdfdf00df, 0xcbcb00cb, + 0x34340034, 0x76760076, 0x6d6d006d, 0xa9a900a9, 0xd1d100d1, 0x04040004, + 0x14140014, 0x3a3a003a, 0xdede00de, 0x11110011, 0x32320032, 0x9c9c009c, + 0x53530053, 0xf2f200f2, 0xfefe00fe, 0xcfcf00cf, 0xc3c300c3, 0x7a7a007a, + 0x24240024, 0xe8e800e8, 0x60600060, 0x69690069, 0xaaaa00aa, 0xa0a000a0, + 0xa1a100a1, 0x62620062, 0x54540054, 0x1e1e001e, 0xe0e000e0, 0x64640064, + 0x10100010, 0x00000000, 0xa3a300a3, 0x75750075, 0x8a8a008a, 0xe6e600e6, + 0x09090009, 0xdddd00dd, 0x87870087, 0x83830083, 0xcdcd00cd, 0x90900090, + 0x73730073, 0xf6f600f6, 0x9d9d009d, 0xbfbf00bf, 0x52520052, 0xd8d800d8, + 0xc8c800c8, 0xc6c600c6, 0x81810081, 0x6f6f006f, 0x13130013, 0x63630063, + 0xe9e900e9, 0xa7a700a7, 0x9f9f009f, 0xbcbc00bc, 0x29290029, 0xf9f900f9, + 0x2f2f002f, 0xb4b400b4, 0x78780078, 0x06060006, 0xe7e700e7, 0x71710071, + 0xd4d400d4, 0xabab00ab, 0x88880088, 0x8d8d008d, 0x72720072, 0xb9b900b9, + 0xf8f800f8, 0xacac00ac, 0x36360036, 0x2a2a002a, 0x3c3c003c, 0xf1f100f1, + 0x40400040, 0xd3d300d3, 0xbbbb00bb, 0x43430043, 0x15150015, 0xadad00ad, + 0x77770077, 0x80800080, 0x82820082, 0xecec00ec, 0x27270027, 0xe5e500e5, + 0x85850085, 0x35350035, 0x0c0c000c, 0x41410041, 0xefef00ef, 0x93930093, + 0x19190019, 0x21210021, 0x0e0e000e, 0x4e4e004e, 0x65650065, 0xbdbd00bd, + 0xb8b800b8, 0x8f8f008f, 0xebeb00eb, 0xcece00ce, 0x30300030, 0x5f5f005f, + 0xc5c500c5, 0x1a1a001a, 0xe1e100e1, 0xcaca00ca, 0x47470047, 0x3d3d003d, + 0x01010001, 0xd6d600d6, 0x56560056, 0x4d4d004d, 0x0d0d000d, 0x66660066, + 0xcccc00cc, 0x2d2d002d, 0x12120012, 0x20200020, 0xb1b100b1, 0x99990099, + 0x4c4c004c, 0xc2c200c2, 0x7e7e007e, 0x05050005, 0xb7b700b7, 0x31310031, + 0x17170017, 0xd7d700d7, 0x58580058, 0x61610061, 0x1b1b001b, 0x1c1c001c, + 0x0f0f000f, 0x16160016, 0x18180018, 0x22220022, 0x44440044, 0xb2b200b2, + 0xb5b500b5, 0x91910091, 0x08080008, 0xa8a800a8, 0xfcfc00fc, 0x50500050, + 0xd0d000d0, 0x7d7d007d, 0x89890089, 0x97970097, 0x5b5b005b, 0x95950095, + 0xffff00ff, 0xd2d200d2, 0xc4c400c4, 0x48480048, 0xf7f700f7, 0xdbdb00db, + 0x03030003, 0xdada00da, 0x3f3f003f, 0x94940094, 0x5c5c005c, 0x02020002, + 0x4a4a004a, 0x33330033, 0x67670067, 0xf3f300f3, 0x7f7f007f, 0xe2e200e2, + 0x9b9b009b, 0x26260026, 0x37370037, 0x3b3b003b, 0x96960096, 0x4b4b004b, + 0xbebe00be, 0x2e2e002e, 0x79790079, 0x8c8c008c, 0x6e6e006e, 0x8e8e008e, + 0xf5f500f5, 0xb6b600b6, 0xfdfd00fd, 0x59590059, 0x98980098, 0x6a6a006a, + 0x46460046, 0xbaba00ba, 0x25250025, 0x42420042, 0xa2a200a2, 0xfafa00fa, + 0x07070007, 0x55550055, 0xeeee00ee, 0x0a0a000a, 0x49490049, 0x68680068, + 0x38380038, 0xa4a400a4, 0x28280028, 0x7b7b007b, 0xc9c900c9, 0xc1c100c1, + 0xe3e300e3, 0xf4f400f4, 0xc7c700c7, 0x9e9e009e + }; + + private static final int SBOX2_0222[] = { + 0x00e0e0e0, 0x00050505, 0x00585858, 0x00d9d9d9, 0x00676767, 0x004e4e4e, + 0x00818181, 0x00cbcbcb, 0x00c9c9c9, 0x000b0b0b, 0x00aeaeae, 0x006a6a6a, + 0x00d5d5d5, 0x00181818, 0x005d5d5d, 0x00828282, 0x00464646, 0x00dfdfdf, + 0x00d6d6d6, 0x00272727, 0x008a8a8a, 0x00323232, 0x004b4b4b, 0x00424242, + 0x00dbdbdb, 0x001c1c1c, 0x009e9e9e, 0x009c9c9c, 0x003a3a3a, 0x00cacaca, + 0x00252525, 0x007b7b7b, 0x000d0d0d, 0x00717171, 0x005f5f5f, 0x001f1f1f, + 0x00f8f8f8, 0x00d7d7d7, 0x003e3e3e, 0x009d9d9d, 0x007c7c7c, 0x00606060, + 0x00b9b9b9, 0x00bebebe, 0x00bcbcbc, 0x008b8b8b, 0x00161616, 0x00343434, + 0x004d4d4d, 0x00c3c3c3, 0x00727272, 0x00959595, 0x00ababab, 0x008e8e8e, + 0x00bababa, 0x007a7a7a, 0x00b3b3b3, 0x00020202, 0x00b4b4b4, 0x00adadad, + 0x00a2a2a2, 0x00acacac, 0x00d8d8d8, 0x009a9a9a, 0x00171717, 0x001a1a1a, + 0x00353535, 0x00cccccc, 0x00f7f7f7, 0x00999999, 0x00616161, 0x005a5a5a, + 0x00e8e8e8, 0x00242424, 0x00565656, 0x00404040, 0x00e1e1e1, 0x00636363, + 0x00090909, 0x00333333, 0x00bfbfbf, 0x00989898, 0x00979797, 0x00858585, + 0x00686868, 0x00fcfcfc, 0x00ececec, 0x000a0a0a, 0x00dadada, 0x006f6f6f, + 0x00535353, 0x00626262, 0x00a3a3a3, 0x002e2e2e, 0x00080808, 0x00afafaf, + 0x00282828, 0x00b0b0b0, 0x00747474, 0x00c2c2c2, 0x00bdbdbd, 0x00363636, + 0x00222222, 0x00383838, 0x00646464, 0x001e1e1e, 0x00393939, 0x002c2c2c, + 0x00a6a6a6, 0x00303030, 0x00e5e5e5, 0x00444444, 0x00fdfdfd, 0x00888888, + 0x009f9f9f, 0x00656565, 0x00878787, 0x006b6b6b, 0x00f4f4f4, 0x00232323, + 0x00484848, 0x00101010, 0x00d1d1d1, 0x00515151, 0x00c0c0c0, 0x00f9f9f9, + 0x00d2d2d2, 0x00a0a0a0, 0x00555555, 0x00a1a1a1, 0x00414141, 0x00fafafa, + 0x00434343, 0x00131313, 0x00c4c4c4, 0x002f2f2f, 0x00a8a8a8, 0x00b6b6b6, + 0x003c3c3c, 0x002b2b2b, 0x00c1c1c1, 0x00ffffff, 0x00c8c8c8, 0x00a5a5a5, + 0x00202020, 0x00898989, 0x00000000, 0x00909090, 0x00474747, 0x00efefef, + 0x00eaeaea, 0x00b7b7b7, 0x00151515, 0x00060606, 0x00cdcdcd, 0x00b5b5b5, + 0x00121212, 0x007e7e7e, 0x00bbbbbb, 0x00292929, 0x000f0f0f, 0x00b8b8b8, + 0x00070707, 0x00040404, 0x009b9b9b, 0x00949494, 0x00212121, 0x00666666, + 0x00e6e6e6, 0x00cecece, 0x00ededed, 0x00e7e7e7, 0x003b3b3b, 0x00fefefe, + 0x007f7f7f, 0x00c5c5c5, 0x00a4a4a4, 0x00373737, 0x00b1b1b1, 0x004c4c4c, + 0x00919191, 0x006e6e6e, 0x008d8d8d, 0x00767676, 0x00030303, 0x002d2d2d, + 0x00dedede, 0x00969696, 0x00262626, 0x007d7d7d, 0x00c6c6c6, 0x005c5c5c, + 0x00d3d3d3, 0x00f2f2f2, 0x004f4f4f, 0x00191919, 0x003f3f3f, 0x00dcdcdc, + 0x00797979, 0x001d1d1d, 0x00525252, 0x00ebebeb, 0x00f3f3f3, 0x006d6d6d, + 0x005e5e5e, 0x00fbfbfb, 0x00696969, 0x00b2b2b2, 0x00f0f0f0, 0x00313131, + 0x000c0c0c, 0x00d4d4d4, 0x00cfcfcf, 0x008c8c8c, 0x00e2e2e2, 0x00757575, + 0x00a9a9a9, 0x004a4a4a, 0x00575757, 0x00848484, 0x00111111, 0x00454545, + 0x001b1b1b, 0x00f5f5f5, 0x00e4e4e4, 0x000e0e0e, 0x00737373, 0x00aaaaaa, + 0x00f1f1f1, 0x00dddddd, 0x00595959, 0x00141414, 0x006c6c6c, 0x00929292, + 0x00545454, 0x00d0d0d0, 0x00787878, 0x00707070, 0x00e3e3e3, 0x00494949, + 0x00808080, 0x00505050, 0x00a7a7a7, 0x00f6f6f6, 0x00777777, 0x00939393, + 0x00868686, 0x00838383, 0x002a2a2a, 0x00c7c7c7, 0x005b5b5b, 0x00e9e9e9, + 0x00eeeeee, 0x008f8f8f, 0x00010101, 0x003d3d3d + }; + + private static final int SBOX3_3033[] = { + 0x38003838, 0x41004141, 0x16001616, 0x76007676, 0xd900d9d9, 0x93009393, + 0x60006060, 0xf200f2f2, 0x72007272, 0xc200c2c2, 0xab00abab, 0x9a009a9a, + 0x75007575, 0x06000606, 0x57005757, 0xa000a0a0, 0x91009191, 0xf700f7f7, + 0xb500b5b5, 0xc900c9c9, 0xa200a2a2, 0x8c008c8c, 0xd200d2d2, 0x90009090, + 0xf600f6f6, 0x07000707, 0xa700a7a7, 0x27002727, 0x8e008e8e, 0xb200b2b2, + 0x49004949, 0xde00dede, 0x43004343, 0x5c005c5c, 0xd700d7d7, 0xc700c7c7, + 0x3e003e3e, 0xf500f5f5, 0x8f008f8f, 0x67006767, 0x1f001f1f, 0x18001818, + 0x6e006e6e, 0xaf00afaf, 0x2f002f2f, 0xe200e2e2, 0x85008585, 0x0d000d0d, + 0x53005353, 0xf000f0f0, 0x9c009c9c, 0x65006565, 0xea00eaea, 0xa300a3a3, + 0xae00aeae, 0x9e009e9e, 0xec00ecec, 0x80008080, 0x2d002d2d, 0x6b006b6b, + 0xa800a8a8, 0x2b002b2b, 0x36003636, 0xa600a6a6, 0xc500c5c5, 0x86008686, + 0x4d004d4d, 0x33003333, 0xfd00fdfd, 0x66006666, 0x58005858, 0x96009696, + 0x3a003a3a, 0x09000909, 0x95009595, 0x10001010, 0x78007878, 0xd800d8d8, + 0x42004242, 0xcc00cccc, 0xef00efef, 0x26002626, 0xe500e5e5, 0x61006161, + 0x1a001a1a, 0x3f003f3f, 0x3b003b3b, 0x82008282, 0xb600b6b6, 0xdb00dbdb, + 0xd400d4d4, 0x98009898, 0xe800e8e8, 0x8b008b8b, 0x02000202, 0xeb00ebeb, + 0x0a000a0a, 0x2c002c2c, 0x1d001d1d, 0xb000b0b0, 0x6f006f6f, 0x8d008d8d, + 0x88008888, 0x0e000e0e, 0x19001919, 0x87008787, 0x4e004e4e, 0x0b000b0b, + 0xa900a9a9, 0x0c000c0c, 0x79007979, 0x11001111, 0x7f007f7f, 0x22002222, + 0xe700e7e7, 0x59005959, 0xe100e1e1, 0xda00dada, 0x3d003d3d, 0xc800c8c8, + 0x12001212, 0x04000404, 0x74007474, 0x54005454, 0x30003030, 0x7e007e7e, + 0xb400b4b4, 0x28002828, 0x55005555, 0x68006868, 0x50005050, 0xbe00bebe, + 0xd000d0d0, 0xc400c4c4, 0x31003131, 0xcb00cbcb, 0x2a002a2a, 0xad00adad, + 0x0f000f0f, 0xca00caca, 0x70007070, 0xff00ffff, 0x32003232, 0x69006969, + 0x08000808, 0x62006262, 0x00000000, 0x24002424, 0xd100d1d1, 0xfb00fbfb, + 0xba00baba, 0xed00eded, 0x45004545, 0x81008181, 0x73007373, 0x6d006d6d, + 0x84008484, 0x9f009f9f, 0xee00eeee, 0x4a004a4a, 0xc300c3c3, 0x2e002e2e, + 0xc100c1c1, 0x01000101, 0xe600e6e6, 0x25002525, 0x48004848, 0x99009999, + 0xb900b9b9, 0xb300b3b3, 0x7b007b7b, 0xf900f9f9, 0xce00cece, 0xbf00bfbf, + 0xdf00dfdf, 0x71007171, 0x29002929, 0xcd00cdcd, 0x6c006c6c, 0x13001313, + 0x64006464, 0x9b009b9b, 0x63006363, 0x9d009d9d, 0xc000c0c0, 0x4b004b4b, + 0xb700b7b7, 0xa500a5a5, 0x89008989, 0x5f005f5f, 0xb100b1b1, 0x17001717, + 0xf400f4f4, 0xbc00bcbc, 0xd300d3d3, 0x46004646, 0xcf00cfcf, 0x37003737, + 0x5e005e5e, 0x47004747, 0x94009494, 0xfa00fafa, 0xfc00fcfc, 0x5b005b5b, + 0x97009797, 0xfe00fefe, 0x5a005a5a, 0xac00acac, 0x3c003c3c, 0x4c004c4c, + 0x03000303, 0x35003535, 0xf300f3f3, 0x23002323, 0xb800b8b8, 0x5d005d5d, + 0x6a006a6a, 0x92009292, 0xd500d5d5, 0x21002121, 0x44004444, 0x51005151, + 0xc600c6c6, 0x7d007d7d, 0x39003939, 0x83008383, 0xdc00dcdc, 0xaa00aaaa, + 0x7c007c7c, 0x77007777, 0x56005656, 0x05000505, 0x1b001b1b, 0xa400a4a4, + 0x15001515, 0x34003434, 0x1e001e1e, 0x1c001c1c, 0xf800f8f8, 0x52005252, + 0x20002020, 0x14001414, 0xe900e9e9, 0xbd00bdbd, 0xdd00dddd, 0xe400e4e4, + 0xa100a1a1, 0xe000e0e0, 0x8a008a8a, 0xf100f1f1, 0xd600d6d6, 0x7a007a7a, + 0xbb00bbbb, 0xe300e3e3, 0x40004040, 0x4f004f4f + }; + + private static int rightRotate(int x, int s) + { + return (((x) >>> (s)) + ((x) << (32 - s))); + } + + private static int leftRotate(int x, int s) + { + return ((x) << (s)) + ((x) >>> (32 - s)); + } + + private static void roldq(int rot, int[] ki, int ioff, + int[] ko, int ooff) + { + ko[0 + ooff] = (ki[0 + ioff] << rot) | (ki[1 + ioff] >>> (32 - rot)); + ko[1 + ooff] = (ki[1 + ioff] << rot) | (ki[2 + ioff] >>> (32 - rot)); + ko[2 + ooff] = (ki[2 + ioff] << rot) | (ki[3 + ioff] >>> (32 - rot)); + ko[3 + ooff] = (ki[3 + ioff] << rot) | (ki[0 + ioff] >>> (32 - rot)); + ki[0 + ioff] = ko[0 + ooff]; + ki[1 + ioff] = ko[1 + ooff]; + ki[2 + ioff] = ko[2 + ooff]; + ki[3 + ioff] = ko[3 + ooff]; + } + + private static void decroldq(int rot, int[] ki, int ioff, + int[] ko, int ooff) + { + ko[2 + ooff] = (ki[0 + ioff] << rot) | (ki[1 + ioff] >>> (32 - rot)); + ko[3 + ooff] = (ki[1 + ioff] << rot) | (ki[2 + ioff] >>> (32 - rot)); + ko[0 + ooff] = (ki[2 + ioff] << rot) | (ki[3 + ioff] >>> (32 - rot)); + ko[1 + ooff] = (ki[3 + ioff] << rot) | (ki[0 + ioff] >>> (32 - rot)); + ki[0 + ioff] = ko[2 + ooff]; + ki[1 + ioff] = ko[3 + ooff]; + ki[2 + ioff] = ko[0 + ooff]; + ki[3 + ioff] = ko[1 + ooff]; + } + + private static void roldqo32(int rot, int[] ki, int ioff, + int[] ko, int ooff) + { + ko[0 + ooff] = (ki[1 + ioff] << (rot - 32)) | (ki[2 + ioff] >>> (64 - rot)); + ko[1 + ooff] = (ki[2 + ioff] << (rot - 32)) | (ki[3 + ioff] >>> (64 - rot)); + ko[2 + ooff] = (ki[3 + ioff] << (rot - 32)) | (ki[0 + ioff] >>> (64 - rot)); + ko[3 + ooff] = (ki[0 + ioff] << (rot - 32)) | (ki[1 + ioff] >>> (64 - rot)); + ki[0 + ioff] = ko[0 + ooff]; + ki[1 + ioff] = ko[1 + ooff]; + ki[2 + ioff] = ko[2 + ooff]; + ki[3 + ioff] = ko[3 + ooff]; + } + + private static void decroldqo32(int rot, int[] ki, int ioff, + int[] ko, int ooff) + { + ko[2 + ooff] = (ki[1 + ioff] << (rot - 32)) | (ki[2 + ioff] >>> (64 - rot)); + ko[3 + ooff] = (ki[2 + ioff] << (rot - 32)) | (ki[3 + ioff] >>> (64 - rot)); + ko[0 + ooff] = (ki[3 + ioff] << (rot - 32)) | (ki[0 + ioff] >>> (64 - rot)); + ko[1 + ooff] = (ki[0 + ioff] << (rot - 32)) | (ki[1 + ioff] >>> (64 - rot)); + ki[0 + ioff] = ko[2 + ooff]; + ki[1 + ioff] = ko[3 + ooff]; + ki[2 + ioff] = ko[0 + ooff]; + ki[3 + ioff] = ko[1 + ooff]; + } + + private int bytes2int(byte[] src, int offset) + { + int word = 0; + + for (int i = 0; i < 4; i++) + { + word = (word << 8) + (src[i + offset] & MASK8); + } + return word; + } + + private void int2bytes(int word, byte[] dst, int offset) + { + for (int i = 0; i < 4; i++) + { + dst[(3 - i) + offset] = (byte)word; + word >>>= 8; + } + } + + private void camelliaF2(int[] s, int[] skey, int keyoff) + { + int t1, t2, u, v; + + t1 = s[0] ^ skey[0 + keyoff]; + u = SBOX4_4404[t1 & MASK8]; + u ^= SBOX3_3033[(t1 >>> 8) & MASK8]; + u ^= SBOX2_0222[(t1 >>> 16) & MASK8]; + u ^= SBOX1_1110[(t1 >>> 24) & MASK8]; + t2 = s[1] ^ skey[1 + keyoff]; + v = SBOX1_1110[t2 & MASK8]; + v ^= SBOX4_4404[(t2 >>> 8) & MASK8]; + v ^= SBOX3_3033[(t2 >>> 16) & MASK8]; + v ^= SBOX2_0222[(t2 >>> 24) & MASK8]; + + s[2] ^= u ^ v; + s[3] ^= u ^ v ^ rightRotate(u, 8); + + t1 = s[2] ^ skey[2 + keyoff]; + u = SBOX4_4404[t1 & MASK8]; + u ^= SBOX3_3033[(t1 >>> 8) & MASK8]; + u ^= SBOX2_0222[(t1 >>> 16) & MASK8]; + u ^= SBOX1_1110[(t1 >>> 24) & MASK8]; + t2 = s[3] ^ skey[3 + keyoff]; + v = SBOX1_1110[t2 & MASK8]; + v ^= SBOX4_4404[(t2 >>> 8) & MASK8]; + v ^= SBOX3_3033[(t2 >>> 16) & MASK8]; + v ^= SBOX2_0222[(t2 >>> 24) & MASK8]; + + s[0] ^= u ^ v; + s[1] ^= u ^ v ^ rightRotate(u, 8); + } + + private void camelliaFLs(int[] s, int[] fkey, int keyoff) + { + + s[1] ^= leftRotate(s[0] & fkey[0 + keyoff], 1); + s[0] ^= fkey[1 + keyoff] | s[1]; + + s[2] ^= fkey[3 + keyoff] | s[3]; + s[3] ^= leftRotate(fkey[2 + keyoff] & s[2], 1); + } + + private void setKey(boolean forEncryption, byte[] key) + { + int[] k = new int[8]; + int[] ka = new int[4]; + int[] kb = new int[4]; + int[] t = new int[4]; + + switch (key.length) + { + case 16: + _keyIs128 = true; + k[0] = bytes2int(key, 0); + k[1] = bytes2int(key, 4); + k[2] = bytes2int(key, 8); + k[3] = bytes2int(key, 12); + k[4] = k[5] = k[6] = k[7] = 0; + break; + case 24: + k[0] = bytes2int(key, 0); + k[1] = bytes2int(key, 4); + k[2] = bytes2int(key, 8); + k[3] = bytes2int(key, 12); + k[4] = bytes2int(key, 16); + k[5] = bytes2int(key, 20); + k[6] = ~k[4]; + k[7] = ~k[5]; + _keyIs128 = false; + break; + case 32: + k[0] = bytes2int(key, 0); + k[1] = bytes2int(key, 4); + k[2] = bytes2int(key, 8); + k[3] = bytes2int(key, 12); + k[4] = bytes2int(key, 16); + k[5] = bytes2int(key, 20); + k[6] = bytes2int(key, 24); + k[7] = bytes2int(key, 28); + _keyIs128 = false; + break; + default: + throw new + IllegalArgumentException("key sizes are only 16/24/32 bytes."); + } + + for (int i = 0; i < 4; i++) + { + ka[i] = k[i] ^ k[i + 4]; + } + /* compute KA */ + camelliaF2(ka, SIGMA, 0); + for (int i = 0; i < 4; i++) + { + ka[i] ^= k[i]; + } + camelliaF2(ka, SIGMA, 4); + + if (_keyIs128) + { + if (forEncryption) + { + /* KL dependant keys */ + kw[0] = k[0]; + kw[1] = k[1]; + kw[2] = k[2]; + kw[3] = k[3]; + roldq(15, k, 0, subkey, 4); + roldq(30, k, 0, subkey, 12); + roldq(15, k, 0, t, 0); + subkey[18] = t[2]; + subkey[19] = t[3]; + roldq(17, k, 0, ke, 4); + roldq(17, k, 0, subkey, 24); + roldq(17, k, 0, subkey, 32); + /* KA dependant keys */ + subkey[0] = ka[0]; + subkey[1] = ka[1]; + subkey[2] = ka[2]; + subkey[3] = ka[3]; + roldq(15, ka, 0, subkey, 8); + roldq(15, ka, 0, ke, 0); + roldq(15, ka, 0, t, 0); + subkey[16] = t[0]; + subkey[17] = t[1]; + roldq(15, ka, 0, subkey, 20); + roldqo32(34, ka, 0, subkey, 28); + roldq(17, ka, 0, kw, 4); + + } + else + { // decryption + /* KL dependant keys */ + kw[4] = k[0]; + kw[5] = k[1]; + kw[6] = k[2]; + kw[7] = k[3]; + decroldq(15, k, 0, subkey, 28); + decroldq(30, k, 0, subkey, 20); + decroldq(15, k, 0, t, 0); + subkey[16] = t[0]; + subkey[17] = t[1]; + decroldq(17, k, 0, ke, 0); + decroldq(17, k, 0, subkey, 8); + decroldq(17, k, 0, subkey, 0); + /* KA dependant keys */ + subkey[34] = ka[0]; + subkey[35] = ka[1]; + subkey[32] = ka[2]; + subkey[33] = ka[3]; + decroldq(15, ka, 0, subkey, 24); + decroldq(15, ka, 0, ke, 4); + decroldq(15, ka, 0, t, 0); + subkey[18] = t[2]; + subkey[19] = t[3]; + decroldq(15, ka, 0, subkey, 12); + decroldqo32(34, ka, 0, subkey, 4); + roldq(17, ka, 0, kw, 0); + } + } + else + { // 192bit or 256bit + /* compute KB */ + for (int i = 0; i < 4; i++) + { + kb[i] = ka[i] ^ k[i + 4]; + } + camelliaF2(kb, SIGMA, 8); + + if (forEncryption) + { + /* KL dependant keys */ + kw[0] = k[0]; + kw[1] = k[1]; + kw[2] = k[2]; + kw[3] = k[3]; + roldqo32(45, k, 0, subkey, 16); + roldq(15, k, 0, ke, 4); + roldq(17, k, 0, subkey, 32); + roldqo32(34, k, 0, subkey, 44); + /* KR dependant keys */ + roldq(15, k, 4, subkey, 4); + roldq(15, k, 4, ke, 0); + roldq(30, k, 4, subkey, 24); + roldqo32(34, k, 4, subkey, 36); + /* KA dependant keys */ + roldq(15, ka, 0, subkey, 8); + roldq(30, ka, 0, subkey, 20); + /* 32bit rotation */ + ke[8] = ka[1]; + ke[9] = ka[2]; + ke[10] = ka[3]; + ke[11] = ka[0]; + roldqo32(49, ka, 0, subkey, 40); + + /* KB dependant keys */ + subkey[0] = kb[0]; + subkey[1] = kb[1]; + subkey[2] = kb[2]; + subkey[3] = kb[3]; + roldq(30, kb, 0, subkey, 12); + roldq(30, kb, 0, subkey, 28); + roldqo32(51, kb, 0, kw, 4); + + } + else + { // decryption + /* KL dependant keys */ + kw[4] = k[0]; + kw[5] = k[1]; + kw[6] = k[2]; + kw[7] = k[3]; + decroldqo32(45, k, 0, subkey, 28); + decroldq(15, k, 0, ke, 4); + decroldq(17, k, 0, subkey, 12); + decroldqo32(34, k, 0, subkey, 0); + /* KR dependant keys */ + decroldq(15, k, 4, subkey, 40); + decroldq(15, k, 4, ke, 8); + decroldq(30, k, 4, subkey, 20); + decroldqo32(34, k, 4, subkey, 8); + /* KA dependant keys */ + decroldq(15, ka, 0, subkey, 36); + decroldq(30, ka, 0, subkey, 24); + /* 32bit rotation */ + ke[2] = ka[1]; + ke[3] = ka[2]; + ke[0] = ka[3]; + ke[1] = ka[0]; + decroldqo32(49, ka, 0, subkey, 4); + + /* KB dependant keys */ + subkey[46] = kb[0]; + subkey[47] = kb[1]; + subkey[44] = kb[2]; + subkey[45] = kb[3]; + decroldq(30, kb, 0, subkey, 32); + decroldq(30, kb, 0, subkey, 16); + roldqo32(51, kb, 0, kw, 0); + } + } + } + + private int processBlock128(byte[] in, int inOff, + byte[] out, int outOff) + { + for (int i = 0; i < 4; i++) + { + state[i] = bytes2int(in, inOff + (i * 4)); + state[i] ^= kw[i]; + } + + camelliaF2(state, subkey, 0); + camelliaF2(state, subkey, 4); + camelliaF2(state, subkey, 8); + camelliaFLs(state, ke, 0); + camelliaF2(state, subkey, 12); + camelliaF2(state, subkey, 16); + camelliaF2(state, subkey, 20); + camelliaFLs(state, ke, 4); + camelliaF2(state, subkey, 24); + camelliaF2(state, subkey, 28); + camelliaF2(state, subkey, 32); + + state[2] ^= kw[4]; + state[3] ^= kw[5]; + state[0] ^= kw[6]; + state[1] ^= kw[7]; + + int2bytes(state[2], out, outOff); + int2bytes(state[3], out, outOff + 4); + int2bytes(state[0], out, outOff + 8); + int2bytes(state[1], out, outOff + 12); + + return BLOCK_SIZE; + } + + private int processBlock192or256(byte[] in, int inOff, + byte[] out, int outOff) + { + for (int i = 0; i < 4; i++) + { + state[i] = bytes2int(in, inOff + (i * 4)); + state[i] ^= kw[i]; + } + + camelliaF2(state, subkey, 0); + camelliaF2(state, subkey, 4); + camelliaF2(state, subkey, 8); + camelliaFLs(state, ke, 0); + camelliaF2(state, subkey, 12); + camelliaF2(state, subkey, 16); + camelliaF2(state, subkey, 20); + camelliaFLs(state, ke, 4); + camelliaF2(state, subkey, 24); + camelliaF2(state, subkey, 28); + camelliaF2(state, subkey, 32); + camelliaFLs(state, ke, 8); + camelliaF2(state, subkey, 36); + camelliaF2(state, subkey, 40); + camelliaF2(state, subkey, 44); + + state[2] ^= kw[4]; + state[3] ^= kw[5]; + state[0] ^= kw[6]; + state[1] ^= kw[7]; + + int2bytes(state[2], out, outOff); + int2bytes(state[3], out, outOff + 4); + int2bytes(state[0], out, outOff + 8); + int2bytes(state[1], out, outOff + 12); + return BLOCK_SIZE; + } + + public CamelliaEngine() + { + } + + public void init(boolean forEncryption, CipherParameters params) + throws IllegalArgumentException + { + if (!(params instanceof KeyParameter)) + { + throw new IllegalArgumentException("only simple KeyParameter expected."); + } + + setKey(forEncryption, ((KeyParameter)params).getKey()); + initialised = true; + } + + public String getAlgorithmName() + { + return "Camellia"; + } + + public int getBlockSize() + { + return BLOCK_SIZE; + } + + public int processBlock( + byte[] in, + int inOff, + byte[] out, + int outOff) + throws DataLengthException, IllegalStateException + { + if (!initialised) + { + throw new IllegalStateException("Camellia engine not initialised"); + } + + if ((inOff + BLOCK_SIZE) > in.length) + { + throw new DataLengthException("input buffer too short"); + } + + if ((outOff + BLOCK_SIZE) > out.length) + { + throw new DataLengthException("output buffer too short"); + } + + if (_keyIs128) + { + return processBlock128(in, inOff, out, outOff); + } + else + { + return processBlock192or256(in, inOff, out, outOff); + } + } + + public void reset() + { + // nothing + + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/CamelliaLightEngine.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/CamelliaLightEngine.java new file mode 100644 index 0000000..f24f950 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/CamelliaLightEngine.java @@ -0,0 +1,591 @@ +package org.bc.crypto.engines; + +import org.bc.crypto.BlockCipher; +import org.bc.crypto.CipherParameters; +import org.bc.crypto.DataLengthException; +import org.bc.crypto.params.KeyParameter; + +/** + * Camellia - based on RFC 3713, smaller implementation, about half the size of CamelliaEngine. + */ + +public class CamelliaLightEngine + implements BlockCipher +{ + private static final int BLOCK_SIZE = 16; + private static final int MASK8 = 0xff; + private boolean initialized; + private boolean _keyis128; + + private int[] subkey = new int[24 * 4]; + private int[] kw = new int[4 * 2]; // for whitening + private int[] ke = new int[6 * 2]; // for FL and FL^(-1) + private int[] state = new int[4]; // for encryption and decryption + + private static final int SIGMA[] = { + 0xa09e667f, 0x3bcc908b, + 0xb67ae858, 0x4caa73b2, + 0xc6ef372f, 0xe94f82be, + 0x54ff53a5, 0xf1d36f1c, + 0x10e527fa, 0xde682d1d, + 0xb05688c2, 0xb3e6c1fd + }; + + /* + * + * S-box data + * + */ + private static final byte SBOX1[] = { + (byte)112, (byte)130, (byte)44, (byte)236, + (byte)179, (byte)39, (byte)192, (byte)229, + (byte)228, (byte)133, (byte)87, (byte)53, + (byte)234, (byte)12, (byte)174, (byte)65, + (byte)35, (byte)239, (byte)107, (byte)147, + (byte)69, (byte)25, (byte)165, (byte)33, + (byte)237, (byte)14, (byte)79, (byte)78, + (byte)29, (byte)101, (byte)146, (byte)189, + (byte)134, (byte)184, (byte)175, (byte)143, + (byte)124, (byte)235, (byte)31, (byte)206, + (byte)62, (byte)48, (byte)220, (byte)95, + (byte)94, (byte)197, (byte)11, (byte)26, + (byte)166, (byte)225, (byte)57, (byte)202, + (byte)213, (byte)71, (byte)93, (byte)61, + (byte)217, (byte)1, (byte)90, (byte)214, + (byte)81, (byte)86, (byte)108, (byte)77, + (byte)139, (byte)13, (byte)154, (byte)102, + (byte)251, (byte)204, (byte)176, (byte)45, + (byte)116, (byte)18, (byte)43, (byte)32, + (byte)240, (byte)177, (byte)132, (byte)153, + (byte)223, (byte)76, (byte)203, (byte)194, + (byte)52, (byte)126, (byte)118, (byte)5, + (byte)109, (byte)183, (byte)169, (byte)49, + (byte)209, (byte)23, (byte)4, (byte)215, + (byte)20, (byte)88, (byte)58, (byte)97, + (byte)222, (byte)27, (byte)17, (byte)28, + (byte)50, (byte)15, (byte)156, (byte)22, + (byte)83, (byte)24, (byte)242, (byte)34, + (byte)254, (byte)68, (byte)207, (byte)178, + (byte)195, (byte)181, (byte)122, (byte)145, + (byte)36, (byte)8, (byte)232, (byte)168, + (byte)96, (byte)252, (byte)105, (byte)80, + (byte)170, (byte)208, (byte)160, (byte)125, + (byte)161, (byte)137, (byte)98, (byte)151, + (byte)84, (byte)91, (byte)30, (byte)149, + (byte)224, (byte)255, (byte)100, (byte)210, + (byte)16, (byte)196, (byte)0, (byte)72, + (byte)163, (byte)247, (byte)117, (byte)219, + (byte)138, (byte)3, (byte)230, (byte)218, + (byte)9, (byte)63, (byte)221, (byte)148, + (byte)135, (byte)92, (byte)131, (byte)2, + (byte)205, (byte)74, (byte)144, (byte)51, + (byte)115, (byte)103, (byte)246, (byte)243, + (byte)157, (byte)127, (byte)191, (byte)226, + (byte)82, (byte)155, (byte)216, (byte)38, + (byte)200, (byte)55, (byte)198, (byte)59, + (byte)129, (byte)150, (byte)111, (byte)75, + (byte)19, (byte)190, (byte)99, (byte)46, + (byte)233, (byte)121, (byte)167, (byte)140, + (byte)159, (byte)110, (byte)188, (byte)142, + (byte)41, (byte)245, (byte)249, (byte)182, + (byte)47, (byte)253, (byte)180, (byte)89, + (byte)120, (byte)152, (byte)6, (byte)106, + (byte)231, (byte)70, (byte)113, (byte)186, + (byte)212, (byte)37, (byte)171, (byte)66, + (byte)136, (byte)162, (byte)141, (byte)250, + (byte)114, (byte)7, (byte)185, (byte)85, + (byte)248, (byte)238, (byte)172, (byte)10, + (byte)54, (byte)73, (byte)42, (byte)104, + (byte)60, (byte)56, (byte)241, (byte)164, + (byte)64, (byte)40, (byte)211, (byte)123, + (byte)187, (byte)201, (byte)67, (byte)193, + (byte)21, (byte)227, (byte)173, (byte)244, + (byte)119, (byte)199, (byte)128, (byte)158 + }; + + private static int rightRotate(int x, int s) + { + return (((x) >>> (s)) + ((x) << (32 - s))); + } + + private static int leftRotate(int x, int s) + { + return ((x) << (s)) + ((x) >>> (32 - s)); + } + + private static void roldq(int rot, int[] ki, int ioff, + int[] ko, int ooff) + { + ko[0 + ooff] = (ki[0 + ioff] << rot) | (ki[1 + ioff] >>> (32 - rot)); + ko[1 + ooff] = (ki[1 + ioff] << rot) | (ki[2 + ioff] >>> (32 - rot)); + ko[2 + ooff] = (ki[2 + ioff] << rot) | (ki[3 + ioff] >>> (32 - rot)); + ko[3 + ooff] = (ki[3 + ioff] << rot) | (ki[0 + ioff] >>> (32 - rot)); + ki[0 + ioff] = ko[0 + ooff]; + ki[1 + ioff] = ko[1 + ooff]; + ki[2 + ioff] = ko[2 + ooff]; + ki[3 + ioff] = ko[3 + ooff]; + } + + private static void decroldq(int rot, int[] ki, int ioff, + int[] ko, int ooff) + { + ko[2 + ooff] = (ki[0 + ioff] << rot) | (ki[1 + ioff] >>> (32 - rot)); + ko[3 + ooff] = (ki[1 + ioff] << rot) | (ki[2 + ioff] >>> (32 - rot)); + ko[0 + ooff] = (ki[2 + ioff] << rot) | (ki[3 + ioff] >>> (32 - rot)); + ko[1 + ooff] = (ki[3 + ioff] << rot) | (ki[0 + ioff] >>> (32 - rot)); + ki[0 + ioff] = ko[2 + ooff]; + ki[1 + ioff] = ko[3 + ooff]; + ki[2 + ioff] = ko[0 + ooff]; + ki[3 + ioff] = ko[1 + ooff]; + } + + private static void roldqo32(int rot, int[] ki, int ioff, + int[] ko, int ooff) + { + ko[0 + ooff] = (ki[1 + ioff] << (rot - 32)) | (ki[2 + ioff] >>> (64 - rot)); + ko[1 + ooff] = (ki[2 + ioff] << (rot - 32)) | (ki[3 + ioff] >>> (64 - rot)); + ko[2 + ooff] = (ki[3 + ioff] << (rot - 32)) | (ki[0 + ioff] >>> (64 - rot)); + ko[3 + ooff] = (ki[0 + ioff] << (rot - 32)) | (ki[1 + ioff] >>> (64 - rot)); + ki[0 + ioff] = ko[0 + ooff]; + ki[1 + ioff] = ko[1 + ooff]; + ki[2 + ioff] = ko[2 + ooff]; + ki[3 + ioff] = ko[3 + ooff]; + } + + private static void decroldqo32(int rot, int[] ki, int ioff, + int[] ko, int ooff) + { + ko[2 + ooff] = (ki[1 + ioff] << (rot - 32)) | (ki[2 + ioff] >>> (64 - rot)); + ko[3 + ooff] = (ki[2 + ioff] << (rot - 32)) | (ki[3 + ioff] >>> (64 - rot)); + ko[0 + ooff] = (ki[3 + ioff] << (rot - 32)) | (ki[0 + ioff] >>> (64 - rot)); + ko[1 + ooff] = (ki[0 + ioff] << (rot - 32)) | (ki[1 + ioff] >>> (64 - rot)); + ki[0 + ioff] = ko[2 + ooff]; + ki[1 + ioff] = ko[3 + ooff]; + ki[2 + ioff] = ko[0 + ooff]; + ki[3 + ioff] = ko[1 + ooff]; + } + + private int bytes2int(byte[] src, int offset) + { + int word = 0; + + for (int i = 0; i < 4; i++) + { + word = (word << 8) + (src[i + offset] & MASK8); + } + return word; + } + + private void int2bytes(int word, byte[] dst, int offset) + { + for (int i = 0; i < 4; i++) + { + dst[(3 - i) + offset] = (byte)word; + word >>>= 8; + } + } + + private byte lRot8(byte v, int rot) + { + return (byte)((v << rot) | ((v & 0xff) >>> (8 - rot))); + } + + private int sbox2(int x) + { + return (lRot8(SBOX1[x], 1) & MASK8); + } + + private int sbox3(int x) + { + return (lRot8(SBOX1[x], 7) & MASK8); + } + + private int sbox4(int x) + { + return (SBOX1[((int)lRot8((byte)x, 1) & MASK8)] & MASK8); + } + + private void camelliaF2(int[] s, int[] skey, int keyoff) + { + int t1, t2, u, v; + + t1 = s[0] ^ skey[0 + keyoff]; + u = sbox4((t1 & MASK8)); + u |= (sbox3(((t1 >>> 8) & MASK8)) << 8); + u |= (sbox2(((t1 >>> 16) & MASK8)) << 16); + u |= ((int)(SBOX1[((t1 >>> 24) & MASK8)] & MASK8) << 24); + + t2 = s[1] ^ skey[1 + keyoff]; + v = (int)SBOX1[(t2 & MASK8)] & MASK8; + v |= (sbox4(((t2 >>> 8) & MASK8)) << 8); + v |= (sbox3(((t2 >>> 16) & MASK8)) << 16); + v |= (sbox2(((t2 >>> 24) & MASK8)) << 24); + + v = leftRotate(v, 8); + u ^= v; + v = leftRotate(v, 8) ^ u; + u = rightRotate(u, 8) ^ v; + s[2] ^= leftRotate(v, 16) ^ u; + s[3] ^= leftRotate(u, 8); + + t1 = s[2] ^ skey[2 + keyoff]; + u = sbox4((t1 & MASK8)); + u |= sbox3(((t1 >>> 8) & MASK8)) << 8; + u |= sbox2(((t1 >>> 16) & MASK8)) << 16; + u |= ((int)SBOX1[((t1 >>> 24) & MASK8)] & MASK8) << 24; + + t2 = s[3] ^ skey[3 + keyoff]; + v = ((int)SBOX1[(t2 & MASK8)] & MASK8); + v |= sbox4(((t2 >>> 8) & MASK8)) << 8; + v |= sbox3(((t2 >>> 16) & MASK8)) << 16; + v |= sbox2(((t2 >>> 24) & MASK8)) << 24; + + v = leftRotate(v, 8); + u ^= v; + v = leftRotate(v, 8) ^ u; + u = rightRotate(u, 8) ^ v; + s[0] ^= leftRotate(v, 16) ^ u; + s[1] ^= leftRotate(u, 8); + } + + private void camelliaFLs(int[] s, int[] fkey, int keyoff) + { + + s[1] ^= leftRotate(s[0] & fkey[0 + keyoff], 1); + s[0] ^= fkey[1 + keyoff] | s[1]; + + s[2] ^= fkey[3 + keyoff] | s[3]; + s[3] ^= leftRotate(fkey[2 + keyoff] & s[2], 1); + } + + private void setKey(boolean forEncryption, byte[] key) + { + int[] k = new int[8]; + int[] ka = new int[4]; + int[] kb = new int[4]; + int[] t = new int[4]; + + switch (key.length) + { + case 16: + _keyis128 = true; + k[0] = bytes2int(key, 0); + k[1] = bytes2int(key, 4); + k[2] = bytes2int(key, 8); + k[3] = bytes2int(key, 12); + k[4] = k[5] = k[6] = k[7] = 0; + break; + case 24: + k[0] = bytes2int(key, 0); + k[1] = bytes2int(key, 4); + k[2] = bytes2int(key, 8); + k[3] = bytes2int(key, 12); + k[4] = bytes2int(key, 16); + k[5] = bytes2int(key, 20); + k[6] = ~k[4]; + k[7] = ~k[5]; + _keyis128 = false; + break; + case 32: + k[0] = bytes2int(key, 0); + k[1] = bytes2int(key, 4); + k[2] = bytes2int(key, 8); + k[3] = bytes2int(key, 12); + k[4] = bytes2int(key, 16); + k[5] = bytes2int(key, 20); + k[6] = bytes2int(key, 24); + k[7] = bytes2int(key, 28); + _keyis128 = false; + break; + default: + throw new + IllegalArgumentException("key sizes are only 16/24/32 bytes."); + } + + for (int i = 0; i < 4; i++) + { + ka[i] = k[i] ^ k[i + 4]; + } + /* compute KA */ + camelliaF2(ka, SIGMA, 0); + for (int i = 0; i < 4; i++) + { + ka[i] ^= k[i]; + } + camelliaF2(ka, SIGMA, 4); + + if (_keyis128) + { + if (forEncryption) + { + /* KL dependant keys */ + kw[0] = k[0]; + kw[1] = k[1]; + kw[2] = k[2]; + kw[3] = k[3]; + roldq(15, k, 0, subkey, 4); + roldq(30, k, 0, subkey, 12); + roldq(15, k, 0, t, 0); + subkey[18] = t[2]; + subkey[19] = t[3]; + roldq(17, k, 0, ke, 4); + roldq(17, k, 0, subkey, 24); + roldq(17, k, 0, subkey, 32); + /* KA dependant keys */ + subkey[0] = ka[0]; + subkey[1] = ka[1]; + subkey[2] = ka[2]; + subkey[3] = ka[3]; + roldq(15, ka, 0, subkey, 8); + roldq(15, ka, 0, ke, 0); + roldq(15, ka, 0, t, 0); + subkey[16] = t[0]; + subkey[17] = t[1]; + roldq(15, ka, 0, subkey, 20); + roldqo32(34, ka, 0, subkey, 28); + roldq(17, ka, 0, kw, 4); + + } + else + { // decryption + /* KL dependant keys */ + kw[4] = k[0]; + kw[5] = k[1]; + kw[6] = k[2]; + kw[7] = k[3]; + decroldq(15, k, 0, subkey, 28); + decroldq(30, k, 0, subkey, 20); + decroldq(15, k, 0, t, 0); + subkey[16] = t[0]; + subkey[17] = t[1]; + decroldq(17, k, 0, ke, 0); + decroldq(17, k, 0, subkey, 8); + decroldq(17, k, 0, subkey, 0); + /* KA dependant keys */ + subkey[34] = ka[0]; + subkey[35] = ka[1]; + subkey[32] = ka[2]; + subkey[33] = ka[3]; + decroldq(15, ka, 0, subkey, 24); + decroldq(15, ka, 0, ke, 4); + decroldq(15, ka, 0, t, 0); + subkey[18] = t[2]; + subkey[19] = t[3]; + decroldq(15, ka, 0, subkey, 12); + decroldqo32(34, ka, 0, subkey, 4); + roldq(17, ka, 0, kw, 0); + } + } + else + { // 192bit or 256bit + /* compute KB */ + for (int i = 0; i < 4; i++) + { + kb[i] = ka[i] ^ k[i + 4]; + } + camelliaF2(kb, SIGMA, 8); + + if (forEncryption) + { + /* KL dependant keys */ + kw[0] = k[0]; + kw[1] = k[1]; + kw[2] = k[2]; + kw[3] = k[3]; + roldqo32(45, k, 0, subkey, 16); + roldq(15, k, 0, ke, 4); + roldq(17, k, 0, subkey, 32); + roldqo32(34, k, 0, subkey, 44); + /* KR dependant keys */ + roldq(15, k, 4, subkey, 4); + roldq(15, k, 4, ke, 0); + roldq(30, k, 4, subkey, 24); + roldqo32(34, k, 4, subkey, 36); + /* KA dependant keys */ + roldq(15, ka, 0, subkey, 8); + roldq(30, ka, 0, subkey, 20); + /* 32bit rotation */ + ke[8] = ka[1]; + ke[9] = ka[2]; + ke[10] = ka[3]; + ke[11] = ka[0]; + roldqo32(49, ka, 0, subkey, 40); + + /* KB dependant keys */ + subkey[0] = kb[0]; + subkey[1] = kb[1]; + subkey[2] = kb[2]; + subkey[3] = kb[3]; + roldq(30, kb, 0, subkey, 12); + roldq(30, kb, 0, subkey, 28); + roldqo32(51, kb, 0, kw, 4); + + } + else + { // decryption + /* KL dependant keys */ + kw[4] = k[0]; + kw[5] = k[1]; + kw[6] = k[2]; + kw[7] = k[3]; + decroldqo32(45, k, 0, subkey, 28); + decroldq(15, k, 0, ke, 4); + decroldq(17, k, 0, subkey, 12); + decroldqo32(34, k, 0, subkey, 0); + /* KR dependant keys */ + decroldq(15, k, 4, subkey, 40); + decroldq(15, k, 4, ke, 8); + decroldq(30, k, 4, subkey, 20); + decroldqo32(34, k, 4, subkey, 8); + /* KA dependant keys */ + decroldq(15, ka, 0, subkey, 36); + decroldq(30, ka, 0, subkey, 24); + /* 32bit rotation */ + ke[2] = ka[1]; + ke[3] = ka[2]; + ke[0] = ka[3]; + ke[1] = ka[0]; + decroldqo32(49, ka, 0, subkey, 4); + + /* KB dependant keys */ + subkey[46] = kb[0]; + subkey[47] = kb[1]; + subkey[44] = kb[2]; + subkey[45] = kb[3]; + decroldq(30, kb, 0, subkey, 32); + decroldq(30, kb, 0, subkey, 16); + roldqo32(51, kb, 0, kw, 0); + } + } + } + + private int processBlock128(byte[] in, int inOff, + byte[] out, int outOff) + { + for (int i = 0; i < 4; i++) + { + state[i] = bytes2int(in, inOff + (i * 4)); + state[i] ^= kw[i]; + } + + camelliaF2(state, subkey, 0); + camelliaF2(state, subkey, 4); + camelliaF2(state, subkey, 8); + camelliaFLs(state, ke, 0); + camelliaF2(state, subkey, 12); + camelliaF2(state, subkey, 16); + camelliaF2(state, subkey, 20); + camelliaFLs(state, ke, 4); + camelliaF2(state, subkey, 24); + camelliaF2(state, subkey, 28); + camelliaF2(state, subkey, 32); + + state[2] ^= kw[4]; + state[3] ^= kw[5]; + state[0] ^= kw[6]; + state[1] ^= kw[7]; + + int2bytes(state[2], out, outOff); + int2bytes(state[3], out, outOff + 4); + int2bytes(state[0], out, outOff + 8); + int2bytes(state[1], out, outOff + 12); + + return BLOCK_SIZE; + } + + private int processBlock192or256(byte[] in, int inOff, + byte[] out, int outOff) + { + for (int i = 0; i < 4; i++) + { + state[i] = bytes2int(in, inOff + (i * 4)); + state[i] ^= kw[i]; + } + + camelliaF2(state, subkey, 0); + camelliaF2(state, subkey, 4); + camelliaF2(state, subkey, 8); + camelliaFLs(state, ke, 0); + camelliaF2(state, subkey, 12); + camelliaF2(state, subkey, 16); + camelliaF2(state, subkey, 20); + camelliaFLs(state, ke, 4); + camelliaF2(state, subkey, 24); + camelliaF2(state, subkey, 28); + camelliaF2(state, subkey, 32); + camelliaFLs(state, ke, 8); + camelliaF2(state, subkey, 36); + camelliaF2(state, subkey, 40); + camelliaF2(state, subkey, 44); + + state[2] ^= kw[4]; + state[3] ^= kw[5]; + state[0] ^= kw[6]; + state[1] ^= kw[7]; + + int2bytes(state[2], out, outOff); + int2bytes(state[3], out, outOff + 4); + int2bytes(state[0], out, outOff + 8); + int2bytes(state[1], out, outOff + 12); + return BLOCK_SIZE; + } + + public CamelliaLightEngine() + { + } + + public String getAlgorithmName() + { + return "Camellia"; + } + + public int getBlockSize() + { + return BLOCK_SIZE; + } + + public void init(boolean forEncryption, CipherParameters params) + { + if (!(params instanceof KeyParameter)) + { + throw new IllegalArgumentException("only simple KeyParameter expected."); + } + + setKey(forEncryption, ((KeyParameter)params).getKey()); + initialized = true; + } + + public int processBlock(byte[] in, int inOff, + byte[] out, int outOff) + throws IllegalStateException + { + + if (!initialized) + { + throw new IllegalStateException("Camellia is not initialized"); + } + + if ((inOff + BLOCK_SIZE) > in.length) + { + throw new DataLengthException("input buffer too short"); + } + + if ((outOff + BLOCK_SIZE) > out.length) + { + throw new DataLengthException("output buffer too short"); + } + + if (_keyis128) + { + return processBlock128(in, inOff, out, outOff); + } + else + { + return processBlock192or256(in, inOff, out, outOff); + } + } + + public void reset() + { + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/CamelliaWrapEngine.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/CamelliaWrapEngine.java new file mode 100644 index 0000000..d60444b --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/CamelliaWrapEngine.java @@ -0,0 +1,15 @@ +package org.bc.crypto.engines; + +/** + * An implementation of the Camellia key wrapper based on RFC 3657/RFC 3394. + *
+ * For further details see: http://www.ietf.org/rfc/rfc3657.txt. + */ +public class CamelliaWrapEngine + extends RFC3394WrapEngine +{ + public CamelliaWrapEngine() + { + super(new CamelliaEngine()); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/DESEngine.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/DESEngine.java new file mode 100644 index 0000000..40641d5 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/DESEngine.java @@ -0,0 +1,494 @@ +package org.bc.crypto.engines; + +import org.bc.crypto.BlockCipher; +import org.bc.crypto.CipherParameters; +import org.bc.crypto.DataLengthException; +import org.bc.crypto.params.KeyParameter; + +/** + * a class that provides a basic DES engine. + */ +public class DESEngine + implements BlockCipher +{ + protected static final int BLOCK_SIZE = 8; + + private int[] workingKey = null; + + /** + * standard constructor. + */ + public DESEngine() + { + } + + /** + * initialise a DES cipher. + * + * @param encrypting whether or not we are for encryption. + * @param params the parameters required to set up the cipher. + * @exception IllegalArgumentException if the params argument is + * inappropriate. + */ + public void init( + boolean encrypting, + CipherParameters params) + { + if (params instanceof KeyParameter) + { + if (((KeyParameter)params).getKey().length > 8) + { + throw new IllegalArgumentException("DES key too long - should be 8 bytes"); + } + + workingKey = generateWorkingKey(encrypting, + ((KeyParameter)params).getKey()); + + return; + } + + throw new IllegalArgumentException("invalid parameter passed to DES init - " + params.getClass().getName()); + } + + public String getAlgorithmName() + { + return "DES"; + } + + public int getBlockSize() + { + return BLOCK_SIZE; + } + + public int processBlock( + byte[] in, + int inOff, + byte[] out, + int outOff) + { + if (workingKey == null) + { + throw new IllegalStateException("DES engine not initialised"); + } + + if ((inOff + BLOCK_SIZE) > in.length) + { + throw new DataLengthException("input buffer too short"); + } + + if ((outOff + BLOCK_SIZE) > out.length) + { + throw new DataLengthException("output buffer too short"); + } + + desFunc(workingKey, in, inOff, out, outOff); + + return BLOCK_SIZE; + } + + public void reset() + { + } + + /** + * what follows is mainly taken from "Applied Cryptography", by + * Bruce Schneier, however it also bears great resemblance to Richard + * Outerbridge's D3DES... + */ + +// private static final short[] Df_Key = +// { +// 0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef, +// 0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10, +// 0x89,0xab,0xcd,0xef,0x01,0x23,0x45,0x67 +// }; + + private static final short[] bytebit = + { + 0200, 0100, 040, 020, 010, 04, 02, 01 + }; + + private static final int[] bigbyte = + { + 0x800000, 0x400000, 0x200000, 0x100000, + 0x80000, 0x40000, 0x20000, 0x10000, + 0x8000, 0x4000, 0x2000, 0x1000, + 0x800, 0x400, 0x200, 0x100, + 0x80, 0x40, 0x20, 0x10, + 0x8, 0x4, 0x2, 0x1 + }; + + /* + * Use the key schedule specified in the Standard (ANSI X3.92-1981). + */ + + private static final byte[] pc1 = + { + 56, 48, 40, 32, 24, 16, 8, 0, 57, 49, 41, 33, 25, 17, + 9, 1, 58, 50, 42, 34, 26, 18, 10, 2, 59, 51, 43, 35, + 62, 54, 46, 38, 30, 22, 14, 6, 61, 53, 45, 37, 29, 21, + 13, 5, 60, 52, 44, 36, 28, 20, 12, 4, 27, 19, 11, 3 + }; + + private static final byte[] totrot = + { + 1, 2, 4, 6, 8, 10, 12, 14, + 15, 17, 19, 21, 23, 25, 27, 28 + }; + + private static final byte[] pc2 = + { + 13, 16, 10, 23, 0, 4, 2, 27, 14, 5, 20, 9, + 22, 18, 11, 3, 25, 7, 15, 6, 26, 19, 12, 1, + 40, 51, 30, 36, 46, 54, 29, 39, 50, 44, 32, 47, + 43, 48, 38, 55, 33, 52, 45, 41, 49, 35, 28, 31 + }; + + private static final int[] SP1 = { + 0x01010400, 0x00000000, 0x00010000, 0x01010404, + 0x01010004, 0x00010404, 0x00000004, 0x00010000, + 0x00000400, 0x01010400, 0x01010404, 0x00000400, + 0x01000404, 0x01010004, 0x01000000, 0x00000004, + 0x00000404, 0x01000400, 0x01000400, 0x00010400, + 0x00010400, 0x01010000, 0x01010000, 0x01000404, + 0x00010004, 0x01000004, 0x01000004, 0x00010004, + 0x00000000, 0x00000404, 0x00010404, 0x01000000, + 0x00010000, 0x01010404, 0x00000004, 0x01010000, + 0x01010400, 0x01000000, 0x01000000, 0x00000400, + 0x01010004, 0x00010000, 0x00010400, 0x01000004, + 0x00000400, 0x00000004, 0x01000404, 0x00010404, + 0x01010404, 0x00010004, 0x01010000, 0x01000404, + 0x01000004, 0x00000404, 0x00010404, 0x01010400, + 0x00000404, 0x01000400, 0x01000400, 0x00000000, + 0x00010004, 0x00010400, 0x00000000, 0x01010004 + }; + + private static final int[] SP2 = { + 0x80108020, 0x80008000, 0x00008000, 0x00108020, + 0x00100000, 0x00000020, 0x80100020, 0x80008020, + 0x80000020, 0x80108020, 0x80108000, 0x80000000, + 0x80008000, 0x00100000, 0x00000020, 0x80100020, + 0x00108000, 0x00100020, 0x80008020, 0x00000000, + 0x80000000, 0x00008000, 0x00108020, 0x80100000, + 0x00100020, 0x80000020, 0x00000000, 0x00108000, + 0x00008020, 0x80108000, 0x80100000, 0x00008020, + 0x00000000, 0x00108020, 0x80100020, 0x00100000, + 0x80008020, 0x80100000, 0x80108000, 0x00008000, + 0x80100000, 0x80008000, 0x00000020, 0x80108020, + 0x00108020, 0x00000020, 0x00008000, 0x80000000, + 0x00008020, 0x80108000, 0x00100000, 0x80000020, + 0x00100020, 0x80008020, 0x80000020, 0x00100020, + 0x00108000, 0x00000000, 0x80008000, 0x00008020, + 0x80000000, 0x80100020, 0x80108020, 0x00108000 + }; + + private static final int[] SP3 = { + 0x00000208, 0x08020200, 0x00000000, 0x08020008, + 0x08000200, 0x00000000, 0x00020208, 0x08000200, + 0x00020008, 0x08000008, 0x08000008, 0x00020000, + 0x08020208, 0x00020008, 0x08020000, 0x00000208, + 0x08000000, 0x00000008, 0x08020200, 0x00000200, + 0x00020200, 0x08020000, 0x08020008, 0x00020208, + 0x08000208, 0x00020200, 0x00020000, 0x08000208, + 0x00000008, 0x08020208, 0x00000200, 0x08000000, + 0x08020200, 0x08000000, 0x00020008, 0x00000208, + 0x00020000, 0x08020200, 0x08000200, 0x00000000, + 0x00000200, 0x00020008, 0x08020208, 0x08000200, + 0x08000008, 0x00000200, 0x00000000, 0x08020008, + 0x08000208, 0x00020000, 0x08000000, 0x08020208, + 0x00000008, 0x00020208, 0x00020200, 0x08000008, + 0x08020000, 0x08000208, 0x00000208, 0x08020000, + 0x00020208, 0x00000008, 0x08020008, 0x00020200 + }; + + private static final int[] SP4 = { + 0x00802001, 0x00002081, 0x00002081, 0x00000080, + 0x00802080, 0x00800081, 0x00800001, 0x00002001, + 0x00000000, 0x00802000, 0x00802000, 0x00802081, + 0x00000081, 0x00000000, 0x00800080, 0x00800001, + 0x00000001, 0x00002000, 0x00800000, 0x00802001, + 0x00000080, 0x00800000, 0x00002001, 0x00002080, + 0x00800081, 0x00000001, 0x00002080, 0x00800080, + 0x00002000, 0x00802080, 0x00802081, 0x00000081, + 0x00800080, 0x00800001, 0x00802000, 0x00802081, + 0x00000081, 0x00000000, 0x00000000, 0x00802000, + 0x00002080, 0x00800080, 0x00800081, 0x00000001, + 0x00802001, 0x00002081, 0x00002081, 0x00000080, + 0x00802081, 0x00000081, 0x00000001, 0x00002000, + 0x00800001, 0x00002001, 0x00802080, 0x00800081, + 0x00002001, 0x00002080, 0x00800000, 0x00802001, + 0x00000080, 0x00800000, 0x00002000, 0x00802080 + }; + + private static final int[] SP5 = { + 0x00000100, 0x02080100, 0x02080000, 0x42000100, + 0x00080000, 0x00000100, 0x40000000, 0x02080000, + 0x40080100, 0x00080000, 0x02000100, 0x40080100, + 0x42000100, 0x42080000, 0x00080100, 0x40000000, + 0x02000000, 0x40080000, 0x40080000, 0x00000000, + 0x40000100, 0x42080100, 0x42080100, 0x02000100, + 0x42080000, 0x40000100, 0x00000000, 0x42000000, + 0x02080100, 0x02000000, 0x42000000, 0x00080100, + 0x00080000, 0x42000100, 0x00000100, 0x02000000, + 0x40000000, 0x02080000, 0x42000100, 0x40080100, + 0x02000100, 0x40000000, 0x42080000, 0x02080100, + 0x40080100, 0x00000100, 0x02000000, 0x42080000, + 0x42080100, 0x00080100, 0x42000000, 0x42080100, + 0x02080000, 0x00000000, 0x40080000, 0x42000000, + 0x00080100, 0x02000100, 0x40000100, 0x00080000, + 0x00000000, 0x40080000, 0x02080100, 0x40000100 + }; + + private static final int[] SP6 = { + 0x20000010, 0x20400000, 0x00004000, 0x20404010, + 0x20400000, 0x00000010, 0x20404010, 0x00400000, + 0x20004000, 0x00404010, 0x00400000, 0x20000010, + 0x00400010, 0x20004000, 0x20000000, 0x00004010, + 0x00000000, 0x00400010, 0x20004010, 0x00004000, + 0x00404000, 0x20004010, 0x00000010, 0x20400010, + 0x20400010, 0x00000000, 0x00404010, 0x20404000, + 0x00004010, 0x00404000, 0x20404000, 0x20000000, + 0x20004000, 0x00000010, 0x20400010, 0x00404000, + 0x20404010, 0x00400000, 0x00004010, 0x20000010, + 0x00400000, 0x20004000, 0x20000000, 0x00004010, + 0x20000010, 0x20404010, 0x00404000, 0x20400000, + 0x00404010, 0x20404000, 0x00000000, 0x20400010, + 0x00000010, 0x00004000, 0x20400000, 0x00404010, + 0x00004000, 0x00400010, 0x20004010, 0x00000000, + 0x20404000, 0x20000000, 0x00400010, 0x20004010 + }; + + private static final int[] SP7 = { + 0x00200000, 0x04200002, 0x04000802, 0x00000000, + 0x00000800, 0x04000802, 0x00200802, 0x04200800, + 0x04200802, 0x00200000, 0x00000000, 0x04000002, + 0x00000002, 0x04000000, 0x04200002, 0x00000802, + 0x04000800, 0x00200802, 0x00200002, 0x04000800, + 0x04000002, 0x04200000, 0x04200800, 0x00200002, + 0x04200000, 0x00000800, 0x00000802, 0x04200802, + 0x00200800, 0x00000002, 0x04000000, 0x00200800, + 0x04000000, 0x00200800, 0x00200000, 0x04000802, + 0x04000802, 0x04200002, 0x04200002, 0x00000002, + 0x00200002, 0x04000000, 0x04000800, 0x00200000, + 0x04200800, 0x00000802, 0x00200802, 0x04200800, + 0x00000802, 0x04000002, 0x04200802, 0x04200000, + 0x00200800, 0x00000000, 0x00000002, 0x04200802, + 0x00000000, 0x00200802, 0x04200000, 0x00000800, + 0x04000002, 0x04000800, 0x00000800, 0x00200002 + }; + + private static final int[] SP8 = { + 0x10001040, 0x00001000, 0x00040000, 0x10041040, + 0x10000000, 0x10001040, 0x00000040, 0x10000000, + 0x00040040, 0x10040000, 0x10041040, 0x00041000, + 0x10041000, 0x00041040, 0x00001000, 0x00000040, + 0x10040000, 0x10000040, 0x10001000, 0x00001040, + 0x00041000, 0x00040040, 0x10040040, 0x10041000, + 0x00001040, 0x00000000, 0x00000000, 0x10040040, + 0x10000040, 0x10001000, 0x00041040, 0x00040000, + 0x00041040, 0x00040000, 0x10041000, 0x00001000, + 0x00000040, 0x10040040, 0x00001000, 0x00041040, + 0x10001000, 0x00000040, 0x10000040, 0x10040000, + 0x10040040, 0x10000000, 0x00040000, 0x10001040, + 0x00000000, 0x10041040, 0x00040040, 0x10000040, + 0x10040000, 0x10001000, 0x10001040, 0x00000000, + 0x10041040, 0x00041000, 0x00041000, 0x00001040, + 0x00001040, 0x00040040, 0x10000000, 0x10041000 + }; + + /** + * generate an integer based working key based on our secret key + * and what we processing we are planning to do. + * + * Acknowledgements for this routine go to James Gillogly & Phil Karn. + * (whoever, and wherever they are!). + */ + protected int[] generateWorkingKey( + boolean encrypting, + byte[] key) + { + int[] newKey = new int[32]; + boolean[] pc1m = new boolean[56], + pcr = new boolean[56]; + + for (int j = 0; j < 56; j++) + { + int l = pc1[j]; + + pc1m[j] = ((key[l >>> 3] & bytebit[l & 07]) != 0); + } + + for (int i = 0; i < 16; i++) + { + int l, m, n; + + if (encrypting) + { + m = i << 1; + } + else + { + m = (15 - i) << 1; + } + + n = m + 1; + newKey[m] = newKey[n] = 0; + + for (int j = 0; j < 28; j++) + { + l = j + totrot[i]; + if (l < 28) + { + pcr[j] = pc1m[l]; + } + else + { + pcr[j] = pc1m[l - 28]; + } + } + + for (int j = 28; j < 56; j++) + { + l = j + totrot[i]; + if (l < 56) + { + pcr[j] = pc1m[l]; + } + else + { + pcr[j] = pc1m[l - 28]; + } + } + + for (int j = 0; j < 24; j++) + { + if (pcr[pc2[j]]) + { + newKey[m] |= bigbyte[j]; + } + + if (pcr[pc2[j + 24]]) + { + newKey[n] |= bigbyte[j]; + } + } + } + + // + // store the processed key + // + for (int i = 0; i != 32; i += 2) + { + int i1, i2; + + i1 = newKey[i]; + i2 = newKey[i + 1]; + + newKey[i] = ((i1 & 0x00fc0000) << 6) | ((i1 & 0x00000fc0) << 10) + | ((i2 & 0x00fc0000) >>> 10) | ((i2 & 0x00000fc0) >>> 6); + + newKey[i + 1] = ((i1 & 0x0003f000) << 12) | ((i1 & 0x0000003f) << 16) + | ((i2 & 0x0003f000) >>> 4) | (i2 & 0x0000003f); + } + + return newKey; + } + + /** + * the DES engine. + */ + protected void desFunc( + int[] wKey, + byte[] in, + int inOff, + byte[] out, + int outOff) + { + int work, right, left; + + left = (in[inOff + 0] & 0xff) << 24; + left |= (in[inOff + 1] & 0xff) << 16; + left |= (in[inOff + 2] & 0xff) << 8; + left |= (in[inOff + 3] & 0xff); + + right = (in[inOff + 4] & 0xff) << 24; + right |= (in[inOff + 5] & 0xff) << 16; + right |= (in[inOff + 6] & 0xff) << 8; + right |= (in[inOff + 7] & 0xff); + + work = ((left >>> 4) ^ right) & 0x0f0f0f0f; + right ^= work; + left ^= (work << 4); + work = ((left >>> 16) ^ right) & 0x0000ffff; + right ^= work; + left ^= (work << 16); + work = ((right >>> 2) ^ left) & 0x33333333; + left ^= work; + right ^= (work << 2); + work = ((right >>> 8) ^ left) & 0x00ff00ff; + left ^= work; + right ^= (work << 8); + right = ((right << 1) | ((right >>> 31) & 1)) & 0xffffffff; + work = (left ^ right) & 0xaaaaaaaa; + left ^= work; + right ^= work; + left = ((left << 1) | ((left >>> 31) & 1)) & 0xffffffff; + + for (int round = 0; round < 8; round++) + { + int fval; + + work = (right << 28) | (right >>> 4); + work ^= wKey[round * 4 + 0]; + fval = SP7[ work & 0x3f]; + fval |= SP5[(work >>> 8) & 0x3f]; + fval |= SP3[(work >>> 16) & 0x3f]; + fval |= SP1[(work >>> 24) & 0x3f]; + work = right ^ wKey[round * 4 + 1]; + fval |= SP8[ work & 0x3f]; + fval |= SP6[(work >>> 8) & 0x3f]; + fval |= SP4[(work >>> 16) & 0x3f]; + fval |= SP2[(work >>> 24) & 0x3f]; + left ^= fval; + work = (left << 28) | (left >>> 4); + work ^= wKey[round * 4 + 2]; + fval = SP7[ work & 0x3f]; + fval |= SP5[(work >>> 8) & 0x3f]; + fval |= SP3[(work >>> 16) & 0x3f]; + fval |= SP1[(work >>> 24) & 0x3f]; + work = left ^ wKey[round * 4 + 3]; + fval |= SP8[ work & 0x3f]; + fval |= SP6[(work >>> 8) & 0x3f]; + fval |= SP4[(work >>> 16) & 0x3f]; + fval |= SP2[(work >>> 24) & 0x3f]; + right ^= fval; + } + + right = (right << 31) | (right >>> 1); + work = (left ^ right) & 0xaaaaaaaa; + left ^= work; + right ^= work; + left = (left << 31) | (left >>> 1); + work = ((left >>> 8) ^ right) & 0x00ff00ff; + right ^= work; + left ^= (work << 8); + work = ((left >>> 2) ^ right) & 0x33333333; + right ^= work; + left ^= (work << 2); + work = ((right >>> 16) ^ left) & 0x0000ffff; + left ^= work; + right ^= (work << 16); + work = ((right >>> 4) ^ left) & 0x0f0f0f0f; + left ^= work; + right ^= (work << 4); + + out[outOff + 0] = (byte)((right >>> 24) & 0xff); + out[outOff + 1] = (byte)((right >>> 16) & 0xff); + out[outOff + 2] = (byte)((right >>> 8) & 0xff); + out[outOff + 3] = (byte)(right & 0xff); + out[outOff + 4] = (byte)((left >>> 24) & 0xff); + out[outOff + 5] = (byte)((left >>> 16) & 0xff); + out[outOff + 6] = (byte)((left >>> 8) & 0xff); + out[outOff + 7] = (byte)(left & 0xff); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/DESedeEngine.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/DESedeEngine.java new file mode 100644 index 0000000..c3d789c --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/DESedeEngine.java @@ -0,0 +1,126 @@ +package org.bc.crypto.engines; + +import org.bc.crypto.CipherParameters; +import org.bc.crypto.DataLengthException; +import org.bc.crypto.params.KeyParameter; + +/** + * a class that provides a basic DESede (or Triple DES) engine. + */ +public class DESedeEngine + extends DESEngine +{ + protected static final int BLOCK_SIZE = 8; + + private int[] workingKey1 = null; + private int[] workingKey2 = null; + private int[] workingKey3 = null; + + private boolean forEncryption; + + /** + * standard constructor. + */ + public DESedeEngine() + { + } + + /** + * initialise a DESede cipher. + * + * @param encrypting whether or not we are for encryption. + * @param params the parameters required to set up the cipher. + * @exception IllegalArgumentException if the params argument is + * inappropriate. + */ + public void init( + boolean encrypting, + CipherParameters params) + { + if (!(params instanceof KeyParameter)) + { + throw new IllegalArgumentException("invalid parameter passed to DESede init - " + params.getClass().getName()); + } + + byte[] keyMaster = ((KeyParameter)params).getKey(); + + if (keyMaster.length != 24 && keyMaster.length != 16) + { + throw new IllegalArgumentException("key size must be 16 or 24 bytes."); + } + + this.forEncryption = encrypting; + + byte[] key1 = new byte[8]; + System.arraycopy(keyMaster, 0, key1, 0, key1.length); + workingKey1 = generateWorkingKey(encrypting, key1); + + byte[] key2 = new byte[8]; + System.arraycopy(keyMaster, 8, key2, 0, key2.length); + workingKey2 = generateWorkingKey(!encrypting, key2); + + if (keyMaster.length == 24) + { + byte[] key3 = new byte[8]; + System.arraycopy(keyMaster, 16, key3, 0, key3.length); + workingKey3 = generateWorkingKey(encrypting, key3); + } + else // 16 byte key + { + workingKey3 = workingKey1; + } + } + + public String getAlgorithmName() + { + return "DESede"; + } + + public int getBlockSize() + { + return BLOCK_SIZE; + } + + public int processBlock( + byte[] in, + int inOff, + byte[] out, + int outOff) + { + if (workingKey1 == null) + { + throw new IllegalStateException("DESede engine not initialised"); + } + + if ((inOff + BLOCK_SIZE) > in.length) + { + throw new DataLengthException("input buffer too short"); + } + + if ((outOff + BLOCK_SIZE) > out.length) + { + throw new DataLengthException("output buffer too short"); + } + + byte[] temp = new byte[BLOCK_SIZE]; + + if (forEncryption) + { + desFunc(workingKey1, in, inOff, temp, 0); + desFunc(workingKey2, temp, 0, temp, 0); + desFunc(workingKey3, temp, 0, out, outOff); + } + else + { + desFunc(workingKey3, in, inOff, temp, 0); + desFunc(workingKey2, temp, 0, temp, 0); + desFunc(workingKey1, temp, 0, out, outOff); + } + + return BLOCK_SIZE; + } + + public void reset() + { + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/DESedeWrapEngine.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/DESedeWrapEngine.java new file mode 100644 index 0000000..ccbf7d9 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/DESedeWrapEngine.java @@ -0,0 +1,348 @@ +package org.bc.crypto.engines; + +import java.security.SecureRandom; + +import org.bc.crypto.CipherParameters; +import org.bc.crypto.Digest; +import org.bc.crypto.InvalidCipherTextException; +import org.bc.crypto.Wrapper; +import org.bc.crypto.digests.SHA1Digest; +import org.bc.crypto.modes.CBCBlockCipher; +import org.bc.crypto.params.KeyParameter; +import org.bc.crypto.params.ParametersWithIV; +import org.bc.crypto.params.ParametersWithRandom; +import org.bc.util.Arrays; + +/** + * Wrap keys according to + * + * draft-ietf-smime-key-wrap-01.txt. + *
+ * Note: + *
+ * http://www.ecrypt.eu.org/stream/p3ciphers/hc/hc128_p3.pdf + *
+ * It is a third phase candidate in the eStream contest, and is patent-free. + * No attacks are known as of today (April 2007). See + * + * http://www.ecrypt.eu.org/stream/hcp3.html + *
+ */ +public class HC128Engine + implements StreamCipher +{ + private int[] p = new int[512]; + private int[] q = new int[512]; + private int cnt = 0; + + private static int f1(int x) + { + return rotateRight(x, 7) ^ rotateRight(x, 18) + ^ (x >>> 3); + } + + private static int f2(int x) + { + return rotateRight(x, 17) ^ rotateRight(x, 19) + ^ (x >>> 10); + } + + private int g1(int x, int y, int z) + { + return (rotateRight(x, 10) ^ rotateRight(z, 23)) + + rotateRight(y, 8); + } + + private int g2(int x, int y, int z) + { + return (rotateLeft(x, 10) ^ rotateLeft(z, 23)) + rotateLeft(y, 8); + } + + private static int rotateLeft( + int x, + int bits) + { + return (x << bits) | (x >>> -bits); + } + + private static int rotateRight( + int x, + int bits) + { + return (x >>> bits) | (x << -bits); + } + + private int h1(int x) + { + return q[x & 0xFF] + q[((x >> 16) & 0xFF) + 256]; + } + + private int h2(int x) + { + return p[x & 0xFF] + p[((x >> 16) & 0xFF) + 256]; + } + + private static int mod1024(int x) + { + return x & 0x3FF; + } + + private static int mod512(int x) + { + return x & 0x1FF; + } + + private static int dim(int x, int y) + { + return mod512(x - y); + } + + private int step() + { + int j = mod512(cnt); + int ret; + if (cnt < 512) + { + p[j] += g1(p[dim(j, 3)], p[dim(j, 10)], p[dim(j, 511)]); + ret = h1(p[dim(j, 12)]) ^ p[j]; + } + else + { + q[j] += g2(q[dim(j, 3)], q[dim(j, 10)], q[dim(j, 511)]); + ret = h2(q[dim(j, 12)]) ^ q[j]; + } + cnt = mod1024(cnt + 1); + return ret; + } + + private byte[] key, iv; + private boolean initialised; + + private void init() + { + if (key.length != 16) + { + throw new java.lang.IllegalArgumentException( + "The key must be 128 bits long"); + } + + cnt = 0; + + int[] w = new int[1280]; + + for (int i = 0; i < 16; i++) + { + w[i >> 2] |= (key[i] & 0xff) << (8 * (i & 0x3)); + } + System.arraycopy(w, 0, w, 4, 4); + + for (int i = 0; i < iv.length && i < 16; i++) + { + w[(i >> 2) + 8] |= (iv[i] & 0xff) << (8 * (i & 0x3)); + } + System.arraycopy(w, 8, w, 12, 4); + + for (int i = 16; i < 1280; i++) + { + w[i] = f2(w[i - 2]) + w[i - 7] + f1(w[i - 15]) + w[i - 16] + i; + } + + System.arraycopy(w, 256, p, 0, 512); + System.arraycopy(w, 768, q, 0, 512); + + for (int i = 0; i < 512; i++) + { + p[i] = step(); + } + for (int i = 0; i < 512; i++) + { + q[i] = step(); + } + + cnt = 0; + } + + public String getAlgorithmName() + { + return "HC-128"; + } + + /** + * Initialise a HC-128 cipher. + * + * @param forEncryption whether or not we are for encryption. Irrelevant, as + * encryption and decryption are the same. + * @param params the parameters required to set up the cipher. + * @throws IllegalArgumentException if the params argument is + * inappropriate (ie. the key is not 128 bit long). + */ + public void init(boolean forEncryption, CipherParameters params) + throws IllegalArgumentException + { + CipherParameters keyParam = params; + + if (params instanceof ParametersWithIV) + { + iv = ((ParametersWithIV)params).getIV(); + keyParam = ((ParametersWithIV)params).getParameters(); + } + else + { + iv = new byte[0]; + } + + if (keyParam instanceof KeyParameter) + { + key = ((KeyParameter)keyParam).getKey(); + init(); + } + else + { + throw new IllegalArgumentException( + "Invalid parameter passed to HC128 init - " + + params.getClass().getName()); + } + + initialised = true; + } + + private byte[] buf = new byte[4]; + private int idx = 0; + + private byte getByte() + { + if (idx == 0) + { + int step = step(); + buf[0] = (byte)(step & 0xFF); + step >>= 8; + buf[1] = (byte)(step & 0xFF); + step >>= 8; + buf[2] = (byte)(step & 0xFF); + step >>= 8; + buf[3] = (byte)(step & 0xFF); + } + byte ret = buf[idx]; + idx = idx + 1 & 0x3; + return ret; + } + + public void processBytes(byte[] in, int inOff, int len, byte[] out, + int outOff) throws DataLengthException + { + if (!initialised) + { + throw new IllegalStateException(getAlgorithmName() + + " not initialised"); + } + + if ((inOff + len) > in.length) + { + throw new DataLengthException("input buffer too short"); + } + + if ((outOff + len) > out.length) + { + throw new DataLengthException("output buffer too short"); + } + + for (int i = 0; i < len; i++) + { + out[outOff + i] = (byte)(in[inOff + i] ^ getByte()); + } + } + + public void reset() + { + idx = 0; + init(); + } + + public byte returnByte(byte in) + { + return (byte)(in ^ getByte()); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/HC256Engine.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/HC256Engine.java new file mode 100644 index 0000000..5a7470c --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/HC256Engine.java @@ -0,0 +1,243 @@ +package org.bc.crypto.engines; + +import org.bc.crypto.CipherParameters; +import org.bc.crypto.DataLengthException; +import org.bc.crypto.StreamCipher; +import org.bc.crypto.params.KeyParameter; +import org.bc.crypto.params.ParametersWithIV; + +/** + * HC-256 is a software-efficient stream cipher created by Hongjun Wu. It + * generates keystream from a 256-bit secret key and a 256-bit initialization + * vector. + *+ * http://www.ecrypt.eu.org/stream/p3ciphers/hc/hc256_p3.pdf + *
+ * Its brother, HC-128, is a third phase candidate in the eStream contest. + * The algorithm is patent-free. No attacks are known as of today (April 2007). + * See + * + * http://www.ecrypt.eu.org/stream/hcp3.html + *
+ */ +public class HC256Engine + implements StreamCipher +{ + private int[] p = new int[1024]; + private int[] q = new int[1024]; + private int cnt = 0; + + private int step() + { + int j = cnt & 0x3FF; + int ret; + if (cnt < 1024) + { + int x = p[(j - 3 & 0x3FF)]; + int y = p[(j - 1023 & 0x3FF)]; + p[j] += p[(j - 10 & 0x3FF)] + + (rotateRight(x, 10) ^ rotateRight(y, 23)) + + q[((x ^ y) & 0x3FF)]; + + x = p[(j - 12 & 0x3FF)]; + ret = (q[x & 0xFF] + q[((x >> 8) & 0xFF) + 256] + + q[((x >> 16) & 0xFF) + 512] + q[((x >> 24) & 0xFF) + 768]) + ^ p[j]; + } + else + { + int x = q[(j - 3 & 0x3FF)]; + int y = q[(j - 1023 & 0x3FF)]; + q[j] += q[(j - 10 & 0x3FF)] + + (rotateRight(x, 10) ^ rotateRight(y, 23)) + + p[((x ^ y) & 0x3FF)]; + + x = q[(j - 12 & 0x3FF)]; + ret = (p[x & 0xFF] + p[((x >> 8) & 0xFF) + 256] + + p[((x >> 16) & 0xFF) + 512] + p[((x >> 24) & 0xFF) + 768]) + ^ q[j]; + } + cnt = cnt + 1 & 0x7FF; + return ret; + } + + private byte[] key, iv; + private boolean initialised; + + private void init() + { + if (key.length != 32 && key.length != 16) + { + throw new IllegalArgumentException( + "The key must be 128/256 bits long"); + } + + if (iv.length < 16) + { + throw new IllegalArgumentException( + "The IV must be at least 128 bits long"); + } + + if (key.length != 32) + { + byte[] k = new byte[32]; + + System.arraycopy(key, 0, k, 0, key.length); + System.arraycopy(key, 0, k, 16, key.length); + + key = k; + } + + if (iv.length < 32) + { + byte[] newIV = new byte[32]; + + System.arraycopy(iv, 0, newIV, 0, iv.length); + System.arraycopy(iv, 0, newIV, iv.length, newIV.length - iv.length); + + iv = newIV; + } + + cnt = 0; + + int[] w = new int[2560]; + + for (int i = 0; i < 32; i++) + { + w[i >> 2] |= (key[i] & 0xff) << (8 * (i & 0x3)); + } + + for (int i = 0; i < 32; i++) + { + w[(i >> 2) + 8] |= (iv[i] & 0xff) << (8 * (i & 0x3)); + } + + for (int i = 16; i < 2560; i++) + { + int x = w[i - 2]; + int y = w[i - 15]; + w[i] = (rotateRight(x, 17) ^ rotateRight(x, 19) ^ (x >>> 10)) + + w[i - 7] + + (rotateRight(y, 7) ^ rotateRight(y, 18) ^ (y >>> 3)) + + w[i - 16] + i; + } + + System.arraycopy(w, 512, p, 0, 1024); + System.arraycopy(w, 1536, q, 0, 1024); + + for (int i = 0; i < 4096; i++) + { + step(); + } + + cnt = 0; + } + + public String getAlgorithmName() + { + return "HC-256"; + } + + /** + * Initialise a HC-256 cipher. + * + * @param forEncryption whether or not we are for encryption. Irrelevant, as + * encryption and decryption are the same. + * @param params the parameters required to set up the cipher. + * @throws IllegalArgumentException if the params argument is + * inappropriate (ie. the key is not 256 bit long). + */ + public void init(boolean forEncryption, CipherParameters params) + throws IllegalArgumentException + { + CipherParameters keyParam = params; + + if (params instanceof ParametersWithIV) + { + iv = ((ParametersWithIV)params).getIV(); + keyParam = ((ParametersWithIV)params).getParameters(); + } + else + { + iv = new byte[0]; + } + + if (keyParam instanceof KeyParameter) + { + key = ((KeyParameter)keyParam).getKey(); + init(); + } + else + { + throw new IllegalArgumentException( + "Invalid parameter passed to HC256 init - " + + params.getClass().getName()); + } + + initialised = true; + } + + private byte[] buf = new byte[4]; + private int idx = 0; + + private byte getByte() + { + if (idx == 0) + { + int step = step(); + buf[0] = (byte)(step & 0xFF); + step >>= 8; + buf[1] = (byte)(step & 0xFF); + step >>= 8; + buf[2] = (byte)(step & 0xFF); + step >>= 8; + buf[3] = (byte)(step & 0xFF); + } + byte ret = buf[idx]; + idx = idx + 1 & 0x3; + return ret; + } + + public void processBytes(byte[] in, int inOff, int len, byte[] out, + int outOff) throws DataLengthException + { + if (!initialised) + { + throw new IllegalStateException(getAlgorithmName() + + " not initialised"); + } + + if ((inOff + len) > in.length) + { + throw new DataLengthException("input buffer too short"); + } + + if ((outOff + len) > out.length) + { + throw new DataLengthException("output buffer too short"); + } + + for (int i = 0; i < len; i++) + { + out[outOff + i] = (byte)(in[inOff + i] ^ getByte()); + } + } + + public void reset() + { + idx = 0; + init(); + } + + public byte returnByte(byte in) + { + return (byte)(in ^ getByte()); + } + + private static int rotateRight( + int x, + int bits) + { + return (x >>> bits) | (x << -bits); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/IDEAEngine.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/IDEAEngine.java new file mode 100644 index 0000000..df5108d --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/IDEAEngine.java @@ -0,0 +1,366 @@ +package org.bc.crypto.engines; + +import org.bc.crypto.BlockCipher; +import org.bc.crypto.CipherParameters; +import org.bc.crypto.DataLengthException; +import org.bc.crypto.params.KeyParameter; + +/** + * A class that provides a basic International Data Encryption Algorithm (IDEA) engine. + *+ * This implementation is based on the "HOWTO: INTERNATIONAL DATA ENCRYPTION ALGORITHM" + * implementation summary by Fauzan Mirza (F.U.Mirza@sheffield.ac.uk). (baring 1 typo at the + * end of the mulinv function!). + *
+ * It can be found at ftp://ftp.funet.fi/pub/crypt/cryptography/symmetric/idea/ + *
+ * Note 1: This algorithm is patented in the USA, Japan, and Europe including + * at least Austria, France, Germany, Italy, Netherlands, Spain, Sweden, Switzerland + * and the United Kingdom. Non-commercial use is free, however any commercial + * products are liable for royalties. Please see + * www.mediacrypt.com for + * further details. This announcement has been included at the request of + * the patent holders. + *
+ * Note 2: Due to the requests concerning the above, this algorithm is now only + * included in the extended Bouncy Castle provider and JCE signed jars. It is + * not included in the default distributions. + */ +public class IDEAEngine + implements BlockCipher +{ + protected static final int BLOCK_SIZE = 8; + + private int[] workingKey = null; + + /** + * standard constructor. + */ + public IDEAEngine() + { + } + + /** + * initialise an IDEA cipher. + * + * @param forEncryption whether or not we are for encryption. + * @param params the parameters required to set up the cipher. + * @exception IllegalArgumentException if the params argument is + * inappropriate. + */ + public void init( + boolean forEncryption, + CipherParameters params) + { + if (params instanceof KeyParameter) + { + workingKey = generateWorkingKey(forEncryption, + ((KeyParameter)params).getKey()); + return; + } + + throw new IllegalArgumentException("invalid parameter passed to IDEA init - " + params.getClass().getName()); + } + + public String getAlgorithmName() + { + return "IDEA"; + } + + public int getBlockSize() + { + return BLOCK_SIZE; + } + + public int processBlock( + byte[] in, + int inOff, + byte[] out, + int outOff) + { + if (workingKey == null) + { + throw new IllegalStateException("IDEA engine not initialised"); + } + + if ((inOff + BLOCK_SIZE) > in.length) + { + throw new DataLengthException("input buffer too short"); + } + + if ((outOff + BLOCK_SIZE) > out.length) + { + throw new DataLengthException("output buffer too short"); + } + + ideaFunc(workingKey, in, inOff, out, outOff); + + return BLOCK_SIZE; + } + + public void reset() + { + } + + private static final int MASK = 0xffff; + private static final int BASE = 0x10001; + + private int bytesToWord( + byte[] in, + int inOff) + { + return ((in[inOff] << 8) & 0xff00) + (in[inOff + 1] & 0xff); + } + + private void wordToBytes( + int word, + byte[] out, + int outOff) + { + out[outOff] = (byte)(word >>> 8); + out[outOff + 1] = (byte)word; + } + + /** + * return x = x * y where the multiplication is done modulo + * 65537 (0x10001) (as defined in the IDEA specification) and + * a zero input is taken to be 65536 (0x10000). + * + * @param x the x value + * @param y the y value + * @return x = x * y + */ + private int mul( + int x, + int y) + { + if (x == 0) + { + x = (BASE - y); + } + else if (y == 0) + { + x = (BASE - x); + } + else + { + int p = x * y; + + y = p & MASK; + x = p >>> 16; + x = y - x + ((y < x) ? 1 : 0); + } + + return x & MASK; + } + + private void ideaFunc( + int[] workingKey, + byte[] in, + int inOff, + byte[] out, + int outOff) + { + int x0, x1, x2, x3, t0, t1; + int keyOff = 0; + + x0 = bytesToWord(in, inOff); + x1 = bytesToWord(in, inOff + 2); + x2 = bytesToWord(in, inOff + 4); + x3 = bytesToWord(in, inOff + 6); + + for (int round = 0; round < 8; round++) + { + x0 = mul(x0, workingKey[keyOff++]); + x1 += workingKey[keyOff++]; + x1 &= MASK; + x2 += workingKey[keyOff++]; + x2 &= MASK; + x3 = mul(x3, workingKey[keyOff++]); + + t0 = x1; + t1 = x2; + x2 ^= x0; + x1 ^= x3; + + x2 = mul(x2, workingKey[keyOff++]); + x1 += x2; + x1 &= MASK; + + x1 = mul(x1, workingKey[keyOff++]); + x2 += x1; + x2 &= MASK; + + x0 ^= x1; + x3 ^= x2; + x1 ^= t1; + x2 ^= t0; + } + + wordToBytes(mul(x0, workingKey[keyOff++]), out, outOff); + wordToBytes(x2 + workingKey[keyOff++], out, outOff + 2); /* NB: Order */ + wordToBytes(x1 + workingKey[keyOff++], out, outOff + 4); + wordToBytes(mul(x3, workingKey[keyOff]), out, outOff + 6); + } + + /** + * The following function is used to expand the user key to the encryption + * subkey. The first 16 bytes are the user key, and the rest of the subkey + * is calculated by rotating the previous 16 bytes by 25 bits to the left, + * and so on until the subkey is completed. + */ + private int[] expandKey( + byte[] uKey) + { + int[] key = new int[52]; + + if (uKey.length < 16) + { + byte[] tmp = new byte[16]; + + System.arraycopy(uKey, 0, tmp, tmp.length - uKey.length, uKey.length); + + uKey = tmp; + } + + for (int i = 0; i < 8; i++) + { + key[i] = bytesToWord(uKey, i * 2); + } + + for (int i = 8; i < 52; i++) + { + if ((i & 7) < 6) + { + key[i] = ((key[i - 7] & 127) << 9 | key[i - 6] >> 7) & MASK; + } + else if ((i & 7) == 6) + { + key[i] = ((key[i - 7] & 127) << 9 | key[i - 14] >> 7) & MASK; + } + else + { + key[i] = ((key[i - 15] & 127) << 9 | key[i - 14] >> 7) & MASK; + } + } + + return key; + } + + /** + * This function computes multiplicative inverse using Euclid's Greatest + * Common Divisor algorithm. Zero and one are self inverse. + *
+ * i.e. x * mulInv(x) == 1 (modulo BASE) + */ + private int mulInv( + int x) + { + int t0, t1, q, y; + + if (x < 2) + { + return x; + } + + t0 = 1; + t1 = BASE / x; + y = BASE % x; + + while (y != 1) + { + q = x / y; + x = x % y; + t0 = (t0 + (t1 * q)) & MASK; + if (x == 1) + { + return t0; + } + q = y / x; + y = y % x; + t1 = (t1 + (t0 * q)) & MASK; + } + + return (1 - t1) & MASK; + } + + /** + * Return the additive inverse of x. + *
+ * i.e. x + addInv(x) == 0
+ */
+ int addInv(
+ int x)
+ {
+ return (0 - x) & MASK;
+ }
+
+ /**
+ * The function to invert the encryption subkey to the decryption subkey.
+ * It also involves the multiplicative inverse and the additive inverse functions.
+ */
+ private int[] invertKey(
+ int[] inKey)
+ {
+ int t1, t2, t3, t4;
+ int p = 52; /* We work backwards */
+ int[] key = new int[52];
+ int inOff = 0;
+
+ t1 = mulInv(inKey[inOff++]);
+ t2 = addInv(inKey[inOff++]);
+ t3 = addInv(inKey[inOff++]);
+ t4 = mulInv(inKey[inOff++]);
+ key[--p] = t4;
+ key[--p] = t3;
+ key[--p] = t2;
+ key[--p] = t1;
+
+ for (int round = 1; round < 8; round++)
+ {
+ t1 = inKey[inOff++];
+ t2 = inKey[inOff++];
+ key[--p] = t2;
+ key[--p] = t1;
+
+ t1 = mulInv(inKey[inOff++]);
+ t2 = addInv(inKey[inOff++]);
+ t3 = addInv(inKey[inOff++]);
+ t4 = mulInv(inKey[inOff++]);
+ key[--p] = t4;
+ key[--p] = t2; /* NB: Order */
+ key[--p] = t3;
+ key[--p] = t1;
+ }
+
+ t1 = inKey[inOff++];
+ t2 = inKey[inOff++];
+ key[--p] = t2;
+ key[--p] = t1;
+
+ t1 = mulInv(inKey[inOff++]);
+ t2 = addInv(inKey[inOff++]);
+ t3 = addInv(inKey[inOff++]);
+ t4 = mulInv(inKey[inOff]);
+ key[--p] = t4;
+ key[--p] = t3;
+ key[--p] = t2;
+ key[--p] = t1;
+
+ return key;
+ }
+
+ private int[] generateWorkingKey(
+ boolean forEncryption,
+ byte[] userKey)
+ {
+ if (forEncryption)
+ {
+ return expandKey(userKey);
+ }
+ else
+ {
+ return invertKey(expandKey(userKey));
+ }
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/IESEngine.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/IESEngine.java
new file mode 100644
index 0000000..6a0fa80
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/IESEngine.java
@@ -0,0 +1,421 @@
+package org.bc.crypto.engines;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+
+import org.bc.crypto.BasicAgreement;
+import org.bc.crypto.BufferedBlockCipher;
+import org.bc.crypto.CipherParameters;
+import org.bc.crypto.DerivationFunction;
+import org.bc.crypto.EphemeralKeyPair;
+import org.bc.crypto.InvalidCipherTextException;
+import org.bc.crypto.KeyParser;
+import org.bc.crypto.Mac;
+import org.bc.crypto.generators.EphemeralKeyPairGenerator;
+import org.bc.crypto.params.AsymmetricKeyParameter;
+import org.bc.crypto.params.IESParameters;
+import org.bc.crypto.params.IESWithCipherParameters;
+import org.bc.crypto.params.KDFParameters;
+import org.bc.crypto.params.KeyParameter;
+import org.bc.crypto.util.Pack;
+import org.bc.util.Arrays;
+import org.bc.util.BigIntegers;
+
+/**
+ * Support class for constructing integrated encryption ciphers
+ * for doing basic message exchanges on top of key agreement ciphers.
+ * Follows the description given in IEEE Std 1363a.
+ */
+public class IESEngine
+{
+ BasicAgreement agree;
+ DerivationFunction kdf;
+ Mac mac;
+ BufferedBlockCipher cipher;
+ byte[] macBuf;
+
+ boolean forEncryption;
+ CipherParameters privParam, pubParam;
+ IESParameters param;
+
+ byte[] V;
+ private EphemeralKeyPairGenerator keyPairGenerator;
+ private KeyParser keyParser;
+
+
+ /**
+ * set up for use with stream mode, where the key derivation function
+ * is used to provide a stream of bytes to xor with the message.
+ *
+ * @param agree the key agreement used as the basis for the encryption
+ * @param kdf the key derivation function used for byte generation
+ * @param mac the message authentication code generator for the message
+ */
+ public IESEngine(
+ BasicAgreement agree,
+ DerivationFunction kdf,
+ Mac mac)
+ {
+ this.agree = agree;
+ this.kdf = kdf;
+ this.mac = mac;
+ this.macBuf = new byte[mac.getMacSize()];
+ this.cipher = null;
+ }
+
+
+ /**
+ * set up for use in conjunction with a block cipher to handle the
+ * message.
+ *
+ * @param agree the key agreement used as the basis for the encryption
+ * @param kdf the key derivation function used for byte generation
+ * @param mac the message authentication code generator for the message
+ * @param cipher the cipher to used for encrypting the message
+ */
+ public IESEngine(
+ BasicAgreement agree,
+ DerivationFunction kdf,
+ Mac mac,
+ BufferedBlockCipher cipher)
+ {
+ this.agree = agree;
+ this.kdf = kdf;
+ this.mac = mac;
+ this.macBuf = new byte[mac.getMacSize()];
+ this.cipher = cipher;
+ }
+
+
+ /**
+ * Initialise the encryptor.
+ *
+ * @param forEncryption whether or not this is encryption/decryption.
+ * @param privParam our private key parameters
+ * @param pubParam the recipient's/sender's public key parameters
+ * @param param encoding and derivation parameters.
+ */
+ public void init(
+ boolean forEncryption,
+ CipherParameters privParam,
+ CipherParameters pubParam,
+ CipherParameters param)
+ {
+ this.forEncryption = forEncryption;
+ this.privParam = privParam;
+ this.pubParam = pubParam;
+ this.param = (IESParameters)param;
+ this.V = new byte[0];
+ }
+
+
+ /**
+ * Initialise the encryptor.
+ *
+ * @param publicKey the recipient's/sender's public key parameters
+ * @param params encoding and derivation parameters.
+ * @param ephemeralKeyPairGenerator the ephemeral key pair generator to use.
+ */
+ public void init(AsymmetricKeyParameter publicKey, CipherParameters params, EphemeralKeyPairGenerator ephemeralKeyPairGenerator)
+ {
+ this.forEncryption = true;
+ this.pubParam = publicKey;
+ this.param = (IESParameters)params;
+ this.keyPairGenerator = ephemeralKeyPairGenerator;
+ }
+
+ /**
+ * Initialise the encryptor.
+ *
+ * @param privateKey the recipient's private key.
+ * @param params encoding and derivation parameters.
+ * @param publicKeyParser the parser for reading the ephemeral public key.
+ */
+ public void init(AsymmetricKeyParameter privateKey, CipherParameters params, KeyParser publicKeyParser)
+ {
+ this.forEncryption = false;
+ this.privParam = privateKey;
+ this.param = (IESParameters)params;
+ this.keyParser = publicKeyParser;
+ }
+
+ public BufferedBlockCipher getCipher()
+ {
+ return cipher;
+ }
+
+ public Mac getMac()
+ {
+ return mac;
+ }
+
+ private byte[] encryptBlock(
+ byte[] in,
+ int inOff,
+ int inLen)
+ throws InvalidCipherTextException
+ {
+ byte[] C = null, K = null, K1 = null, K2 = null;
+ int len;
+
+ if (cipher == null)
+ {
+ // Streaming mode.
+ K1 = new byte[inLen];
+ K2 = new byte[param.getMacKeySize() / 8];
+ K = new byte[K1.length + K2.length];
+
+ kdf.generateBytes(K, 0, K.length);
+
+ if (V.length != 0)
+ {
+ System.arraycopy(K, 0, K2, 0, K2.length);
+ System.arraycopy(K, K2.length, K1, 0, K1.length);
+ }
+ else
+ {
+ System.arraycopy(K, 0, K1, 0, K1.length);
+ System.arraycopy(K, inLen, K2, 0, K2.length);
+ }
+
+ C = new byte[inLen];
+
+ for (int i = 0; i != inLen; i++)
+ {
+ C[i] = (byte)(in[inOff + i] ^ K1[i]);
+ }
+ len = inLen;
+
+ }
+ else
+ {
+ // Block cipher mode.
+ K1 = new byte[((IESWithCipherParameters)param).getCipherKeySize() / 8];
+ K2 = new byte[param.getMacKeySize() / 8];
+ K = new byte[K1.length + K2.length];
+
+ kdf.generateBytes(K, 0, K.length);
+ System.arraycopy(K, 0, K1, 0, K1.length);
+ System.arraycopy(K, K1.length, K2, 0, K2.length);
+
+ cipher.init(true, new KeyParameter(K1));
+ C = new byte[cipher.getOutputSize(inLen)];
+ len = cipher.processBytes(in, inOff, inLen, C, 0);
+ len += cipher.doFinal(C, len);
+ }
+
+
+ // Convert the length of the encoding vector into a byte array.
+ byte[] P2 = param.getEncodingV();
+ byte[] L2 = new byte[4];
+ if (V.length != 0)
+ {
+ if (P2 == null)
+ {
+ Pack.intToBigEndian(0, L2, 0);
+ }
+ else
+ {
+ Pack.intToBigEndian(P2.length * 8, L2, 0);
+ }
+ }
+
+
+ // Apply the MAC.
+ byte[] T = new byte[mac.getMacSize()];
+
+ mac.init(new KeyParameter(K2));
+ mac.update(C, 0, C.length);
+ if (P2 != null)
+ {
+ mac.update(P2, 0, P2.length);
+ }
+ if (V.length != 0)
+ {
+ mac.update(L2, 0, L2.length);
+ }
+ mac.doFinal(T, 0);
+
+
+ // Output the triple (V,C,T).
+ byte[] Output = new byte[V.length + len + T.length];
+ System.arraycopy(V, 0, Output, 0, V.length);
+ System.arraycopy(C, 0, Output, V.length, len);
+ System.arraycopy(T, 0, Output, V.length + len, T.length);
+ return Output;
+ }
+
+ private byte[] decryptBlock(
+ byte[] in_enc,
+ int inOff,
+ int inLen)
+ throws InvalidCipherTextException
+ {
+ byte[] M = null, K = null, K1 = null, K2 = null;
+ int len;
+
+ if (cipher == null)
+ {
+ // Streaming mode.
+ K1 = new byte[inLen - V.length - mac.getMacSize()];
+ K2 = new byte[param.getMacKeySize() / 8];
+ K = new byte[K1.length + K2.length];
+
+ kdf.generateBytes(K, 0, K.length);
+
+ if (V.length != 0)
+ {
+ System.arraycopy(K, 0, K2, 0, K2.length);
+ System.arraycopy(K, K2.length, K1, 0, K1.length);
+ }
+ else
+ {
+ System.arraycopy(K, 0, K1, 0, K1.length);
+ System.arraycopy(K, K1.length, K2, 0, K2.length);
+ }
+
+ M = new byte[K1.length];
+
+ for (int i = 0; i != K1.length; i++)
+ {
+ M[i] = (byte)(in_enc[inOff + V.length + i] ^ K1[i]);
+ }
+
+
+ len = K1.length;
+
+ }
+ else
+ {
+ // Block cipher mode.
+ K1 = new byte[((IESWithCipherParameters)param).getCipherKeySize() / 8];
+ K2 = new byte[param.getMacKeySize() / 8];
+ K = new byte[K1.length + K2.length];
+
+ kdf.generateBytes(K, 0, K.length);
+ System.arraycopy(K, 0, K1, 0, K1.length);
+ System.arraycopy(K, K1.length, K2, 0, K2.length);
+
+ cipher.init(false, new KeyParameter(K1));
+
+ M = new byte[cipher.getOutputSize(inLen - V.length - mac.getMacSize())];
+ len = cipher.processBytes(in_enc, inOff + V.length, inLen - V.length - mac.getMacSize(), M, 0);
+ len += cipher.doFinal(M, len);
+
+ }
+
+
+ // Convert the length of the encoding vector into a byte array.
+ byte[] P2 = param.getEncodingV();
+ byte[] L2 = new byte[4];
+ if (V.length != 0)
+ {
+ if (P2 != null)
+ {
+ Pack.intToBigEndian(P2.length * 8, L2, 0);
+ }
+ else
+ {
+ Pack.intToBigEndian(0, L2, 0);
+ }
+ }
+
+
+ // Verify the MAC.
+ byte[] T1 = new byte[mac.getMacSize()];
+ System.arraycopy(in_enc, inOff + inLen - T1.length, T1, 0, T1.length);
+
+ byte[] T2 = new byte[T1.length];
+ mac.init(new KeyParameter(K2));
+ mac.update(in_enc, inOff + V.length, inLen - V.length - T2.length);
+
+ if (P2 != null)
+ {
+ mac.update(P2, 0, P2.length);
+ }
+ if (V.length != 0)
+ {
+ mac.update(L2, 0, L2.length);
+ }
+ mac.doFinal(T2, 0);
+
+ if (!Arrays.areEqual(T1, T2))
+ {
+ throw new InvalidCipherTextException("Invalid MAC.");
+ }
+
+
+ // Output the message.
+ byte[] Output = new byte[len];
+ System.arraycopy(M, 0, Output, 0, len);
+ return Output;
+ }
+
+
+ public byte[] processBlock(
+ byte[] in,
+ int inOff,
+ int inLen)
+ throws InvalidCipherTextException
+ {
+ if (forEncryption)
+ {
+ if (keyPairGenerator != null)
+ {
+ EphemeralKeyPair ephKeyPair = keyPairGenerator.generate();
+
+ this.privParam = ephKeyPair.getKeyPair().getPrivate();
+ this.V = ephKeyPair.getEncodedPublicKey();
+ }
+ }
+ else
+ {
+ if (keyParser != null)
+ {
+ ByteArrayInputStream bIn = new ByteArrayInputStream(in, inOff, inLen);
+
+ try
+ {
+ this.pubParam = keyParser.readKey(bIn);
+ }
+ catch (IOException e)
+ {
+ throw new InvalidCipherTextException("unable to recover ephemeral public key: " + e.getMessage(), e);
+ }
+
+ int encLength = (inLen - bIn.available());
+
+ this.V = new byte[encLength];
+ System.arraycopy(in, inOff, V, 0, V.length);
+ }
+ }
+
+ // Compute the common value and convert to byte array.
+ agree.init(privParam);
+ BigInteger z = agree.calculateAgreement(pubParam);
+ byte[] Z = BigIntegers.asUnsignedByteArray(agree.getFieldSize(), z);
+
+ // Create input to KDF.
+ byte[] VZ = null;
+
+ if (V.length != 0)
+ {
+ VZ = new byte[V.length + Z.length];
+ System.arraycopy(V, 0, VZ, 0, V.length);
+ System.arraycopy(Z, 0, VZ, V.length, Z.length);
+ }
+ else
+ {
+ VZ = Z;
+ }
+
+ // Initialise the KDF.
+ KDFParameters kdfParam = new KDFParameters(VZ, param.getDerivationV());
+ kdf.init(kdfParam);
+
+ return forEncryption
+ ? encryptBlock(in, inOff, inLen)
+ : decryptBlock(in, inOff, inLen);
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/ISAACEngine.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/ISAACEngine.java
new file mode 100644
index 0000000..168e1bd
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/ISAACEngine.java
@@ -0,0 +1,245 @@
+package org.bc.crypto.engines;
+
+import org.bc.crypto.CipherParameters;
+import org.bc.crypto.DataLengthException;
+import org.bc.crypto.StreamCipher;
+import org.bc.crypto.params.KeyParameter;
+
+/**
+ * Implementation of Bob Jenkin's ISAAC (Indirection Shift Accumulate Add and Count).
+ * see: http://www.burtleburtle.net/bob/rand/isaacafa.html
+*/
+public class ISAACEngine
+ implements StreamCipher
+{
+ // Constants
+ private final int sizeL = 8,
+ stateArraySize = sizeL<<5; // 256
+
+ // Cipher's internal state
+ private int[] engineState = null, // mm
+ results = null; // randrsl
+ private int a = 0, b = 0, c = 0;
+
+ // Engine state
+ private int index = 0;
+ private byte[] keyStream = new byte[stateArraySize<<2], // results expanded into bytes
+ workingKey = null;
+ private boolean initialised = false;
+
+ /**
+ * initialise an ISAAC cipher.
+ *
+ * @param forEncryption whether or not we are for encryption.
+ * @param params the parameters required to set up the cipher.
+ * @exception IllegalArgumentException if the params argument is
+ * inappropriate.
+ */
+ public void init(
+ boolean forEncryption,
+ CipherParameters params)
+ {
+ if (!(params instanceof KeyParameter))
+ {
+ throw new IllegalArgumentException("invalid parameter passed to ISAAC init - " + params.getClass().getName());
+ }
+ /*
+ * ISAAC encryption and decryption is completely
+ * symmetrical, so the 'forEncryption' is
+ * irrelevant.
+ */
+ KeyParameter p = (KeyParameter)params;
+ setKey(p.getKey());
+
+ return;
+ }
+
+ public byte returnByte(byte in)
+ {
+ if (index == 0)
+ {
+ isaac();
+ keyStream = intToByteLittle(results);
+ }
+ byte out = (byte)(keyStream[index]^in);
+ index = (index + 1) & 1023;
+
+ return out;
+ }
+
+ public void processBytes(
+ byte[] in,
+ int inOff,
+ int len,
+ byte[] out,
+ int outOff)
+ {
+ if (!initialised)
+ {
+ throw new IllegalStateException(getAlgorithmName()+" not initialised");
+ }
+
+ if ((inOff + len) > in.length)
+ {
+ throw new DataLengthException("input buffer too short");
+ }
+
+ if ((outOff + len) > out.length)
+ {
+ throw new DataLengthException("output buffer too short");
+ }
+
+ for (int i = 0; i < len; i++)
+ {
+ if (index == 0)
+ {
+ isaac();
+ keyStream = intToByteLittle(results);
+ }
+ out[i+outOff] = (byte)(keyStream[index]^in[i+inOff]);
+ index = (index + 1) & 1023;
+ }
+ }
+
+ public String getAlgorithmName()
+ {
+ return "ISAAC";
+ }
+
+ public void reset()
+ {
+ setKey(workingKey);
+ }
+
+ // Private implementation
+ private void setKey(byte[] keyBytes)
+ {
+ workingKey = keyBytes;
+
+ if (engineState == null)
+ {
+ engineState = new int[stateArraySize];
+ }
+
+ if (results == null)
+ {
+ results = new int[stateArraySize];
+ }
+
+ int i, j, k;
+
+ // Reset state
+ for (i = 0; i < stateArraySize; i++)
+ {
+ engineState[i] = results[i] = 0;
+ }
+ a = b = c = 0;
+
+ // Reset index counter for output
+ index = 0;
+
+ // Convert the key bytes to ints and put them into results[] for initialization
+ byte[] t = new byte[keyBytes.length + (keyBytes.length & 3)];
+ System.arraycopy(keyBytes, 0, t, 0, keyBytes.length);
+ for (i = 0; i < t.length; i+=4)
+ {
+ results[i>>2] = byteToIntLittle(t, i);
+ }
+
+ // It has begun?
+ int[] abcdefgh = new int[sizeL];
+
+ for (i = 0; i < sizeL; i++)
+ {
+ abcdefgh[i] = 0x9e3779b9; // Phi (golden ratio)
+ }
+
+ for (i = 0; i < 4; i++)
+ {
+ mix(abcdefgh);
+ }
+
+ for (i = 0; i < 2; i++)
+ {
+ for (j = 0; j < stateArraySize; j+=sizeL)
+ {
+ for (k = 0; k < sizeL; k++)
+ {
+ abcdefgh[k] += (i<1) ? results[j+k] : engineState[j+k];
+ }
+
+ mix(abcdefgh);
+
+ for (k = 0; k < sizeL; k++)
+ {
+ engineState[j+k] = abcdefgh[k];
+ }
+ }
+ }
+
+ isaac();
+
+ initialised = true;
+ }
+
+ private void isaac()
+ {
+ int i, x, y;
+
+ b += ++c;
+ for (i = 0; i < stateArraySize; i++)
+ {
+ x = engineState[i];
+ switch (i & 3)
+ {
+ case 0: a ^= (a << 13); break;
+ case 1: a ^= (a >>> 6); break;
+ case 2: a ^= (a << 2); break;
+ case 3: a ^= (a >>> 16); break;
+ }
+ a += engineState[(i+128) & 0xFF];
+ engineState[i] = y = engineState[(x >>> 2) & 0xFF] + a + b;
+ results[i] = b = engineState[(y >>> 10) & 0xFF] + x;
+ }
+ }
+
+ private void mix(int[] x)
+ {
+ x[0]^=x[1]<< 11; x[3]+=x[0]; x[1]+=x[2];
+ x[1]^=x[2]>>> 2; x[4]+=x[1]; x[2]+=x[3];
+ x[2]^=x[3]<< 8; x[5]+=x[2]; x[3]+=x[4];
+ x[3]^=x[4]>>>16; x[6]+=x[3]; x[4]+=x[5];
+ x[4]^=x[5]<< 10; x[7]+=x[4]; x[5]+=x[6];
+ x[5]^=x[6]>>> 4; x[0]+=x[5]; x[6]+=x[7];
+ x[6]^=x[7]<< 8; x[1]+=x[6]; x[7]+=x[0];
+ x[7]^=x[0]>>> 9; x[2]+=x[7]; x[0]+=x[1];
+ }
+
+ private int byteToIntLittle(byte[] x, int offset)
+ {
+ return (int)(x[offset++] & 0xFF) |
+ ((x[offset++] & 0xFF) << 8) |
+ ((x[offset++] & 0xFF) << 16) |
+ (x[offset++] << 24);
+ }
+
+ private byte[] intToByteLittle(int x)
+ {
+ byte[] out = new byte[4];
+ out[3] = (byte)x;
+ out[2] = (byte)(x >>> 8);
+ out[1] = (byte)(x >>> 16);
+ out[0] = (byte)(x >>> 24);
+ return out;
+ }
+
+ private byte[] intToByteLittle(int[] x)
+ {
+ byte[] out = new byte[4*x.length];
+ for (int i = 0, j = 0; i < x.length; i++,j+=4)
+ {
+ System.arraycopy(intToByteLittle(x[i]), 0, out, j, 4);
+ }
+ return out;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/IndexGenerator.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/IndexGenerator.java
new file mode 100644
index 0000000..c507a2d
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/IndexGenerator.java
@@ -0,0 +1,240 @@
+package org.bc.crypto.engines;
+
+import org.bc.crypto.Digest;
+import org.bc.crypto.params.NTRUEncryptionParameters;
+import org.bc.util.Arrays;
+
+/**
+ * An implementation of the Index Generation Function in IEEE P1363.1.
+ */
+public class IndexGenerator
+{
+ private byte[] seed;
+ private int N;
+ private int c;
+ private int minCallsR;
+ private int totLen;
+ private int remLen;
+ private BitString buf;
+ private int counter;
+ private boolean initialized;
+ private Digest hashAlg;
+ private int hLen;
+
+ /**
+ * Constructs a new index generator.
+ *
+ * @param seed a seed of arbitrary length to initialize the index generator with
+ * @param params NtruEncrypt parameters
+ */
+ IndexGenerator(byte[] seed, NTRUEncryptionParameters params)
+ {
+ this.seed = seed;
+ N = params.N;
+ c = params.c;
+ minCallsR = params.minCallsR;
+
+ totLen = 0;
+ remLen = 0;
+ counter = 0;
+ hashAlg = params.hashAlg;
+
+ hLen = hashAlg.getDigestSize(); // hash length
+ initialized = false;
+ }
+
+ /**
+ * Returns a number i
such that 0 <= i < N
.
+ *
+ * @return
+ */
+ int nextIndex()
+ {
+ if (!initialized)
+ {
+ buf = new BitString();
+ byte[] hash = new byte[hashAlg.getDigestSize()];
+ while (counter < minCallsR)
+ {
+ appendHash(buf, hash);
+ counter++;
+ }
+ totLen = minCallsR * 8 * hLen;
+ remLen = totLen;
+ initialized = true;
+ }
+
+ while (true)
+ {
+ totLen += c;
+ BitString M = buf.getTrailing(remLen);
+ if (remLen < c)
+ {
+ int tmpLen = c - remLen;
+ int cThreshold = counter + (tmpLen + hLen - 1) / hLen;
+ byte[] hash = new byte[hashAlg.getDigestSize()];
+ while (counter < cThreshold)
+ {
+ appendHash(M, hash);
+ counter++;
+ if (tmpLen > 8 * hLen)
+ {
+ tmpLen -= 8 * hLen;
+ }
+ }
+ remLen = 8 * hLen - tmpLen;
+ buf = new BitString();
+ buf.appendBits(hash);
+ }
+ else
+ {
+ remLen -= c;
+ }
+
+ int i = M.getLeadingAsInt(c); // assume c<32
+ if (i < (1 << c) - ((1 << c) % N))
+ {
+ return i % N;
+ }
+ }
+ }
+
+ private void appendHash(BitString m, byte[] hash)
+ {
+ hashAlg.update(seed, 0, seed.length);
+
+ putInt(hashAlg, counter);
+
+ hashAlg.doFinal(hash, 0);
+
+ m.appendBits(hash);
+ }
+
+ private void putInt(Digest hashAlg, int counter)
+ {
+ hashAlg.update((byte)(counter >> 24));
+ hashAlg.update((byte)(counter >> 16));
+ hashAlg.update((byte)(counter >> 8));
+ hashAlg.update((byte)counter);
+ }
+
+ /**
+ * Represents a string of bits and supports appending, reading the head, and reading the tail.
+ */
+ public static class BitString
+ {
+ byte[] bytes = new byte[4];
+ int numBytes; // includes the last byte even if only some of its bits are used
+ int lastByteBits; // lastByteBits <= 8
+
+ /**
+ * Appends all bits in a byte array to the end of the bit string.
+ *
+ * @param bytes a byte array
+ */
+ void appendBits(byte[] bytes)
+ {
+ for (int i = 0; i != bytes.length; i++)
+ {
+ appendBits(bytes[i]);
+ }
+ }
+
+ /**
+ * Appends all bits in a byte to the end of the bit string.
+ *
+ * @param b a byte
+ */
+ public void appendBits(byte b)
+ {
+ if (numBytes == bytes.length)
+ {
+ bytes = copyOf(bytes, 2 * bytes.length);
+ }
+
+ if (numBytes == 0)
+ {
+ numBytes = 1;
+ bytes[0] = b;
+ lastByteBits = 8;
+ }
+ else if (lastByteBits == 8)
+ {
+ bytes[numBytes++] = b;
+ }
+ else
+ {
+ int s = 8 - lastByteBits;
+ bytes[numBytes - 1] |= (b & 0xFF) << lastByteBits;
+ bytes[numBytes++] = (byte)((b & 0xFF) >> s);
+ }
+ }
+
+ /**
+ * Returns the last numBits
bits from the end of the bit string.
+ *
+ * @param numBits number of bits
+ * @return a new BitString
of length numBits
+ */
+ public BitString getTrailing(int numBits)
+ {
+ BitString newStr = new BitString();
+ newStr.numBytes = (numBits + 7) / 8;
+ newStr.bytes = new byte[newStr.numBytes];
+ for (int i = 0; i < newStr.numBytes; i++)
+ {
+ newStr.bytes[i] = bytes[i];
+ }
+
+ newStr.lastByteBits = numBits % 8;
+ if (newStr.lastByteBits == 0)
+ {
+ newStr.lastByteBits = 8;
+ }
+ else
+ {
+ int s = 32 - newStr.lastByteBits;
+ newStr.bytes[newStr.numBytes - 1] = (byte)(newStr.bytes[newStr.numBytes - 1] << s >>> s);
+ }
+
+ return newStr;
+ }
+
+ /**
+ * Returns up to 32 bits from the beginning of the bit string.
+ *
+ * @param numBits number of bits
+ * @return an int
whose lower numBits
bits are the beginning of the bit string
+ */
+ public int getLeadingAsInt(int numBits)
+ {
+ int startBit = (numBytes - 1) * 8 + lastByteBits - numBits;
+ int startByte = startBit / 8;
+
+ int startBitInStartByte = startBit % 8;
+ int sum = (bytes[startByte] & 0xFF) >>> startBitInStartByte;
+ int shift = 8 - startBitInStartByte;
+ for (int i = startByte + 1; i < numBytes; i++)
+ {
+ sum |= (bytes[i] & 0xFF) << shift;
+ shift += 8;
+ }
+
+ return sum;
+ }
+
+ public byte[] getBytes()
+ {
+ return Arrays.clone(bytes);
+ }
+ }
+
+ private static byte[] copyOf(byte[] src, int len)
+ {
+ byte[] tmp = new byte[len];
+
+ System.arraycopy(src, 0, tmp, 0, len < src.length ? len : src.length);
+
+ return tmp;
+ }
+}
\ No newline at end of file
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/NTRUEngine.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/NTRUEngine.java
new file mode 100644
index 0000000..ce13395
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/NTRUEngine.java
@@ -0,0 +1,499 @@
+package org.bc.crypto.engines;
+
+import java.security.SecureRandom;
+
+import org.bc.crypto.AsymmetricBlockCipher;
+import org.bc.crypto.CipherParameters;
+import org.bc.crypto.DataLengthException;
+import org.bc.crypto.Digest;
+import org.bc.crypto.InvalidCipherTextException;
+import org.bc.crypto.params.NTRUEncryptionParameters;
+import org.bc.crypto.params.NTRUEncryptionPrivateKeyParameters;
+import org.bc.crypto.params.NTRUEncryptionPublicKeyParameters;
+import org.bc.crypto.params.NTRUParameters;
+import org.bc.crypto.params.ParametersWithRandom;
+import org.bc.math.ntru.polynomial.DenseTernaryPolynomial;
+import org.bc.math.ntru.polynomial.IntegerPolynomial;
+import org.bc.math.ntru.polynomial.Polynomial;
+import org.bc.math.ntru.polynomial.ProductFormPolynomial;
+import org.bc.math.ntru.polynomial.SparseTernaryPolynomial;
+import org.bc.math.ntru.polynomial.TernaryPolynomial;
+import org.bc.util.Arrays;
+
+/**
+ * Encrypts, decrypts data and generates key pairs.
+ * The parameter p is hardcoded to 3.
+ */
+public class NTRUEngine
+ implements AsymmetricBlockCipher
+{
+ private boolean forEncryption;
+ private NTRUEncryptionParameters params;
+ private NTRUEncryptionPublicKeyParameters pubKey;
+ private NTRUEncryptionPrivateKeyParameters privKey;
+ private SecureRandom random;
+
+ /**
+ * Constructs a new instance with a set of encryption parameters.
+ *
+ */
+ public NTRUEngine()
+ {
+ }
+
+ public void init(boolean forEncryption, CipherParameters parameters)
+ {
+ this.forEncryption = forEncryption;
+ if (forEncryption)
+ {
+ if (parameters instanceof ParametersWithRandom)
+ {
+ ParametersWithRandom p = (ParametersWithRandom)parameters;
+
+ this.random = p.getRandom();
+ this.pubKey = (NTRUEncryptionPublicKeyParameters)p.getParameters();
+ }
+ else
+ {
+ this.random = new SecureRandom();
+ this.pubKey = (NTRUEncryptionPublicKeyParameters)parameters;
+ }
+
+ this.params = pubKey.getParameters();
+ }
+ else
+ {
+ this.privKey = (NTRUEncryptionPrivateKeyParameters)parameters;
+ this.params = privKey.getParameters();
+ }
+ }
+
+ public int getInputBlockSize()
+ {
+ return params.maxMsgLenBytes;
+ }
+
+ public int getOutputBlockSize()
+ {
+ return ((params.N * log2(params.q)) + 7) / 8;
+ }
+
+ public byte[] processBlock(byte[] in, int inOff, int len)
+ throws InvalidCipherTextException
+ {
+ byte[] tmp = new byte[len];
+
+ System.arraycopy(in, inOff, tmp, 0, len);
+
+ if (forEncryption)
+ {
+ return encrypt(tmp, pubKey);
+ }
+ else
+ {
+ return decrypt(tmp, privKey);
+ }
+ }
+
+ /**
+ * Encrypts a message.
+ * See P1363.1 section 9.2.2.
+ *
+ * @param m The message to encrypt
+ * @param pubKey the public key to encrypt the message with
+ * @return the encrypted message
+ */
+ private byte[] encrypt(byte[] m, NTRUEncryptionPublicKeyParameters pubKey)
+ {
+ IntegerPolynomial pub = pubKey.h;
+ int N = params.N;
+ int q = params.q;
+
+ int maxLenBytes = params.maxMsgLenBytes;
+ int db = params.db;
+ int bufferLenBits = params.bufferLenBits;
+ int dm0 = params.dm0;
+ int pkLen = params.pkLen;
+ int minCallsMask = params.minCallsMask;
+ boolean hashSeed = params.hashSeed;
+ byte[] oid = params.oid;
+
+ int l = m.length;
+ if (maxLenBytes > 255)
+ {
+ throw new IllegalArgumentException("llen values bigger than 1 are not supported");
+ }
+ if (l > maxLenBytes)
+ {
+ throw new DataLengthException("Message too long: " + l + ">" + maxLenBytes);
+ }
+
+ while (true)
+ {
+ // M = b|octL|m|p0
+ byte[] b = new byte[db / 8];
+ random.nextBytes(b);
+ byte[] p0 = new byte[maxLenBytes + 1 - l];
+ byte[] M = new byte[bufferLenBits / 8];
+
+ System.arraycopy(b, 0, M, 0, b.length);
+ M[b.length] = (byte)l;
+ System.arraycopy(m, 0, M, b.length + 1, m.length);
+ System.arraycopy(p0, 0, M, b.length + 1 + m.length, p0.length);
+
+ IntegerPolynomial mTrin = IntegerPolynomial.fromBinary3Sves(M, N);
+
+ // sData = OID|m|b|hTrunc
+ byte[] bh = pub.toBinary(q);
+ byte[] hTrunc = copyOf(bh, pkLen / 8);
+ byte[] sData = buildSData(oid, m, l, b, hTrunc);
+
+ Polynomial r = generateBlindingPoly(sData, M);
+ IntegerPolynomial R = r.mult(pub, q);
+ IntegerPolynomial R4 = (IntegerPolynomial)R.clone();
+ R4.modPositive(4);
+ byte[] oR4 = R4.toBinary(4);
+ IntegerPolynomial mask = MGF(oR4, N, minCallsMask, hashSeed);
+ mTrin.add(mask);
+ mTrin.mod3();
+
+ if (mTrin.count(-1) < dm0)
+ {
+ continue;
+ }
+ if (mTrin.count(0) < dm0)
+ {
+ continue;
+ }
+ if (mTrin.count(1) < dm0)
+ {
+ continue;
+ }
+
+ R.add(mTrin, q);
+ R.ensurePositive(q);
+ return R.toBinary(q);
+ }
+ }
+
+ private byte[] buildSData(byte[] oid, byte[] m, int l, byte[] b, byte[] hTrunc)
+ {
+ byte[] sData = new byte[oid.length + l + b.length + hTrunc.length];
+
+ System.arraycopy(oid, 0, sData, 0, oid.length);
+ System.arraycopy(m, 0, sData, oid.length, m.length);
+ System.arraycopy(b, 0, sData, oid.length + m.length, b.length);
+ System.arraycopy(hTrunc, 0, sData, oid.length + m.length + b.length, hTrunc.length);
+ return sData;
+ }
+
+ protected IntegerPolynomial encrypt(IntegerPolynomial m, TernaryPolynomial r, IntegerPolynomial pubKey)
+ {
+ IntegerPolynomial e = r.mult(pubKey, params.q);
+ e.add(m, params.q);
+ e.ensurePositive(params.q);
+ return e;
+ }
+
+ /**
+ * Deterministically generates a blinding polynomial from a seed and a message representative.
+ *
+ * @param seed
+ * @param M message representative
+ * @return a blinding polynomial
+ */
+ private Polynomial generateBlindingPoly(byte[] seed, byte[] M)
+ {
+ IndexGenerator ig = new IndexGenerator(seed, params);
+
+ if (params.polyType == NTRUParameters.TERNARY_POLYNOMIAL_TYPE_PRODUCT)
+ {
+ SparseTernaryPolynomial r1 = new SparseTernaryPolynomial(generateBlindingCoeffs(ig, params.dr1));
+ SparseTernaryPolynomial r2 = new SparseTernaryPolynomial(generateBlindingCoeffs(ig, params.dr2));
+ SparseTernaryPolynomial r3 = new SparseTernaryPolynomial(generateBlindingCoeffs(ig, params.dr3));
+ return new ProductFormPolynomial(r1, r2, r3);
+ }
+ else
+ {
+ int dr = params.dr;
+ boolean sparse = params.sparse;
+ int[] r = generateBlindingCoeffs(ig, dr);
+ if (sparse)
+ {
+ return new SparseTernaryPolynomial(r);
+ }
+ else
+ {
+ return new DenseTernaryPolynomial(r);
+ }
+ }
+ }
+
+ /**
+ * Generates an int
array containing dr
elements equal to 1
+ * and dr
elements equal to -1
using an index generator.
+ *
+ * @param ig an index generator
+ * @param dr number of ones / negative ones
+ * @return an array containing numbers between -1
and 1
+ */
+ private int[] generateBlindingCoeffs(IndexGenerator ig, int dr)
+ {
+ int N = params.N;
+
+ int[] r = new int[N];
+ for (int coeff = -1; coeff <= 1; coeff += 2)
+ {
+ int t = 0;
+ while (t < dr)
+ {
+ int i = ig.nextIndex();
+ if (r[i] == 0)
+ {
+ r[i] = coeff;
+ t++;
+ }
+ }
+ }
+
+ return r;
+ }
+
+ /**
+ * An implementation of MGF-TP-1 from P1363.1 section 8.4.1.1.
+ *
+ * @param seed
+ * @param N
+ * @param minCallsR
+ * @param hashSeed whether to hash the seed
+ * @return
+ */
+ private IntegerPolynomial MGF(byte[] seed, int N, int minCallsR, boolean hashSeed)
+ {
+ Digest hashAlg = params.hashAlg;
+ int hashLen = hashAlg.getDigestSize();
+ byte[] buf = new byte[minCallsR * hashLen];
+ byte[] Z = hashSeed ? calcHash(hashAlg, seed) : seed;
+ int counter = 0;
+ while (counter < minCallsR)
+ {
+ hashAlg.update(Z, 0, Z.length);
+ putInt(hashAlg, counter);
+
+ byte[] hash = calcHash(hashAlg);
+ System.arraycopy(hash, 0, buf, counter * hashLen, hashLen);
+ counter++;
+ }
+
+ IntegerPolynomial i = new IntegerPolynomial(N);
+ while (true)
+ {
+ int cur = 0;
+ for (int index = 0; index != buf.length; index++)
+ {
+ int O = (int)buf[index] & 0xFF;
+ if (O >= 243) // 243 = 3^5
+ {
+ continue;
+ }
+
+ for (int terIdx = 0; terIdx < 4; terIdx++)
+ {
+ int rem3 = O % 3;
+ i.coeffs[cur] = rem3 - 1;
+ cur++;
+ if (cur == N)
+ {
+ return i;
+ }
+ O = (O - rem3) / 3;
+ }
+
+ i.coeffs[cur] = O - 1;
+ cur++;
+ if (cur == N)
+ {
+ return i;
+ }
+ }
+
+ if (cur >= N)
+ {
+ return i;
+ }
+
+ hashAlg.update(Z, 0, Z.length);
+ putInt(hashAlg, counter);
+
+ byte[] hash = calcHash(hashAlg);
+
+ buf = hash;
+
+ counter++;
+ }
+ }
+
+ private void putInt(Digest hashAlg, int counter)
+ {
+ hashAlg.update((byte)(counter >> 24));
+ hashAlg.update((byte)(counter >> 16));
+ hashAlg.update((byte)(counter >> 8));
+ hashAlg.update((byte)counter);
+ }
+
+ private byte[] calcHash(Digest hashAlg)
+ {
+ byte[] tmp = new byte[hashAlg.getDigestSize()];
+
+ hashAlg.doFinal(tmp, 0);
+
+ return tmp;
+ }
+
+ private byte[] calcHash(Digest hashAlg, byte[] input)
+ {
+ byte[] tmp = new byte[hashAlg.getDigestSize()];
+
+ hashAlg.update(input, 0, input.length);
+ hashAlg.doFinal(tmp, 0);
+
+ return tmp;
+ }
+ /**
+ * Decrypts a message.
+ * See P1363.1 section 9.2.3.
+ *
+ * @param data The message to decrypt
+ * @param privKey the corresponding private key
+ * @return the decrypted message
+ * @throws InvalidCipherTextException if the encrypted data is invalid, or maxLenBytes
is greater than 255
+ */
+ private byte[] decrypt(byte[] data, NTRUEncryptionPrivateKeyParameters privKey)
+ throws InvalidCipherTextException
+ {
+ Polynomial priv_t = privKey.t;
+ IntegerPolynomial priv_fp = privKey.fp;
+ IntegerPolynomial pub = privKey.h;
+ int N = params.N;
+ int q = params.q;
+ int db = params.db;
+ int maxMsgLenBytes = params.maxMsgLenBytes;
+ int dm0 = params.dm0;
+ int pkLen = params.pkLen;
+ int minCallsMask = params.minCallsMask;
+ boolean hashSeed = params.hashSeed;
+ byte[] oid = params.oid;
+
+ if (maxMsgLenBytes > 255)
+ {
+ throw new DataLengthException("maxMsgLenBytes values bigger than 255 are not supported");
+ }
+
+ int bLen = db / 8;
+
+ IntegerPolynomial e = IntegerPolynomial.fromBinary(data, N, q);
+ IntegerPolynomial ci = decrypt(e, priv_t, priv_fp);
+
+ if (ci.count(-1) < dm0)
+ {
+ throw new InvalidCipherTextException("Less than dm0 coefficients equal -1");
+ }
+ if (ci.count(0) < dm0)
+ {
+ throw new InvalidCipherTextException("Less than dm0 coefficients equal 0");
+ }
+ if (ci.count(1) < dm0)
+ {
+ throw new InvalidCipherTextException("Less than dm0 coefficients equal 1");
+ }
+
+ IntegerPolynomial cR = (IntegerPolynomial)e.clone();
+ cR.sub(ci);
+ cR.modPositive(q);
+ IntegerPolynomial cR4 = (IntegerPolynomial)cR.clone();
+ cR4.modPositive(4);
+ byte[] coR4 = cR4.toBinary(4);
+ IntegerPolynomial mask = MGF(coR4, N, minCallsMask, hashSeed);
+ IntegerPolynomial cMTrin = ci;
+ cMTrin.sub(mask);
+ cMTrin.mod3();
+ byte[] cM = cMTrin.toBinary3Sves();
+
+ byte[] cb = new byte[bLen];
+ System.arraycopy(cM, 0, cb, 0, bLen);
+ int cl = cM[bLen] & 0xFF; // llen=1, so read one byte
+ if (cl > maxMsgLenBytes)
+ {
+ throw new InvalidCipherTextException("Message too long: " + cl + ">" + maxMsgLenBytes);
+ }
+ byte[] cm = new byte[cl];
+ System.arraycopy(cM, bLen + 1, cm, 0, cl);
+ byte[] p0 = new byte[cM.length - (bLen + 1 + cl)];
+ System.arraycopy(cM, bLen + 1 + cl, p0, 0, p0.length);
+ if (!Arrays.areEqual(p0, new byte[p0.length]))
+ {
+ throw new InvalidCipherTextException("The message is not followed by zeroes");
+ }
+
+ // sData = OID|m|b|hTrunc
+ byte[] bh = pub.toBinary(q);
+ byte[] hTrunc = copyOf(bh, pkLen / 8);
+ byte[] sData = buildSData(oid, cm, cl, cb, hTrunc);
+
+ Polynomial cr = generateBlindingPoly(sData, cm);
+ IntegerPolynomial cRPrime = cr.mult(pub);
+ cRPrime.modPositive(q);
+ if (!cRPrime.equals(cR))
+ {
+ throw new InvalidCipherTextException("Invalid message encoding");
+ }
+
+ return cm;
+ }
+
+ /**
+ * @param e
+ * @param priv_t a polynomial such that if fastFp=true
, f=1+3*priv_t
; otherwise, f=priv_t
+ * @param priv_fp
+ * @return
+ */
+ protected IntegerPolynomial decrypt(IntegerPolynomial e, Polynomial priv_t, IntegerPolynomial priv_fp)
+ {
+ IntegerPolynomial a;
+ if (params.fastFp)
+ {
+ a = priv_t.mult(e, params.q);
+ a.mult(3);
+ a.add(e);
+ }
+ else
+ {
+ a = priv_t.mult(e, params.q);
+ }
+ a.center0(params.q);
+ a.mod3();
+
+ IntegerPolynomial c = params.fastFp ? a : new DenseTernaryPolynomial(a).mult(priv_fp, 3);
+ c.center0(3);
+ return c;
+ }
+
+ private byte[] copyOf(byte[] src, int len)
+ {
+ byte[] tmp = new byte[len];
+
+ System.arraycopy(src, 0, tmp, 0, len < src.length ? len : src.length);
+
+ return tmp;
+ }
+
+ private int log2(int value)
+ {
+ if (value == 2048)
+ {
+ return 11;
+ }
+
+ throw new IllegalStateException("log2 not fully implemented");
+ }
+}
\ No newline at end of file
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/NaccacheSternEngine.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/NaccacheSternEngine.java
new file mode 100644
index 0000000..6e6033a
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/NaccacheSternEngine.java
@@ -0,0 +1,438 @@
+package org.bc.crypto.engines;
+
+import java.math.BigInteger;
+import java.util.Vector;
+
+import org.bc.crypto.AsymmetricBlockCipher;
+import org.bc.crypto.CipherParameters;
+import org.bc.crypto.DataLengthException;
+import org.bc.crypto.InvalidCipherTextException;
+import org.bc.crypto.params.NaccacheSternKeyParameters;
+import org.bc.crypto.params.NaccacheSternPrivateKeyParameters;
+import org.bc.crypto.params.ParametersWithRandom;
+import org.bc.util.Arrays;
+
+
+/**
+ * NaccacheStern Engine. For details on this cipher, please see
+ * http://www.gemplus.com/smart/rd/publications/pdf/NS98pkcs.pdf
+ */
+public class NaccacheSternEngine
+ implements AsymmetricBlockCipher
+{
+ private boolean forEncryption;
+
+ private NaccacheSternKeyParameters key;
+
+ private Vector[] lookup = null;
+
+ private boolean debug = false;
+
+ private static BigInteger ZERO = BigInteger.valueOf(0);
+ private static BigInteger ONE = BigInteger.valueOf(1);
+
+ /**
+ * Initializes this algorithm. Must be called before all other Functions.
+ *
+ * @see org.bc.crypto.AsymmetricBlockCipher#init(boolean,
+ * org.bc.crypto.CipherParameters)
+ */
+ public void init(boolean forEncryption, CipherParameters param)
+ {
+ this.forEncryption = forEncryption;
+
+ if (param instanceof ParametersWithRandom)
+ {
+ param = ((ParametersWithRandom) param).getParameters();
+ }
+
+ key = (NaccacheSternKeyParameters)param;
+
+ // construct lookup table for faster decryption if necessary
+ if (!this.forEncryption)
+ {
+ if (debug)
+ {
+ System.out.println("Constructing lookup Array");
+ }
+ NaccacheSternPrivateKeyParameters priv = (NaccacheSternPrivateKeyParameters)key;
+ Vector primes = priv.getSmallPrimes();
+ lookup = new Vector[primes.size()];
+ for (int i = 0; i < primes.size(); i++)
+ {
+ BigInteger actualPrime = (BigInteger)primes.elementAt(i);
+ int actualPrimeValue = actualPrime.intValue();
+
+ lookup[i] = new Vector();
+ lookup[i].addElement(ONE);
+
+ if (debug)
+ {
+ System.out.println("Constructing lookup ArrayList for " + actualPrimeValue);
+ }
+
+ BigInteger accJ = ZERO;
+
+ for (int j = 1; j < actualPrimeValue; j++)
+ {
+ accJ = accJ.add(priv.getPhi_n());
+ BigInteger comp = accJ.divide(actualPrime);
+ lookup[i].addElement(priv.getG().modPow(comp, priv.getModulus()));
+ }
+ }
+ }
+ }
+
+ public void setDebug(boolean debug)
+ {
+ this.debug = debug;
+ }
+
+ /**
+ * Returns the input block size of this algorithm.
+ *
+ * @see org.bc.crypto.AsymmetricBlockCipher#getInputBlockSize()
+ */
+ public int getInputBlockSize()
+ {
+ if (forEncryption)
+ {
+ // We can only encrypt values up to lowerSigmaBound
+ return (key.getLowerSigmaBound() + 7) / 8 - 1;
+ }
+ else
+ {
+ // We pad to modulus-size bytes for easier decryption.
+ return key.getModulus().toByteArray().length;
+ }
+ }
+
+ /**
+ * Returns the output block size of this algorithm.
+ *
+ * @see org.bc.crypto.AsymmetricBlockCipher#getOutputBlockSize()
+ */
+ public int getOutputBlockSize()
+ {
+ if (forEncryption)
+ {
+ // encrypted Data is always padded up to modulus size
+ return key.getModulus().toByteArray().length;
+ }
+ else
+ {
+ // decrypted Data has upper limit lowerSigmaBound
+ return (key.getLowerSigmaBound() + 7) / 8 - 1;
+ }
+ }
+
+ /**
+ * Process a single Block using the Naccache-Stern algorithm.
+ *
+ * @see org.bc.crypto.AsymmetricBlockCipher#processBlock(byte[],
+ * int, int)
+ */
+ public byte[] processBlock(byte[] in, int inOff, int len) throws InvalidCipherTextException
+ {
+ if (key == null)
+ {
+ throw new IllegalStateException("NaccacheStern engine not initialised");
+ }
+ if (len > (getInputBlockSize() + 1))
+ {
+ throw new DataLengthException("input too large for Naccache-Stern cipher.\n");
+ }
+
+ if (!forEncryption)
+ {
+ // At decryption make sure that we receive padded data blocks
+ if (len < getInputBlockSize())
+ {
+ throw new InvalidCipherTextException("BlockLength does not match modulus for Naccache-Stern cipher.\n");
+ }
+ }
+
+ byte[] block;
+
+ if (inOff != 0 || len != in.length)
+ {
+ block = new byte[len];
+ System.arraycopy(in, inOff, block, 0, len);
+ }
+ else
+ {
+ block = in;
+ }
+
+ // transform input into BigInteger
+ BigInteger input = new BigInteger(1, block);
+ if (debug)
+ {
+ System.out.println("input as BigInteger: " + input);
+ }
+ byte[] output;
+ if (forEncryption)
+ {
+ output = encrypt(input);
+ }
+ else
+ {
+ Vector plain = new Vector();
+ NaccacheSternPrivateKeyParameters priv = (NaccacheSternPrivateKeyParameters)key;
+ Vector primes = priv.getSmallPrimes();
+ // Get Chinese Remainders of CipherText
+ for (int i = 0; i < primes.size(); i++)
+ {
+ BigInteger exp = input.modPow(priv.getPhi_n().divide((BigInteger)primes.elementAt(i)), priv.getModulus());
+ Vector al = lookup[i];
+ if (lookup[i].size() != ((BigInteger)primes.elementAt(i)).intValue())
+ {
+ if (debug)
+ {
+ System.out.println("Prime is " + primes.elementAt(i) + ", lookup table has size " + al.size());
+ }
+ throw new InvalidCipherTextException("Error in lookup Array for "
+ + ((BigInteger)primes.elementAt(i)).intValue()
+ + ": Size mismatch. Expected ArrayList with length "
+ + ((BigInteger)primes.elementAt(i)).intValue() + " but found ArrayList of length "
+ + lookup[i].size());
+ }
+ int lookedup = al.indexOf(exp);
+
+ if (lookedup == -1)
+ {
+ if (debug)
+ {
+ System.out.println("Actual prime is " + primes.elementAt(i));
+ System.out.println("Decrypted value is " + exp);
+
+ System.out.println("LookupList for " + primes.elementAt(i) + " with size " + lookup[i].size()
+ + " is: ");
+ for (int j = 0; j < lookup[i].size(); j++)
+ {
+ System.out.println(lookup[i].elementAt(j));
+ }
+ }
+ throw new InvalidCipherTextException("Lookup failed");
+ }
+ plain.addElement(BigInteger.valueOf(lookedup));
+ }
+ BigInteger test = chineseRemainder(plain, primes);
+
+ // Should not be used as an oracle, so reencrypt output to see
+ // if it corresponds to input
+
+ // this breaks probabilisic encryption, so disable it. Anyway, we do
+ // use the first n primes for key generation, so it is pretty easy
+ // to guess them. But as stated in the paper, this is not a security
+ // breach. So we can just work with the correct sigma.
+
+ // if (debug) {
+ // System.out.println("Decryption is " + test);
+ // }
+ // if ((key.getG().modPow(test, key.getModulus())).equals(input)) {
+ // output = test.toByteArray();
+ // } else {
+ // if(debug){
+ // System.out.println("Engine seems to be used as an oracle,
+ // returning null");
+ // }
+ // output = null;
+ // }
+
+ output = test.toByteArray();
+
+ }
+
+ return output;
+ }
+
+ /**
+ * Encrypts a BigInteger aka Plaintext with the public key.
+ *
+ * @param plain
+ * The BigInteger to encrypt
+ * @return The byte[] representation of the encrypted BigInteger (i.e.
+ * crypted.toByteArray())
+ */
+ public byte[] encrypt(BigInteger plain)
+ {
+ // Always return modulus size values 0-padded at the beginning
+ // 0-padding at the beginning is correctly parsed by BigInteger :)
+ byte[] output = key.getModulus().toByteArray();
+ Arrays.fill(output, (byte)0);
+ byte[] tmp = key.getG().modPow(plain, key.getModulus()).toByteArray();
+ System
+ .arraycopy(tmp, 0, output, output.length - tmp.length,
+ tmp.length);
+ if (debug)
+ {
+ System.out
+ .println("Encrypted value is: " + new BigInteger(output));
+ }
+ return output;
+ }
+
+ /**
+ * Adds the contents of two encrypted blocks mod sigma
+ *
+ * @param block1
+ * the first encrypted block
+ * @param block2
+ * the second encrypted block
+ * @return encrypt((block1 + block2) mod sigma)
+ * @throws InvalidCipherTextException
+ */
+ public byte[] addCryptedBlocks(byte[] block1, byte[] block2)
+ throws InvalidCipherTextException
+ {
+ // check for correct blocksize
+ if (forEncryption)
+ {
+ if ((block1.length > getOutputBlockSize())
+ || (block2.length > getOutputBlockSize()))
+ {
+ throw new InvalidCipherTextException(
+ "BlockLength too large for simple addition.\n");
+ }
+ }
+ else
+ {
+ if ((block1.length > getInputBlockSize())
+ || (block2.length > getInputBlockSize()))
+ {
+ throw new InvalidCipherTextException(
+ "BlockLength too large for simple addition.\n");
+ }
+ }
+
+ // calculate resulting block
+ BigInteger m1Crypt = new BigInteger(1, block1);
+ BigInteger m2Crypt = new BigInteger(1, block2);
+ BigInteger m1m2Crypt = m1Crypt.multiply(m2Crypt);
+ m1m2Crypt = m1m2Crypt.mod(key.getModulus());
+ if (debug)
+ {
+ System.out.println("c(m1) as BigInteger:....... " + m1Crypt);
+ System.out.println("c(m2) as BigInteger:....... " + m2Crypt);
+ System.out.println("c(m1)*c(m2)%n = c(m1+m2)%n: " + m1m2Crypt);
+ }
+
+ byte[] output = key.getModulus().toByteArray();
+ Arrays.fill(output, (byte)0);
+ System.arraycopy(m1m2Crypt.toByteArray(), 0, output, output.length
+ - m1m2Crypt.toByteArray().length,
+ m1m2Crypt.toByteArray().length);
+
+ return output;
+ }
+
+ /**
+ * Convenience Method for data exchange with the cipher.
+ *
+ * Determines blocksize and splits data to blocksize.
+ *
+ * @param data the data to be processed
+ * @return the data after it went through the NaccacheSternEngine.
+ * @throws InvalidCipherTextException
+ */
+ public byte[] processData(byte[] data) throws InvalidCipherTextException
+ {
+ if (debug)
+ {
+ System.out.println();
+ }
+ if (data.length > getInputBlockSize())
+ {
+ int inBlocksize = getInputBlockSize();
+ int outBlocksize = getOutputBlockSize();
+ if (debug)
+ {
+ System.out.println("Input blocksize is: " + inBlocksize + " bytes");
+ System.out.println("Output blocksize is: " + outBlocksize + " bytes");
+ System.out.println("Data has length:.... " + data.length + " bytes");
+ }
+ int datapos = 0;
+ int retpos = 0;
+ byte[] retval = new byte[(data.length / inBlocksize + 1) * outBlocksize];
+ while (datapos < data.length)
+ {
+ byte[] tmp;
+ if (datapos + inBlocksize < data.length)
+ {
+ tmp = processBlock(data, datapos, inBlocksize);
+ datapos += inBlocksize;
+ }
+ else
+ {
+ tmp = processBlock(data, datapos, data.length - datapos);
+ datapos += data.length - datapos;
+ }
+ if (debug)
+ {
+ System.out.println("new datapos is " + datapos);
+ }
+ if (tmp != null)
+ {
+ System.arraycopy(tmp, 0, retval, retpos, tmp.length);
+
+ retpos += tmp.length;
+ }
+ else
+ {
+ if (debug)
+ {
+ System.out.println("cipher returned null");
+ }
+ throw new InvalidCipherTextException("cipher returned null");
+ }
+ }
+ byte[] ret = new byte[retpos];
+ System.arraycopy(retval, 0, ret, 0, retpos);
+ if (debug)
+ {
+ System.out.println("returning " + ret.length + " bytes");
+ }
+ return ret;
+ }
+ else
+ {
+ if (debug)
+ {
+ System.out.println("data size is less then input block size, processing directly");
+ }
+ return processBlock(data, 0, data.length);
+ }
+ }
+
+ /**
+ * Computes the integer x that is expressed through the given primes and the
+ * congruences with the chinese remainder theorem (CRT).
+ *
+ * @param congruences
+ * the congruences c_i
+ * @param primes
+ * the primes p_i
+ * @return an integer x for that x % p_i == c_i
+ */
+ private static BigInteger chineseRemainder(Vector congruences, Vector primes)
+ {
+ BigInteger retval = ZERO;
+ BigInteger all = ONE;
+ for (int i = 0; i < primes.size(); i++)
+ {
+ all = all.multiply((BigInteger)primes.elementAt(i));
+ }
+ for (int i = 0; i < primes.size(); i++)
+ {
+ BigInteger a = (BigInteger)primes.elementAt(i);
+ BigInteger b = all.divide(a);
+ BigInteger b_ = b.modInverse(a);
+ BigInteger tmp = b.multiply(b_);
+ tmp = tmp.multiply((BigInteger)congruences.elementAt(i));
+ retval = retval.add(tmp);
+ }
+
+ return retval.mod(all);
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/NoekeonEngine.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/NoekeonEngine.java
new file mode 100644
index 0000000..52019e0
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/NoekeonEngine.java
@@ -0,0 +1,262 @@
+package org.bc.crypto.engines;
+
+import org.bc.crypto.BlockCipher;
+import org.bc.crypto.CipherParameters;
+import org.bc.crypto.DataLengthException;
+import org.bc.crypto.params.KeyParameter;
+
+/**
+ * A Noekeon engine, using direct-key mode.
+ */
+
+public class NoekeonEngine
+ implements BlockCipher
+{
+ private static final int genericSize = 16; // Block and key size, as well as the amount of rounds.
+
+ private static final int[] nullVector =
+ {
+ 0x00, 0x00, 0x00, 0x00 // Used in decryption
+ },
+
+ roundConstants =
+ {
+ 0x80, 0x1b, 0x36, 0x6c,
+ 0xd8, 0xab, 0x4d, 0x9a,
+ 0x2f, 0x5e, 0xbc, 0x63,
+ 0xc6, 0x97, 0x35, 0x6a,
+ 0xd4
+ };
+
+ private int[] state = new int[4], // a
+ subKeys = new int[4], // k
+ decryptKeys = new int[4];
+
+ private boolean _initialised,
+ _forEncryption;
+
+ /**
+ * Create an instance of the Noekeon encryption algorithm
+ * and set some defaults
+ */
+ public NoekeonEngine()
+ {
+ _initialised = false;
+ }
+
+ public String getAlgorithmName()
+ {
+ return "Noekeon";
+ }
+
+ public int getBlockSize()
+ {
+ return genericSize;
+ }
+
+ /**
+ * initialise
+ *
+ * @param forEncryption whether or not we are for encryption.
+ * @param params the parameters required to set up the cipher.
+ * @exception IllegalArgumentException if the params argument is
+ * inappropriate.
+ */
+ public void init(
+ boolean forEncryption,
+ CipherParameters params)
+ {
+ if (!(params instanceof KeyParameter))
+ {
+ throw new IllegalArgumentException("invalid parameter passed to Noekeon init - " + params.getClass().getName());
+ }
+
+ _forEncryption = forEncryption;
+ _initialised = true;
+
+ KeyParameter p = (KeyParameter)params;
+
+ setKey(p.getKey());
+ }
+
+ public int processBlock(
+ byte[] in,
+ int inOff,
+ byte[] out,
+ int outOff)
+ {
+ if (!_initialised)
+ {
+ throw new IllegalStateException(getAlgorithmName()+" not initialised");
+ }
+
+ if ((inOff + genericSize) > in.length)
+ {
+ throw new DataLengthException("input buffer too short");
+ }
+
+ if ((outOff + genericSize) > out.length)
+ {
+ throw new DataLengthException("output buffer too short");
+ }
+
+ return (_forEncryption) ? encryptBlock(in, inOff, out, outOff)
+ : decryptBlock(in, inOff, out, outOff);
+ }
+
+ public void reset()
+ {
+ }
+
+ /**
+ * Re-key the cipher.
+ *
+ * @param key the key to be used
+ */
+ private void setKey(
+ byte[] key)
+ {
+ subKeys[0] = bytesToIntBig(key, 0);
+ subKeys[1] = bytesToIntBig(key, 4);
+ subKeys[2] = bytesToIntBig(key, 8);
+ subKeys[3] = bytesToIntBig(key, 12);
+ }
+
+ private int encryptBlock(
+ byte[] in,
+ int inOff,
+ byte[] out,
+ int outOff)
+ {
+ state[0] = bytesToIntBig(in, inOff);
+ state[1] = bytesToIntBig(in, inOff+4);
+ state[2] = bytesToIntBig(in, inOff+8);
+ state[3] = bytesToIntBig(in, inOff+12);
+
+ int i;
+ for (i = 0; i < genericSize; i++)
+ {
+ state[0] ^= roundConstants[i];
+ theta(state, subKeys);
+ pi1(state);
+ gamma(state);
+ pi2(state);
+ }
+
+ state[0] ^= roundConstants[i];
+ theta(state, subKeys);
+
+ intToBytesBig(state[0], out, outOff);
+ intToBytesBig(state[1], out, outOff+4);
+ intToBytesBig(state[2], out, outOff+8);
+ intToBytesBig(state[3], out, outOff+12);
+
+ return genericSize;
+ }
+
+ private int decryptBlock(
+ byte[] in,
+ int inOff,
+ byte[] out,
+ int outOff)
+ {
+ state[0] = bytesToIntBig(in, inOff);
+ state[1] = bytesToIntBig(in, inOff+4);
+ state[2] = bytesToIntBig(in, inOff+8);
+ state[3] = bytesToIntBig(in, inOff+12);
+
+ System.arraycopy(subKeys, 0, decryptKeys, 0, subKeys.length);
+ theta(decryptKeys, nullVector);
+
+ int i;
+ for (i = genericSize; i > 0; i--)
+ {
+ theta(state, decryptKeys);
+ state[0] ^= roundConstants[i];
+ pi1(state);
+ gamma(state);
+ pi2(state);
+ }
+
+ theta(state, decryptKeys);
+ state[0] ^= roundConstants[i];
+
+ intToBytesBig(state[0], out, outOff);
+ intToBytesBig(state[1], out, outOff+4);
+ intToBytesBig(state[2], out, outOff+8);
+ intToBytesBig(state[3], out, outOff+12);
+
+ return genericSize;
+ }
+
+ private void gamma(int[] a)
+ {
+ a[1] ^= ~a[3] & ~a[2];
+ a[0] ^= a[2] & a[1];
+
+ int tmp = a[3];
+ a[3] = a[0];
+ a[0] = tmp;
+ a[2] ^= a[0]^a[1]^a[3];
+
+ a[1] ^= ~a[3] & ~a[2];
+ a[0] ^= a[2] & a[1];
+ }
+
+ private void theta(int[] a, int[] k)
+ {
+ int tmp;
+
+ tmp = a[0]^a[2];
+ tmp ^= rotl(tmp,8)^rotl(tmp,24);
+ a[1] ^= tmp;
+ a[3] ^= tmp;
+
+ for (int i = 0; i < 4; i++)
+ {
+ a[i] ^= k[i];
+ }
+
+ tmp = a[1]^a[3];
+ tmp ^= rotl(tmp,8)^rotl(tmp,24);
+ a[0] ^= tmp;
+ a[2] ^= tmp;
+ }
+
+ private void pi1(int[] a)
+ {
+ a[1] = rotl(a[1], 1);
+ a[2] = rotl(a[2], 5);
+ a[3] = rotl(a[3], 2);
+ }
+
+ private void pi2(int[] a)
+ {
+ a[1] = rotl(a[1], 31);
+ a[2] = rotl(a[2], 27);
+ a[3] = rotl(a[3], 30);
+ }
+
+ // Helpers
+
+ private int bytesToIntBig(byte[] in, int off)
+ {
+ return ((in[off++]) << 24) |
+ ((in[off++] & 0xff) << 16) |
+ ((in[off++] & 0xff) << 8) |
+ (in[off ] & 0xff);
+ }
+
+ private void intToBytesBig(int x, byte[] out, int off)
+ {
+ out[off++] = (byte)(x >>> 24);
+ out[off++] = (byte)(x >>> 16);
+ out[off++] = (byte)(x >>> 8);
+ out[off ] = (byte)x;
+ }
+
+ private int rotl(int x, int y)
+ {
+ return (x << y) | (x >>> (32-y));
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/NullEngine.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/NullEngine.java
new file mode 100644
index 0000000..a89909e
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/NullEngine.java
@@ -0,0 +1,84 @@
+package org.bc.crypto.engines;
+
+import org.bc.crypto.BlockCipher;
+import org.bc.crypto.CipherParameters;
+import org.bc.crypto.DataLengthException;
+
+/**
+ * The no-op engine that just copies bytes through, irrespective of whether encrypting and decrypting.
+ * Provided for the sake of completeness.
+ */
+public class NullEngine implements BlockCipher
+{
+ private boolean initialised;
+ protected static final int BLOCK_SIZE = 1;
+
+ /**
+ * Standard constructor.
+ */
+ public NullEngine()
+ {
+ super();
+ }
+
+ /* (non-Javadoc)
+ * @see org.bouncycastle.crypto.BlockCipher#init(boolean, org.bouncycastle.crypto.CipherParameters)
+ */
+ public void init(boolean forEncryption, CipherParameters params) throws IllegalArgumentException
+ {
+ // we don't mind any parameters that may come in
+ this.initialised = true;
+ }
+
+ /* (non-Javadoc)
+ * @see org.bouncycastle.crypto.BlockCipher#getAlgorithmName()
+ */
+ public String getAlgorithmName()
+ {
+ return "Null";
+ }
+
+ /* (non-Javadoc)
+ * @see org.bouncycastle.crypto.BlockCipher#getBlockSize()
+ */
+ public int getBlockSize()
+ {
+ return BLOCK_SIZE;
+ }
+
+ /* (non-Javadoc)
+ * @see org.bouncycastle.crypto.BlockCipher#processBlock(byte[], int, byte[], int)
+ */
+ public int processBlock(byte[] in, int inOff, byte[] out, int outOff)
+ throws DataLengthException, IllegalStateException
+ {
+ if (!initialised)
+ {
+ throw new IllegalStateException("Null engine not initialised");
+ }
+ if ((inOff + BLOCK_SIZE) > in.length)
+ {
+ throw new DataLengthException("input buffer too short");
+ }
+
+ if ((outOff + BLOCK_SIZE) > out.length)
+ {
+ throw new DataLengthException("output buffer too short");
+ }
+
+ for (int i = 0; i < BLOCK_SIZE; ++i)
+ {
+ out[outOff + i] = in[inOff + i];
+ }
+
+ return BLOCK_SIZE;
+ }
+
+ /* (non-Javadoc)
+ * @see org.bouncycastle.crypto.BlockCipher#reset()
+ */
+ public void reset()
+ {
+ // nothing needs to be done
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/RC2Engine.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/RC2Engine.java
new file mode 100644
index 0000000..5b0aae4
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/RC2Engine.java
@@ -0,0 +1,316 @@
+package org.bc.crypto.engines;
+
+import org.bc.crypto.BlockCipher;
+import org.bc.crypto.CipherParameters;
+import org.bc.crypto.DataLengthException;
+import org.bc.crypto.params.KeyParameter;
+import org.bc.crypto.params.RC2Parameters;
+
+/**
+ * an implementation of RC2 as described in RFC 2268
+ * "A Description of the RC2(r) Encryption Algorithm" R. Rivest.
+ */
+public class RC2Engine
+ implements BlockCipher
+{
+ //
+ // the values we use for key expansion (based on the digits of PI)
+ //
+ private static byte[] piTable =
+ {
+ (byte)0xd9, (byte)0x78, (byte)0xf9, (byte)0xc4, (byte)0x19, (byte)0xdd, (byte)0xb5, (byte)0xed,
+ (byte)0x28, (byte)0xe9, (byte)0xfd, (byte)0x79, (byte)0x4a, (byte)0xa0, (byte)0xd8, (byte)0x9d,
+ (byte)0xc6, (byte)0x7e, (byte)0x37, (byte)0x83, (byte)0x2b, (byte)0x76, (byte)0x53, (byte)0x8e,
+ (byte)0x62, (byte)0x4c, (byte)0x64, (byte)0x88, (byte)0x44, (byte)0x8b, (byte)0xfb, (byte)0xa2,
+ (byte)0x17, (byte)0x9a, (byte)0x59, (byte)0xf5, (byte)0x87, (byte)0xb3, (byte)0x4f, (byte)0x13,
+ (byte)0x61, (byte)0x45, (byte)0x6d, (byte)0x8d, (byte)0x9, (byte)0x81, (byte)0x7d, (byte)0x32,
+ (byte)0xbd, (byte)0x8f, (byte)0x40, (byte)0xeb, (byte)0x86, (byte)0xb7, (byte)0x7b, (byte)0xb,
+ (byte)0xf0, (byte)0x95, (byte)0x21, (byte)0x22, (byte)0x5c, (byte)0x6b, (byte)0x4e, (byte)0x82,
+ (byte)0x54, (byte)0xd6, (byte)0x65, (byte)0x93, (byte)0xce, (byte)0x60, (byte)0xb2, (byte)0x1c,
+ (byte)0x73, (byte)0x56, (byte)0xc0, (byte)0x14, (byte)0xa7, (byte)0x8c, (byte)0xf1, (byte)0xdc,
+ (byte)0x12, (byte)0x75, (byte)0xca, (byte)0x1f, (byte)0x3b, (byte)0xbe, (byte)0xe4, (byte)0xd1,
+ (byte)0x42, (byte)0x3d, (byte)0xd4, (byte)0x30, (byte)0xa3, (byte)0x3c, (byte)0xb6, (byte)0x26,
+ (byte)0x6f, (byte)0xbf, (byte)0xe, (byte)0xda, (byte)0x46, (byte)0x69, (byte)0x7, (byte)0x57,
+ (byte)0x27, (byte)0xf2, (byte)0x1d, (byte)0x9b, (byte)0xbc, (byte)0x94, (byte)0x43, (byte)0x3,
+ (byte)0xf8, (byte)0x11, (byte)0xc7, (byte)0xf6, (byte)0x90, (byte)0xef, (byte)0x3e, (byte)0xe7,
+ (byte)0x6, (byte)0xc3, (byte)0xd5, (byte)0x2f, (byte)0xc8, (byte)0x66, (byte)0x1e, (byte)0xd7,
+ (byte)0x8, (byte)0xe8, (byte)0xea, (byte)0xde, (byte)0x80, (byte)0x52, (byte)0xee, (byte)0xf7,
+ (byte)0x84, (byte)0xaa, (byte)0x72, (byte)0xac, (byte)0x35, (byte)0x4d, (byte)0x6a, (byte)0x2a,
+ (byte)0x96, (byte)0x1a, (byte)0xd2, (byte)0x71, (byte)0x5a, (byte)0x15, (byte)0x49, (byte)0x74,
+ (byte)0x4b, (byte)0x9f, (byte)0xd0, (byte)0x5e, (byte)0x4, (byte)0x18, (byte)0xa4, (byte)0xec,
+ (byte)0xc2, (byte)0xe0, (byte)0x41, (byte)0x6e, (byte)0xf, (byte)0x51, (byte)0xcb, (byte)0xcc,
+ (byte)0x24, (byte)0x91, (byte)0xaf, (byte)0x50, (byte)0xa1, (byte)0xf4, (byte)0x70, (byte)0x39,
+ (byte)0x99, (byte)0x7c, (byte)0x3a, (byte)0x85, (byte)0x23, (byte)0xb8, (byte)0xb4, (byte)0x7a,
+ (byte)0xfc, (byte)0x2, (byte)0x36, (byte)0x5b, (byte)0x25, (byte)0x55, (byte)0x97, (byte)0x31,
+ (byte)0x2d, (byte)0x5d, (byte)0xfa, (byte)0x98, (byte)0xe3, (byte)0x8a, (byte)0x92, (byte)0xae,
+ (byte)0x5, (byte)0xdf, (byte)0x29, (byte)0x10, (byte)0x67, (byte)0x6c, (byte)0xba, (byte)0xc9,
+ (byte)0xd3, (byte)0x0, (byte)0xe6, (byte)0xcf, (byte)0xe1, (byte)0x9e, (byte)0xa8, (byte)0x2c,
+ (byte)0x63, (byte)0x16, (byte)0x1, (byte)0x3f, (byte)0x58, (byte)0xe2, (byte)0x89, (byte)0xa9,
+ (byte)0xd, (byte)0x38, (byte)0x34, (byte)0x1b, (byte)0xab, (byte)0x33, (byte)0xff, (byte)0xb0,
+ (byte)0xbb, (byte)0x48, (byte)0xc, (byte)0x5f, (byte)0xb9, (byte)0xb1, (byte)0xcd, (byte)0x2e,
+ (byte)0xc5, (byte)0xf3, (byte)0xdb, (byte)0x47, (byte)0xe5, (byte)0xa5, (byte)0x9c, (byte)0x77,
+ (byte)0xa, (byte)0xa6, (byte)0x20, (byte)0x68, (byte)0xfe, (byte)0x7f, (byte)0xc1, (byte)0xad
+ };
+
+ private static final int BLOCK_SIZE = 8;
+
+ private int[] workingKey;
+ private boolean encrypting;
+
+ private int[] generateWorkingKey(
+ byte[] key,
+ int bits)
+ {
+ int x;
+ int[] xKey = new int[128];
+
+ for (int i = 0; i != key.length; i++)
+ {
+ xKey[i] = key[i] & 0xff;
+ }
+
+ // Phase 1: Expand input key to 128 bytes
+ int len = key.length;
+
+ if (len < 128)
+ {
+ int index = 0;
+
+ x = xKey[len - 1];
+
+ do
+ {
+ x = piTable[(x + xKey[index++]) & 255] & 0xff;
+ xKey[len++] = x;
+ }
+ while (len < 128);
+ }
+
+ // Phase 2 - reduce effective key size to "bits"
+ len = (bits + 7) >> 3;
+ x = piTable[xKey[128 - len] & (255 >> (7 & -bits))] & 0xff;
+ xKey[128 - len] = x;
+
+ for (int i = 128 - len - 1; i >= 0; i--)
+ {
+ x = piTable[x ^ xKey[i + len]] & 0xff;
+ xKey[i] = x;
+ }
+
+ // Phase 3 - copy to newKey in little-endian order
+ int[] newKey = new int[64];
+
+ for (int i = 0; i != newKey.length; i++)
+ {
+ newKey[i] = (xKey[2 * i] + (xKey[2 * i + 1] << 8));
+ }
+
+ return newKey;
+ }
+
+ /**
+ * initialise a RC2 cipher.
+ *
+ * @param encrypting whether or not we are for encryption.
+ * @param params the parameters required to set up the cipher.
+ * @exception IllegalArgumentException if the params argument is
+ * inappropriate.
+ */
+ public void init(
+ boolean encrypting,
+ CipherParameters params)
+ {
+ this.encrypting = encrypting;
+
+ if (params instanceof RC2Parameters)
+ {
+ RC2Parameters param = (RC2Parameters)params;
+
+ workingKey = generateWorkingKey(param.getKey(),
+ param.getEffectiveKeyBits());
+ }
+ else if (params instanceof KeyParameter)
+ {
+ byte[] key = ((KeyParameter)params).getKey();
+
+ workingKey = generateWorkingKey(key, key.length * 8);
+ }
+ else
+ {
+ throw new IllegalArgumentException("invalid parameter passed to RC2 init - " + params.getClass().getName());
+ }
+
+ }
+
+ public void reset()
+ {
+ }
+
+ public String getAlgorithmName()
+ {
+ return "RC2";
+ }
+
+ public int getBlockSize()
+ {
+ return BLOCK_SIZE;
+ }
+
+ public final int processBlock(
+ byte[] in,
+ int inOff,
+ byte[] out,
+ int outOff)
+ {
+ if (workingKey == null)
+ {
+ throw new IllegalStateException("RC2 engine not initialised");
+ }
+
+ if ((inOff + BLOCK_SIZE) > in.length)
+ {
+ throw new DataLengthException("input buffer too short");
+ }
+
+ if ((outOff + BLOCK_SIZE) > out.length)
+ {
+ throw new DataLengthException("output buffer too short");
+ }
+
+ if (encrypting)
+ {
+ encryptBlock(in, inOff, out, outOff);
+ }
+ else
+ {
+ decryptBlock(in, inOff, out, outOff);
+ }
+
+ return BLOCK_SIZE;
+ }
+
+ /**
+ * return the result rotating the 16 bit number in x left by y
+ */
+ private int rotateWordLeft(
+ int x,
+ int y)
+ {
+ x &= 0xffff;
+ return (x << y) | (x >> (16 - y));
+ }
+
+ private void encryptBlock(
+ byte[] in,
+ int inOff,
+ byte[] out,
+ int outOff)
+ {
+ int x76, x54, x32, x10;
+
+ x76 = ((in[inOff + 7] & 0xff) << 8) + (in[inOff + 6] & 0xff);
+ x54 = ((in[inOff + 5] & 0xff) << 8) + (in[inOff + 4] & 0xff);
+ x32 = ((in[inOff + 3] & 0xff) << 8) + (in[inOff + 2] & 0xff);
+ x10 = ((in[inOff + 1] & 0xff) << 8) + (in[inOff + 0] & 0xff);
+
+ for (int i = 0; i <= 16; i += 4)
+ {
+ x10 = rotateWordLeft(x10 + (x32 & ~x76) + (x54 & x76) + workingKey[i ], 1);
+ x32 = rotateWordLeft(x32 + (x54 & ~x10) + (x76 & x10) + workingKey[i+1], 2);
+ x54 = rotateWordLeft(x54 + (x76 & ~x32) + (x10 & x32) + workingKey[i+2], 3);
+ x76 = rotateWordLeft(x76 + (x10 & ~x54) + (x32 & x54) + workingKey[i+3], 5);
+ }
+
+ x10 += workingKey[x76 & 63];
+ x32 += workingKey[x10 & 63];
+ x54 += workingKey[x32 & 63];
+ x76 += workingKey[x54 & 63];
+
+ for (int i = 20; i <= 40; i += 4)
+ {
+ x10 = rotateWordLeft(x10 + (x32 & ~x76) + (x54 & x76) + workingKey[i ], 1);
+ x32 = rotateWordLeft(x32 + (x54 & ~x10) + (x76 & x10) + workingKey[i+1], 2);
+ x54 = rotateWordLeft(x54 + (x76 & ~x32) + (x10 & x32) + workingKey[i+2], 3);
+ x76 = rotateWordLeft(x76 + (x10 & ~x54) + (x32 & x54) + workingKey[i+3], 5);
+ }
+
+ x10 += workingKey[x76 & 63];
+ x32 += workingKey[x10 & 63];
+ x54 += workingKey[x32 & 63];
+ x76 += workingKey[x54 & 63];
+
+ for (int i = 44; i < 64; i += 4)
+ {
+ x10 = rotateWordLeft(x10 + (x32 & ~x76) + (x54 & x76) + workingKey[i ], 1);
+ x32 = rotateWordLeft(x32 + (x54 & ~x10) + (x76 & x10) + workingKey[i+1], 2);
+ x54 = rotateWordLeft(x54 + (x76 & ~x32) + (x10 & x32) + workingKey[i+2], 3);
+ x76 = rotateWordLeft(x76 + (x10 & ~x54) + (x32 & x54) + workingKey[i+3], 5);
+ }
+
+ out[outOff + 0] = (byte)x10;
+ out[outOff + 1] = (byte)(x10 >> 8);
+ out[outOff + 2] = (byte)x32;
+ out[outOff + 3] = (byte)(x32 >> 8);
+ out[outOff + 4] = (byte)x54;
+ out[outOff + 5] = (byte)(x54 >> 8);
+ out[outOff + 6] = (byte)x76;
+ out[outOff + 7] = (byte)(x76 >> 8);
+ }
+
+ private void decryptBlock(
+ byte[] in,
+ int inOff,
+ byte[] out,
+ int outOff)
+ {
+ int x76, x54, x32, x10;
+
+ x76 = ((in[inOff + 7] & 0xff) << 8) + (in[inOff + 6] & 0xff);
+ x54 = ((in[inOff + 5] & 0xff) << 8) + (in[inOff + 4] & 0xff);
+ x32 = ((in[inOff + 3] & 0xff) << 8) + (in[inOff + 2] & 0xff);
+ x10 = ((in[inOff + 1] & 0xff) << 8) + (in[inOff + 0] & 0xff);
+
+ for (int i = 60; i >= 44; i -= 4)
+ {
+ x76 = rotateWordLeft(x76, 11) - ((x10 & ~x54) + (x32 & x54) + workingKey[i+3]);
+ x54 = rotateWordLeft(x54, 13) - ((x76 & ~x32) + (x10 & x32) + workingKey[i+2]);
+ x32 = rotateWordLeft(x32, 14) - ((x54 & ~x10) + (x76 & x10) + workingKey[i+1]);
+ x10 = rotateWordLeft(x10, 15) - ((x32 & ~x76) + (x54 & x76) + workingKey[i ]);
+ }
+
+ x76 -= workingKey[x54 & 63];
+ x54 -= workingKey[x32 & 63];
+ x32 -= workingKey[x10 & 63];
+ x10 -= workingKey[x76 & 63];
+
+ for (int i = 40; i >= 20; i -= 4)
+ {
+ x76 = rotateWordLeft(x76, 11) - ((x10 & ~x54) + (x32 & x54) + workingKey[i+3]);
+ x54 = rotateWordLeft(x54, 13) - ((x76 & ~x32) + (x10 & x32) + workingKey[i+2]);
+ x32 = rotateWordLeft(x32, 14) - ((x54 & ~x10) + (x76 & x10) + workingKey[i+1]);
+ x10 = rotateWordLeft(x10, 15) - ((x32 & ~x76) + (x54 & x76) + workingKey[i ]);
+ }
+
+ x76 -= workingKey[x54 & 63];
+ x54 -= workingKey[x32 & 63];
+ x32 -= workingKey[x10 & 63];
+ x10 -= workingKey[x76 & 63];
+
+ for (int i = 16; i >= 0; i -= 4)
+ {
+ x76 = rotateWordLeft(x76, 11) - ((x10 & ~x54) + (x32 & x54) + workingKey[i+3]);
+ x54 = rotateWordLeft(x54, 13) - ((x76 & ~x32) + (x10 & x32) + workingKey[i+2]);
+ x32 = rotateWordLeft(x32, 14) - ((x54 & ~x10) + (x76 & x10) + workingKey[i+1]);
+ x10 = rotateWordLeft(x10, 15) - ((x32 & ~x76) + (x54 & x76) + workingKey[i ]);
+ }
+
+ out[outOff + 0] = (byte)x10;
+ out[outOff + 1] = (byte)(x10 >> 8);
+ out[outOff + 2] = (byte)x32;
+ out[outOff + 3] = (byte)(x32 >> 8);
+ out[outOff + 4] = (byte)x54;
+ out[outOff + 5] = (byte)(x54 >> 8);
+ out[outOff + 6] = (byte)x76;
+ out[outOff + 7] = (byte)(x76 >> 8);
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/RC2WrapEngine.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/RC2WrapEngine.java
new file mode 100644
index 0000000..27ff9ab
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/RC2WrapEngine.java
@@ -0,0 +1,383 @@
+package org.bc.crypto.engines;
+
+import java.security.SecureRandom;
+
+import org.bc.crypto.CipherParameters;
+import org.bc.crypto.Digest;
+import org.bc.crypto.InvalidCipherTextException;
+import org.bc.crypto.Wrapper;
+import org.bc.crypto.digests.SHA1Digest;
+import org.bc.crypto.modes.CBCBlockCipher;
+import org.bc.crypto.params.ParametersWithIV;
+import org.bc.crypto.params.ParametersWithRandom;
+import org.bc.util.Arrays;
+
+/**
+ * Wrap keys according to RFC 3217 - RC2 mechanism
+ */
+public class RC2WrapEngine
+ implements Wrapper
+{
+ /** Field engine */
+ private CBCBlockCipher engine;
+
+ /** Field param */
+ private CipherParameters param;
+
+ /** Field paramPlusIV */
+ private ParametersWithIV paramPlusIV;
+
+ /** Field iv */
+ private byte[] iv;
+
+ /** Field forWrapping */
+ private boolean forWrapping;
+
+ private SecureRandom sr;
+
+ /** Field IV2 */
+ private static final byte[] IV2 = { (byte) 0x4a, (byte) 0xdd, (byte) 0xa2,
+ (byte) 0x2c, (byte) 0x79, (byte) 0xe8,
+ (byte) 0x21, (byte) 0x05 };
+
+ //
+ // checksum digest
+ //
+ Digest sha1 = new SHA1Digest();
+ byte[] digest = new byte[20];
+
+ /**
+ * Method init
+ *
+ * @param forWrapping
+ * @param param
+ */
+ public void init(boolean forWrapping, CipherParameters param)
+ {
+ this.forWrapping = forWrapping;
+ this.engine = new CBCBlockCipher(new RC2Engine());
+
+ if (param instanceof ParametersWithRandom)
+ {
+ ParametersWithRandom pWithR = (ParametersWithRandom)param;
+ sr = pWithR.getRandom();
+ param = pWithR.getParameters();
+ }
+ else
+ {
+ sr = new SecureRandom();
+ }
+
+ if (param instanceof ParametersWithIV)
+ {
+ this.paramPlusIV = (ParametersWithIV)param;
+ this.iv = this.paramPlusIV.getIV();
+ this.param = this.paramPlusIV.getParameters();
+
+ if (this.forWrapping)
+ {
+ if ((this.iv == null) || (this.iv.length != 8))
+ {
+ throw new IllegalArgumentException("IV is not 8 octets");
+ }
+ }
+ else
+ {
+ throw new IllegalArgumentException(
+ "You should not supply an IV for unwrapping");
+ }
+ }
+ else
+ {
+ this.param = param;
+
+ if (this.forWrapping)
+ {
+
+ // Hm, we have no IV but we want to wrap ?!?
+ // well, then we have to create our own IV.
+ this.iv = new byte[8];
+
+ sr.nextBytes(iv);
+
+ this.paramPlusIV = new ParametersWithIV(this.param, this.iv);
+ }
+ }
+
+ }
+
+ /**
+ * Method getAlgorithmName
+ *
+ * @return the algorithm name "RC2".
+ */
+ public String getAlgorithmName()
+ {
+ return "RC2";
+ }
+
+ /**
+ * Method wrap
+ *
+ * @param in
+ * @param inOff
+ * @param inLen
+ * @return the wrapped bytes.
+ */
+ public byte[] wrap(byte[] in, int inOff, int inLen)
+ {
+
+ if (!forWrapping)
+ {
+ throw new IllegalStateException("Not initialized for wrapping");
+ }
+
+ int length = inLen + 1;
+ if ((length % 8) != 0)
+ {
+ length += 8 - (length % 8);
+ }
+
+ byte keyToBeWrapped[] = new byte[length];
+
+ keyToBeWrapped[0] = (byte)inLen;
+ System.arraycopy(in, inOff, keyToBeWrapped, 1, inLen);
+
+ byte[] pad = new byte[keyToBeWrapped.length - inLen - 1];
+
+ if (pad.length > 0)
+ {
+ sr.nextBytes(pad);
+ System.arraycopy(pad, 0, keyToBeWrapped, inLen + 1, pad.length);
+ }
+
+ // Compute the CMS Key Checksum, (section 5.6.1), call this CKS.
+ byte[] CKS = calculateCMSKeyChecksum(keyToBeWrapped);
+
+ // Let WKCKS = WK || CKS where || is concatenation.
+ byte[] WKCKS = new byte[keyToBeWrapped.length + CKS.length];
+
+ System.arraycopy(keyToBeWrapped, 0, WKCKS, 0, keyToBeWrapped.length);
+ System.arraycopy(CKS, 0, WKCKS, keyToBeWrapped.length, CKS.length);
+
+ // Encrypt WKCKS in CBC mode using KEK as the key and IV as the
+ // initialization vector. Call the results TEMP1.
+ byte TEMP1[] = new byte[WKCKS.length];
+
+ System.arraycopy(WKCKS, 0, TEMP1, 0, WKCKS.length);
+
+ int noOfBlocks = WKCKS.length / engine.getBlockSize();
+ int extraBytes = WKCKS.length % engine.getBlockSize();
+
+ if (extraBytes != 0)
+ {
+ throw new IllegalStateException("Not multiple of block length");
+ }
+
+ engine.init(true, paramPlusIV);
+
+ for (int i = 0; i < noOfBlocks; i++)
+ {
+ int currentBytePos = i * engine.getBlockSize();
+
+ engine.processBlock(TEMP1, currentBytePos, TEMP1, currentBytePos);
+ }
+
+ // Left TEMP2 = IV || TEMP1.
+ byte[] TEMP2 = new byte[this.iv.length + TEMP1.length];
+
+ System.arraycopy(this.iv, 0, TEMP2, 0, this.iv.length);
+ System.arraycopy(TEMP1, 0, TEMP2, this.iv.length, TEMP1.length);
+
+ // Reverse the order of the octets in TEMP2 and call the result TEMP3.
+ byte[] TEMP3 = new byte[TEMP2.length];
+
+ for (int i = 0; i < TEMP2.length; i++)
+ {
+ TEMP3[i] = TEMP2[TEMP2.length - (i + 1)];
+ }
+
+ // Encrypt TEMP3 in CBC mode using the KEK and an initialization vector
+ // of 0x 4a dd a2 2c 79 e8 21 05. The resulting cipher text is the
+ // desired
+ // result. It is 40 octets long if a 168 bit key is being wrapped.
+ ParametersWithIV param2 = new ParametersWithIV(this.param, IV2);
+
+ this.engine.init(true, param2);
+
+ for (int i = 0; i < noOfBlocks + 1; i++)
+ {
+ int currentBytePos = i * engine.getBlockSize();
+
+ engine.processBlock(TEMP3, currentBytePos, TEMP3, currentBytePos);
+ }
+
+ return TEMP3;
+ }
+
+ /**
+ * Method unwrap
+ *
+ * @param in
+ * @param inOff
+ * @param inLen
+ * @return the unwrapped bytes.
+ * @throws InvalidCipherTextException
+ */
+ public byte[] unwrap(byte[] in, int inOff, int inLen)
+ throws InvalidCipherTextException
+ {
+
+ if (forWrapping)
+ {
+ throw new IllegalStateException("Not set for unwrapping");
+ }
+
+ if (in == null)
+ {
+ throw new InvalidCipherTextException("Null pointer as ciphertext");
+ }
+
+ if (inLen % engine.getBlockSize() != 0)
+ {
+ throw new InvalidCipherTextException("Ciphertext not multiple of "
+ + engine.getBlockSize());
+ }
+
+ /*
+ * // Check if the length of the cipher text is reasonable given the key //
+ * type. It must be 40 bytes for a 168 bit key and either 32, 40, or //
+ * 48 bytes for a 128, 192, or 256 bit key. If the length is not
+ * supported // or inconsistent with the algorithm for which the key is
+ * intended, // return error. // // we do not accept 168 bit keys. it
+ * has to be 192 bit. int lengthA = (estimatedKeyLengthInBit / 8) + 16;
+ * int lengthB = estimatedKeyLengthInBit % 8;
+ *
+ * if ((lengthA != keyToBeUnwrapped.length) || (lengthB != 0)) { throw
+ * new XMLSecurityException("empty"); }
+ */
+
+ // Decrypt the cipher text with TRIPLedeS in CBC mode using the KEK
+ // and an initialization vector (IV) of 0x4adda22c79e82105. Call the
+ // output TEMP3.
+ ParametersWithIV param2 = new ParametersWithIV(this.param, IV2);
+
+ this.engine.init(false, param2);
+
+ byte TEMP3[] = new byte[inLen];
+
+ System.arraycopy(in, inOff, TEMP3, 0, inLen);
+
+ for (int i = 0; i < (TEMP3.length / engine.getBlockSize()); i++)
+ {
+ int currentBytePos = i * engine.getBlockSize();
+
+ engine.processBlock(TEMP3, currentBytePos, TEMP3, currentBytePos);
+ }
+
+ // Reverse the order of the octets in TEMP3 and call the result TEMP2.
+ byte[] TEMP2 = new byte[TEMP3.length];
+
+ for (int i = 0; i < TEMP3.length; i++)
+ {
+ TEMP2[i] = TEMP3[TEMP3.length - (i + 1)];
+ }
+
+ // Decompose TEMP2 into IV, the first 8 octets, and TEMP1, the remaining
+ // octets.
+ this.iv = new byte[8];
+
+ byte[] TEMP1 = new byte[TEMP2.length - 8];
+
+ System.arraycopy(TEMP2, 0, this.iv, 0, 8);
+ System.arraycopy(TEMP2, 8, TEMP1, 0, TEMP2.length - 8);
+
+ // Decrypt TEMP1 using TRIPLedeS in CBC mode using the KEK and the IV
+ // found in the previous step. Call the result WKCKS.
+ this.paramPlusIV = new ParametersWithIV(this.param, this.iv);
+
+ this.engine.init(false, this.paramPlusIV);
+
+ byte[] LCEKPADICV = new byte[TEMP1.length];
+
+ System.arraycopy(TEMP1, 0, LCEKPADICV, 0, TEMP1.length);
+
+ for (int i = 0; i < (LCEKPADICV.length / engine.getBlockSize()); i++)
+ {
+ int currentBytePos = i * engine.getBlockSize();
+
+ engine.processBlock(LCEKPADICV, currentBytePos, LCEKPADICV,
+ currentBytePos);
+ }
+
+ // Decompose LCEKPADICV. CKS is the last 8 octets and WK, the wrapped
+ // key, are
+ // those octets before the CKS.
+ byte[] result = new byte[LCEKPADICV.length - 8];
+ byte[] CKStoBeVerified = new byte[8];
+
+ System.arraycopy(LCEKPADICV, 0, result, 0, LCEKPADICV.length - 8);
+ System.arraycopy(LCEKPADICV, LCEKPADICV.length - 8, CKStoBeVerified, 0,
+ 8);
+
+ // Calculate a CMS Key Checksum, (section 5.6.1), over the WK and
+ // compare
+ // with the CKS extracted in the above step. If they are not equal,
+ // return error.
+ if (!checkCMSKeyChecksum(result, CKStoBeVerified))
+ {
+ throw new InvalidCipherTextException(
+ "Checksum inside ciphertext is corrupted");
+ }
+
+ if ((result.length - ((result[0] & 0xff) + 1)) > 7)
+ {
+ throw new InvalidCipherTextException("too many pad bytes ("
+ + (result.length - ((result[0] & 0xff) + 1)) + ")");
+ }
+
+ // CEK is the wrapped key, now extracted for use in data decryption.
+ byte[] CEK = new byte[result[0]];
+ System.arraycopy(result, 1, CEK, 0, CEK.length);
+ return CEK;
+ }
+
+ /**
+ * Some key wrap algorithms make use of the Key Checksum defined
+ * in CMS [CMS-Algorithms]. This is used to provide an integrity
+ * check value for the key being wrapped. The algorithm is
+ *
+ * - Compute the 20 octet SHA-1 hash on the key being wrapped.
+ * - Use the first 8 octets of this hash as the checksum value.
+ *
+ * @param key
+ * @return
+ * @throws RuntimeException
+ * @see http://www.w3.org/TR/xmlenc-core/#sec-CMSKeyChecksum
+ */
+ private byte[] calculateCMSKeyChecksum(
+ byte[] key)
+ {
+ byte[] result = new byte[8];
+
+ sha1.update(key, 0, key.length);
+ sha1.doFinal(digest, 0);
+
+ System.arraycopy(digest, 0, result, 0, 8);
+
+ return result;
+ }
+
+ /**
+ * @param key
+ * @param checksum
+ * @return
+ * @see http://www.w3.org/TR/xmlenc-core/#sec-CMSKeyChecksum
+ */
+ private boolean checkCMSKeyChecksum(
+ byte[] key,
+ byte[] checksum)
+ {
+ return Arrays.constantTimeAreEqual(calculateCMSKeyChecksum(key), checksum);
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/RC4Engine.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/RC4Engine.java
new file mode 100644
index 0000000..3684ef4
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/RC4Engine.java
@@ -0,0 +1,143 @@
+package org.bc.crypto.engines;
+
+import org.bc.crypto.CipherParameters;
+import org.bc.crypto.DataLengthException;
+import org.bc.crypto.StreamCipher;
+import org.bc.crypto.params.KeyParameter;
+
+public class RC4Engine implements StreamCipher
+{
+ private final static int STATE_LENGTH = 256;
+
+ /*
+ * variables to hold the state of the RC4 engine
+ * during encryption and decryption
+ */
+
+ private byte[] engineState = null;
+ private int x = 0;
+ private int y = 0;
+ private byte[] workingKey = null;
+
+ /**
+ * initialise a RC4 cipher.
+ *
+ * @param forEncryption whether or not we are for encryption.
+ * @param params the parameters required to set up the cipher.
+ * @exception IllegalArgumentException if the params argument is
+ * inappropriate.
+ */
+ public void init(
+ boolean forEncryption,
+ CipherParameters params
+ )
+ {
+ if (params instanceof KeyParameter)
+ {
+ /*
+ * RC4 encryption and decryption is completely
+ * symmetrical, so the 'forEncryption' is
+ * irrelevant.
+ */
+ workingKey = ((KeyParameter)params).getKey();
+ setKey(workingKey);
+
+ return;
+ }
+
+ throw new IllegalArgumentException("invalid parameter passed to RC4 init - " + params.getClass().getName());
+ }
+
+ public String getAlgorithmName()
+ {
+ return "RC4";
+ }
+
+ public byte returnByte(byte in)
+ {
+ x = (x + 1) & 0xff;
+ y = (engineState[x] + y) & 0xff;
+
+ // swap
+ byte tmp = engineState[x];
+ engineState[x] = engineState[y];
+ engineState[y] = tmp;
+
+ // xor
+ return (byte)(in ^ engineState[(engineState[x] + engineState[y]) & 0xff]);
+ }
+
+ public void processBytes(
+ byte[] in,
+ int inOff,
+ int len,
+ byte[] out,
+ int outOff)
+ {
+ if ((inOff + len) > in.length)
+ {
+ throw new DataLengthException("input buffer too short");
+ }
+
+ if ((outOff + len) > out.length)
+ {
+ throw new DataLengthException("output buffer too short");
+ }
+
+ for (int i = 0; i < len ; i++)
+ {
+ x = (x + 1) & 0xff;
+ y = (engineState[x] + y) & 0xff;
+
+ // swap
+ byte tmp = engineState[x];
+ engineState[x] = engineState[y];
+ engineState[y] = tmp;
+
+ // xor
+ out[i+outOff] = (byte)(in[i + inOff]
+ ^ engineState[(engineState[x] + engineState[y]) & 0xff]);
+ }
+ }
+
+ public void reset()
+ {
+ setKey(workingKey);
+ }
+
+ // Private implementation
+
+ private void setKey(byte[] keyBytes)
+ {
+ workingKey = keyBytes;
+
+ // System.out.println("the key length is ; "+ workingKey.length);
+
+ x = 0;
+ y = 0;
+
+ if (engineState == null)
+ {
+ engineState = new byte[STATE_LENGTH];
+ }
+
+ // reset the state of the engine
+ for (int i=0; i < STATE_LENGTH; i++)
+ {
+ engineState[i] = (byte)i;
+ }
+
+ int i1 = 0;
+ int i2 = 0;
+
+ for (int i=0; i < STATE_LENGTH; i++)
+ {
+ i2 = ((keyBytes[i1] & 0xff) + engineState[i] + i2) & 0xff;
+ // do the byte-swap inline
+ byte tmp = engineState[i];
+ engineState[i] = engineState[i2];
+ engineState[i2] = tmp;
+ i1 = (i1+1) % keyBytes.length;
+ }
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/RC532Engine.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/RC532Engine.java
new file mode 100644
index 0000000..12a2ee7
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/RC532Engine.java
@@ -0,0 +1,287 @@
+package org.bc.crypto.engines;
+
+import org.bc.crypto.BlockCipher;
+import org.bc.crypto.CipherParameters;
+import org.bc.crypto.params.KeyParameter;
+import org.bc.crypto.params.RC5Parameters;
+
+/**
+ * The specification for RC5 came from the RC5 Encryption Algorithm
+ * publication in RSA CryptoBytes, Spring of 1995.
+ * http://www.rsasecurity.com/rsalabs/cryptobytes.
+ *
+ * This implementation has a word size of 32 bits. + *
+ * Implementation courtesy of Tito Pena. + */ +public class RC532Engine + implements BlockCipher +{ + /* + * the number of rounds to perform + */ + private int _noRounds; + + /* + * the expanded key array of size 2*(rounds + 1) + */ + private int _S[]; + + /* + * our "magic constants" for 32 32 + * + * Pw = Odd((e-2) * 2^wordsize) + * Qw = Odd((o-2) * 2^wordsize) + * + * where e is the base of natural logarithms (2.718281828...) + * and o is the golden ratio (1.61803398...) + */ + private static final int P32 = 0xb7e15163; + private static final int Q32 = 0x9e3779b9; + + private boolean forEncryption; + + /** + * Create an instance of the RC5 encryption algorithm + * and set some defaults + */ + public RC532Engine() + { + _noRounds = 12; // the default + _S = null; + } + + public String getAlgorithmName() + { + return "RC5-32"; + } + + public int getBlockSize() + { + return 2 * 4; + } + + /** + * initialise a RC5-32 cipher. + * + * @param forEncryption whether or not we are for encryption. + * @param params the parameters required to set up the cipher. + * @exception IllegalArgumentException if the params argument is + * inappropriate. + */ + public void init( + boolean forEncryption, + CipherParameters params) + { + if (params instanceof RC5Parameters) + { + RC5Parameters p = (RC5Parameters)params; + + _noRounds = p.getRounds(); + + setKey(p.getKey()); + } + else if (params instanceof KeyParameter) + { + KeyParameter p = (KeyParameter)params; + + setKey(p.getKey()); + } + else + { + throw new IllegalArgumentException("invalid parameter passed to RC532 init - " + params.getClass().getName()); + } + + this.forEncryption = forEncryption; + } + + public int processBlock( + byte[] in, + int inOff, + byte[] out, + int outOff) + { + return (forEncryption) ? encryptBlock(in, inOff, out, outOff) + : decryptBlock(in, inOff, out, outOff); + } + + public void reset() + { + } + + /** + * Re-key the cipher. + *
+ * @param key the key to be used + */ + private void setKey( + byte[] key) + { + // + // KEY EXPANSION: + // + // There are 3 phases to the key expansion. + // + // Phase 1: + // Copy the secret key K[0...b-1] into an array L[0..c-1] of + // c = ceil(b/u), where u = 32/8 in little-endian order. + // In other words, we fill up L using u consecutive key bytes + // of K. Any unfilled byte positions in L are zeroed. In the + // case that b = c = 0, set c = 1 and L[0] = 0. + // + int[] L = new int[(key.length + (4 - 1)) / 4]; + + for (int i = 0; i != key.length; i++) + { + L[i / 4] += (key[i] & 0xff) << (8 * (i % 4)); + } + + // + // Phase 2: + // Initialize S to a particular fixed pseudo-random bit pattern + // using an arithmetic progression modulo 2^wordsize determined + // by the magic numbers, Pw & Qw. + // + _S = new int[2*(_noRounds + 1)]; + + _S[0] = P32; + for (int i=1; i < _S.length; i++) + { + _S[i] = (_S[i-1] + Q32); + } + + // + // Phase 3: + // Mix in the user's secret key in 3 passes over the arrays S & L. + // The max of the arrays sizes is used as the loop control + // + int iter; + + if (L.length > _S.length) + { + iter = 3 * L.length; + } + else + { + iter = 3 * _S.length; + } + + int A = 0, B = 0; + int i = 0, j = 0; + + for (int k = 0; k < iter; k++) + { + A = _S[i] = rotateLeft(_S[i] + A + B, 3); + B = L[j] = rotateLeft(L[j] + A + B, A+B); + i = (i+1) % _S.length; + j = (j+1) % L.length; + } + } + + /** + * Encrypt the given block starting at the given offset and place + * the result in the provided buffer starting at the given offset. + *
+ * @param in in byte buffer containing data to encrypt + * @param inOff offset into src buffer + * @param out out buffer where encrypted data is written + * @param outOff offset into out buffer + */ + private int encryptBlock( + byte[] in, + int inOff, + byte[] out, + int outOff) + { + int A = bytesToWord(in, inOff) + _S[0]; + int B = bytesToWord(in, inOff + 4) + _S[1]; + + for (int i = 1; i <= _noRounds; i++) + { + A = rotateLeft(A ^ B, B) + _S[2*i]; + B = rotateLeft(B ^ A, A) + _S[2*i+1]; + } + + wordToBytes(A, out, outOff); + wordToBytes(B, out, outOff + 4); + + return 2 * 4; + } + + private int decryptBlock( + byte[] in, + int inOff, + byte[] out, + int outOff) + { + int A = bytesToWord(in, inOff); + int B = bytesToWord(in, inOff + 4); + + for (int i = _noRounds; i >= 1; i--) + { + B = rotateRight(B - _S[2*i+1], A) ^ A; + A = rotateRight(A - _S[2*i], B) ^ B; + } + + wordToBytes(A - _S[0], out, outOff); + wordToBytes(B - _S[1], out, outOff + 4); + + return 2 * 4; + } + + + ////////////////////////////////////////////////////////////// + // + // PRIVATE Helper Methods + // + ////////////////////////////////////////////////////////////// + + /** + * Perform a left "spin" of the word. The rotation of the given + * word x is rotated left by y bits. + * Only the lg(32) low-order bits of y + * are used to determine the rotation amount. Here it is + * assumed that the wordsize used is a power of 2. + *
+ * @param x word to rotate + * @param y number of bits to rotate % 32 + */ + private int rotateLeft(int x, int y) + { + return ((x << (y & (32-1))) | (x >>> (32 - (y & (32-1))))); + } + + /** + * Perform a right "spin" of the word. The rotation of the given + * word x is rotated left by y bits. + * Only the lg(32) low-order bits of y + * are used to determine the rotation amount. Here it is + * assumed that the wordsize used is a power of 2. + *
+ * @param x word to rotate
+ * @param y number of bits to rotate % 32
+ */
+ private int rotateRight(int x, int y)
+ {
+ return ((x >>> (y & (32-1))) | (x << (32 - (y & (32-1)))));
+ }
+
+ private int bytesToWord(
+ byte[] src,
+ int srcOff)
+ {
+ return (src[srcOff] & 0xff) | ((src[srcOff + 1] & 0xff) << 8)
+ | ((src[srcOff + 2] & 0xff) << 16) | ((src[srcOff + 3] & 0xff) << 24);
+ }
+
+ private void wordToBytes(
+ int word,
+ byte[] dst,
+ int dstOff)
+ {
+ dst[dstOff] = (byte)word;
+ dst[dstOff + 1] = (byte)(word >> 8);
+ dst[dstOff + 2] = (byte)(word >> 16);
+ dst[dstOff + 3] = (byte)(word >> 24);
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/RC564Engine.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/RC564Engine.java
new file mode 100644
index 0000000..50a5e12
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/RC564Engine.java
@@ -0,0 +1,288 @@
+package org.bc.crypto.engines;
+
+import org.bc.crypto.BlockCipher;
+import org.bc.crypto.CipherParameters;
+import org.bc.crypto.params.RC5Parameters;
+
+/**
+ * The specification for RC5 came from the RC5 Encryption Algorithm
+ * publication in RSA CryptoBytes, Spring of 1995.
+ * http://www.rsasecurity.com/rsalabs/cryptobytes.
+ *
+ * This implementation is set to work with a 64 bit word size. + *
+ * Implementation courtesy of Tito Pena. + */ +public class RC564Engine + implements BlockCipher +{ + private static final int wordSize = 64; + private static final int bytesPerWord = wordSize / 8; + + /* + * the number of rounds to perform + */ + private int _noRounds; + + /* + * the expanded key array of size 2*(rounds + 1) + */ + private long _S[]; + + /* + * our "magic constants" for wordSize 62 + * + * Pw = Odd((e-2) * 2^wordsize) + * Qw = Odd((o-2) * 2^wordsize) + * + * where e is the base of natural logarithms (2.718281828...) + * and o is the golden ratio (1.61803398...) + */ + private static final long P64 = 0xb7e151628aed2a6bL; + private static final long Q64 = 0x9e3779b97f4a7c15L; + + private boolean forEncryption; + + /** + * Create an instance of the RC5 encryption algorithm + * and set some defaults + */ + public RC564Engine() + { + _noRounds = 12; + _S = null; + } + + public String getAlgorithmName() + { + return "RC5-64"; + } + + public int getBlockSize() + { + return 2 * bytesPerWord; + } + + /** + * initialise a RC5-64 cipher. + * + * @param forEncryption whether or not we are for encryption. + * @param params the parameters required to set up the cipher. + * @exception IllegalArgumentException if the params argument is + * inappropriate. + */ + public void init( + boolean forEncryption, + CipherParameters params) + { + if (!(params instanceof RC5Parameters)) + { + throw new IllegalArgumentException("invalid parameter passed to RC564 init - " + params.getClass().getName()); + } + + RC5Parameters p = (RC5Parameters)params; + + this.forEncryption = forEncryption; + + _noRounds = p.getRounds(); + + setKey(p.getKey()); + } + + public int processBlock( + byte[] in, + int inOff, + byte[] out, + int outOff) + { + return (forEncryption) ? encryptBlock(in, inOff, out, outOff) + : decryptBlock(in, inOff, out, outOff); + } + + public void reset() + { + } + + /** + * Re-key the cipher. + *
+ * @param key the key to be used + */ + private void setKey( + byte[] key) + { + // + // KEY EXPANSION: + // + // There are 3 phases to the key expansion. + // + // Phase 1: + // Copy the secret key K[0...b-1] into an array L[0..c-1] of + // c = ceil(b/u), where u = wordSize/8 in little-endian order. + // In other words, we fill up L using u consecutive key bytes + // of K. Any unfilled byte positions in L are zeroed. In the + // case that b = c = 0, set c = 1 and L[0] = 0. + // + long[] L = new long[(key.length + (bytesPerWord - 1)) / bytesPerWord]; + + for (int i = 0; i != key.length; i++) + { + L[i / bytesPerWord] += (long)(key[i] & 0xff) << (8 * (i % bytesPerWord)); + } + + // + // Phase 2: + // Initialize S to a particular fixed pseudo-random bit pattern + // using an arithmetic progression modulo 2^wordsize determined + // by the magic numbers, Pw & Qw. + // + _S = new long[2*(_noRounds + 1)]; + + _S[0] = P64; + for (int i=1; i < _S.length; i++) + { + _S[i] = (_S[i-1] + Q64); + } + + // + // Phase 3: + // Mix in the user's secret key in 3 passes over the arrays S & L. + // The max of the arrays sizes is used as the loop control + // + int iter; + + if (L.length > _S.length) + { + iter = 3 * L.length; + } + else + { + iter = 3 * _S.length; + } + + long A = 0, B = 0; + int i = 0, j = 0; + + for (int k = 0; k < iter; k++) + { + A = _S[i] = rotateLeft(_S[i] + A + B, 3); + B = L[j] = rotateLeft(L[j] + A + B, A+B); + i = (i+1) % _S.length; + j = (j+1) % L.length; + } + } + + /** + * Encrypt the given block starting at the given offset and place + * the result in the provided buffer starting at the given offset. + *
+ * @param in in byte buffer containing data to encrypt + * @param inOff offset into src buffer + * @param out out buffer where encrypted data is written + * @param outOff offset into out buffer + */ + private int encryptBlock( + byte[] in, + int inOff, + byte[] out, + int outOff) + { + long A = bytesToWord(in, inOff) + _S[0]; + long B = bytesToWord(in, inOff + bytesPerWord) + _S[1]; + + for (int i = 1; i <= _noRounds; i++) + { + A = rotateLeft(A ^ B, B) + _S[2*i]; + B = rotateLeft(B ^ A, A) + _S[2*i+1]; + } + + wordToBytes(A, out, outOff); + wordToBytes(B, out, outOff + bytesPerWord); + + return 2 * bytesPerWord; + } + + private int decryptBlock( + byte[] in, + int inOff, + byte[] out, + int outOff) + { + long A = bytesToWord(in, inOff); + long B = bytesToWord(in, inOff + bytesPerWord); + + for (int i = _noRounds; i >= 1; i--) + { + B = rotateRight(B - _S[2*i+1], A) ^ A; + A = rotateRight(A - _S[2*i], B) ^ B; + } + + wordToBytes(A - _S[0], out, outOff); + wordToBytes(B - _S[1], out, outOff + bytesPerWord); + + return 2 * bytesPerWord; + } + + + ////////////////////////////////////////////////////////////// + // + // PRIVATE Helper Methods + // + ////////////////////////////////////////////////////////////// + + /** + * Perform a left "spin" of the word. The rotation of the given + * word x is rotated left by y bits. + * Only the lg(wordSize) low-order bits of y + * are used to determine the rotation amount. Here it is + * assumed that the wordsize used is a power of 2. + *
+ * @param x word to rotate + * @param y number of bits to rotate % wordSize + */ + private long rotateLeft(long x, long y) + { + return ((x << (y & (wordSize-1))) | (x >>> (wordSize - (y & (wordSize-1))))); + } + + /** + * Perform a right "spin" of the word. The rotation of the given + * word x is rotated left by y bits. + * Only the lg(wordSize) low-order bits of y + * are used to determine the rotation amount. Here it is + * assumed that the wordsize used is a power of 2. + *
+ * @param x word to rotate + * @param y number of bits to rotate % wordSize + */ + private long rotateRight(long x, long y) + { + return ((x >>> (y & (wordSize-1))) | (x << (wordSize - (y & (wordSize-1))))); + } + + private long bytesToWord( + byte[] src, + int srcOff) + { + long word = 0; + + for (int i = bytesPerWord - 1; i >= 0; i--) + { + word = (word << 8) + (src[i + srcOff] & 0xff); + } + + return word; + } + + private void wordToBytes( + long word, + byte[] dst, + int dstOff) + { + for (int i = 0; i < bytesPerWord; i++) + { + dst[i + dstOff] = (byte)word; + word >>>= 8; + } + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/RC6Engine.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/RC6Engine.java new file mode 100644 index 0000000..e2634f9 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/RC6Engine.java @@ -0,0 +1,362 @@ +package org.bc.crypto.engines; + +import org.bc.crypto.BlockCipher; +import org.bc.crypto.CipherParameters; +import org.bc.crypto.DataLengthException; +import org.bc.crypto.params.KeyParameter; + +/** + * An RC6 engine. + */ +public class RC6Engine + implements BlockCipher +{ + private static final int wordSize = 32; + private static final int bytesPerWord = wordSize / 8; + + /* + * the number of rounds to perform + */ + private static final int _noRounds = 20; + + /* + * the expanded key array of size 2*(rounds + 1) + */ + private int _S[]; + + /* + * our "magic constants" for wordSize 32 + * + * Pw = Odd((e-2) * 2^wordsize) + * Qw = Odd((o-2) * 2^wordsize) + * + * where e is the base of natural logarithms (2.718281828...) + * and o is the golden ratio (1.61803398...) + */ + private static final int P32 = 0xb7e15163; + private static final int Q32 = 0x9e3779b9; + + private static final int LGW = 5; // log2(32) + + private boolean forEncryption; + + /** + * Create an instance of the RC6 encryption algorithm + * and set some defaults + */ + public RC6Engine() + { + _S = null; + } + + public String getAlgorithmName() + { + return "RC6"; + } + + public int getBlockSize() + { + return 4 * bytesPerWord; + } + + /** + * initialise a RC5-32 cipher. + * + * @param forEncryption whether or not we are for encryption. + * @param params the parameters required to set up the cipher. + * @exception IllegalArgumentException if the params argument is + * inappropriate. + */ + public void init( + boolean forEncryption, + CipherParameters params) + { + if (!(params instanceof KeyParameter)) + { + throw new IllegalArgumentException("invalid parameter passed to RC6 init - " + params.getClass().getName()); + } + + KeyParameter p = (KeyParameter)params; + this.forEncryption = forEncryption; + setKey(p.getKey()); + } + + public int processBlock( + byte[] in, + int inOff, + byte[] out, + int outOff) + { + int blockSize = getBlockSize(); + if (_S == null) + { + throw new IllegalStateException("RC6 engine not initialised"); + } + if ((inOff + blockSize) > in.length) + { + throw new DataLengthException("input buffer too short"); + } + if ((outOff + blockSize) > out.length) + { + throw new DataLengthException("output buffer too short"); + } + + return (forEncryption) + ? encryptBlock(in, inOff, out, outOff) + : decryptBlock(in, inOff, out, outOff); + } + + public void reset() + { + } + + /** + * Re-key the cipher. + *
+ * @param inKey the key to be used + */ + private void setKey( + byte[] key) + { + + // + // KEY EXPANSION: + // + // There are 3 phases to the key expansion. + // + // Phase 1: + // Copy the secret key K[0...b-1] into an array L[0..c-1] of + // c = ceil(b/u), where u = wordSize/8 in little-endian order. + // In other words, we fill up L using u consecutive key bytes + // of K. Any unfilled byte positions in L are zeroed. In the + // case that b = c = 0, set c = 1 and L[0] = 0. + // + // compute number of dwords + int c = (key.length + (bytesPerWord - 1)) / bytesPerWord; + if (c == 0) + { + c = 1; + } + int[] L = new int[(key.length + bytesPerWord - 1) / bytesPerWord]; + + // load all key bytes into array of key dwords + for (int i = key.length - 1; i >= 0; i--) + { + L[i / bytesPerWord] = (L[i / bytesPerWord] << 8) + (key[i] & 0xff); + } + + // + // Phase 2: + // Key schedule is placed in a array of 2+2*ROUNDS+2 = 44 dwords. + // Initialize S to a particular fixed pseudo-random bit pattern + // using an arithmetic progression modulo 2^wordsize determined + // by the magic numbers, Pw & Qw. + // + _S = new int[2+2*_noRounds+2]; + + _S[0] = P32; + for (int i=1; i < _S.length; i++) + { + _S[i] = (_S[i-1] + Q32); + } + + // + // Phase 3: + // Mix in the user's secret key in 3 passes over the arrays S & L. + // The max of the arrays sizes is used as the loop control + // + int iter; + + if (L.length > _S.length) + { + iter = 3 * L.length; + } + else + { + iter = 3 * _S.length; + } + + int A = 0; + int B = 0; + int i = 0, j = 0; + + for (int k = 0; k < iter; k++) + { + A = _S[i] = rotateLeft(_S[i] + A + B, 3); + B = L[j] = rotateLeft(L[j] + A + B, A+B); + i = (i+1) % _S.length; + j = (j+1) % L.length; + } + } + + private int encryptBlock( + byte[] in, + int inOff, + byte[] out, + int outOff) + { + // load A,B,C and D registers from in. + int A = bytesToWord(in, inOff); + int B = bytesToWord(in, inOff + bytesPerWord); + int C = bytesToWord(in, inOff + bytesPerWord*2); + int D = bytesToWord(in, inOff + bytesPerWord*3); + + // Do pseudo-round #0: pre-whitening of B and D + B += _S[0]; + D += _S[1]; + + // perform round #1,#2 ... #ROUNDS of encryption + for (int i = 1; i <= _noRounds; i++) + { + int t = 0,u = 0; + + t = B*(2*B+1); + t = rotateLeft(t,5); + + u = D*(2*D+1); + u = rotateLeft(u,5); + + A ^= t; + A = rotateLeft(A,u); + A += _S[2*i]; + + C ^= u; + C = rotateLeft(C,t); + C += _S[2*i+1]; + + int temp = A; + A = B; + B = C; + C = D; + D = temp; + } + // do pseudo-round #(ROUNDS+1) : post-whitening of A and C + A += _S[2*_noRounds+2]; + C += _S[2*_noRounds+3]; + + // store A, B, C and D registers to out + wordToBytes(A, out, outOff); + wordToBytes(B, out, outOff + bytesPerWord); + wordToBytes(C, out, outOff + bytesPerWord*2); + wordToBytes(D, out, outOff + bytesPerWord*3); + + return 4 * bytesPerWord; + } + + private int decryptBlock( + byte[] in, + int inOff, + byte[] out, + int outOff) + { + // load A,B,C and D registers from out. + int A = bytesToWord(in, inOff); + int B = bytesToWord(in, inOff + bytesPerWord); + int C = bytesToWord(in, inOff + bytesPerWord*2); + int D = bytesToWord(in, inOff + bytesPerWord*3); + + // Undo pseudo-round #(ROUNDS+1) : post whitening of A and C + C -= _S[2*_noRounds+3]; + A -= _S[2*_noRounds+2]; + + // Undo round #ROUNDS, .., #2,#1 of encryption + for (int i = _noRounds; i >= 1; i--) + { + int t=0,u = 0; + + int temp = D; + D = C; + C = B; + B = A; + A = temp; + + t = B*(2*B+1); + t = rotateLeft(t, LGW); + + u = D*(2*D+1); + u = rotateLeft(u, LGW); + + C -= _S[2*i+1]; + C = rotateRight(C,t); + C ^= u; + + A -= _S[2*i]; + A = rotateRight(A,u); + A ^= t; + + } + // Undo pseudo-round #0: pre-whitening of B and D + D -= _S[1]; + B -= _S[0]; + + wordToBytes(A, out, outOff); + wordToBytes(B, out, outOff + bytesPerWord); + wordToBytes(C, out, outOff + bytesPerWord*2); + wordToBytes(D, out, outOff + bytesPerWord*3); + + return 4 * bytesPerWord; + } + + + ////////////////////////////////////////////////////////////// + // + // PRIVATE Helper Methods + // + ////////////////////////////////////////////////////////////// + + /** + * Perform a left "spin" of the word. The rotation of the given + * word x is rotated left by y bits. + * Only the lg(wordSize) low-order bits of y + * are used to determine the rotation amount. Here it is + * assumed that the wordsize used is 32. + *
+ * @param x word to rotate + * @param y number of bits to rotate % wordSize + */ + private int rotateLeft(int x, int y) + { + return (x << y) | (x >>> -y); + } + + /** + * Perform a right "spin" of the word. The rotation of the given + * word x is rotated left by y bits. + * Only the lg(wordSize) low-order bits of y + * are used to determine the rotation amount. Here it is + * assumed that the wordsize used is a power of 2. + *
+ * @param x word to rotate + * @param y number of bits to rotate % wordSize + */ + private int rotateRight(int x, int y) + { + return (x >>> y) | (x << -y); + } + + private int bytesToWord( + byte[] src, + int srcOff) + { + int word = 0; + + for (int i = bytesPerWord - 1; i >= 0; i--) + { + word = (word << 8) + (src[i + srcOff] & 0xff); + } + + return word; + } + + private void wordToBytes( + int word, + byte[] dst, + int dstOff) + { + for (int i = 0; i < bytesPerWord; i++) + { + dst[i + dstOff] = (byte)word; + word >>>= 8; + } + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/RFC3211WrapEngine.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/RFC3211WrapEngine.java new file mode 100644 index 0000000..8eee7aa --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/RFC3211WrapEngine.java @@ -0,0 +1,175 @@ +package org.bc.crypto.engines; + +import org.bc.crypto.BlockCipher; +import org.bc.crypto.CipherParameters; +import org.bc.crypto.InvalidCipherTextException; +import org.bc.crypto.Wrapper; +import org.bc.crypto.modes.CBCBlockCipher; +import org.bc.crypto.params.ParametersWithIV; +import org.bc.crypto.params.ParametersWithRandom; + +import java.security.SecureRandom; + +/** + * an implementation of the RFC 3211 Key Wrap + * Specification. + */ +public class RFC3211WrapEngine + implements Wrapper +{ + private CBCBlockCipher engine; + private ParametersWithIV param; + private boolean forWrapping; + private SecureRandom rand; + + public RFC3211WrapEngine(BlockCipher engine) + { + this.engine = new CBCBlockCipher(engine); + } + + public void init( + boolean forWrapping, + CipherParameters param) + { + this.forWrapping = forWrapping; + + if (param instanceof ParametersWithRandom) + { + ParametersWithRandom p = (ParametersWithRandom)param; + + rand = p.getRandom(); + this.param = (ParametersWithIV)p.getParameters(); + } + else + { + if (forWrapping) + { + rand = new SecureRandom(); + } + + this.param = (ParametersWithIV)param; + } + } + + public String getAlgorithmName() + { + return engine.getUnderlyingCipher().getAlgorithmName() + "/RFC3211Wrap"; + } + + public byte[] wrap( + byte[] in, + int inOff, + int inLen) + { + if (!forWrapping) + { + throw new IllegalStateException("not set for wrapping"); + } + + engine.init(true, param); + + int blockSize = engine.getBlockSize(); + byte[] cekBlock; + + if (inLen + 4 < blockSize * 2) + { + cekBlock = new byte[blockSize * 2]; + } + else + { + cekBlock = new byte[(inLen + 4) % blockSize == 0 ? inLen + 4 : ((inLen + 4) / blockSize + 1) * blockSize]; + } + + cekBlock[0] = (byte)inLen; + cekBlock[1] = (byte)~in[inOff]; + cekBlock[2] = (byte)~in[inOff + 1]; + cekBlock[3] = (byte)~in[inOff + 2]; + + System.arraycopy(in, inOff, cekBlock, 4, inLen); + + for (int i = inLen + 4; i < cekBlock.length; i++) + { + cekBlock[i] = (byte)rand.nextInt(); + } + + for (int i = 0; i < cekBlock.length; i += blockSize) + { + engine.processBlock(cekBlock, i, cekBlock, i); + } + + for (int i = 0; i < cekBlock.length; i += blockSize) + { + engine.processBlock(cekBlock, i, cekBlock, i); + } + + return cekBlock; + } + + public byte[] unwrap( + byte[] in, + int inOff, + int inLen) + throws InvalidCipherTextException + { + if (forWrapping) + { + throw new IllegalStateException("not set for unwrapping"); + } + + int blockSize = engine.getBlockSize(); + + if (inLen < 2 * blockSize) + { + throw new InvalidCipherTextException("input too short"); + } + + byte[] cekBlock = new byte[inLen]; + byte[] iv = new byte[blockSize]; + + System.arraycopy(in, inOff, cekBlock, 0, inLen); + System.arraycopy(in, inOff, iv, 0, iv.length); + + engine.init(false, new ParametersWithIV(param.getParameters(), iv)); + + for (int i = blockSize; i < cekBlock.length; i += blockSize) + { + engine.processBlock(cekBlock, i, cekBlock, i); + } + + System.arraycopy(cekBlock, cekBlock.length - iv.length, iv, 0, iv.length); + + engine.init(false, new ParametersWithIV(param.getParameters(), iv)); + + engine.processBlock(cekBlock, 0, cekBlock, 0); + + engine.init(false, param); + + for (int i = 0; i < cekBlock.length; i += blockSize) + { + engine.processBlock(cekBlock, i, cekBlock, i); + } + + if ((cekBlock[0] & 0xff) > cekBlock.length - 4) + { + throw new InvalidCipherTextException("wrapped key corrupted"); + } + + byte[] key = new byte[cekBlock[0] & 0xff]; + + System.arraycopy(cekBlock, 4, key, 0, cekBlock[0]); + + // Note: Using constant time comparison + int nonEqual = 0; + for (int i = 0; i != 3; i++) + { + byte check = (byte)~cekBlock[1 + i]; + nonEqual |= (check ^ key[i]); + } + if (nonEqual != 0) + { + throw new InvalidCipherTextException("wrapped key fails checksum"); + } + + return key; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/RFC3394WrapEngine.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/RFC3394WrapEngine.java new file mode 100644 index 0000000..b29db11 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/RFC3394WrapEngine.java @@ -0,0 +1,177 @@ +package org.bc.crypto.engines; + +import org.bc.crypto.BlockCipher; +import org.bc.crypto.CipherParameters; +import org.bc.crypto.DataLengthException; +import org.bc.crypto.InvalidCipherTextException; +import org.bc.crypto.Wrapper; +import org.bc.crypto.params.KeyParameter; +import org.bc.crypto.params.ParametersWithIV; +import org.bc.crypto.params.ParametersWithRandom; +import org.bc.util.Arrays; + +/** + * an implementation of the AES Key Wrapper from the NIST Key Wrap + * Specification as described in RFC 3394. + *
+ * For further details see: http://www.ietf.org/rfc/rfc3394.txt + * and http://csrc.nist.gov/encryption/kms/key-wrap.pdf. + */ +public class RFC3394WrapEngine + implements Wrapper +{ + private BlockCipher engine; + private KeyParameter param; + private boolean forWrapping; + + private byte[] iv = { + (byte)0xa6, (byte)0xa6, (byte)0xa6, (byte)0xa6, + (byte)0xa6, (byte)0xa6, (byte)0xa6, (byte)0xa6 }; + + public RFC3394WrapEngine(BlockCipher engine) + { + this.engine = engine; + } + + public void init( + boolean forWrapping, + CipherParameters param) + { + this.forWrapping = forWrapping; + + if (param instanceof ParametersWithRandom) + { + param = ((ParametersWithRandom) param).getParameters(); + } + + if (param instanceof KeyParameter) + { + this.param = (KeyParameter)param; + } + else if (param instanceof ParametersWithIV) + { + this.iv = ((ParametersWithIV)param).getIV(); + this.param = (KeyParameter)((ParametersWithIV) param).getParameters(); + if (this.iv.length != 8) + { + throw new IllegalArgumentException("IV not equal to 8"); + } + } + } + + public String getAlgorithmName() + { + return engine.getAlgorithmName(); + } + + public byte[] wrap( + byte[] in, + int inOff, + int inLen) + { + if (!forWrapping) + { + throw new IllegalStateException("not set for wrapping"); + } + + int n = inLen / 8; + + if ((n * 8) != inLen) + { + throw new DataLengthException("wrap data must be a multiple of 8 bytes"); + } + + byte[] block = new byte[inLen + iv.length]; + byte[] buf = new byte[8 + iv.length]; + + System.arraycopy(iv, 0, block, 0, iv.length); + System.arraycopy(in, 0, block, iv.length, inLen); + + engine.init(true, param); + + for (int j = 0; j != 6; j++) + { + for (int i = 1; i <= n; i++) + { + System.arraycopy(block, 0, buf, 0, iv.length); + System.arraycopy(block, 8 * i, buf, iv.length, 8); + engine.processBlock(buf, 0, buf, 0); + + int t = n * j + i; + for (int k = 1; t != 0; k++) + { + byte v = (byte)t; + + buf[iv.length - k] ^= v; + + t >>>= 8; + } + + System.arraycopy(buf, 0, block, 0, 8); + System.arraycopy(buf, 8, block, 8 * i, 8); + } + } + + return block; + } + + public byte[] unwrap( + byte[] in, + int inOff, + int inLen) + throws InvalidCipherTextException + { + if (forWrapping) + { + throw new IllegalStateException("not set for unwrapping"); + } + + int n = inLen / 8; + + if ((n * 8) != inLen) + { + throw new InvalidCipherTextException("unwrap data must be a multiple of 8 bytes"); + } + + byte[] block = new byte[inLen - iv.length]; + byte[] a = new byte[iv.length]; + byte[] buf = new byte[8 + iv.length]; + + System.arraycopy(in, 0, a, 0, iv.length); + System.arraycopy(in, iv.length, block, 0, inLen - iv.length); + + engine.init(false, param); + + n = n - 1; + + for (int j = 5; j >= 0; j--) + { + for (int i = n; i >= 1; i--) + { + System.arraycopy(a, 0, buf, 0, iv.length); + System.arraycopy(block, 8 * (i - 1), buf, iv.length, 8); + + int t = n * j + i; + for (int k = 1; t != 0; k++) + { + byte v = (byte)t; + + buf[iv.length - k] ^= v; + + t >>>= 8; + } + + engine.processBlock(buf, 0, buf, 0); + System.arraycopy(buf, 0, a, 0, 8); + System.arraycopy(buf, 8, block, 8 * (i - 1), 8); + } + } + + if (!Arrays.constantTimeAreEqual(a, iv)) + { + throw new InvalidCipherTextException("checksum failed"); + } + + return block; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/RSABlindedEngine.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/RSABlindedEngine.java new file mode 100644 index 0000000..ef04335 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/RSABlindedEngine.java @@ -0,0 +1,126 @@ +package org.bc.crypto.engines; + +import org.bc.crypto.AsymmetricBlockCipher; +import org.bc.crypto.CipherParameters; +import org.bc.crypto.DataLengthException; +import org.bc.crypto.params.ParametersWithRandom; +import org.bc.crypto.params.RSAKeyParameters; +import org.bc.crypto.params.RSAPrivateCrtKeyParameters; +import org.bc.util.BigIntegers; + +import java.math.BigInteger; +import java.security.SecureRandom; + +/** + * this does your basic RSA algorithm with blinding + */ +public class RSABlindedEngine + implements AsymmetricBlockCipher +{ + private static BigInteger ONE = BigInteger.valueOf(1); + + private RSACoreEngine core = new RSACoreEngine(); + private RSAKeyParameters key; + private SecureRandom random; + + /** + * initialise the RSA engine. + * + * @param forEncryption true if we are encrypting, false otherwise. + * @param param the necessary RSA key parameters. + */ + public void init( + boolean forEncryption, + CipherParameters param) + { + core.init(forEncryption, param); + + if (param instanceof ParametersWithRandom) + { + ParametersWithRandom rParam = (ParametersWithRandom)param; + + key = (RSAKeyParameters)rParam.getParameters(); + random = rParam.getRandom(); + } + else + { + key = (RSAKeyParameters)param; + random = new SecureRandom(); + } + } + + /** + * Return the maximum size for an input block to this engine. + * For RSA this is always one byte less than the key size on + * encryption, and the same length as the key size on decryption. + * + * @return maximum size for an input block. + */ + public int getInputBlockSize() + { + return core.getInputBlockSize(); + } + + /** + * Return the maximum size for an output block to this engine. + * For RSA this is always one byte less than the key size on + * decryption, and the same length as the key size on encryption. + * + * @return maximum size for an output block. + */ + public int getOutputBlockSize() + { + return core.getOutputBlockSize(); + } + + /** + * Process a single block using the basic RSA algorithm. + * + * @param in the input array. + * @param inOff the offset into the input buffer where the data starts. + * @param inLen the length of the data to be processed. + * @return the result of the RSA process. + * @exception DataLengthException the input block is too large. + */ + public byte[] processBlock( + byte[] in, + int inOff, + int inLen) + { + if (key == null) + { + throw new IllegalStateException("RSA engine not initialised"); + } + + BigInteger input = core.convertInput(in, inOff, inLen); + + BigInteger result; + if (key instanceof RSAPrivateCrtKeyParameters) + { + RSAPrivateCrtKeyParameters k = (RSAPrivateCrtKeyParameters)key; + + BigInteger e = k.getPublicExponent(); + if (e != null) // can't do blinding without a public exponent + { + BigInteger m = k.getModulus(); + BigInteger r = BigIntegers.createRandomInRange(ONE, m.subtract(ONE), random); + + BigInteger blindedInput = r.modPow(e, m).multiply(input).mod(m); + BigInteger blindedResult = core.processBlock(blindedInput); + + BigInteger rInv = r.modInverse(m); + result = blindedResult.multiply(rInv).mod(m); + } + else + { + result = core.processBlock(input); + } + } + else + { + result = core.processBlock(input); + } + + return core.convertOutput(result); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/RSABlindingEngine.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/RSABlindingEngine.java new file mode 100644 index 0000000..04805bf --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/RSABlindingEngine.java @@ -0,0 +1,137 @@ +package org.bc.crypto.engines; + +import org.bc.crypto.AsymmetricBlockCipher; +import org.bc.crypto.CipherParameters; +import org.bc.crypto.DataLengthException; +import org.bc.crypto.params.ParametersWithRandom; +import org.bc.crypto.params.RSABlindingParameters; +import org.bc.crypto.params.RSAKeyParameters; + +import java.math.BigInteger; + +/** + * This does your basic RSA Chaum's blinding and unblinding as outlined in + * "Handbook of Applied Cryptography", page 475. You need to use this if you are + * trying to get another party to generate signatures without them being aware + * of the message they are signing. + */ +public class RSABlindingEngine + implements AsymmetricBlockCipher +{ + private RSACoreEngine core = new RSACoreEngine(); + + private RSAKeyParameters key; + private BigInteger blindingFactor; + + private boolean forEncryption; + + /** + * Initialise the blinding engine. + * + * @param forEncryption true if we are encrypting (blinding), false otherwise. + * @param param the necessary RSA key parameters. + */ + public void init( + boolean forEncryption, + CipherParameters param) + { + RSABlindingParameters p; + + if (param instanceof ParametersWithRandom) + { + ParametersWithRandom rParam = (ParametersWithRandom)param; + + p = (RSABlindingParameters)rParam.getParameters(); + } + else + { + p = (RSABlindingParameters)param; + } + + core.init(forEncryption, p.getPublicKey()); + + this.forEncryption = forEncryption; + this.key = p.getPublicKey(); + this.blindingFactor = p.getBlindingFactor(); + } + + /** + * Return the maximum size for an input block to this engine. + * For RSA this is always one byte less than the key size on + * encryption, and the same length as the key size on decryption. + * + * @return maximum size for an input block. + */ + public int getInputBlockSize() + { + return core.getInputBlockSize(); + } + + /** + * Return the maximum size for an output block to this engine. + * For RSA this is always one byte less than the key size on + * decryption, and the same length as the key size on encryption. + * + * @return maximum size for an output block. + */ + public int getOutputBlockSize() + { + return core.getOutputBlockSize(); + } + + /** + * Process a single block using the RSA blinding algorithm. + * + * @param in the input array. + * @param inOff the offset into the input buffer where the data starts. + * @param inLen the length of the data to be processed. + * @return the result of the RSA process. + * @throws DataLengthException the input block is too large. + */ + public byte[] processBlock( + byte[] in, + int inOff, + int inLen) + { + BigInteger msg = core.convertInput(in, inOff, inLen); + + if (forEncryption) + { + msg = blindMessage(msg); + } + else + { + msg = unblindMessage(msg); + } + + return core.convertOutput(msg); + } + + /* + * Blind message with the blind factor. + */ + private BigInteger blindMessage( + BigInteger msg) + { + BigInteger blindMsg = blindingFactor; + blindMsg = msg.multiply(blindMsg.modPow(key.getExponent(), key.getModulus())); + blindMsg = blindMsg.mod(key.getModulus()); + + return blindMsg; + } + + /* + * Unblind the message blinded with the blind factor. + */ + private BigInteger unblindMessage( + BigInteger blindedMsg) + { + BigInteger m = key.getModulus(); + BigInteger msg = blindedMsg; + BigInteger blindFactorInverse = blindingFactor.modInverse(m); + msg = msg.multiply(blindFactorInverse); + msg = msg.mod(m); + + return msg; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/RSACoreEngine.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/RSACoreEngine.java new file mode 100644 index 0000000..98b7c0a --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/RSACoreEngine.java @@ -0,0 +1,203 @@ +package org.bc.crypto.engines; + +import org.bc.crypto.CipherParameters; +import org.bc.crypto.DataLengthException; +import org.bc.crypto.params.ParametersWithRandom; +import org.bc.crypto.params.RSAKeyParameters; +import org.bc.crypto.params.RSAPrivateCrtKeyParameters; + +import java.math.BigInteger; + +/** + * this does your basic RSA algorithm. + */ +class RSACoreEngine +{ + private RSAKeyParameters key; + private boolean forEncryption; + + /** + * initialise the RSA engine. + * + * @param forEncryption true if we are encrypting, false otherwise. + * @param param the necessary RSA key parameters. + */ + public void init( + boolean forEncryption, + CipherParameters param) + { + if (param instanceof ParametersWithRandom) + { + ParametersWithRandom rParam = (ParametersWithRandom)param; + + key = (RSAKeyParameters)rParam.getParameters(); + } + else + { + key = (RSAKeyParameters)param; + } + + this.forEncryption = forEncryption; + } + + /** + * Return the maximum size for an input block to this engine. + * For RSA this is always one byte less than the key size on + * encryption, and the same length as the key size on decryption. + * + * @return maximum size for an input block. + */ + public int getInputBlockSize() + { + int bitSize = key.getModulus().bitLength(); + + if (forEncryption) + { + return (bitSize + 7) / 8 - 1; + } + else + { + return (bitSize + 7) / 8; + } + } + + /** + * Return the maximum size for an output block to this engine. + * For RSA this is always one byte less than the key size on + * decryption, and the same length as the key size on encryption. + * + * @return maximum size for an output block. + */ + public int getOutputBlockSize() + { + int bitSize = key.getModulus().bitLength(); + + if (forEncryption) + { + return (bitSize + 7) / 8; + } + else + { + return (bitSize + 7) / 8 - 1; + } + } + + public BigInteger convertInput( + byte[] in, + int inOff, + int inLen) + { + if (inLen > (getInputBlockSize() + 1)) + { + throw new DataLengthException("input too large for RSA cipher."); + } + else if (inLen == (getInputBlockSize() + 1) && !forEncryption) + { + throw new DataLengthException("input too large for RSA cipher."); + } + + byte[] block; + + if (inOff != 0 || inLen != in.length) + { + block = new byte[inLen]; + + System.arraycopy(in, inOff, block, 0, inLen); + } + else + { + block = in; + } + + BigInteger res = new BigInteger(1, block); + if (res.compareTo(key.getModulus()) >= 0) + { + throw new DataLengthException("input too large for RSA cipher."); + } + + return res; + } + + public byte[] convertOutput( + BigInteger result) + { + byte[] output = result.toByteArray(); + + if (forEncryption) + { + if (output[0] == 0 && output.length > getOutputBlockSize()) // have ended up with an extra zero byte, copy down. + { + byte[] tmp = new byte[output.length - 1]; + + System.arraycopy(output, 1, tmp, 0, tmp.length); + + return tmp; + } + + if (output.length < getOutputBlockSize()) // have ended up with less bytes than normal, lengthen + { + byte[] tmp = new byte[getOutputBlockSize()]; + + System.arraycopy(output, 0, tmp, tmp.length - output.length, output.length); + + return tmp; + } + } + else + { + if (output[0] == 0) // have ended up with an extra zero byte, copy down. + { + byte[] tmp = new byte[output.length - 1]; + + System.arraycopy(output, 1, tmp, 0, tmp.length); + + return tmp; + } + } + + return output; + } + + public BigInteger processBlock(BigInteger input) + { + if (key instanceof RSAPrivateCrtKeyParameters) + { + // + // we have the extra factors, use the Chinese Remainder Theorem - the author + // wishes to express his thanks to Dirk Bonekaemper at rtsffm.com for + // advice regarding the expression of this. + // + RSAPrivateCrtKeyParameters crtKey = (RSAPrivateCrtKeyParameters)key; + + BigInteger p = crtKey.getP(); + BigInteger q = crtKey.getQ(); + BigInteger dP = crtKey.getDP(); + BigInteger dQ = crtKey.getDQ(); + BigInteger qInv = crtKey.getQInv(); + + BigInteger mP, mQ, h, m; + + // mP = ((input mod p) ^ dP)) mod p + mP = (input.remainder(p)).modPow(dP, p); + + // mQ = ((input mod q) ^ dQ)) mod q + mQ = (input.remainder(q)).modPow(dQ, q); + + // h = qInv * (mP - mQ) mod p + h = mP.subtract(mQ); + h = h.multiply(qInv); + h = h.mod(p); // mod (in Java) returns the positive residual + + // m = h * q + mQ + m = h.multiply(q); + m = m.add(mQ); + + return m; + } + else + { + return input.modPow( + key.getExponent(), key.getModulus()); + } + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/RSAEngine.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/RSAEngine.java new file mode 100644 index 0000000..c96d86a --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/RSAEngine.java @@ -0,0 +1,78 @@ +package org.bc.crypto.engines; + +import org.bc.crypto.AsymmetricBlockCipher; +import org.bc.crypto.CipherParameters; +import org.bc.crypto.DataLengthException; + +/** + * this does your basic RSA algorithm. + */ +public class RSAEngine + implements AsymmetricBlockCipher +{ + private RSACoreEngine core; + + /** + * initialise the RSA engine. + * + * @param forEncryption true if we are encrypting, false otherwise. + * @param param the necessary RSA key parameters. + */ + public void init( + boolean forEncryption, + CipherParameters param) + { + if (core == null) + { + core = new RSACoreEngine(); + } + + core.init(forEncryption, param); + } + + /** + * Return the maximum size for an input block to this engine. + * For RSA this is always one byte less than the key size on + * encryption, and the same length as the key size on decryption. + * + * @return maximum size for an input block. + */ + public int getInputBlockSize() + { + return core.getInputBlockSize(); + } + + /** + * Return the maximum size for an output block to this engine. + * For RSA this is always one byte less than the key size on + * decryption, and the same length as the key size on encryption. + * + * @return maximum size for an output block. + */ + public int getOutputBlockSize() + { + return core.getOutputBlockSize(); + } + + /** + * Process a single block using the basic RSA algorithm. + * + * @param in the input array. + * @param inOff the offset into the input buffer where the data starts. + * @param inLen the length of the data to be processed. + * @return the result of the RSA process. + * @exception DataLengthException the input block is too large. + */ + public byte[] processBlock( + byte[] in, + int inOff, + int inLen) + { + if (core == null) + { + throw new IllegalStateException("RSA engine not initialised"); + } + + return core.convertOutput(core.processBlock(core.convertInput(in, inOff, inLen))); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/RijndaelEngine.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/RijndaelEngine.java new file mode 100644 index 0000000..53a1142 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/RijndaelEngine.java @@ -0,0 +1,724 @@ +package org.bc.crypto.engines; + +import org.bc.crypto.BlockCipher; +import org.bc.crypto.CipherParameters; +import org.bc.crypto.DataLengthException; +import org.bc.crypto.params.KeyParameter; + +/** + * an implementation of Rijndael, based on the documentation and reference implementation + * by Paulo Barreto, Vincent Rijmen, for v2.0 August '99. + *
+ * Note: this implementation is based on information prior to final NIST publication. + */ +public class RijndaelEngine + implements BlockCipher +{ + private static final int MAXROUNDS = 14; + + private static final int MAXKC = (256/4); + + private static final byte[] logtable = { + (byte)0, (byte)0, (byte)25, (byte)1, (byte)50, (byte)2, (byte)26, (byte)198, + (byte)75, (byte)199, (byte)27, (byte)104, (byte)51, (byte)238, (byte)223, (byte)3, + (byte)100, (byte)4, (byte)224, (byte)14, (byte)52, (byte)141, (byte)129, (byte)239, + (byte)76, (byte)113, (byte)8, (byte)200, (byte)248, (byte)105, (byte)28, (byte)193, + (byte)125, (byte)194, (byte)29, (byte)181, (byte)249, (byte)185, (byte)39, (byte)106, + (byte)77, (byte)228, (byte)166, (byte)114, (byte)154, (byte)201, (byte)9, (byte)120, + (byte)101, (byte)47, (byte)138, (byte)5, (byte)33, (byte)15, (byte)225, (byte)36, + (byte)18, (byte)240, (byte)130, (byte)69, (byte)53, (byte)147, (byte)218, (byte)142, + (byte)150, (byte)143, (byte)219, (byte)189, (byte)54, (byte)208, (byte)206, (byte)148, + (byte)19, (byte)92, (byte)210, (byte)241, (byte)64, (byte)70, (byte)131, (byte)56, + (byte)102, (byte)221, (byte)253, (byte)48, (byte)191, (byte)6, (byte)139, (byte)98, + (byte)179, (byte)37, (byte)226, (byte)152, (byte)34, (byte)136, (byte)145, (byte)16, + (byte)126, (byte)110, (byte)72, (byte)195, (byte)163, (byte)182, (byte)30, (byte)66, + (byte)58, (byte)107, (byte)40, (byte)84, (byte)250, (byte)133, (byte)61, (byte)186, + (byte)43, (byte)121, (byte)10, (byte)21, (byte)155, (byte)159, (byte)94, (byte)202, + (byte)78, (byte)212, (byte)172, (byte)229, (byte)243, (byte)115, (byte)167, (byte)87, + (byte)175, (byte)88, (byte)168, (byte)80, (byte)244, (byte)234, (byte)214, (byte)116, + (byte)79, (byte)174, (byte)233, (byte)213, (byte)231, (byte)230, (byte)173, (byte)232, + (byte)44, (byte)215, (byte)117, (byte)122, (byte)235, (byte)22, (byte)11, (byte)245, + (byte)89, (byte)203, (byte)95, (byte)176, (byte)156, (byte)169, (byte)81, (byte)160, + (byte)127, (byte)12, (byte)246, (byte)111, (byte)23, (byte)196, (byte)73, (byte)236, + (byte)216, (byte)67, (byte)31, (byte)45, (byte)164, (byte)118, (byte)123, (byte)183, + (byte)204, (byte)187, (byte)62, (byte)90, (byte)251, (byte)96, (byte)177, (byte)134, + (byte)59, (byte)82, (byte)161, (byte)108, (byte)170, (byte)85, (byte)41, (byte)157, + (byte)151, (byte)178, (byte)135, (byte)144, (byte)97, (byte)190, (byte)220, (byte)252, + (byte)188, (byte)149, (byte)207, (byte)205, (byte)55, (byte)63, (byte)91, (byte)209, + (byte)83, (byte)57, (byte)132, (byte)60, (byte)65, (byte)162, (byte)109, (byte)71, + (byte)20, (byte)42, (byte)158, (byte)93, (byte)86, (byte)242, (byte)211, (byte)171, + (byte)68, (byte)17, (byte)146, (byte)217, (byte)35, (byte)32, (byte)46, (byte)137, + (byte)180, (byte)124, (byte)184, (byte)38, (byte)119, (byte)153, (byte)227, (byte)165, + (byte)103, (byte)74, (byte)237, (byte)222, (byte)197, (byte)49, (byte)254, (byte)24, + (byte)13, (byte)99, (byte)140, (byte)128, (byte)192, (byte)247, (byte)112, (byte)7 + }; + + private static final byte[] aLogtable = { + (byte)0, (byte)3, (byte)5, (byte)15, (byte)17, (byte)51, (byte)85, (byte)255, (byte)26, (byte)46, (byte)114, (byte)150, (byte)161, (byte)248, (byte)19, (byte)53, + (byte)95, (byte)225, (byte)56, (byte)72, (byte)216, (byte)115, (byte)149, (byte)164, (byte)247, (byte)2, (byte)6, (byte)10, (byte)30, (byte)34, (byte)102, (byte)170, + (byte)229, (byte)52, (byte)92, (byte)228, (byte)55, (byte)89, (byte)235, (byte)38, (byte)106, (byte)190, (byte)217, (byte)112, (byte)144, (byte)171, (byte)230, (byte)49, + (byte)83, (byte)245, (byte)4, (byte)12, (byte)20, (byte)60, (byte)68, (byte)204, (byte)79, (byte)209, (byte)104, (byte)184, (byte)211, (byte)110, (byte)178, (byte)205, + (byte)76, (byte)212, (byte)103, (byte)169, (byte)224, (byte)59, (byte)77, (byte)215, (byte)98, (byte)166, (byte)241, (byte)8, (byte)24, (byte)40, (byte)120, (byte)136, + (byte)131, (byte)158, (byte)185, (byte)208, (byte)107, (byte)189, (byte)220, (byte)127, (byte)129, (byte)152, (byte)179, (byte)206, (byte)73, (byte)219, (byte)118, (byte)154, + (byte)181, (byte)196, (byte)87, (byte)249, (byte)16, (byte)48, (byte)80, (byte)240, (byte)11, (byte)29, (byte)39, (byte)105, (byte)187, (byte)214, (byte)97, (byte)163, + (byte)254, (byte)25, (byte)43, (byte)125, (byte)135, (byte)146, (byte)173, (byte)236, (byte)47, (byte)113, (byte)147, (byte)174, (byte)233, (byte)32, (byte)96, (byte)160, + (byte)251, (byte)22, (byte)58, (byte)78, (byte)210, (byte)109, (byte)183, (byte)194, (byte)93, (byte)231, (byte)50, (byte)86, (byte)250, (byte)21, (byte)63, (byte)65, + (byte)195, (byte)94, (byte)226, (byte)61, (byte)71, (byte)201, (byte)64, (byte)192, (byte)91, (byte)237, (byte)44, (byte)116, (byte)156, (byte)191, (byte)218, (byte)117, + (byte)159, (byte)186, (byte)213, (byte)100, (byte)172, (byte)239, (byte)42, (byte)126, (byte)130, (byte)157, (byte)188, (byte)223, (byte)122, (byte)142, (byte)137, (byte)128, + (byte)155, (byte)182, (byte)193, (byte)88, (byte)232, (byte)35, (byte)101, (byte)175, (byte)234, (byte)37, (byte)111, (byte)177, (byte)200, (byte)67, (byte)197, (byte)84, + (byte)252, (byte)31, (byte)33, (byte)99, (byte)165, (byte)244, (byte)7, (byte)9, (byte)27, (byte)45, (byte)119, (byte)153, (byte)176, (byte)203, (byte)70, (byte)202, + (byte)69, (byte)207, (byte)74, (byte)222, (byte)121, (byte)139, (byte)134, (byte)145, (byte)168, (byte)227, (byte)62, (byte)66, (byte)198, (byte)81, (byte)243, (byte)14, + (byte)18, (byte)54, (byte)90, (byte)238, (byte)41, (byte)123, (byte)141, (byte)140, (byte)143, (byte)138, (byte)133, (byte)148, (byte)167, (byte)242, (byte)13, (byte)23, + (byte)57, (byte)75, (byte)221, (byte)124, (byte)132, (byte)151, (byte)162, (byte)253, (byte)28, (byte)36, (byte)108, (byte)180, (byte)199, (byte)82, (byte)246, (byte)1, + (byte)3, (byte)5, (byte)15, (byte)17, (byte)51, (byte)85, (byte)255, (byte)26, (byte)46, (byte)114, (byte)150, (byte)161, (byte)248, (byte)19, (byte)53, + (byte)95, (byte)225, (byte)56, (byte)72, (byte)216, (byte)115, (byte)149, (byte)164, (byte)247, (byte)2, (byte)6, (byte)10, (byte)30, (byte)34, (byte)102, (byte)170, + (byte)229, (byte)52, (byte)92, (byte)228, (byte)55, (byte)89, (byte)235, (byte)38, (byte)106, (byte)190, (byte)217, (byte)112, (byte)144, (byte)171, (byte)230, (byte)49, + (byte)83, (byte)245, (byte)4, (byte)12, (byte)20, (byte)60, (byte)68, (byte)204, (byte)79, (byte)209, (byte)104, (byte)184, (byte)211, (byte)110, (byte)178, (byte)205, + (byte)76, (byte)212, (byte)103, (byte)169, (byte)224, (byte)59, (byte)77, (byte)215, (byte)98, (byte)166, (byte)241, (byte)8, (byte)24, (byte)40, (byte)120, (byte)136, + (byte)131, (byte)158, (byte)185, (byte)208, (byte)107, (byte)189, (byte)220, (byte)127, (byte)129, (byte)152, (byte)179, (byte)206, (byte)73, (byte)219, (byte)118, (byte)154, + (byte)181, (byte)196, (byte)87, (byte)249, (byte)16, (byte)48, (byte)80, (byte)240, (byte)11, (byte)29, (byte)39, (byte)105, (byte)187, (byte)214, (byte)97, (byte)163, + (byte)254, (byte)25, (byte)43, (byte)125, (byte)135, (byte)146, (byte)173, (byte)236, (byte)47, (byte)113, (byte)147, (byte)174, (byte)233, (byte)32, (byte)96, (byte)160, + (byte)251, (byte)22, (byte)58, (byte)78, (byte)210, (byte)109, (byte)183, (byte)194, (byte)93, (byte)231, (byte)50, (byte)86, (byte)250, (byte)21, (byte)63, (byte)65, + (byte)195, (byte)94, (byte)226, (byte)61, (byte)71, (byte)201, (byte)64, (byte)192, (byte)91, (byte)237, (byte)44, (byte)116, (byte)156, (byte)191, (byte)218, (byte)117, + (byte)159, (byte)186, (byte)213, (byte)100, (byte)172, (byte)239, (byte)42, (byte)126, (byte)130, (byte)157, (byte)188, (byte)223, (byte)122, (byte)142, (byte)137, (byte)128, + (byte)155, (byte)182, (byte)193, (byte)88, (byte)232, (byte)35, (byte)101, (byte)175, (byte)234, (byte)37, (byte)111, (byte)177, (byte)200, (byte)67, (byte)197, (byte)84, + (byte)252, (byte)31, (byte)33, (byte)99, (byte)165, (byte)244, (byte)7, (byte)9, (byte)27, (byte)45, (byte)119, (byte)153, (byte)176, (byte)203, (byte)70, (byte)202, + (byte)69, (byte)207, (byte)74, (byte)222, (byte)121, (byte)139, (byte)134, (byte)145, (byte)168, (byte)227, (byte)62, (byte)66, (byte)198, (byte)81, (byte)243, (byte)14, + (byte)18, (byte)54, (byte)90, (byte)238, (byte)41, (byte)123, (byte)141, (byte)140, (byte)143, (byte)138, (byte)133, (byte)148, (byte)167, (byte)242, (byte)13, (byte)23, + (byte)57, (byte)75, (byte)221, (byte)124, (byte)132, (byte)151, (byte)162, (byte)253, (byte)28, (byte)36, (byte)108, (byte)180, (byte)199, (byte)82, (byte)246, (byte)1, + }; + + private static final byte[] S = { + (byte)99, (byte)124, (byte)119, (byte)123, (byte)242, (byte)107, (byte)111, (byte)197, (byte)48, (byte)1, (byte)103, (byte)43, (byte)254, (byte)215, (byte)171, (byte)118, + (byte)202, (byte)130, (byte)201, (byte)125, (byte)250, (byte)89, (byte)71, (byte)240, (byte)173, (byte)212, (byte)162, (byte)175, (byte)156, (byte)164, (byte)114, (byte)192, + (byte)183, (byte)253, (byte)147, (byte)38, (byte)54, (byte)63, (byte)247, (byte)204, (byte)52, (byte)165, (byte)229, (byte)241, (byte)113, (byte)216, (byte)49, (byte)21, + (byte)4, (byte)199, (byte)35, (byte)195, (byte)24, (byte)150, (byte)5, (byte)154, (byte)7, (byte)18, (byte)128, (byte)226, (byte)235, (byte)39, (byte)178, (byte)117, + (byte)9, (byte)131, (byte)44, (byte)26, (byte)27, (byte)110, (byte)90, (byte)160, (byte)82, (byte)59, (byte)214, (byte)179, (byte)41, (byte)227, (byte)47, (byte)132, + (byte)83, (byte)209, (byte)0, (byte)237, (byte)32, (byte)252, (byte)177, (byte)91, (byte)106, (byte)203, (byte)190, (byte)57, (byte)74, (byte)76, (byte)88, (byte)207, + (byte)208, (byte)239, (byte)170, (byte)251, (byte)67, (byte)77, (byte)51, (byte)133, (byte)69, (byte)249, (byte)2, (byte)127, (byte)80, (byte)60, (byte)159, (byte)168, + (byte)81, (byte)163, (byte)64, (byte)143, (byte)146, (byte)157, (byte)56, (byte)245, (byte)188, (byte)182, (byte)218, (byte)33, (byte)16, (byte)255, (byte)243, (byte)210, + (byte)205, (byte)12, (byte)19, (byte)236, (byte)95, (byte)151, (byte)68, (byte)23, (byte)196, (byte)167, (byte)126, (byte)61, (byte)100, (byte)93, (byte)25, (byte)115, + (byte)96, (byte)129, (byte)79, (byte)220, (byte)34, (byte)42, (byte)144, (byte)136, (byte)70, (byte)238, (byte)184, (byte)20, (byte)222, (byte)94, (byte)11, (byte)219, + (byte)224, (byte)50, (byte)58, (byte)10, (byte)73, (byte)6, (byte)36, (byte)92, (byte)194, (byte)211, (byte)172, (byte)98, (byte)145, (byte)149, (byte)228, (byte)121, + (byte)231, (byte)200, (byte)55, (byte)109, (byte)141, (byte)213, (byte)78, (byte)169, (byte)108, (byte)86, (byte)244, (byte)234, (byte)101, (byte)122, (byte)174, (byte)8, + (byte)186, (byte)120, (byte)37, (byte)46, (byte)28, (byte)166, (byte)180, (byte)198, (byte)232, (byte)221, (byte)116, (byte)31, (byte)75, (byte)189, (byte)139, (byte)138, + (byte)112, (byte)62, (byte)181, (byte)102, (byte)72, (byte)3, (byte)246, (byte)14, (byte)97, (byte)53, (byte)87, (byte)185, (byte)134, (byte)193, (byte)29, (byte)158, + (byte)225, (byte)248, (byte)152, (byte)17, (byte)105, (byte)217, (byte)142, (byte)148, (byte)155, (byte)30, (byte)135, (byte)233, (byte)206, (byte)85, (byte)40, (byte)223, + (byte)140, (byte)161, (byte)137, (byte)13, (byte)191, (byte)230, (byte)66, (byte)104, (byte)65, (byte)153, (byte)45, (byte)15, (byte)176, (byte)84, (byte)187, (byte)22, + }; + + private static final byte[] Si = { + (byte)82, (byte)9, (byte)106, (byte)213, (byte)48, (byte)54, (byte)165, (byte)56, (byte)191, (byte)64, (byte)163, (byte)158, (byte)129, (byte)243, (byte)215, (byte)251, + (byte)124, (byte)227, (byte)57, (byte)130, (byte)155, (byte)47, (byte)255, (byte)135, (byte)52, (byte)142, (byte)67, (byte)68, (byte)196, (byte)222, (byte)233, (byte)203, + (byte)84, (byte)123, (byte)148, (byte)50, (byte)166, (byte)194, (byte)35, (byte)61, (byte)238, (byte)76, (byte)149, (byte)11, (byte)66, (byte)250, (byte)195, (byte)78, + (byte)8, (byte)46, (byte)161, (byte)102, (byte)40, (byte)217, (byte)36, (byte)178, (byte)118, (byte)91, (byte)162, (byte)73, (byte)109, (byte)139, (byte)209, (byte)37, + (byte)114, (byte)248, (byte)246, (byte)100, (byte)134, (byte)104, (byte)152, (byte)22, (byte)212, (byte)164, (byte)92, (byte)204, (byte)93, (byte)101, (byte)182, (byte)146, + (byte)108, (byte)112, (byte)72, (byte)80, (byte)253, (byte)237, (byte)185, (byte)218, (byte)94, (byte)21, (byte)70, (byte)87, (byte)167, (byte)141, (byte)157, (byte)132, + (byte)144, (byte)216, (byte)171, (byte)0, (byte)140, (byte)188, (byte)211, (byte)10, (byte)247, (byte)228, (byte)88, (byte)5, (byte)184, (byte)179, (byte)69, (byte)6, + (byte)208, (byte)44, (byte)30, (byte)143, (byte)202, (byte)63, (byte)15, (byte)2, (byte)193, (byte)175, (byte)189, (byte)3, (byte)1, (byte)19, (byte)138, (byte)107, + (byte)58, (byte)145, (byte)17, (byte)65, (byte)79, (byte)103, (byte)220, (byte)234, (byte)151, (byte)242, (byte)207, (byte)206, (byte)240, (byte)180, (byte)230, (byte)115, + (byte)150, (byte)172, (byte)116, (byte)34, (byte)231, (byte)173, (byte)53, (byte)133, (byte)226, (byte)249, (byte)55, (byte)232, (byte)28, (byte)117, (byte)223, (byte)110, + (byte)71, (byte)241, (byte)26, (byte)113, (byte)29, (byte)41, (byte)197, (byte)137, (byte)111, (byte)183, (byte)98, (byte)14, (byte)170, (byte)24, (byte)190, (byte)27, + (byte)252, (byte)86, (byte)62, (byte)75, (byte)198, (byte)210, (byte)121, (byte)32, (byte)154, (byte)219, (byte)192, (byte)254, (byte)120, (byte)205, (byte)90, (byte)244, + (byte)31, (byte)221, (byte)168, (byte)51, (byte)136, (byte)7, (byte)199, (byte)49, (byte)177, (byte)18, (byte)16, (byte)89, (byte)39, (byte)128, (byte)236, (byte)95, + (byte)96, (byte)81, (byte)127, (byte)169, (byte)25, (byte)181, (byte)74, (byte)13, (byte)45, (byte)229, (byte)122, (byte)159, (byte)147, (byte)201, (byte)156, (byte)239, + (byte)160, (byte)224, (byte)59, (byte)77, (byte)174, (byte)42, (byte)245, (byte)176, (byte)200, (byte)235, (byte)187, (byte)60, (byte)131, (byte)83, (byte)153, (byte)97, + (byte)23, (byte)43, (byte)4, (byte)126, (byte)186, (byte)119, (byte)214, (byte)38, (byte)225, (byte)105, (byte)20, (byte)99, (byte)85, (byte)33, (byte)12, (byte)125, + }; + + private static final int[] rcon = { + 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91 }; + + static byte[][] shifts0 = + { + { 0, 8, 16, 24 }, + { 0, 8, 16, 24 }, + { 0, 8, 16, 24 }, + { 0, 8, 16, 32 }, + { 0, 8, 24, 32 } + }; + + static byte[][] shifts1 = + { + { 0, 24, 16, 8 }, + { 0, 32, 24, 16 }, + { 0, 40, 32, 24 }, + { 0, 48, 40, 24 }, + { 0, 56, 40, 32 } + }; + + /** + * multiply two elements of GF(2^m) + * needed for MixColumn and InvMixColumn + */ + private byte mul0x2( + int b) + { + if (b != 0) + { + return aLogtable[25 + (logtable[b] & 0xff)]; + } + else + { + return 0; + } + } + + private byte mul0x3( + int b) + { + if (b != 0) + { + return aLogtable[1 + (logtable[b] & 0xff)]; + } + else + { + return 0; + } + } + + private byte mul0x9( + int b) + { + if (b >= 0) + { + return aLogtable[199 + b]; + } + else + { + return 0; + } + } + + private byte mul0xb( + int b) + { + if (b >= 0) + { + return aLogtable[104 + b]; + } + else + { + return 0; + } + } + + private byte mul0xd( + int b) + { + if (b >= 0) + { + return aLogtable[238 + b]; + } + else + { + return 0; + } + } + + private byte mul0xe( + int b) + { + if (b >= 0) + { + return aLogtable[223 + b]; + } + else + { + return 0; + } + } + + /** + * xor corresponding text input and round key input bytes + */ + private void KeyAddition( + long[] rk) + { + A0 ^= rk[0]; + A1 ^= rk[1]; + A2 ^= rk[2]; + A3 ^= rk[3]; + } + + private long shift( + long r, + int shift) + { + return (((r >>> shift) | (r << (BC - shift)))) & BC_MASK; + } + + /** + * Row 0 remains unchanged + * The other three rows are shifted a variable amount + */ + private void ShiftRow( + byte[] shiftsSC) + { + A1 = shift(A1, shiftsSC[1]); + A2 = shift(A2, shiftsSC[2]); + A3 = shift(A3, shiftsSC[3]); + } + + private long applyS( + long r, + byte[] box) + { + long res = 0; + + for (int j = 0; j < BC; j += 8) + { + res |= (long)(box[(int)((r >> j) & 0xff)] & 0xff) << j; + } + + return res; + } + + /** + * Replace every byte of the input by the byte at that place + * in the nonlinear S-box + */ + private void Substitution( + byte[] box) + { + A0 = applyS(A0, box); + A1 = applyS(A1, box); + A2 = applyS(A2, box); + A3 = applyS(A3, box); + } + + /** + * Mix the bytes of every column in a linear way + */ + private void MixColumn() + { + long r0, r1, r2, r3; + + r0 = r1 = r2 = r3 = 0; + + for (int j = 0; j < BC; j += 8) + { + int a0 = (int)((A0 >> j) & 0xff); + int a1 = (int)((A1 >> j) & 0xff); + int a2 = (int)((A2 >> j) & 0xff); + int a3 = (int)((A3 >> j) & 0xff); + + r0 |= (long)((mul0x2(a0) ^ mul0x3(a1) ^ a2 ^ a3) & 0xff) << j; + + r1 |= (long)((mul0x2(a1) ^ mul0x3(a2) ^ a3 ^ a0) & 0xff) << j; + + r2 |= (long)((mul0x2(a2) ^ mul0x3(a3) ^ a0 ^ a1) & 0xff) << j; + + r3 |= (long)((mul0x2(a3) ^ mul0x3(a0) ^ a1 ^ a2) & 0xff) << j; + } + + A0 = r0; + A1 = r1; + A2 = r2; + A3 = r3; + } + + /** + * Mix the bytes of every column in a linear way + * This is the opposite operation of Mixcolumn + */ + private void InvMixColumn() + { + long r0, r1, r2, r3; + + r0 = r1 = r2 = r3 = 0; + for (int j = 0; j < BC; j += 8) + { + int a0 = (int)((A0 >> j) & 0xff); + int a1 = (int)((A1 >> j) & 0xff); + int a2 = (int)((A2 >> j) & 0xff); + int a3 = (int)((A3 >> j) & 0xff); + + // + // pre-lookup the log table + // + a0 = (a0 != 0) ? (logtable[a0 & 0xff] & 0xff) : -1; + a1 = (a1 != 0) ? (logtable[a1 & 0xff] & 0xff) : -1; + a2 = (a2 != 0) ? (logtable[a2 & 0xff] & 0xff) : -1; + a3 = (a3 != 0) ? (logtable[a3 & 0xff] & 0xff) : -1; + + r0 |= (long)((mul0xe(a0) ^ mul0xb(a1) ^ mul0xd(a2) ^ mul0x9(a3)) & 0xff) << j; + + r1 |= (long)((mul0xe(a1) ^ mul0xb(a2) ^ mul0xd(a3) ^ mul0x9(a0)) & 0xff) << j; + + r2 |= (long)((mul0xe(a2) ^ mul0xb(a3) ^ mul0xd(a0) ^ mul0x9(a1)) & 0xff) << j; + + r3 |= (long)((mul0xe(a3) ^ mul0xb(a0) ^ mul0xd(a1) ^ mul0x9(a2)) & 0xff) << j; + } + + A0 = r0; + A1 = r1; + A2 = r2; + A3 = r3; + } + + /** + * Calculate the necessary round keys + * The number of calculations depends on keyBits and blockBits + */ + private long[][] generateWorkingKey( + byte[] key) + { + int KC; + int t, rconpointer = 0; + int keyBits = key.length * 8; + byte[][] tk = new byte[4][MAXKC]; + long[][] W = new long[MAXROUNDS+1][4]; + + switch (keyBits) + { + case 128: + KC = 4; + break; + case 160: + KC = 5; + break; + case 192: + KC = 6; + break; + case 224: + KC = 7; + break; + case 256: + KC = 8; + break; + default : + throw new IllegalArgumentException("Key length not 128/160/192/224/256 bits."); + } + + if (keyBits >= blockBits) + { + ROUNDS = KC + 6; + } + else + { + ROUNDS = (BC / 8) + 6; + } + + // + // copy the key into the processing area + // + int index = 0; + + for (int i = 0; i < key.length; i++) + { + tk[i % 4][i / 4] = key[index++]; + } + + t = 0; + + // + // copy values into round key array + // + for (int j = 0; (j < KC) && (t < (ROUNDS+1)*(BC / 8)); j++, t++) + { + for (int i = 0; i < 4; i++) + { + W[t / (BC / 8)][i] |= (long)(tk[i][j] & 0xff) << ((t * 8) % BC); + } + } + + // + // while not enough round key material calculated + // calculate new values + // + while (t < (ROUNDS+1)*(BC/8)) + { + for (int i = 0; i < 4; i++) + { + tk[i][0] ^= S[tk[(i+1)%4][KC-1] & 0xff]; + } + tk[0][0] ^= rcon[rconpointer++]; + + if (KC <= 6) + { + for (int j = 1; j < KC; j++) + { + for (int i = 0; i < 4; i++) + { + tk[i][j] ^= tk[i][j-1]; + } + } + } + else + { + for (int j = 1; j < 4; j++) + { + for (int i = 0; i < 4; i++) + { + tk[i][j] ^= tk[i][j-1]; + } + } + for (int i = 0; i < 4; i++) + { + tk[i][4] ^= S[tk[i][3] & 0xff]; + } + for (int j = 5; j < KC; j++) + { + for (int i = 0; i < 4; i++) + { + tk[i][j] ^= tk[i][j-1]; + } + } + } + + // + // copy values into round key array + // + for (int j = 0; (j < KC) && (t < (ROUNDS+1)*(BC/8)); j++, t++) + { + for (int i = 0; i < 4; i++) + { + W[t / (BC/8)][i] |= (long)(tk[i][j] & 0xff) << ((t * 8) % (BC)); + } + } + } + + return W; + } + + private int BC; + private long BC_MASK; + private int ROUNDS; + private int blockBits; + private long[][] workingKey; + private long A0, A1, A2, A3; + private boolean forEncryption; + private byte[] shifts0SC; + private byte[] shifts1SC; + + /** + * default constructor - 128 bit block size. + */ + public RijndaelEngine() + { + this(128); + } + + /** + * basic constructor - set the cipher up for a given blocksize + * + * @param blockBits the blocksize in bits, must be 128, 192, or 256. + */ + public RijndaelEngine( + int blockBits) + { + switch (blockBits) + { + case 128: + BC = 32; + BC_MASK = 0xffffffffL; + shifts0SC = shifts0[0]; + shifts1SC = shifts1[0]; + break; + case 160: + BC = 40; + BC_MASK = 0xffffffffffL; + shifts0SC = shifts0[1]; + shifts1SC = shifts1[1]; + break; + case 192: + BC = 48; + BC_MASK = 0xffffffffffffL; + shifts0SC = shifts0[2]; + shifts1SC = shifts1[2]; + break; + case 224: + BC = 56; + BC_MASK = 0xffffffffffffffL; + shifts0SC = shifts0[3]; + shifts1SC = shifts1[3]; + break; + case 256: + BC = 64; + BC_MASK = 0xffffffffffffffffL; + shifts0SC = shifts0[4]; + shifts1SC = shifts1[4]; + break; + default: + throw new IllegalArgumentException("unknown blocksize to Rijndael"); + } + + this.blockBits = blockBits; + } + + /** + * initialise a Rijndael cipher. + * + * @param forEncryption whether or not we are for encryption. + * @param params the parameters required to set up the cipher. + * @exception IllegalArgumentException if the params argument is + * inappropriate. + */ + public void init( + boolean forEncryption, + CipherParameters params) + { + if (params instanceof KeyParameter) + { + workingKey = generateWorkingKey(((KeyParameter)params).getKey()); + this.forEncryption = forEncryption; + return; + } + + throw new IllegalArgumentException("invalid parameter passed to Rijndael init - " + params.getClass().getName()); + } + + public String getAlgorithmName() + { + return "Rijndael"; + } + + public int getBlockSize() + { + return BC / 2; + } + + public int processBlock( + byte[] in, + int inOff, + byte[] out, + int outOff) + { + if (workingKey == null) + { + throw new IllegalStateException("Rijndael engine not initialised"); + } + + if ((inOff + (BC / 2)) > in.length) + { + throw new DataLengthException("input buffer too short"); + } + + if ((outOff + (BC / 2)) > out.length) + { + throw new DataLengthException("output buffer too short"); + } + + if (forEncryption) + { + unpackBlock(in, inOff); + encryptBlock(workingKey); + packBlock(out, outOff); + } + else + { + unpackBlock(in, inOff); + decryptBlock(workingKey); + packBlock(out, outOff); + } + + return BC / 2; + } + + public void reset() + { + } + + private void unpackBlock( + byte[] bytes, + int off) + { + int index = off; + + A0 = (bytes[index++] & 0xff); + A1 = (bytes[index++] & 0xff); + A2 = (bytes[index++] & 0xff); + A3 = (bytes[index++] & 0xff); + + for (int j = 8; j != BC; j += 8) + { + A0 |= (long)(bytes[index++] & 0xff) << j; + A1 |= (long)(bytes[index++] & 0xff) << j; + A2 |= (long)(bytes[index++] & 0xff) << j; + A3 |= (long)(bytes[index++] & 0xff) << j; + } + } + + private void packBlock( + byte[] bytes, + int off) + { + int index = off; + + for (int j = 0; j != BC; j += 8) + { + bytes[index++] = (byte)(A0 >> j); + bytes[index++] = (byte)(A1 >> j); + bytes[index++] = (byte)(A2 >> j); + bytes[index++] = (byte)(A3 >> j); + } + } + + private void encryptBlock( + long[][] rk) + { + int r; + + // + // begin with a key addition + // + KeyAddition(rk[0]); + + // + // ROUNDS-1 ordinary rounds + // + for (r = 1; r < ROUNDS; r++) + { + Substitution(S); + ShiftRow(shifts0SC); + MixColumn(); + KeyAddition(rk[r]); + } + + // + // Last round is special: there is no MixColumn + // + Substitution(S); + ShiftRow(shifts0SC); + KeyAddition(rk[ROUNDS]); + } + + private void decryptBlock( + long[][] rk) + { + int r; + + // To decrypt: apply the inverse operations of the encrypt routine, + // in opposite order + // + // (KeyAddition is an involution: it 's equal to its inverse) + // (the inverse of Substitution with table S is Substitution with the inverse table of S) + // (the inverse of Shiftrow is Shiftrow over a suitable distance) + // + + // First the special round: + // without InvMixColumn + // with extra KeyAddition + // + KeyAddition(rk[ROUNDS]); + Substitution(Si); + ShiftRow(shifts1SC); + + // + // ROUNDS-1 ordinary rounds + // + for (r = ROUNDS-1; r > 0; r--) + { + KeyAddition(rk[r]); + InvMixColumn(); + Substitution(Si); + ShiftRow(shifts1SC); + } + + // + // End with the extra key addition + // + KeyAddition(rk[0]); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/SEEDEngine.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/SEEDEngine.java new file mode 100644 index 0000000..0d45e92 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/SEEDEngine.java @@ -0,0 +1,345 @@ +package org.bc.crypto.engines; + +import org.bc.crypto.BlockCipher; +import org.bc.crypto.CipherParameters; +import org.bc.crypto.DataLengthException; +import org.bc.crypto.params.KeyParameter; + +/** + * Implementation of the SEED algorithm as described in RFC 4009 + */ +public class SEEDEngine + implements BlockCipher +{ + private final int BLOCK_SIZE = 16; + + private static final int[] SS0 = + { + 0x2989a1a8, 0x05858184, 0x16c6d2d4, 0x13c3d3d0, 0x14445054, 0x1d0d111c, 0x2c8ca0ac, 0x25052124, + 0x1d4d515c, 0x03434340, 0x18081018, 0x1e0e121c, 0x11415150, 0x3cccf0fc, 0x0acac2c8, 0x23436360, + 0x28082028, 0x04444044, 0x20002020, 0x1d8d919c, 0x20c0e0e0, 0x22c2e2e0, 0x08c8c0c8, 0x17071314, + 0x2585a1a4, 0x0f8f838c, 0x03030300, 0x3b4b7378, 0x3b8bb3b8, 0x13031310, 0x12c2d2d0, 0x2ecee2ec, + 0x30407070, 0x0c8c808c, 0x3f0f333c, 0x2888a0a8, 0x32023230, 0x1dcdd1dc, 0x36c6f2f4, 0x34447074, + 0x2ccce0ec, 0x15859194, 0x0b0b0308, 0x17475354, 0x1c4c505c, 0x1b4b5358, 0x3d8db1bc, 0x01010100, + 0x24042024, 0x1c0c101c, 0x33437370, 0x18889098, 0x10001010, 0x0cccc0cc, 0x32c2f2f0, 0x19c9d1d8, + 0x2c0c202c, 0x27c7e3e4, 0x32427270, 0x03838380, 0x1b8b9398, 0x11c1d1d0, 0x06868284, 0x09c9c1c8, + 0x20406060, 0x10405050, 0x2383a3a0, 0x2bcbe3e8, 0x0d0d010c, 0x3686b2b4, 0x1e8e929c, 0x0f4f434c, + 0x3787b3b4, 0x1a4a5258, 0x06c6c2c4, 0x38487078, 0x2686a2a4, 0x12021210, 0x2f8fa3ac, 0x15c5d1d4, + 0x21416160, 0x03c3c3c0, 0x3484b0b4, 0x01414140, 0x12425250, 0x3d4d717c, 0x0d8d818c, 0x08080008, + 0x1f0f131c, 0x19899198, 0x00000000, 0x19091118, 0x04040004, 0x13435350, 0x37c7f3f4, 0x21c1e1e0, + 0x3dcdf1fc, 0x36467274, 0x2f0f232c, 0x27072324, 0x3080b0b0, 0x0b8b8388, 0x0e0e020c, 0x2b8ba3a8, + 0x2282a2a0, 0x2e4e626c, 0x13839390, 0x0d4d414c, 0x29496168, 0x3c4c707c, 0x09090108, 0x0a0a0208, + 0x3f8fb3bc, 0x2fcfe3ec, 0x33c3f3f0, 0x05c5c1c4, 0x07878384, 0x14041014, 0x3ecef2fc, 0x24446064, + 0x1eced2dc, 0x2e0e222c, 0x0b4b4348, 0x1a0a1218, 0x06060204, 0x21012120, 0x2b4b6368, 0x26466264, + 0x02020200, 0x35c5f1f4, 0x12829290, 0x0a8a8288, 0x0c0c000c, 0x3383b3b0, 0x3e4e727c, 0x10c0d0d0, + 0x3a4a7278, 0x07474344, 0x16869294, 0x25c5e1e4, 0x26062224, 0x00808080, 0x2d8da1ac, 0x1fcfd3dc, + 0x2181a1a0, 0x30003030, 0x37073334, 0x2e8ea2ac, 0x36063234, 0x15051114, 0x22022220, 0x38083038, + 0x34c4f0f4, 0x2787a3a4, 0x05454144, 0x0c4c404c, 0x01818180, 0x29c9e1e8, 0x04848084, 0x17879394, + 0x35053134, 0x0bcbc3c8, 0x0ecec2cc, 0x3c0c303c, 0x31417170, 0x11011110, 0x07c7c3c4, 0x09898188, + 0x35457174, 0x3bcbf3f8, 0x1acad2d8, 0x38c8f0f8, 0x14849094, 0x19495158, 0x02828280, 0x04c4c0c4, + 0x3fcff3fc, 0x09494148, 0x39093138, 0x27476364, 0x00c0c0c0, 0x0fcfc3cc, 0x17c7d3d4, 0x3888b0b8, + 0x0f0f030c, 0x0e8e828c, 0x02424240, 0x23032320, 0x11819190, 0x2c4c606c, 0x1bcbd3d8, 0x2484a0a4, + 0x34043034, 0x31c1f1f0, 0x08484048, 0x02c2c2c0, 0x2f4f636c, 0x3d0d313c, 0x2d0d212c, 0x00404040, + 0x3e8eb2bc, 0x3e0e323c, 0x3c8cb0bc, 0x01c1c1c0, 0x2a8aa2a8, 0x3a8ab2b8, 0x0e4e424c, 0x15455154, + 0x3b0b3338, 0x1cccd0dc, 0x28486068, 0x3f4f737c, 0x1c8c909c, 0x18c8d0d8, 0x0a4a4248, 0x16465254, + 0x37477374, 0x2080a0a0, 0x2dcde1ec, 0x06464244, 0x3585b1b4, 0x2b0b2328, 0x25456164, 0x3acaf2f8, + 0x23c3e3e0, 0x3989b1b8, 0x3181b1b0, 0x1f8f939c, 0x1e4e525c, 0x39c9f1f8, 0x26c6e2e4, 0x3282b2b0, + 0x31013130, 0x2acae2e8, 0x2d4d616c, 0x1f4f535c, 0x24c4e0e4, 0x30c0f0f0, 0x0dcdc1cc, 0x08888088, + 0x16061214, 0x3a0a3238, 0x18485058, 0x14c4d0d4, 0x22426260, 0x29092128, 0x07070304, 0x33033330, + 0x28c8e0e8, 0x1b0b1318, 0x05050104, 0x39497178, 0x10809090, 0x2a4a6268, 0x2a0a2228, 0x1a8a9298 + }; + + private static final int[] SS1 = + { + + 0x38380830, 0xe828c8e0, 0x2c2d0d21, 0xa42686a2, 0xcc0fcfc3, 0xdc1eced2, 0xb03383b3, 0xb83888b0, + 0xac2f8fa3, 0x60204060, 0x54154551, 0xc407c7c3, 0x44044440, 0x6c2f4f63, 0x682b4b63, 0x581b4b53, + 0xc003c3c3, 0x60224262, 0x30330333, 0xb43585b1, 0x28290921, 0xa02080a0, 0xe022c2e2, 0xa42787a3, + 0xd013c3d3, 0x90118191, 0x10110111, 0x04060602, 0x1c1c0c10, 0xbc3c8cb0, 0x34360632, 0x480b4b43, + 0xec2fcfe3, 0x88088880, 0x6c2c4c60, 0xa82888a0, 0x14170713, 0xc404c4c0, 0x14160612, 0xf434c4f0, + 0xc002c2c2, 0x44054541, 0xe021c1e1, 0xd416c6d2, 0x3c3f0f33, 0x3c3d0d31, 0x8c0e8e82, 0x98188890, + 0x28280820, 0x4c0e4e42, 0xf436c6f2, 0x3c3e0e32, 0xa42585a1, 0xf839c9f1, 0x0c0d0d01, 0xdc1fcfd3, + 0xd818c8d0, 0x282b0b23, 0x64264662, 0x783a4a72, 0x24270723, 0x2c2f0f23, 0xf031c1f1, 0x70324272, + 0x40024242, 0xd414c4d0, 0x40014141, 0xc000c0c0, 0x70334373, 0x64274763, 0xac2c8ca0, 0x880b8b83, + 0xf437c7f3, 0xac2d8da1, 0x80008080, 0x1c1f0f13, 0xc80acac2, 0x2c2c0c20, 0xa82a8aa2, 0x34340430, + 0xd012c2d2, 0x080b0b03, 0xec2ecee2, 0xe829c9e1, 0x5c1d4d51, 0x94148490, 0x18180810, 0xf838c8f0, + 0x54174753, 0xac2e8ea2, 0x08080800, 0xc405c5c1, 0x10130313, 0xcc0dcdc1, 0x84068682, 0xb83989b1, + 0xfc3fcff3, 0x7c3d4d71, 0xc001c1c1, 0x30310131, 0xf435c5f1, 0x880a8a82, 0x682a4a62, 0xb03181b1, + 0xd011c1d1, 0x20200020, 0xd417c7d3, 0x00020202, 0x20220222, 0x04040400, 0x68284860, 0x70314171, + 0x04070703, 0xd81bcbd3, 0x9c1d8d91, 0x98198991, 0x60214161, 0xbc3e8eb2, 0xe426c6e2, 0x58194951, + 0xdc1dcdd1, 0x50114151, 0x90108090, 0xdc1cccd0, 0x981a8a92, 0xa02383a3, 0xa82b8ba3, 0xd010c0d0, + 0x80018181, 0x0c0f0f03, 0x44074743, 0x181a0a12, 0xe023c3e3, 0xec2ccce0, 0x8c0d8d81, 0xbc3f8fb3, + 0x94168692, 0x783b4b73, 0x5c1c4c50, 0xa02282a2, 0xa02181a1, 0x60234363, 0x20230323, 0x4c0d4d41, + 0xc808c8c0, 0x9c1e8e92, 0x9c1c8c90, 0x383a0a32, 0x0c0c0c00, 0x2c2e0e22, 0xb83a8ab2, 0x6c2e4e62, + 0x9c1f8f93, 0x581a4a52, 0xf032c2f2, 0x90128292, 0xf033c3f3, 0x48094941, 0x78384870, 0xcc0cccc0, + 0x14150511, 0xf83bcbf3, 0x70304070, 0x74354571, 0x7c3f4f73, 0x34350531, 0x10100010, 0x00030303, + 0x64244460, 0x6c2d4d61, 0xc406c6c2, 0x74344470, 0xd415c5d1, 0xb43484b0, 0xe82acae2, 0x08090901, + 0x74364672, 0x18190911, 0xfc3ecef2, 0x40004040, 0x10120212, 0xe020c0e0, 0xbc3d8db1, 0x04050501, + 0xf83acaf2, 0x00010101, 0xf030c0f0, 0x282a0a22, 0x5c1e4e52, 0xa82989a1, 0x54164652, 0x40034343, + 0x84058581, 0x14140410, 0x88098981, 0x981b8b93, 0xb03080b0, 0xe425c5e1, 0x48084840, 0x78394971, + 0x94178793, 0xfc3cccf0, 0x1c1e0e12, 0x80028282, 0x20210121, 0x8c0c8c80, 0x181b0b13, 0x5c1f4f53, + 0x74374773, 0x54144450, 0xb03282b2, 0x1c1d0d11, 0x24250521, 0x4c0f4f43, 0x00000000, 0x44064642, + 0xec2dcde1, 0x58184850, 0x50124252, 0xe82bcbe3, 0x7c3e4e72, 0xd81acad2, 0xc809c9c1, 0xfc3dcdf1, + 0x30300030, 0x94158591, 0x64254561, 0x3c3c0c30, 0xb43686b2, 0xe424c4e0, 0xb83b8bb3, 0x7c3c4c70, + 0x0c0e0e02, 0x50104050, 0x38390931, 0x24260622, 0x30320232, 0x84048480, 0x68294961, 0x90138393, + 0x34370733, 0xe427c7e3, 0x24240420, 0xa42484a0, 0xc80bcbc3, 0x50134353, 0x080a0a02, 0x84078783, + 0xd819c9d1, 0x4c0c4c40, 0x80038383, 0x8c0f8f83, 0xcc0ecec2, 0x383b0b33, 0x480a4a42, 0xb43787b3 + }; + + private static final int[] SS2 = + { + + 0xa1a82989, 0x81840585, 0xd2d416c6, 0xd3d013c3, 0x50541444, 0x111c1d0d, 0xa0ac2c8c, 0x21242505, + 0x515c1d4d, 0x43400343, 0x10181808, 0x121c1e0e, 0x51501141, 0xf0fc3ccc, 0xc2c80aca, 0x63602343, + 0x20282808, 0x40440444, 0x20202000, 0x919c1d8d, 0xe0e020c0, 0xe2e022c2, 0xc0c808c8, 0x13141707, + 0xa1a42585, 0x838c0f8f, 0x03000303, 0x73783b4b, 0xb3b83b8b, 0x13101303, 0xd2d012c2, 0xe2ec2ece, + 0x70703040, 0x808c0c8c, 0x333c3f0f, 0xa0a82888, 0x32303202, 0xd1dc1dcd, 0xf2f436c6, 0x70743444, + 0xe0ec2ccc, 0x91941585, 0x03080b0b, 0x53541747, 0x505c1c4c, 0x53581b4b, 0xb1bc3d8d, 0x01000101, + 0x20242404, 0x101c1c0c, 0x73703343, 0x90981888, 0x10101000, 0xc0cc0ccc, 0xf2f032c2, 0xd1d819c9, + 0x202c2c0c, 0xe3e427c7, 0x72703242, 0x83800383, 0x93981b8b, 0xd1d011c1, 0x82840686, 0xc1c809c9, + 0x60602040, 0x50501040, 0xa3a02383, 0xe3e82bcb, 0x010c0d0d, 0xb2b43686, 0x929c1e8e, 0x434c0f4f, + 0xb3b43787, 0x52581a4a, 0xc2c406c6, 0x70783848, 0xa2a42686, 0x12101202, 0xa3ac2f8f, 0xd1d415c5, + 0x61602141, 0xc3c003c3, 0xb0b43484, 0x41400141, 0x52501242, 0x717c3d4d, 0x818c0d8d, 0x00080808, + 0x131c1f0f, 0x91981989, 0x00000000, 0x11181909, 0x00040404, 0x53501343, 0xf3f437c7, 0xe1e021c1, + 0xf1fc3dcd, 0x72743646, 0x232c2f0f, 0x23242707, 0xb0b03080, 0x83880b8b, 0x020c0e0e, 0xa3a82b8b, + 0xa2a02282, 0x626c2e4e, 0x93901383, 0x414c0d4d, 0x61682949, 0x707c3c4c, 0x01080909, 0x02080a0a, + 0xb3bc3f8f, 0xe3ec2fcf, 0xf3f033c3, 0xc1c405c5, 0x83840787, 0x10141404, 0xf2fc3ece, 0x60642444, + 0xd2dc1ece, 0x222c2e0e, 0x43480b4b, 0x12181a0a, 0x02040606, 0x21202101, 0x63682b4b, 0x62642646, + 0x02000202, 0xf1f435c5, 0x92901282, 0x82880a8a, 0x000c0c0c, 0xb3b03383, 0x727c3e4e, 0xd0d010c0, + 0x72783a4a, 0x43440747, 0x92941686, 0xe1e425c5, 0x22242606, 0x80800080, 0xa1ac2d8d, 0xd3dc1fcf, + 0xa1a02181, 0x30303000, 0x33343707, 0xa2ac2e8e, 0x32343606, 0x11141505, 0x22202202, 0x30383808, + 0xf0f434c4, 0xa3a42787, 0x41440545, 0x404c0c4c, 0x81800181, 0xe1e829c9, 0x80840484, 0x93941787, + 0x31343505, 0xc3c80bcb, 0xc2cc0ece, 0x303c3c0c, 0x71703141, 0x11101101, 0xc3c407c7, 0x81880989, + 0x71743545, 0xf3f83bcb, 0xd2d81aca, 0xf0f838c8, 0x90941484, 0x51581949, 0x82800282, 0xc0c404c4, + 0xf3fc3fcf, 0x41480949, 0x31383909, 0x63642747, 0xc0c000c0, 0xc3cc0fcf, 0xd3d417c7, 0xb0b83888, + 0x030c0f0f, 0x828c0e8e, 0x42400242, 0x23202303, 0x91901181, 0x606c2c4c, 0xd3d81bcb, 0xa0a42484, + 0x30343404, 0xf1f031c1, 0x40480848, 0xc2c002c2, 0x636c2f4f, 0x313c3d0d, 0x212c2d0d, 0x40400040, + 0xb2bc3e8e, 0x323c3e0e, 0xb0bc3c8c, 0xc1c001c1, 0xa2a82a8a, 0xb2b83a8a, 0x424c0e4e, 0x51541545, + 0x33383b0b, 0xd0dc1ccc, 0x60682848, 0x737c3f4f, 0x909c1c8c, 0xd0d818c8, 0x42480a4a, 0x52541646, + 0x73743747, 0xa0a02080, 0xe1ec2dcd, 0x42440646, 0xb1b43585, 0x23282b0b, 0x61642545, 0xf2f83aca, + 0xe3e023c3, 0xb1b83989, 0xb1b03181, 0x939c1f8f, 0x525c1e4e, 0xf1f839c9, 0xe2e426c6, 0xb2b03282, + 0x31303101, 0xe2e82aca, 0x616c2d4d, 0x535c1f4f, 0xe0e424c4, 0xf0f030c0, 0xc1cc0dcd, 0x80880888, + 0x12141606, 0x32383a0a, 0x50581848, 0xd0d414c4, 0x62602242, 0x21282909, 0x03040707, 0x33303303, + 0xe0e828c8, 0x13181b0b, 0x01040505, 0x71783949, 0x90901080, 0x62682a4a, 0x22282a0a, 0x92981a8a + }; + + + private static final int[] SS3 = + { + + 0x08303838, 0xc8e0e828, 0x0d212c2d, 0x86a2a426, 0xcfc3cc0f, 0xced2dc1e, 0x83b3b033, 0x88b0b838, + 0x8fa3ac2f, 0x40606020, 0x45515415, 0xc7c3c407, 0x44404404, 0x4f636c2f, 0x4b63682b, 0x4b53581b, + 0xc3c3c003, 0x42626022, 0x03333033, 0x85b1b435, 0x09212829, 0x80a0a020, 0xc2e2e022, 0x87a3a427, + 0xc3d3d013, 0x81919011, 0x01111011, 0x06020406, 0x0c101c1c, 0x8cb0bc3c, 0x06323436, 0x4b43480b, + 0xcfe3ec2f, 0x88808808, 0x4c606c2c, 0x88a0a828, 0x07131417, 0xc4c0c404, 0x06121416, 0xc4f0f434, + 0xc2c2c002, 0x45414405, 0xc1e1e021, 0xc6d2d416, 0x0f333c3f, 0x0d313c3d, 0x8e828c0e, 0x88909818, + 0x08202828, 0x4e424c0e, 0xc6f2f436, 0x0e323c3e, 0x85a1a425, 0xc9f1f839, 0x0d010c0d, 0xcfd3dc1f, + 0xc8d0d818, 0x0b23282b, 0x46626426, 0x4a72783a, 0x07232427, 0x0f232c2f, 0xc1f1f031, 0x42727032, + 0x42424002, 0xc4d0d414, 0x41414001, 0xc0c0c000, 0x43737033, 0x47636427, 0x8ca0ac2c, 0x8b83880b, + 0xc7f3f437, 0x8da1ac2d, 0x80808000, 0x0f131c1f, 0xcac2c80a, 0x0c202c2c, 0x8aa2a82a, 0x04303434, + 0xc2d2d012, 0x0b03080b, 0xcee2ec2e, 0xc9e1e829, 0x4d515c1d, 0x84909414, 0x08101818, 0xc8f0f838, + 0x47535417, 0x8ea2ac2e, 0x08000808, 0xc5c1c405, 0x03131013, 0xcdc1cc0d, 0x86828406, 0x89b1b839, + 0xcff3fc3f, 0x4d717c3d, 0xc1c1c001, 0x01313031, 0xc5f1f435, 0x8a82880a, 0x4a62682a, 0x81b1b031, + 0xc1d1d011, 0x00202020, 0xc7d3d417, 0x02020002, 0x02222022, 0x04000404, 0x48606828, 0x41717031, + 0x07030407, 0xcbd3d81b, 0x8d919c1d, 0x89919819, 0x41616021, 0x8eb2bc3e, 0xc6e2e426, 0x49515819, + 0xcdd1dc1d, 0x41515011, 0x80909010, 0xccd0dc1c, 0x8a92981a, 0x83a3a023, 0x8ba3a82b, 0xc0d0d010, + 0x81818001, 0x0f030c0f, 0x47434407, 0x0a12181a, 0xc3e3e023, 0xcce0ec2c, 0x8d818c0d, 0x8fb3bc3f, + 0x86929416, 0x4b73783b, 0x4c505c1c, 0x82a2a022, 0x81a1a021, 0x43636023, 0x03232023, 0x4d414c0d, + 0xc8c0c808, 0x8e929c1e, 0x8c909c1c, 0x0a32383a, 0x0c000c0c, 0x0e222c2e, 0x8ab2b83a, 0x4e626c2e, + 0x8f939c1f, 0x4a52581a, 0xc2f2f032, 0x82929012, 0xc3f3f033, 0x49414809, 0x48707838, 0xccc0cc0c, + 0x05111415, 0xcbf3f83b, 0x40707030, 0x45717435, 0x4f737c3f, 0x05313435, 0x00101010, 0x03030003, + 0x44606424, 0x4d616c2d, 0xc6c2c406, 0x44707434, 0xc5d1d415, 0x84b0b434, 0xcae2e82a, 0x09010809, + 0x46727436, 0x09111819, 0xcef2fc3e, 0x40404000, 0x02121012, 0xc0e0e020, 0x8db1bc3d, 0x05010405, + 0xcaf2f83a, 0x01010001, 0xc0f0f030, 0x0a22282a, 0x4e525c1e, 0x89a1a829, 0x46525416, 0x43434003, + 0x85818405, 0x04101414, 0x89818809, 0x8b93981b, 0x80b0b030, 0xc5e1e425, 0x48404808, 0x49717839, + 0x87939417, 0xccf0fc3c, 0x0e121c1e, 0x82828002, 0x01212021, 0x8c808c0c, 0x0b13181b, 0x4f535c1f, + 0x47737437, 0x44505414, 0x82b2b032, 0x0d111c1d, 0x05212425, 0x4f434c0f, 0x00000000, 0x46424406, + 0xcde1ec2d, 0x48505818, 0x42525012, 0xcbe3e82b, 0x4e727c3e, 0xcad2d81a, 0xc9c1c809, 0xcdf1fc3d, + 0x00303030, 0x85919415, 0x45616425, 0x0c303c3c, 0x86b2b436, 0xc4e0e424, 0x8bb3b83b, 0x4c707c3c, + 0x0e020c0e, 0x40505010, 0x09313839, 0x06222426, 0x02323032, 0x84808404, 0x49616829, 0x83939013, + 0x07333437, 0xc7e3e427, 0x04202424, 0x84a0a424, 0xcbc3c80b, 0x43535013, 0x0a02080a, 0x87838407, + 0xc9d1d819, 0x4c404c0c, 0x83838003, 0x8f838c0f, 0xcec2cc0e, 0x0b33383b, 0x4a42480a, 0x87b3b437 + }; + + + private static final int[] KC = + { + 0x9e3779b9, 0x3c6ef373, 0x78dde6e6, 0xf1bbcdcc, + 0xe3779b99, 0xc6ef3733, 0x8dde6e67, 0x1bbcdccf, + 0x3779b99e, 0x6ef3733c, 0xdde6e678, 0xbbcdccf1, + 0x779b99e3, 0xef3733c6, 0xde6e678d, 0xbcdccf1b + }; + + private int[] wKey; + private boolean forEncryption; + + public void init(boolean forEncryption, CipherParameters params) throws IllegalArgumentException + { + this.forEncryption = forEncryption; + wKey = createWorkingKey(((KeyParameter)params).getKey()); + } + + public String getAlgorithmName() + { + return "SEED"; + } + + public int getBlockSize() + { + return BLOCK_SIZE; + } + + public int processBlock(byte[] in, int inOff, byte[] out, int outOff) throws DataLengthException, IllegalStateException + { + if (wKey == null) + { + throw new IllegalStateException("SEED engine not initialised"); + } + + if (inOff + BLOCK_SIZE > in.length) + { + throw new DataLengthException("input buffer too short"); + } + + if (outOff + BLOCK_SIZE > out.length) + { + throw new DataLengthException("output buffer too short"); + } + + long l = bytesToLong(in, inOff + 0); + long r = bytesToLong(in, inOff + 8); + + if (forEncryption) + { + for (int i = 0; i < 16; i++) + { + long nl = r; + + r = l ^ F(wKey[2 * i], wKey[(2 * i) + 1], r); + l = nl; + } + } + else + { + for (int i = 15; i >= 0; i--) + { + long nl = r; + + r = l ^ F(wKey[2 * i], wKey[(2 * i) + 1], r); + l = nl; + } + } + + longToBytes(out, outOff + 0, r); + longToBytes(out, outOff + 8, l); + + return BLOCK_SIZE; + } + + public void reset() + { + } + + private int[] createWorkingKey(byte[] inKey) + { + int[] key = new int[32]; + long lower = bytesToLong(inKey, 0); + long upper = bytesToLong(inKey, 8); + + int key0 = extractW0(lower); + int key1 = extractW1(lower); + int key2 = extractW0(upper); + int key3 = extractW1(upper); + + for (int i = 0; i < 16; i++) + { + key[2 * i] = G(key0 + key2 - KC[i]); + key[2 * i + 1] = G(key1 - key3 + KC[i]); + + if (i % 2 == 0) + { + lower = rotateRight8(lower); + key0 = extractW0(lower); + key1 = extractW1(lower); + } + else + { + upper = rotateLeft8(upper); + key2 = extractW0(upper); + key3 = extractW1(upper); + } + } + + return key; + } + + private int extractW1(long lVal) + { + return (int)lVal; + } + + private int extractW0(long lVal) + { + return (int)(lVal >> 32); + } + + private long rotateLeft8(long x) + { + return (x << 8) | (x >>> 56); + } + + private long rotateRight8(long x) + { + return (x >>> 8) | (x << 56); + } + + private long bytesToLong( + byte[] src, + int srcOff) + { + long word = 0; + + for (int i = 0; i <= 7; i++) + { + word = (word << 8) + (src[i + srcOff] & 0xff); + } + + return word; + } + + private void longToBytes( + byte[] dest, + int destOff, + long value) + { + for (int i = 0; i < 8; i++) + { + dest[i + destOff] = (byte)(value >> ((7 - i) * 8)); + } + } + + private int G(int x) + { + return SS0[x & 0xff] ^ SS1[(x >> 8) & 0xff] ^ SS2[(x >> 16) & 0xff] ^ SS3[(x >> 24) & 0xff]; + } + + private long F(int ki0, int ki1, long r) + { + int r0 = (int)(r >> 32); + int r1 = (int)r; + int rd1 = phaseCalc2(r0, ki0, r1, ki1); + int rd0 = rd1 + phaseCalc1(r0, ki0, r1, ki1); + + return ((long)rd0 << 32) | (rd1 & 0xffffffffL); + } + + private int phaseCalc1(int r0, int ki0, int r1, int ki1) + { + return G(G((r0 ^ ki0) ^ (r1 ^ ki1)) + (r0 ^ ki0)); + } + + private int phaseCalc2(int r0, int ki0, int r1, int ki1) + { + return G(phaseCalc1(r0, ki0, r1, ki1) + G((r0 ^ ki0) ^ (r1 ^ ki1))); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/SEEDWrapEngine.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/SEEDWrapEngine.java new file mode 100644 index 0000000..3b3adb9 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/SEEDWrapEngine.java @@ -0,0 +1,15 @@ +package org.bc.crypto.engines; + +/** + * An implementation of the SEED key wrapper based on RFC 4010/RFC 3394. + *
+ * For further details see: http://www.ietf.org/rfc/rfc4010.txt. + */ +public class SEEDWrapEngine + extends RFC3394WrapEngine +{ + public SEEDWrapEngine() + { + super(new SEEDEngine()); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/Salsa20Engine.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/Salsa20Engine.java new file mode 100644 index 0000000..ef3143f --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/Salsa20Engine.java @@ -0,0 +1,320 @@ +package org.bc.crypto.engines; + +import org.bc.crypto.CipherParameters; +import org.bc.crypto.DataLengthException; +import org.bc.crypto.MaxBytesExceededException; +import org.bc.crypto.StreamCipher; +import org.bc.crypto.params.KeyParameter; +import org.bc.crypto.params.ParametersWithIV; +import org.bc.crypto.util.Pack; +import org.bc.util.Strings; + +/** + * Implementation of Daniel J. Bernstein's Salsa20 stream cipher, Snuffle 2005 + */ + +public class Salsa20Engine + implements StreamCipher +{ + /** Constants */ + private final static int STATE_SIZE = 16; // 16, 32 bit ints = 64 bytes + + private final static byte[] + sigma = Strings.toByteArray("expand 32-byte k"), + tau = Strings.toByteArray("expand 16-byte k"); + + /* + * variables to hold the state of the engine + * during encryption and decryption + */ + private int index = 0; + private int[] engineState = new int[STATE_SIZE]; // state + private int[] x = new int[STATE_SIZE] ; // internal buffer + private byte[] keyStream = new byte[STATE_SIZE * 4], // expanded state, 64 bytes + workingKey = null, + workingIV = null; + private boolean initialised = false; + + /* + * internal counter + */ + private int cW0, cW1, cW2; + + /** + * initialise a Salsa20 cipher. + * + * @param forEncryption whether or not we are for encryption. + * @param params the parameters required to set up the cipher. + * @exception IllegalArgumentException if the params argument is + * inappropriate. + */ + public void init( + boolean forEncryption, + CipherParameters params) + { + /* + * Salsa20 encryption and decryption is completely + * symmetrical, so the 'forEncryption' is + * irrelevant. (Like 90% of stream ciphers) + */ + + if (!(params instanceof ParametersWithIV)) + { + throw new IllegalArgumentException("Salsa20 Init parameters must include an IV"); + } + + ParametersWithIV ivParams = (ParametersWithIV) params; + + byte[] iv = ivParams.getIV(); + + if (iv == null || iv.length != 8) + { + throw new IllegalArgumentException("Salsa20 requires exactly 8 bytes of IV"); + } + + if (!(ivParams.getParameters() instanceof KeyParameter)) + { + throw new IllegalArgumentException("Salsa20 Init parameters must include a key"); + } + + KeyParameter key = (KeyParameter) ivParams.getParameters(); + + workingKey = key.getKey(); + workingIV = iv; + + setKey(workingKey, workingIV); + } + + public String getAlgorithmName() + { + return "Salsa20"; + } + + public byte returnByte(byte in) + { + if (limitExceeded()) + { + throw new MaxBytesExceededException("2^70 byte limit per IV; Change IV"); + } + + if (index == 0) + { + generateKeyStream(keyStream); + + if (++engineState[8] == 0) + { + ++engineState[9]; + } + } + + byte out = (byte)(keyStream[index]^in); + index = (index + 1) & 63; + + return out; + } + + public void processBytes( + byte[] in, + int inOff, + int len, + byte[] out, + int outOff) + { + if (!initialised) + { + throw new IllegalStateException(getAlgorithmName()+" not initialised"); + } + + if ((inOff + len) > in.length) + { + throw new DataLengthException("input buffer too short"); + } + + if ((outOff + len) > out.length) + { + throw new DataLengthException("output buffer too short"); + } + + if (limitExceeded(len)) + { + throw new MaxBytesExceededException("2^70 byte limit per IV would be exceeded; Change IV"); + } + + for (int i = 0; i < len; i++) + { + if (index == 0) + { + generateKeyStream(keyStream); + + if (++engineState[8] == 0) + { + ++engineState[9]; + } + } + + out[i+outOff] = (byte)(keyStream[index]^in[i+inOff]); + index = (index + 1) & 63; + } + } + + public void reset() + { + setKey(workingKey, workingIV); + } + + // Private implementation + + private void setKey(byte[] keyBytes, byte[] ivBytes) + { + workingKey = keyBytes; + workingIV = ivBytes; + + index = 0; + resetCounter(); + int offset = 0; + byte[] constants; + + // Key + engineState[1] = Pack.littleEndianToInt(workingKey, 0); + engineState[2] = Pack.littleEndianToInt(workingKey, 4); + engineState[3] = Pack.littleEndianToInt(workingKey, 8); + engineState[4] = Pack.littleEndianToInt(workingKey, 12); + + if (workingKey.length == 32) + { + constants = sigma; + offset = 16; + } + else + { + constants = tau; + } + + engineState[11] = Pack.littleEndianToInt(workingKey, offset); + engineState[12] = Pack.littleEndianToInt(workingKey, offset+4); + engineState[13] = Pack.littleEndianToInt(workingKey, offset+8); + engineState[14] = Pack.littleEndianToInt(workingKey, offset+12); + engineState[0 ] = Pack.littleEndianToInt(constants, 0); + engineState[5 ] = Pack.littleEndianToInt(constants, 4); + engineState[10] = Pack.littleEndianToInt(constants, 8); + engineState[15] = Pack.littleEndianToInt(constants, 12); + + // IV + engineState[6] = Pack.littleEndianToInt(workingIV, 0); + engineState[7] = Pack.littleEndianToInt(workingIV, 4); + engineState[8] = engineState[9] = 0; + + initialised = true; + } + + private void generateKeyStream(byte[] output) + { + salsaCore(20, engineState, x); + Pack.intToLittleEndian(x, output, 0); + } + + /** + * Salsa20 function + * + * @param input input data + * + * @return keystream + */ + public static void salsaCore(int rounds, int[] input, int[] x) + { + // TODO Exception if rounds odd? + + System.arraycopy(input, 0, x, 0, input.length); + + for (int i = rounds; i > 0; i -= 2) + { + x[ 4] ^= rotl((x[ 0]+x[12]), 7); + x[ 8] ^= rotl((x[ 4]+x[ 0]), 9); + x[12] ^= rotl((x[ 8]+x[ 4]),13); + x[ 0] ^= rotl((x[12]+x[ 8]),18); + x[ 9] ^= rotl((x[ 5]+x[ 1]), 7); + x[13] ^= rotl((x[ 9]+x[ 5]), 9); + x[ 1] ^= rotl((x[13]+x[ 9]),13); + x[ 5] ^= rotl((x[ 1]+x[13]),18); + x[14] ^= rotl((x[10]+x[ 6]), 7); + x[ 2] ^= rotl((x[14]+x[10]), 9); + x[ 6] ^= rotl((x[ 2]+x[14]),13); + x[10] ^= rotl((x[ 6]+x[ 2]),18); + x[ 3] ^= rotl((x[15]+x[11]), 7); + x[ 7] ^= rotl((x[ 3]+x[15]), 9); + x[11] ^= rotl((x[ 7]+x[ 3]),13); + x[15] ^= rotl((x[11]+x[ 7]),18); + x[ 1] ^= rotl((x[ 0]+x[ 3]), 7); + x[ 2] ^= rotl((x[ 1]+x[ 0]), 9); + x[ 3] ^= rotl((x[ 2]+x[ 1]),13); + x[ 0] ^= rotl((x[ 3]+x[ 2]),18); + x[ 6] ^= rotl((x[ 5]+x[ 4]), 7); + x[ 7] ^= rotl((x[ 6]+x[ 5]), 9); + x[ 4] ^= rotl((x[ 7]+x[ 6]),13); + x[ 5] ^= rotl((x[ 4]+x[ 7]),18); + x[11] ^= rotl((x[10]+x[ 9]), 7); + x[ 8] ^= rotl((x[11]+x[10]), 9); + x[ 9] ^= rotl((x[ 8]+x[11]),13); + x[10] ^= rotl((x[ 9]+x[ 8]),18); + x[12] ^= rotl((x[15]+x[14]), 7); + x[13] ^= rotl((x[12]+x[15]), 9); + x[14] ^= rotl((x[13]+x[12]),13); + x[15] ^= rotl((x[14]+x[13]),18); + } + + for (int i = 0; i < STATE_SIZE; ++i) + { + x[i] += input[i]; + } + } + + /** + * Rotate left + * + * @param x value to rotate + * @param y amount to rotate x + * + * @return rotated x + */ + private static int rotl(int x, int y) + { + return (x << y) | (x >>> -y); + } + + private void resetCounter() + { + cW0 = 0; + cW1 = 0; + cW2 = 0; + } + + private boolean limitExceeded() + { + if (++cW0 == 0) + { + if (++cW1 == 0) + { + return (++cW2 & 0x20) != 0; // 2^(32 + 32 + 6) + } + } + + return false; + } + + /* + * this relies on the fact len will always be positive. + */ + private boolean limitExceeded(int len) + { + cW0 += len; + if (cW0 < len && cW0 >= 0) + { + if (++cW1 == 0) + { + return (++cW2 & 0x20) != 0; // 2^(32 + 32 + 6) + } + } + + return false; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/SerpentEngine.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/SerpentEngine.java new file mode 100644 index 0000000..d38d076 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/SerpentEngine.java @@ -0,0 +1,782 @@ +package org.bc.crypto.engines; + +import org.bc.crypto.BlockCipher; +import org.bc.crypto.CipherParameters; +import org.bc.crypto.DataLengthException; +import org.bc.crypto.params.KeyParameter; + +/** + * Serpent is a 128-bit 32-round block cipher with variable key lengths, + * including 128, 192 and 256 bit keys conjectured to be at least as + * secure as three-key triple-DES. + *
+ * Serpent was designed by Ross Anderson, Eli Biham and Lars Knudsen as a + * candidate algorithm for the NIST AES Quest.> + *
+ * For full details see the The Serpent home page + */ +public class SerpentEngine + implements BlockCipher +{ + private static final int BLOCK_SIZE = 16; + + static final int ROUNDS = 32; + static final int PHI = 0x9E3779B9; // (sqrt(5) - 1) * 2**31 + + private boolean encrypting; + private int[] wKey; + + private int X0, X1, X2, X3; // registers + + /** + * initialise a Serpent cipher. + * + * @param encrypting whether or not we are for encryption. + * @param params the parameters required to set up the cipher. + * @exception IllegalArgumentException if the params argument is + * inappropriate. + */ + public void init( + boolean encrypting, + CipherParameters params) + { + if (params instanceof KeyParameter) + { + this.encrypting = encrypting; + this.wKey = makeWorkingKey(((KeyParameter)params).getKey()); + return; + } + + throw new IllegalArgumentException("invalid parameter passed to Serpent init - " + params.getClass().getName()); + } + + public String getAlgorithmName() + { + return "Serpent"; + } + + public int getBlockSize() + { + return BLOCK_SIZE; + } + + /** + * Process one block of input from the array in and write it to + * the out array. + * + * @param in the array containing the input data. + * @param inOff offset into the in array the data starts at. + * @param out the array the output data will be copied into. + * @param outOff the offset into the out array the output will start at. + * @exception DataLengthException if there isn't enough data in in, or + * space in out. + * @exception IllegalStateException if the cipher isn't initialised. + * @return the number of bytes processed and produced. + */ + public final int processBlock( + byte[] in, + int inOff, + byte[] out, + int outOff) + { + if (wKey == null) + { + throw new IllegalStateException("Serpent not initialised"); + } + + if ((inOff + BLOCK_SIZE) > in.length) + { + throw new DataLengthException("input buffer too short"); + } + + if ((outOff + BLOCK_SIZE) > out.length) + { + throw new DataLengthException("output buffer too short"); + } + + if (encrypting) + { + encryptBlock(in, inOff, out, outOff); + } + else + { + decryptBlock(in, inOff, out, outOff); + } + + return BLOCK_SIZE; + } + + public void reset() + { + } + + /** + * Expand a user-supplied key material into a session key. + * + * @param key The user-key bytes (multiples of 4) to use. + * @exception IllegalArgumentException + */ + private int[] makeWorkingKey( + byte[] key) + throws IllegalArgumentException + { + // + // pad key to 256 bits + // + int[] kPad = new int[16]; + int off = 0; + int length = 0; + + for (off = key.length - 4; off > 0; off -= 4) + { + kPad[length++] = bytesToWord(key, off); + } + + if (off == 0) + { + kPad[length++] = bytesToWord(key, 0); + if (length < 8) + { + kPad[length] = 1; + } + } + else + { + throw new IllegalArgumentException("key must be a multiple of 4 bytes"); + } + + // + // expand the padded key up to 33 x 128 bits of key material + // + int amount = (ROUNDS + 1) * 4; + int[] w = new int[amount]; + + // + // compute w0 to w7 from w-8 to w-1 + // + for (int i = 8; i < 16; i++) + { + kPad[i] = rotateLeft(kPad[i - 8] ^ kPad[i - 5] ^ kPad[i - 3] ^ kPad[i - 1] ^ PHI ^ (i - 8), 11); + } + + System.arraycopy(kPad, 8, w, 0, 8); + + // + // compute w8 to w136 + // + for (int i = 8; i < amount; i++) + { + w[i] = rotateLeft(w[i - 8] ^ w[i - 5] ^ w[i - 3] ^ w[i - 1] ^ PHI ^ i, 11); + } + + // + // create the working keys by processing w with the Sbox and IP + // + sb3(w[0], w[1], w[2], w[3]); + w[0] = X0; w[1] = X1; w[2] = X2; w[3] = X3; + sb2(w[4], w[5], w[6], w[7]); + w[4] = X0; w[5] = X1; w[6] = X2; w[7] = X3; + sb1(w[8], w[9], w[10], w[11]); + w[8] = X0; w[9] = X1; w[10] = X2; w[11] = X3; + sb0(w[12], w[13], w[14], w[15]); + w[12] = X0; w[13] = X1; w[14] = X2; w[15] = X3; + sb7(w[16], w[17], w[18], w[19]); + w[16] = X0; w[17] = X1; w[18] = X2; w[19] = X3; + sb6(w[20], w[21], w[22], w[23]); + w[20] = X0; w[21] = X1; w[22] = X2; w[23] = X3; + sb5(w[24], w[25], w[26], w[27]); + w[24] = X0; w[25] = X1; w[26] = X2; w[27] = X3; + sb4(w[28], w[29], w[30], w[31]); + w[28] = X0; w[29] = X1; w[30] = X2; w[31] = X3; + sb3(w[32], w[33], w[34], w[35]); + w[32] = X0; w[33] = X1; w[34] = X2; w[35] = X3; + sb2(w[36], w[37], w[38], w[39]); + w[36] = X0; w[37] = X1; w[38] = X2; w[39] = X3; + sb1(w[40], w[41], w[42], w[43]); + w[40] = X0; w[41] = X1; w[42] = X2; w[43] = X3; + sb0(w[44], w[45], w[46], w[47]); + w[44] = X0; w[45] = X1; w[46] = X2; w[47] = X3; + sb7(w[48], w[49], w[50], w[51]); + w[48] = X0; w[49] = X1; w[50] = X2; w[51] = X3; + sb6(w[52], w[53], w[54], w[55]); + w[52] = X0; w[53] = X1; w[54] = X2; w[55] = X3; + sb5(w[56], w[57], w[58], w[59]); + w[56] = X0; w[57] = X1; w[58] = X2; w[59] = X3; + sb4(w[60], w[61], w[62], w[63]); + w[60] = X0; w[61] = X1; w[62] = X2; w[63] = X3; + sb3(w[64], w[65], w[66], w[67]); + w[64] = X0; w[65] = X1; w[66] = X2; w[67] = X3; + sb2(w[68], w[69], w[70], w[71]); + w[68] = X0; w[69] = X1; w[70] = X2; w[71] = X3; + sb1(w[72], w[73], w[74], w[75]); + w[72] = X0; w[73] = X1; w[74] = X2; w[75] = X3; + sb0(w[76], w[77], w[78], w[79]); + w[76] = X0; w[77] = X1; w[78] = X2; w[79] = X3; + sb7(w[80], w[81], w[82], w[83]); + w[80] = X0; w[81] = X1; w[82] = X2; w[83] = X3; + sb6(w[84], w[85], w[86], w[87]); + w[84] = X0; w[85] = X1; w[86] = X2; w[87] = X3; + sb5(w[88], w[89], w[90], w[91]); + w[88] = X0; w[89] = X1; w[90] = X2; w[91] = X3; + sb4(w[92], w[93], w[94], w[95]); + w[92] = X0; w[93] = X1; w[94] = X2; w[95] = X3; + sb3(w[96], w[97], w[98], w[99]); + w[96] = X0; w[97] = X1; w[98] = X2; w[99] = X3; + sb2(w[100], w[101], w[102], w[103]); + w[100] = X0; w[101] = X1; w[102] = X2; w[103] = X3; + sb1(w[104], w[105], w[106], w[107]); + w[104] = X0; w[105] = X1; w[106] = X2; w[107] = X3; + sb0(w[108], w[109], w[110], w[111]); + w[108] = X0; w[109] = X1; w[110] = X2; w[111] = X3; + sb7(w[112], w[113], w[114], w[115]); + w[112] = X0; w[113] = X1; w[114] = X2; w[115] = X3; + sb6(w[116], w[117], w[118], w[119]); + w[116] = X0; w[117] = X1; w[118] = X2; w[119] = X3; + sb5(w[120], w[121], w[122], w[123]); + w[120] = X0; w[121] = X1; w[122] = X2; w[123] = X3; + sb4(w[124], w[125], w[126], w[127]); + w[124] = X0; w[125] = X1; w[126] = X2; w[127] = X3; + sb3(w[128], w[129], w[130], w[131]); + w[128] = X0; w[129] = X1; w[130] = X2; w[131] = X3; + + return w; + } + + private int rotateLeft( + int x, + int bits) + { + return (x << bits) | (x >>> -bits); + } + + private int rotateRight( + int x, + int bits) + { + return (x >>> bits) | (x << -bits); + } + + private int bytesToWord( + byte[] src, + int srcOff) + { + return (((src[srcOff] & 0xff) << 24) | ((src[srcOff + 1] & 0xff) << 16) | + ((src[srcOff + 2] & 0xff) << 8) | ((src[srcOff + 3] & 0xff))); + } + + private void wordToBytes( + int word, + byte[] dst, + int dstOff) + { + dst[dstOff + 3] = (byte)(word); + dst[dstOff + 2] = (byte)(word >>> 8); + dst[dstOff + 1] = (byte)(word >>> 16); + dst[dstOff] = (byte)(word >>> 24); + } + + /** + * Encrypt one block of plaintext. + * + * @param in the array containing the input data. + * @param inOff offset into the in array the data starts at. + * @param out the array the output data will be copied into. + * @param outOff the offset into the out array the output will start at. + */ + private void encryptBlock( + byte[] in, + int inOff, + byte[] out, + int outOff) + { + X3 = bytesToWord(in, inOff); + X2 = bytesToWord(in, inOff + 4); + X1 = bytesToWord(in, inOff + 8); + X0 = bytesToWord(in, inOff + 12); + + sb0(wKey[0] ^ X0, wKey[1] ^ X1, wKey[2] ^ X2, wKey[3] ^ X3); LT(); + sb1(wKey[4] ^ X0, wKey[5] ^ X1, wKey[6] ^ X2, wKey[7] ^ X3); LT(); + sb2(wKey[8] ^ X0, wKey[9] ^ X1, wKey[10] ^ X2, wKey[11] ^ X3); LT(); + sb3(wKey[12] ^ X0, wKey[13] ^ X1, wKey[14] ^ X2, wKey[15] ^ X3); LT(); + sb4(wKey[16] ^ X0, wKey[17] ^ X1, wKey[18] ^ X2, wKey[19] ^ X3); LT(); + sb5(wKey[20] ^ X0, wKey[21] ^ X1, wKey[22] ^ X2, wKey[23] ^ X3); LT(); + sb6(wKey[24] ^ X0, wKey[25] ^ X1, wKey[26] ^ X2, wKey[27] ^ X3); LT(); + sb7(wKey[28] ^ X0, wKey[29] ^ X1, wKey[30] ^ X2, wKey[31] ^ X3); LT(); + sb0(wKey[32] ^ X0, wKey[33] ^ X1, wKey[34] ^ X2, wKey[35] ^ X3); LT(); + sb1(wKey[36] ^ X0, wKey[37] ^ X1, wKey[38] ^ X2, wKey[39] ^ X3); LT(); + sb2(wKey[40] ^ X0, wKey[41] ^ X1, wKey[42] ^ X2, wKey[43] ^ X3); LT(); + sb3(wKey[44] ^ X0, wKey[45] ^ X1, wKey[46] ^ X2, wKey[47] ^ X3); LT(); + sb4(wKey[48] ^ X0, wKey[49] ^ X1, wKey[50] ^ X2, wKey[51] ^ X3); LT(); + sb5(wKey[52] ^ X0, wKey[53] ^ X1, wKey[54] ^ X2, wKey[55] ^ X3); LT(); + sb6(wKey[56] ^ X0, wKey[57] ^ X1, wKey[58] ^ X2, wKey[59] ^ X3); LT(); + sb7(wKey[60] ^ X0, wKey[61] ^ X1, wKey[62] ^ X2, wKey[63] ^ X3); LT(); + sb0(wKey[64] ^ X0, wKey[65] ^ X1, wKey[66] ^ X2, wKey[67] ^ X3); LT(); + sb1(wKey[68] ^ X0, wKey[69] ^ X1, wKey[70] ^ X2, wKey[71] ^ X3); LT(); + sb2(wKey[72] ^ X0, wKey[73] ^ X1, wKey[74] ^ X2, wKey[75] ^ X3); LT(); + sb3(wKey[76] ^ X0, wKey[77] ^ X1, wKey[78] ^ X2, wKey[79] ^ X3); LT(); + sb4(wKey[80] ^ X0, wKey[81] ^ X1, wKey[82] ^ X2, wKey[83] ^ X3); LT(); + sb5(wKey[84] ^ X0, wKey[85] ^ X1, wKey[86] ^ X2, wKey[87] ^ X3); LT(); + sb6(wKey[88] ^ X0, wKey[89] ^ X1, wKey[90] ^ X2, wKey[91] ^ X3); LT(); + sb7(wKey[92] ^ X0, wKey[93] ^ X1, wKey[94] ^ X2, wKey[95] ^ X3); LT(); + sb0(wKey[96] ^ X0, wKey[97] ^ X1, wKey[98] ^ X2, wKey[99] ^ X3); LT(); + sb1(wKey[100] ^ X0, wKey[101] ^ X1, wKey[102] ^ X2, wKey[103] ^ X3); LT(); + sb2(wKey[104] ^ X0, wKey[105] ^ X1, wKey[106] ^ X2, wKey[107] ^ X3); LT(); + sb3(wKey[108] ^ X0, wKey[109] ^ X1, wKey[110] ^ X2, wKey[111] ^ X3); LT(); + sb4(wKey[112] ^ X0, wKey[113] ^ X1, wKey[114] ^ X2, wKey[115] ^ X3); LT(); + sb5(wKey[116] ^ X0, wKey[117] ^ X1, wKey[118] ^ X2, wKey[119] ^ X3); LT(); + sb6(wKey[120] ^ X0, wKey[121] ^ X1, wKey[122] ^ X2, wKey[123] ^ X3); LT(); + sb7(wKey[124] ^ X0, wKey[125] ^ X1, wKey[126] ^ X2, wKey[127] ^ X3); + + wordToBytes(wKey[131] ^ X3, out, outOff); + wordToBytes(wKey[130] ^ X2, out, outOff + 4); + wordToBytes(wKey[129] ^ X1, out, outOff + 8); + wordToBytes(wKey[128] ^ X0, out, outOff + 12); + } + + /** + * Decrypt one block of ciphertext. + * + * @param in the array containing the input data. + * @param inOff offset into the in array the data starts at. + * @param out the array the output data will be copied into. + * @param outOff the offset into the out array the output will start at. + */ + private void decryptBlock( + byte[] in, + int inOff, + byte[] out, + int outOff) + { + X3 = wKey[131] ^ bytesToWord(in, inOff); + X2 = wKey[130] ^ bytesToWord(in, inOff + 4); + X1 = wKey[129] ^ bytesToWord(in, inOff + 8); + X0 = wKey[128] ^ bytesToWord(in, inOff + 12); + + ib7(X0, X1, X2, X3); + X0 ^= wKey[124]; X1 ^= wKey[125]; X2 ^= wKey[126]; X3 ^= wKey[127]; + inverseLT(); ib6(X0, X1, X2, X3); + X0 ^= wKey[120]; X1 ^= wKey[121]; X2 ^= wKey[122]; X3 ^= wKey[123]; + inverseLT(); ib5(X0, X1, X2, X3); + X0 ^= wKey[116]; X1 ^= wKey[117]; X2 ^= wKey[118]; X3 ^= wKey[119]; + inverseLT(); ib4(X0, X1, X2, X3); + X0 ^= wKey[112]; X1 ^= wKey[113]; X2 ^= wKey[114]; X3 ^= wKey[115]; + inverseLT(); ib3(X0, X1, X2, X3); + X0 ^= wKey[108]; X1 ^= wKey[109]; X2 ^= wKey[110]; X3 ^= wKey[111]; + inverseLT(); ib2(X0, X1, X2, X3); + X0 ^= wKey[104]; X1 ^= wKey[105]; X2 ^= wKey[106]; X3 ^= wKey[107]; + inverseLT(); ib1(X0, X1, X2, X3); + X0 ^= wKey[100]; X1 ^= wKey[101]; X2 ^= wKey[102]; X3 ^= wKey[103]; + inverseLT(); ib0(X0, X1, X2, X3); + X0 ^= wKey[96]; X1 ^= wKey[97]; X2 ^= wKey[98]; X3 ^= wKey[99]; + inverseLT(); ib7(X0, X1, X2, X3); + X0 ^= wKey[92]; X1 ^= wKey[93]; X2 ^= wKey[94]; X3 ^= wKey[95]; + inverseLT(); ib6(X0, X1, X2, X3); + X0 ^= wKey[88]; X1 ^= wKey[89]; X2 ^= wKey[90]; X3 ^= wKey[91]; + inverseLT(); ib5(X0, X1, X2, X3); + X0 ^= wKey[84]; X1 ^= wKey[85]; X2 ^= wKey[86]; X3 ^= wKey[87]; + inverseLT(); ib4(X0, X1, X2, X3); + X0 ^= wKey[80]; X1 ^= wKey[81]; X2 ^= wKey[82]; X3 ^= wKey[83]; + inverseLT(); ib3(X0, X1, X2, X3); + X0 ^= wKey[76]; X1 ^= wKey[77]; X2 ^= wKey[78]; X3 ^= wKey[79]; + inverseLT(); ib2(X0, X1, X2, X3); + X0 ^= wKey[72]; X1 ^= wKey[73]; X2 ^= wKey[74]; X3 ^= wKey[75]; + inverseLT(); ib1(X0, X1, X2, X3); + X0 ^= wKey[68]; X1 ^= wKey[69]; X2 ^= wKey[70]; X3 ^= wKey[71]; + inverseLT(); ib0(X0, X1, X2, X3); + X0 ^= wKey[64]; X1 ^= wKey[65]; X2 ^= wKey[66]; X3 ^= wKey[67]; + inverseLT(); ib7(X0, X1, X2, X3); + X0 ^= wKey[60]; X1 ^= wKey[61]; X2 ^= wKey[62]; X3 ^= wKey[63]; + inverseLT(); ib6(X0, X1, X2, X3); + X0 ^= wKey[56]; X1 ^= wKey[57]; X2 ^= wKey[58]; X3 ^= wKey[59]; + inverseLT(); ib5(X0, X1, X2, X3); + X0 ^= wKey[52]; X1 ^= wKey[53]; X2 ^= wKey[54]; X3 ^= wKey[55]; + inverseLT(); ib4(X0, X1, X2, X3); + X0 ^= wKey[48]; X1 ^= wKey[49]; X2 ^= wKey[50]; X3 ^= wKey[51]; + inverseLT(); ib3(X0, X1, X2, X3); + X0 ^= wKey[44]; X1 ^= wKey[45]; X2 ^= wKey[46]; X3 ^= wKey[47]; + inverseLT(); ib2(X0, X1, X2, X3); + X0 ^= wKey[40]; X1 ^= wKey[41]; X2 ^= wKey[42]; X3 ^= wKey[43]; + inverseLT(); ib1(X0, X1, X2, X3); + X0 ^= wKey[36]; X1 ^= wKey[37]; X2 ^= wKey[38]; X3 ^= wKey[39]; + inverseLT(); ib0(X0, X1, X2, X3); + X0 ^= wKey[32]; X1 ^= wKey[33]; X2 ^= wKey[34]; X3 ^= wKey[35]; + inverseLT(); ib7(X0, X1, X2, X3); + X0 ^= wKey[28]; X1 ^= wKey[29]; X2 ^= wKey[30]; X3 ^= wKey[31]; + inverseLT(); ib6(X0, X1, X2, X3); + X0 ^= wKey[24]; X1 ^= wKey[25]; X2 ^= wKey[26]; X3 ^= wKey[27]; + inverseLT(); ib5(X0, X1, X2, X3); + X0 ^= wKey[20]; X1 ^= wKey[21]; X2 ^= wKey[22]; X3 ^= wKey[23]; + inverseLT(); ib4(X0, X1, X2, X3); + X0 ^= wKey[16]; X1 ^= wKey[17]; X2 ^= wKey[18]; X3 ^= wKey[19]; + inverseLT(); ib3(X0, X1, X2, X3); + X0 ^= wKey[12]; X1 ^= wKey[13]; X2 ^= wKey[14]; X3 ^= wKey[15]; + inverseLT(); ib2(X0, X1, X2, X3); + X0 ^= wKey[8]; X1 ^= wKey[9]; X2 ^= wKey[10]; X3 ^= wKey[11]; + inverseLT(); ib1(X0, X1, X2, X3); + X0 ^= wKey[4]; X1 ^= wKey[5]; X2 ^= wKey[6]; X3 ^= wKey[7]; + inverseLT(); ib0(X0, X1, X2, X3); + + wordToBytes(X3 ^ wKey[3], out, outOff); + wordToBytes(X2 ^ wKey[2], out, outOff + 4); + wordToBytes(X1 ^ wKey[1], out, outOff + 8); + wordToBytes(X0 ^ wKey[0], out, outOff + 12); + } + + /** + * The sboxes below are based on the work of Brian Gladman and + * Sam Simpson, whose original notice appears below. + *
+ * For further details see: + * http://fp.gladman.plus.com/cryptography_technology/serpent/ + */ + + /* Partially optimised Serpent S Box boolean functions derived */ + /* using a recursive descent analyser but without a full search */ + /* of all subtrees. This set of S boxes is the result of work */ + /* by Sam Simpson and Brian Gladman using the spare time on a */ + /* cluster of high capacity servers to search for S boxes with */ + /* this customised search engine. There are now an average of */ + /* 15.375 terms per S box. */ + /* */ + /* Copyright: Dr B. R Gladman (gladman@seven77.demon.co.uk) */ + /* and Sam Simpson (s.simpson@mia.co.uk) */ + /* 17th December 1998 */ + /* */ + /* We hereby give permission for information in this file to be */ + /* used freely subject only to acknowledgement of its origin. */ + + /** + * S0 - { 3, 8,15, 1,10, 6, 5,11,14,13, 4, 2, 7, 0, 9,12 } - 15 terms. + */ + private void sb0(int a, int b, int c, int d) + { + int t1 = a ^ d; + int t3 = c ^ t1; + int t4 = b ^ t3; + X3 = (a & d) ^ t4; + int t7 = a ^ (b & t1); + X2 = t4 ^ (c | t7); + int t12 = X3 & (t3 ^ t7); + X1 = (~t3) ^ t12; + X0 = t12 ^ (~t7); + } + + /** + * InvSO - {13, 3,11, 0,10, 6, 5,12, 1,14, 4, 7,15, 9, 8, 2 } - 15 terms. + */ + private void ib0(int a, int b, int c, int d) + { + int t1 = ~a; + int t2 = a ^ b; + int t4 = d ^ (t1 | t2); + int t5 = c ^ t4; + X2 = t2 ^ t5; + int t8 = t1 ^ (d & t2); + X1 = t4 ^ (X2 & t8); + X3 = (a & t4) ^ (t5 | X1); + X0 = X3 ^ (t5 ^ t8); + } + + /** + * S1 - {15,12, 2, 7, 9, 0, 5,10, 1,11,14, 8, 6,13, 3, 4 } - 14 terms. + */ + private void sb1(int a, int b, int c, int d) + { + int t2 = b ^ (~a); + int t5 = c ^ (a | t2); + X2 = d ^ t5; + int t7 = b ^ (d | t2); + int t8 = t2 ^ X2; + X3 = t8 ^ (t5 & t7); + int t11 = t5 ^ t7; + X1 = X3 ^ t11; + X0 = t5 ^ (t8 & t11); + } + + /** + * InvS1 - { 5, 8, 2,14,15, 6,12, 3,11, 4, 7, 9, 1,13,10, 0 } - 14 steps. + */ + private void ib1(int a, int b, int c, int d) + { + int t1 = b ^ d; + int t3 = a ^ (b & t1); + int t4 = t1 ^ t3; + X3 = c ^ t4; + int t7 = b ^ (t1 & t3); + int t8 = X3 | t7; + X1 = t3 ^ t8; + int t10 = ~X1; + int t11 = X3 ^ t7; + X0 = t10 ^ t11; + X2 = t4 ^ (t10 | t11); + } + + /** + * S2 - { 8, 6, 7, 9, 3,12,10,15,13, 1,14, 4, 0,11, 5, 2 } - 16 terms. + */ + private void sb2(int a, int b, int c, int d) + { + int t1 = ~a; + int t2 = b ^ d; + int t3 = c & t1; + X0 = t2 ^ t3; + int t5 = c ^ t1; + int t6 = c ^ X0; + int t7 = b & t6; + X3 = t5 ^ t7; + X2 = a ^ ((d | t7) & (X0 | t5)); + X1 = (t2 ^ X3) ^ (X2 ^ (d | t1)); + } + + /** + * InvS2 - {12, 9,15, 4,11,14, 1, 2, 0, 3, 6,13, 5, 8,10, 7 } - 16 steps. + */ + private void ib2(int a, int b, int c, int d) + { + int t1 = b ^ d; + int t2 = ~t1; + int t3 = a ^ c; + int t4 = c ^ t1; + int t5 = b & t4; + X0 = t3 ^ t5; + int t7 = a | t2; + int t8 = d ^ t7; + int t9 = t3 | t8; + X3 = t1 ^ t9; + int t11 = ~t4; + int t12 = X0 | X3; + X1 = t11 ^ t12; + X2 = (d & t11) ^ (t3 ^ t12); + } + + /** + * S3 - { 0,15,11, 8,12, 9, 6, 3,13, 1, 2, 4,10, 7, 5,14 } - 16 terms. + */ + private void sb3(int a, int b, int c, int d) + { + int t1 = a ^ b; + int t2 = a & c; + int t3 = a | d; + int t4 = c ^ d; + int t5 = t1 & t3; + int t6 = t2 | t5; + X2 = t4 ^ t6; + int t8 = b ^ t3; + int t9 = t6 ^ t8; + int t10 = t4 & t9; + X0 = t1 ^ t10; + int t12 = X2 & X0; + X1 = t9 ^ t12; + X3 = (b | d) ^ (t4 ^ t12); + } + + /** + * InvS3 - { 0, 9,10, 7,11,14, 6,13, 3, 5,12, 2, 4, 8,15, 1 } - 15 terms + */ + private void ib3(int a, int b, int c, int d) + { + int t1 = a | b; + int t2 = b ^ c; + int t3 = b & t2; + int t4 = a ^ t3; + int t5 = c ^ t4; + int t6 = d | t4; + X0 = t2 ^ t6; + int t8 = t2 | t6; + int t9 = d ^ t8; + X2 = t5 ^ t9; + int t11 = t1 ^ t9; + int t12 = X0 & t11; + X3 = t4 ^ t12; + X1 = X3 ^ (X0 ^ t11); + } + + /** + * S4 - { 1,15, 8, 3,12, 0,11, 6, 2, 5, 4,10, 9,14, 7,13 } - 15 terms. + */ + private void sb4(int a, int b, int c, int d) + { + int t1 = a ^ d; + int t2 = d & t1; + int t3 = c ^ t2; + int t4 = b | t3; + X3 = t1 ^ t4; + int t6 = ~b; + int t7 = t1 | t6; + X0 = t3 ^ t7; + int t9 = a & X0; + int t10 = t1 ^ t6; + int t11 = t4 & t10; + X2 = t9 ^ t11; + X1 = (a ^ t3) ^ (t10 & X2); + } + + /** + * InvS4 - { 5, 0, 8, 3,10, 9, 7,14, 2,12,11, 6, 4,15,13, 1 } - 15 terms. + */ + private void ib4(int a, int b, int c, int d) + { + int t1 = c | d; + int t2 = a & t1; + int t3 = b ^ t2; + int t4 = a & t3; + int t5 = c ^ t4; + X1 = d ^ t5; + int t7 = ~a; + int t8 = t5 & X1; + X3 = t3 ^ t8; + int t10 = X1 | t7; + int t11 = d ^ t10; + X0 = X3 ^ t11; + X2 = (t3 & t11) ^ (X1 ^ t7); + } + + /** + * S5 - {15, 5, 2,11, 4,10, 9,12, 0, 3,14, 8,13, 6, 7, 1 } - 16 terms. + */ + private void sb5(int a, int b, int c, int d) + { + int t1 = ~a; + int t2 = a ^ b; + int t3 = a ^ d; + int t4 = c ^ t1; + int t5 = t2 | t3; + X0 = t4 ^ t5; + int t7 = d & X0; + int t8 = t2 ^ X0; + X1 = t7 ^ t8; + int t10 = t1 | X0; + int t11 = t2 | t7; + int t12 = t3 ^ t10; + X2 = t11 ^ t12; + X3 = (b ^ t7) ^ (X1 & t12); + } + + /** + * InvS5 - { 8,15, 2, 9, 4, 1,13,14,11, 6, 5, 3, 7,12,10, 0 } - 16 terms. + */ + private void ib5(int a, int b, int c, int d) + { + int t1 = ~c; + int t2 = b & t1; + int t3 = d ^ t2; + int t4 = a & t3; + int t5 = b ^ t1; + X3 = t4 ^ t5; + int t7 = b | X3; + int t8 = a & t7; + X1 = t3 ^ t8; + int t10 = a | d; + int t11 = t1 ^ t7; + X0 = t10 ^ t11; + X2 = (b & t10) ^ (t4 | (a ^ c)); + } + + /** + * S6 - { 7, 2,12, 5, 8, 4, 6,11,14, 9, 1,15,13, 3,10, 0 } - 15 terms. + */ + private void sb6(int a, int b, int c, int d) + { + int t1 = ~a; + int t2 = a ^ d; + int t3 = b ^ t2; + int t4 = t1 | t2; + int t5 = c ^ t4; + X1 = b ^ t5; + int t7 = t2 | X1; + int t8 = d ^ t7; + int t9 = t5 & t8; + X2 = t3 ^ t9; + int t11 = t5 ^ t8; + X0 = X2 ^ t11; + X3 = (~t5) ^ (t3 & t11); + } + + /** + * InvS6 - {15,10, 1,13, 5, 3, 6, 0, 4, 9,14, 7, 2,12, 8,11 } - 15 terms. + */ + private void ib6(int a, int b, int c, int d) + { + int t1 = ~a; + int t2 = a ^ b; + int t3 = c ^ t2; + int t4 = c | t1; + int t5 = d ^ t4; + X1 = t3 ^ t5; + int t7 = t3 & t5; + int t8 = t2 ^ t7; + int t9 = b | t8; + X3 = t5 ^ t9; + int t11 = b | X3; + X0 = t8 ^ t11; + X2 = (d & t1) ^ (t3 ^ t11); + } + + /** + * S7 - { 1,13,15, 0,14, 8, 2,11, 7, 4,12,10, 9, 3, 5, 6 } - 16 terms. + */ + private void sb7(int a, int b, int c, int d) + { + int t1 = b ^ c; + int t2 = c & t1; + int t3 = d ^ t2; + int t4 = a ^ t3; + int t5 = d | t1; + int t6 = t4 & t5; + X1 = b ^ t6; + int t8 = t3 | X1; + int t9 = a & t4; + X3 = t1 ^ t9; + int t11 = t4 ^ t8; + int t12 = X3 & t11; + X2 = t3 ^ t12; + X0 = (~t11) ^ (X3 & X2); + } + + /** + * InvS7 - { 3, 0, 6,13, 9,14,15, 8, 5,12,11, 7,10, 1, 4, 2 } - 17 terms. + */ + private void ib7(int a, int b, int c, int d) + { + int t3 = c | (a & b); + int t4 = d & (a | b); + X3 = t3 ^ t4; + int t6 = ~d; + int t7 = b ^ t4; + int t9 = t7 | (X3 ^ t6); + X1 = a ^ t9; + X0 = (c ^ t7) ^ (d | X1); + X2 = (t3 ^ X1) ^ (X0 ^ (a & X3)); + } + + /** + * Apply the linear transformation to the register set. + */ + private void LT() + { + int x0 = rotateLeft(X0, 13); + int x2 = rotateLeft(X2, 3); + int x1 = X1 ^ x0 ^ x2 ; + int x3 = X3 ^ x2 ^ x0 << 3; + + X1 = rotateLeft(x1, 1); + X3 = rotateLeft(x3, 7); + X0 = rotateLeft(x0 ^ X1 ^ X3, 5); + X2 = rotateLeft(x2 ^ X3 ^ (X1 << 7), 22); + } + + /** + * Apply the inverse of the linear transformation to the register set. + */ + private void inverseLT() + { + int x2 = rotateRight(X2, 22) ^ X3 ^ (X1 << 7); + int x0 = rotateRight(X0, 5) ^ X1 ^ X3; + int x3 = rotateRight(X3, 7); + int x1 = rotateRight(X1, 1); + X3 = x3 ^ x2 ^ x0 << 3; + X1 = x1 ^ x0 ^ x2; + X2 = rotateRight(x2, 3); + X0 = rotateRight(x0, 13); + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/SkipjackEngine.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/SkipjackEngine.java new file mode 100644 index 0000000..e2d669d --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/SkipjackEngine.java @@ -0,0 +1,259 @@ +package org.bc.crypto.engines; + +import org.bc.crypto.BlockCipher; +import org.bc.crypto.CipherParameters; +import org.bc.crypto.DataLengthException; +import org.bc.crypto.params.KeyParameter; + +/** + * a class that provides a basic SKIPJACK engine. + */ +public class SkipjackEngine + implements BlockCipher +{ + static final int BLOCK_SIZE = 8; + + static short ftable[] = + { + 0xa3, 0xd7, 0x09, 0x83, 0xf8, 0x48, 0xf6, 0xf4, 0xb3, 0x21, 0x15, 0x78, 0x99, 0xb1, 0xaf, 0xf9, + 0xe7, 0x2d, 0x4d, 0x8a, 0xce, 0x4c, 0xca, 0x2e, 0x52, 0x95, 0xd9, 0x1e, 0x4e, 0x38, 0x44, 0x28, + 0x0a, 0xdf, 0x02, 0xa0, 0x17, 0xf1, 0x60, 0x68, 0x12, 0xb7, 0x7a, 0xc3, 0xe9, 0xfa, 0x3d, 0x53, + 0x96, 0x84, 0x6b, 0xba, 0xf2, 0x63, 0x9a, 0x19, 0x7c, 0xae, 0xe5, 0xf5, 0xf7, 0x16, 0x6a, 0xa2, + 0x39, 0xb6, 0x7b, 0x0f, 0xc1, 0x93, 0x81, 0x1b, 0xee, 0xb4, 0x1a, 0xea, 0xd0, 0x91, 0x2f, 0xb8, + 0x55, 0xb9, 0xda, 0x85, 0x3f, 0x41, 0xbf, 0xe0, 0x5a, 0x58, 0x80, 0x5f, 0x66, 0x0b, 0xd8, 0x90, + 0x35, 0xd5, 0xc0, 0xa7, 0x33, 0x06, 0x65, 0x69, 0x45, 0x00, 0x94, 0x56, 0x6d, 0x98, 0x9b, 0x76, + 0x97, 0xfc, 0xb2, 0xc2, 0xb0, 0xfe, 0xdb, 0x20, 0xe1, 0xeb, 0xd6, 0xe4, 0xdd, 0x47, 0x4a, 0x1d, + 0x42, 0xed, 0x9e, 0x6e, 0x49, 0x3c, 0xcd, 0x43, 0x27, 0xd2, 0x07, 0xd4, 0xde, 0xc7, 0x67, 0x18, + 0x89, 0xcb, 0x30, 0x1f, 0x8d, 0xc6, 0x8f, 0xaa, 0xc8, 0x74, 0xdc, 0xc9, 0x5d, 0x5c, 0x31, 0xa4, + 0x70, 0x88, 0x61, 0x2c, 0x9f, 0x0d, 0x2b, 0x87, 0x50, 0x82, 0x54, 0x64, 0x26, 0x7d, 0x03, 0x40, + 0x34, 0x4b, 0x1c, 0x73, 0xd1, 0xc4, 0xfd, 0x3b, 0xcc, 0xfb, 0x7f, 0xab, 0xe6, 0x3e, 0x5b, 0xa5, + 0xad, 0x04, 0x23, 0x9c, 0x14, 0x51, 0x22, 0xf0, 0x29, 0x79, 0x71, 0x7e, 0xff, 0x8c, 0x0e, 0xe2, + 0x0c, 0xef, 0xbc, 0x72, 0x75, 0x6f, 0x37, 0xa1, 0xec, 0xd3, 0x8e, 0x62, 0x8b, 0x86, 0x10, 0xe8, + 0x08, 0x77, 0x11, 0xbe, 0x92, 0x4f, 0x24, 0xc5, 0x32, 0x36, 0x9d, 0xcf, 0xf3, 0xa6, 0xbb, 0xac, + 0x5e, 0x6c, 0xa9, 0x13, 0x57, 0x25, 0xb5, 0xe3, 0xbd, 0xa8, 0x3a, 0x01, 0x05, 0x59, 0x2a, 0x46 + }; + + private int[] key0, key1, key2, key3; + private boolean encrypting; + + /** + * initialise a SKIPJACK cipher. + * + * @param encrypting whether or not we are for encryption. + * @param params the parameters required to set up the cipher. + * @exception IllegalArgumentException if the params argument is + * inappropriate. + */ + public void init( + boolean encrypting, + CipherParameters params) + { + if (!(params instanceof KeyParameter)) + { + throw new IllegalArgumentException("invalid parameter passed to SKIPJACK init - " + params.getClass().getName()); + } + + byte[] keyBytes = ((KeyParameter)params).getKey(); + + this.encrypting = encrypting; + this.key0 = new int[32]; + this.key1 = new int[32]; + this.key2 = new int[32]; + this.key3 = new int[32]; + + // + // expand the key to 128 bytes in 4 parts (saving us a modulo, multiply + // and an addition). + // + for (int i = 0; i < 32; i ++) + { + key0[i] = keyBytes[(i * 4) % 10] & 0xff; + key1[i] = keyBytes[(i * 4 + 1) % 10] & 0xff; + key2[i] = keyBytes[(i * 4 + 2) % 10] & 0xff; + key3[i] = keyBytes[(i * 4 + 3) % 10] & 0xff; + } + } + + public String getAlgorithmName() + { + return "SKIPJACK"; + } + + public int getBlockSize() + { + return BLOCK_SIZE; + } + + public int processBlock( + byte[] in, + int inOff, + byte[] out, + int outOff) + { + if (key1 == null) + { + throw new IllegalStateException("SKIPJACK engine not initialised"); + } + + if ((inOff + BLOCK_SIZE) > in.length) + { + throw new DataLengthException("input buffer too short"); + } + + if ((outOff + BLOCK_SIZE) > out.length) + { + throw new DataLengthException("output buffer too short"); + } + + if (encrypting) + { + encryptBlock(in, inOff, out, outOff); + } + else + { + decryptBlock(in, inOff, out, outOff); + } + + return BLOCK_SIZE; + } + + public void reset() + { + } + + /** + * The G permutation + */ + private int g( + int k, + int w) + { + int g1, g2, g3, g4, g5, g6; + + g1 = (w >> 8) & 0xff; + g2 = w & 0xff; + + g3 = ftable[g2 ^ key0[k]] ^ g1; + g4 = ftable[g3 ^ key1[k]] ^ g2; + g5 = ftable[g4 ^ key2[k]] ^ g3; + g6 = ftable[g5 ^ key3[k]] ^ g4; + + return ((g5 << 8) + g6); + } + + public int encryptBlock( + byte[] in, + int inOff, + byte[] out, + int outOff) + { + int w1 = (in[inOff + 0] << 8) + (in[inOff + 1] & 0xff); + int w2 = (in[inOff + 2] << 8) + (in[inOff + 3] & 0xff); + int w3 = (in[inOff + 4] << 8) + (in[inOff + 5] & 0xff); + int w4 = (in[inOff + 6] << 8) + (in[inOff + 7] & 0xff); + + int k = 0; + + for (int t = 0; t < 2; t++) + { + for(int i = 0; i < 8; i++) + { + int tmp = w4; + w4 = w3; + w3 = w2; + w2 = g(k, w1); + w1 = w2 ^ tmp ^ (k + 1); + k++; + } + + for(int i = 0; i < 8; i++) + { + int tmp = w4; + w4 = w3; + w3 = w1 ^ w2 ^ (k + 1); + w2 = g(k, w1); + w1 = tmp; + k++; + } + } + + out[outOff + 0] = (byte)((w1 >> 8)); + out[outOff + 1] = (byte)(w1); + out[outOff + 2] = (byte)((w2 >> 8)); + out[outOff + 3] = (byte)(w2); + out[outOff + 4] = (byte)((w3 >> 8)); + out[outOff + 5] = (byte)(w3); + out[outOff + 6] = (byte)((w4 >> 8)); + out[outOff + 7] = (byte)(w4); + + return BLOCK_SIZE; + } + + /** + * the inverse of the G permutation. + */ + private int h( + int k, + int w) + { + int h1, h2, h3, h4, h5, h6; + + h1 = w & 0xff; + h2 = (w >> 8) & 0xff; + + h3 = ftable[h2 ^ key3[k]] ^ h1; + h4 = ftable[h3 ^ key2[k]] ^ h2; + h5 = ftable[h4 ^ key1[k]] ^ h3; + h6 = ftable[h5 ^ key0[k]] ^ h4; + + return ((h6 << 8) + h5); + } + + public int decryptBlock( + byte[] in, + int inOff, + byte[] out, + int outOff) + { + int w2 = (in[inOff + 0] << 8) + (in[inOff + 1] & 0xff); + int w1 = (in[inOff + 2] << 8) + (in[inOff + 3] & 0xff); + int w4 = (in[inOff + 4] << 8) + (in[inOff + 5] & 0xff); + int w3 = (in[inOff + 6] << 8) + (in[inOff + 7] & 0xff); + + int k = 31; + + for (int t = 0; t < 2; t++) + { + for(int i = 0; i < 8; i++) + { + int tmp = w4; + w4 = w3; + w3 = w2; + w2 = h(k, w1); + w1 = w2 ^ tmp ^ (k + 1); + k--; + } + + for(int i = 0; i < 8; i++) + { + int tmp = w4; + w4 = w3; + w3 = w1 ^ w2 ^ (k + 1); + w2 = h(k, w1); + w1 = tmp; + k--; + } + } + + out[outOff + 0] = (byte)((w2 >> 8)); + out[outOff + 1] = (byte)(w2); + out[outOff + 2] = (byte)((w1 >> 8)); + out[outOff + 3] = (byte)(w1); + out[outOff + 4] = (byte)((w4 >> 8)); + out[outOff + 5] = (byte)(w4); + out[outOff + 6] = (byte)((w3 >> 8)); + out[outOff + 7] = (byte)(w3); + + return BLOCK_SIZE; + } +} diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/TEAEngine.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/TEAEngine.java new file mode 100644 index 0000000..b7aa136 --- /dev/null +++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/TEAEngine.java @@ -0,0 +1,178 @@ +package org.bc.crypto.engines; + +import org.bc.crypto.BlockCipher; +import org.bc.crypto.CipherParameters; +import org.bc.crypto.DataLengthException; +import org.bc.crypto.params.KeyParameter; + +/** + * An TEA engine. + */ +public class TEAEngine + implements BlockCipher +{ + private static final int rounds = 32, + block_size = 8, +// key_size = 16, + delta = 0x9E3779B9, + d_sum = 0xC6EF3720; // sum on decrypt + /* + * the expanded key array of 4 subkeys + */ + private int _a, _b, _c, _d; + private boolean _initialised; + private boolean _forEncryption; + + /** + * Create an instance of the TEA encryption algorithm + * and set some defaults + */ + public TEAEngine() + { + _initialised = false; + } + + public String getAlgorithmName() + { + return "TEA"; + } + + public int getBlockSize() + { + return block_size; + } + + /** + * initialise + * + * @param forEncryption whether or not we are for encryption. + * @param params the parameters required to set up the cipher. + * @exception IllegalArgumentException if the params argument is + * inappropriate. + */ + public void init( + boolean forEncryption, + CipherParameters params) + { + if (!(params instanceof KeyParameter)) + { + throw new IllegalArgumentException("invalid parameter passed to TEA init - " + params.getClass().getName()); + } + + _forEncryption = forEncryption; + _initialised = true; + + KeyParameter p = (KeyParameter)params; + + setKey(p.getKey()); + } + + public int processBlock( + byte[] in, + int inOff, + byte[] out, + int outOff) + { + if (!_initialised) + { + throw new IllegalStateException(getAlgorithmName()+" not initialised"); + } + + if ((inOff + block_size) > in.length) + { + throw new DataLengthException("input buffer too short"); + } + + if ((outOff + block_size) > out.length) + { + throw new DataLengthException("output buffer too short"); + } + + return (_forEncryption) ? encryptBlock(in, inOff, out, outOff) + : decryptBlock(in, inOff, out, outOff); + } + + public void reset() + { + } + + /** + * Re-key the cipher. + *
+ * @param key the key to be used
+ */
+ private void setKey(
+ byte[] key)
+ {
+ _a = bytesToInt(key, 0);
+ _b = bytesToInt(key, 4);
+ _c = bytesToInt(key, 8);
+ _d = bytesToInt(key, 12);
+ }
+
+ private int encryptBlock(
+ byte[] in,
+ int inOff,
+ byte[] out,
+ int outOff)
+ {
+ // Pack bytes into integers
+ int v0 = bytesToInt(in, inOff);
+ int v1 = bytesToInt(in, inOff + 4);
+
+ int sum = 0;
+
+ for (int i = 0; i != rounds; i++)
+ {
+ sum += delta;
+ v0 += ((v1 << 4) + _a) ^ (v1 + sum) ^ ((v1 >>> 5) + _b);
+ v1 += ((v0 << 4) + _c) ^ (v0 + sum) ^ ((v0 >>> 5) + _d);
+ }
+
+ unpackInt(v0, out, outOff);
+ unpackInt(v1, out, outOff + 4);
+
+ return block_size;
+ }
+
+ private int decryptBlock(
+ byte[] in,
+ int inOff,
+ byte[] out,
+ int outOff)
+ {
+ // Pack bytes into integers
+ int v0 = bytesToInt(in, inOff);
+ int v1 = bytesToInt(in, inOff + 4);
+
+ int sum = d_sum;
+
+ for (int i = 0; i != rounds; i++)
+ {
+ v1 -= ((v0 << 4) + _c) ^ (v0 + sum) ^ ((v0 >>> 5) + _d);
+ v0 -= ((v1 << 4) + _a) ^ (v1 + sum) ^ ((v1 >>> 5) + _b);
+ sum -= delta;
+ }
+
+ unpackInt(v0, out, outOff);
+ unpackInt(v1, out, outOff + 4);
+
+ return block_size;
+ }
+
+ private int bytesToInt(byte[] in, int inOff)
+ {
+ return ((in[inOff++]) << 24) |
+ ((in[inOff++] & 255) << 16) |
+ ((in[inOff++] & 255) << 8) |
+ ((in[inOff] & 255));
+ }
+
+ private void unpackInt(int v, byte[] out, int outOff)
+ {
+ out[outOff++] = (byte)(v >>> 24);
+ out[outOff++] = (byte)(v >>> 16);
+ out[outOff++] = (byte)(v >>> 8);
+ out[outOff ] = (byte)v;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/TwofishEngine.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/TwofishEngine.java
new file mode 100644
index 0000000..04615ba
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/TwofishEngine.java
@@ -0,0 +1,679 @@
+package org.bc.crypto.engines;
+
+import org.bc.crypto.BlockCipher;
+import org.bc.crypto.CipherParameters;
+import org.bc.crypto.DataLengthException;
+import org.bc.crypto.params.KeyParameter;
+
+/**
+ * A class that provides Twofish encryption operations.
+ *
+ * This Java implementation is based on the Java reference
+ * implementation provided by Bruce Schneier and developed
+ * by Raif S. Naffah.
+ */
+public final class TwofishEngine
+ implements BlockCipher
+{
+ private static final byte[][] P = {
+ { // p0
+ (byte) 0xA9, (byte) 0x67, (byte) 0xB3, (byte) 0xE8,
+ (byte) 0x04, (byte) 0xFD, (byte) 0xA3, (byte) 0x76,
+ (byte) 0x9A, (byte) 0x92, (byte) 0x80, (byte) 0x78,
+ (byte) 0xE4, (byte) 0xDD, (byte) 0xD1, (byte) 0x38,
+ (byte) 0x0D, (byte) 0xC6, (byte) 0x35, (byte) 0x98,
+ (byte) 0x18, (byte) 0xF7, (byte) 0xEC, (byte) 0x6C,
+ (byte) 0x43, (byte) 0x75, (byte) 0x37, (byte) 0x26,
+ (byte) 0xFA, (byte) 0x13, (byte) 0x94, (byte) 0x48,
+ (byte) 0xF2, (byte) 0xD0, (byte) 0x8B, (byte) 0x30,
+ (byte) 0x84, (byte) 0x54, (byte) 0xDF, (byte) 0x23,
+ (byte) 0x19, (byte) 0x5B, (byte) 0x3D, (byte) 0x59,
+ (byte) 0xF3, (byte) 0xAE, (byte) 0xA2, (byte) 0x82,
+ (byte) 0x63, (byte) 0x01, (byte) 0x83, (byte) 0x2E,
+ (byte) 0xD9, (byte) 0x51, (byte) 0x9B, (byte) 0x7C,
+ (byte) 0xA6, (byte) 0xEB, (byte) 0xA5, (byte) 0xBE,
+ (byte) 0x16, (byte) 0x0C, (byte) 0xE3, (byte) 0x61,
+ (byte) 0xC0, (byte) 0x8C, (byte) 0x3A, (byte) 0xF5,
+ (byte) 0x73, (byte) 0x2C, (byte) 0x25, (byte) 0x0B,
+ (byte) 0xBB, (byte) 0x4E, (byte) 0x89, (byte) 0x6B,
+ (byte) 0x53, (byte) 0x6A, (byte) 0xB4, (byte) 0xF1,
+ (byte) 0xE1, (byte) 0xE6, (byte) 0xBD, (byte) 0x45,
+ (byte) 0xE2, (byte) 0xF4, (byte) 0xB6, (byte) 0x66,
+ (byte) 0xCC, (byte) 0x95, (byte) 0x03, (byte) 0x56,
+ (byte) 0xD4, (byte) 0x1C, (byte) 0x1E, (byte) 0xD7,
+ (byte) 0xFB, (byte) 0xC3, (byte) 0x8E, (byte) 0xB5,
+ (byte) 0xE9, (byte) 0xCF, (byte) 0xBF, (byte) 0xBA,
+ (byte) 0xEA, (byte) 0x77, (byte) 0x39, (byte) 0xAF,
+ (byte) 0x33, (byte) 0xC9, (byte) 0x62, (byte) 0x71,
+ (byte) 0x81, (byte) 0x79, (byte) 0x09, (byte) 0xAD,
+ (byte) 0x24, (byte) 0xCD, (byte) 0xF9, (byte) 0xD8,
+ (byte) 0xE5, (byte) 0xC5, (byte) 0xB9, (byte) 0x4D,
+ (byte) 0x44, (byte) 0x08, (byte) 0x86, (byte) 0xE7,
+ (byte) 0xA1, (byte) 0x1D, (byte) 0xAA, (byte) 0xED,
+ (byte) 0x06, (byte) 0x70, (byte) 0xB2, (byte) 0xD2,
+ (byte) 0x41, (byte) 0x7B, (byte) 0xA0, (byte) 0x11,
+ (byte) 0x31, (byte) 0xC2, (byte) 0x27, (byte) 0x90,
+ (byte) 0x20, (byte) 0xF6, (byte) 0x60, (byte) 0xFF,
+ (byte) 0x96, (byte) 0x5C, (byte) 0xB1, (byte) 0xAB,
+ (byte) 0x9E, (byte) 0x9C, (byte) 0x52, (byte) 0x1B,
+ (byte) 0x5F, (byte) 0x93, (byte) 0x0A, (byte) 0xEF,
+ (byte) 0x91, (byte) 0x85, (byte) 0x49, (byte) 0xEE,
+ (byte) 0x2D, (byte) 0x4F, (byte) 0x8F, (byte) 0x3B,
+ (byte) 0x47, (byte) 0x87, (byte) 0x6D, (byte) 0x46,
+ (byte) 0xD6, (byte) 0x3E, (byte) 0x69, (byte) 0x64,
+ (byte) 0x2A, (byte) 0xCE, (byte) 0xCB, (byte) 0x2F,
+ (byte) 0xFC, (byte) 0x97, (byte) 0x05, (byte) 0x7A,
+ (byte) 0xAC, (byte) 0x7F, (byte) 0xD5, (byte) 0x1A,
+ (byte) 0x4B, (byte) 0x0E, (byte) 0xA7, (byte) 0x5A,
+ (byte) 0x28, (byte) 0x14, (byte) 0x3F, (byte) 0x29,
+ (byte) 0x88, (byte) 0x3C, (byte) 0x4C, (byte) 0x02,
+ (byte) 0xB8, (byte) 0xDA, (byte) 0xB0, (byte) 0x17,
+ (byte) 0x55, (byte) 0x1F, (byte) 0x8A, (byte) 0x7D,
+ (byte) 0x57, (byte) 0xC7, (byte) 0x8D, (byte) 0x74,
+ (byte) 0xB7, (byte) 0xC4, (byte) 0x9F, (byte) 0x72,
+ (byte) 0x7E, (byte) 0x15, (byte) 0x22, (byte) 0x12,
+ (byte) 0x58, (byte) 0x07, (byte) 0x99, (byte) 0x34,
+ (byte) 0x6E, (byte) 0x50, (byte) 0xDE, (byte) 0x68,
+ (byte) 0x65, (byte) 0xBC, (byte) 0xDB, (byte) 0xF8,
+ (byte) 0xC8, (byte) 0xA8, (byte) 0x2B, (byte) 0x40,
+ (byte) 0xDC, (byte) 0xFE, (byte) 0x32, (byte) 0xA4,
+ (byte) 0xCA, (byte) 0x10, (byte) 0x21, (byte) 0xF0,
+ (byte) 0xD3, (byte) 0x5D, (byte) 0x0F, (byte) 0x00,
+ (byte) 0x6F, (byte) 0x9D, (byte) 0x36, (byte) 0x42,
+ (byte) 0x4A, (byte) 0x5E, (byte) 0xC1, (byte) 0xE0 },
+ { // p1
+ (byte) 0x75, (byte) 0xF3, (byte) 0xC6, (byte) 0xF4,
+ (byte) 0xDB, (byte) 0x7B, (byte) 0xFB, (byte) 0xC8,
+ (byte) 0x4A, (byte) 0xD3, (byte) 0xE6, (byte) 0x6B,
+ (byte) 0x45, (byte) 0x7D, (byte) 0xE8, (byte) 0x4B,
+ (byte) 0xD6, (byte) 0x32, (byte) 0xD8, (byte) 0xFD,
+ (byte) 0x37, (byte) 0x71, (byte) 0xF1, (byte) 0xE1,
+ (byte) 0x30, (byte) 0x0F, (byte) 0xF8, (byte) 0x1B,
+ (byte) 0x87, (byte) 0xFA, (byte) 0x06, (byte) 0x3F,
+ (byte) 0x5E, (byte) 0xBA, (byte) 0xAE, (byte) 0x5B,
+ (byte) 0x8A, (byte) 0x00, (byte) 0xBC, (byte) 0x9D,
+ (byte) 0x6D, (byte) 0xC1, (byte) 0xB1, (byte) 0x0E,
+ (byte) 0x80, (byte) 0x5D, (byte) 0xD2, (byte) 0xD5,
+ (byte) 0xA0, (byte) 0x84, (byte) 0x07, (byte) 0x14,
+ (byte) 0xB5, (byte) 0x90, (byte) 0x2C, (byte) 0xA3,
+ (byte) 0xB2, (byte) 0x73, (byte) 0x4C, (byte) 0x54,
+ (byte) 0x92, (byte) 0x74, (byte) 0x36, (byte) 0x51,
+ (byte) 0x38, (byte) 0xB0, (byte) 0xBD, (byte) 0x5A,
+ (byte) 0xFC, (byte) 0x60, (byte) 0x62, (byte) 0x96,
+ (byte) 0x6C, (byte) 0x42, (byte) 0xF7, (byte) 0x10,
+ (byte) 0x7C, (byte) 0x28, (byte) 0x27, (byte) 0x8C,
+ (byte) 0x13, (byte) 0x95, (byte) 0x9C, (byte) 0xC7,
+ (byte) 0x24, (byte) 0x46, (byte) 0x3B, (byte) 0x70,
+ (byte) 0xCA, (byte) 0xE3, (byte) 0x85, (byte) 0xCB,
+ (byte) 0x11, (byte) 0xD0, (byte) 0x93, (byte) 0xB8,
+ (byte) 0xA6, (byte) 0x83, (byte) 0x20, (byte) 0xFF,
+ (byte) 0x9F, (byte) 0x77, (byte) 0xC3, (byte) 0xCC,
+ (byte) 0x03, (byte) 0x6F, (byte) 0x08, (byte) 0xBF,
+ (byte) 0x40, (byte) 0xE7, (byte) 0x2B, (byte) 0xE2,
+ (byte) 0x79, (byte) 0x0C, (byte) 0xAA, (byte) 0x82,
+ (byte) 0x41, (byte) 0x3A, (byte) 0xEA, (byte) 0xB9,
+ (byte) 0xE4, (byte) 0x9A, (byte) 0xA4, (byte) 0x97,
+ (byte) 0x7E, (byte) 0xDA, (byte) 0x7A, (byte) 0x17,
+ (byte) 0x66, (byte) 0x94, (byte) 0xA1, (byte) 0x1D,
+ (byte) 0x3D, (byte) 0xF0, (byte) 0xDE, (byte) 0xB3,
+ (byte) 0x0B, (byte) 0x72, (byte) 0xA7, (byte) 0x1C,
+ (byte) 0xEF, (byte) 0xD1, (byte) 0x53, (byte) 0x3E,
+ (byte) 0x8F, (byte) 0x33, (byte) 0x26, (byte) 0x5F,
+ (byte) 0xEC, (byte) 0x76, (byte) 0x2A, (byte) 0x49,
+ (byte) 0x81, (byte) 0x88, (byte) 0xEE, (byte) 0x21,
+ (byte) 0xC4, (byte) 0x1A, (byte) 0xEB, (byte) 0xD9,
+ (byte) 0xC5, (byte) 0x39, (byte) 0x99, (byte) 0xCD,
+ (byte) 0xAD, (byte) 0x31, (byte) 0x8B, (byte) 0x01,
+ (byte) 0x18, (byte) 0x23, (byte) 0xDD, (byte) 0x1F,
+ (byte) 0x4E, (byte) 0x2D, (byte) 0xF9, (byte) 0x48,
+ (byte) 0x4F, (byte) 0xF2, (byte) 0x65, (byte) 0x8E,
+ (byte) 0x78, (byte) 0x5C, (byte) 0x58, (byte) 0x19,
+ (byte) 0x8D, (byte) 0xE5, (byte) 0x98, (byte) 0x57,
+ (byte) 0x67, (byte) 0x7F, (byte) 0x05, (byte) 0x64,
+ (byte) 0xAF, (byte) 0x63, (byte) 0xB6, (byte) 0xFE,
+ (byte) 0xF5, (byte) 0xB7, (byte) 0x3C, (byte) 0xA5,
+ (byte) 0xCE, (byte) 0xE9, (byte) 0x68, (byte) 0x44,
+ (byte) 0xE0, (byte) 0x4D, (byte) 0x43, (byte) 0x69,
+ (byte) 0x29, (byte) 0x2E, (byte) 0xAC, (byte) 0x15,
+ (byte) 0x59, (byte) 0xA8, (byte) 0x0A, (byte) 0x9E,
+ (byte) 0x6E, (byte) 0x47, (byte) 0xDF, (byte) 0x34,
+ (byte) 0x35, (byte) 0x6A, (byte) 0xCF, (byte) 0xDC,
+ (byte) 0x22, (byte) 0xC9, (byte) 0xC0, (byte) 0x9B,
+ (byte) 0x89, (byte) 0xD4, (byte) 0xED, (byte) 0xAB,
+ (byte) 0x12, (byte) 0xA2, (byte) 0x0D, (byte) 0x52,
+ (byte) 0xBB, (byte) 0x02, (byte) 0x2F, (byte) 0xA9,
+ (byte) 0xD7, (byte) 0x61, (byte) 0x1E, (byte) 0xB4,
+ (byte) 0x50, (byte) 0x04, (byte) 0xF6, (byte) 0xC2,
+ (byte) 0x16, (byte) 0x25, (byte) 0x86, (byte) 0x56,
+ (byte) 0x55, (byte) 0x09, (byte) 0xBE, (byte) 0x91 }
+ };
+
+ /**
+ * Define the fixed p0/p1 permutations used in keyed S-box lookup.
+ * By changing the following constant definitions, the S-boxes will
+ * automatically get changed in the Twofish engine.
+ */
+ private static final int P_00 = 1;
+ private static final int P_01 = 0;
+ private static final int P_02 = 0;
+ private static final int P_03 = P_01 ^ 1;
+ private static final int P_04 = 1;
+
+ private static final int P_10 = 0;
+ private static final int P_11 = 0;
+ private static final int P_12 = 1;
+ private static final int P_13 = P_11 ^ 1;
+ private static final int P_14 = 0;
+
+ private static final int P_20 = 1;
+ private static final int P_21 = 1;
+ private static final int P_22 = 0;
+ private static final int P_23 = P_21 ^ 1;
+ private static final int P_24 = 0;
+
+ private static final int P_30 = 0;
+ private static final int P_31 = 1;
+ private static final int P_32 = 1;
+ private static final int P_33 = P_31 ^ 1;
+ private static final int P_34 = 1;
+
+ /* Primitive polynomial for GF(256) */
+ private static final int GF256_FDBK = 0x169;
+ private static final int GF256_FDBK_2 = GF256_FDBK / 2;
+ private static final int GF256_FDBK_4 = GF256_FDBK / 4;
+
+ private static final int RS_GF_FDBK = 0x14D; // field generator
+
+ //====================================
+ // Useful constants
+ //====================================
+
+ private static final int ROUNDS = 16;
+ private static final int MAX_ROUNDS = 16; // bytes = 128 bits
+ private static final int BLOCK_SIZE = 16; // bytes = 128 bits
+ private static final int MAX_KEY_BITS = 256;
+
+ private static final int INPUT_WHITEN=0;
+ private static final int OUTPUT_WHITEN=INPUT_WHITEN+BLOCK_SIZE/4; // 4
+ private static final int ROUND_SUBKEYS=OUTPUT_WHITEN+BLOCK_SIZE/4;// 8
+
+ private static final int TOTAL_SUBKEYS=ROUND_SUBKEYS+2*MAX_ROUNDS;// 40
+
+ private static final int SK_STEP = 0x02020202;
+ private static final int SK_BUMP = 0x01010101;
+ private static final int SK_ROTL = 9;
+
+ private boolean encrypting = false;
+
+ private int[] gMDS0 = new int[MAX_KEY_BITS];
+ private int[] gMDS1 = new int[MAX_KEY_BITS];
+ private int[] gMDS2 = new int[MAX_KEY_BITS];
+ private int[] gMDS3 = new int[MAX_KEY_BITS];
+
+ /**
+ * gSubKeys[] and gSBox[] are eventually used in the
+ * encryption and decryption methods.
+ */
+ private int[] gSubKeys;
+ private int[] gSBox;
+
+ private int k64Cnt = 0;
+
+ private byte[] workingKey = null;
+
+ public TwofishEngine()
+ {
+ // calculate the MDS matrix
+ int[] m1 = new int[2];
+ int[] mX = new int[2];
+ int[] mY = new int[2];
+ int j;
+
+ for (int i=0; i< MAX_KEY_BITS ; i++)
+ {
+ j = P[0][i] & 0xff;
+ m1[0] = j;
+ mX[0] = Mx_X(j) & 0xff;
+ mY[0] = Mx_Y(j) & 0xff;
+
+ j = P[1][i] & 0xff;
+ m1[1] = j;
+ mX[1] = Mx_X(j) & 0xff;
+ mY[1] = Mx_Y(j) & 0xff;
+
+ gMDS0[i] = m1[P_00] | mX[P_00] << 8 |
+ mY[P_00] << 16 | mY[P_00] << 24;
+
+ gMDS1[i] = mY[P_10] | mY[P_10] << 8 |
+ mX[P_10] << 16 | m1[P_10] << 24;
+
+ gMDS2[i] = mX[P_20] | mY[P_20] << 8 |
+ m1[P_20] << 16 | mY[P_20] << 24;
+
+ gMDS3[i] = mX[P_30] | m1[P_30] << 8 |
+ mY[P_30] << 16 | mX[P_30] << 24;
+ }
+ }
+
+ /**
+ * initialise a Twofish cipher.
+ *
+ * @param encrypting whether or not we are for encryption.
+ * @param params the parameters required to set up the cipher.
+ * @exception IllegalArgumentException if the params argument is
+ * inappropriate.
+ */
+ public void init(
+ boolean encrypting,
+ CipherParameters params)
+ {
+ if (params instanceof KeyParameter)
+ {
+ this.encrypting = encrypting;
+ this.workingKey = ((KeyParameter)params).getKey();
+ this.k64Cnt = (this.workingKey.length / 8); // pre-padded ?
+ setKey(this.workingKey);
+
+ return;
+ }
+
+ throw new IllegalArgumentException("invalid parameter passed to Twofish init - " + params.getClass().getName());
+ }
+
+ public String getAlgorithmName()
+ {
+ return "Twofish";
+ }
+
+ public int processBlock(
+ byte[] in,
+ int inOff,
+ byte[] out,
+ int outOff)
+ {
+ if (workingKey == null)
+ {
+ throw new IllegalStateException("Twofish not initialised");
+ }
+
+ if ((inOff + BLOCK_SIZE) > in.length)
+ {
+ throw new DataLengthException("input buffer too short");
+ }
+
+ if ((outOff + BLOCK_SIZE) > out.length)
+ {
+ throw new DataLengthException("output buffer too short");
+ }
+
+ if (encrypting)
+ {
+ encryptBlock(in, inOff, out, outOff);
+ }
+ else
+ {
+ decryptBlock(in, inOff, out, outOff);
+ }
+
+ return BLOCK_SIZE;
+ }
+
+ public void reset()
+ {
+ if (this.workingKey != null)
+ {
+ setKey(this.workingKey);
+ }
+ }
+
+ public int getBlockSize()
+ {
+ return BLOCK_SIZE;
+ }
+
+ //==================================
+ // Private Implementation
+ //==================================
+
+ private void setKey(byte[] key)
+ {
+ int[] k32e = new int[MAX_KEY_BITS/64]; // 4
+ int[] k32o = new int[MAX_KEY_BITS/64]; // 4
+
+ int[] sBoxKeys = new int[MAX_KEY_BITS/64]; // 4
+ gSubKeys = new int[TOTAL_SUBKEYS];
+
+ if (k64Cnt < 1)
+ {
+ throw new IllegalArgumentException("Key size less than 64 bits");
+ }
+
+ if (k64Cnt > 4)
+ {
+ throw new IllegalArgumentException("Key size larger than 256 bits");
+ }
+
+ /*
+ * k64Cnt is the number of 8 byte blocks (64 chunks)
+ * that are in the input key. The input key is a
+ * maximum of 32 bytes (256 bits), so the range
+ * for k64Cnt is 1..4
+ */
+ for (int i=0; i
+ *
+ * @param key the key to be used
+ */
+ private void setKey(
+ byte[] key)
+ {
+ int i, j;
+ for (i = j = 0; i < 4; i++,j+=4)
+ {
+ _S[i] = bytesToInt(key, j);
+ }
+
+ for (i = j = 0; i < rounds; i++)
+ {
+ _sum0[i] = (j + _S[j & 3]);
+ j += delta;
+ _sum1[i] = (j + _S[j >>> 11 & 3]);
+ }
+ }
+
+ private int encryptBlock(
+ byte[] in,
+ int inOff,
+ byte[] out,
+ int outOff)
+ {
+ // Pack bytes into integers
+ int v0 = bytesToInt(in, inOff);
+ int v1 = bytesToInt(in, inOff + 4);
+
+ for (int i = 0; i < rounds; i++)
+ {
+ v0 += ((v1 << 4 ^ v1 >>> 5) + v1) ^ _sum0[i];
+ v1 += ((v0 << 4 ^ v0 >>> 5) + v0) ^ _sum1[i];
+ }
+
+ unpackInt(v0, out, outOff);
+ unpackInt(v1, out, outOff + 4);
+
+ return block_size;
+ }
+
+ private int decryptBlock(
+ byte[] in,
+ int inOff,
+ byte[] out,
+ int outOff)
+ {
+ // Pack bytes into integers
+ int v0 = bytesToInt(in, inOff);
+ int v1 = bytesToInt(in, inOff + 4);
+
+ for (int i = rounds-1; i >= 0; i--)
+ {
+ v1 -= ((v0 << 4 ^ v0 >>> 5) + v0) ^ _sum1[i];
+ v0 -= ((v1 << 4 ^ v1 >>> 5) + v1) ^ _sum0[i];
+ }
+
+ unpackInt(v0, out, outOff);
+ unpackInt(v1, out, outOff + 4);
+
+ return block_size;
+ }
+
+ private int bytesToInt(byte[] in, int inOff)
+ {
+ return ((in[inOff++]) << 24) |
+ ((in[inOff++] & 255) << 16) |
+ ((in[inOff++] & 255) << 8) |
+ ((in[inOff] & 255));
+ }
+
+ private void unpackInt(int v, byte[] out, int outOff)
+ {
+ out[outOff++] = (byte)(v >>> 24);
+ out[outOff++] = (byte)(v >>> 16);
+ out[outOff++] = (byte)(v >>> 8);
+ out[outOff ] = (byte)v;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/examples/DESExample.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/examples/DESExample.java
new file mode 100644
index 0000000..9c50776
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/examples/DESExample.java
@@ -0,0 +1,419 @@
+package org.bc.crypto.examples;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.BufferedReader;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.security.SecureRandom;
+
+import org.bc.crypto.CryptoException;
+import org.bc.crypto.KeyGenerationParameters;
+import org.bc.crypto.engines.DESedeEngine;
+import org.bc.crypto.generators.DESedeKeyGenerator;
+import org.bc.crypto.modes.CBCBlockCipher;
+import org.bc.crypto.paddings.PaddedBufferedBlockCipher;
+import org.bc.crypto.params.DESedeParameters;
+import org.bc.crypto.params.KeyParameter;
+import org.bc.util.encoders.Hex;
+
+/**
+ * DESExample is a simple DES based encryptor/decryptor.
+ *
+ * The program is command line driven, with the input
+ * and output files specified on the command line.
+ *
+ * When encrypting;
+ *
+ * When decrypting;
+ *
+ * This example shows how to use the light-weight API, DES and
+ * the filesystem for message encryption and decryption.
+ *
+ */
+public class DESExample extends Object
+{
+ // Encrypting or decrypting ?
+ private boolean encrypt = true;
+
+ // To hold the initialised DESede cipher
+ private PaddedBufferedBlockCipher cipher = null;
+
+ // The input stream of bytes to be processed for encryption
+ private BufferedInputStream in = null;
+
+ // The output stream of bytes to be procssed
+ private BufferedOutputStream out = null;
+
+ // The key
+ private byte[] key = null;
+
+ /*
+ * start the application
+ */
+ public static void main(String[] args)
+ {
+ boolean encrypt = true;
+ String infile = null;
+ String outfile = null;
+ String keyfile = null;
+
+ if (args.length < 2)
+ {
+ DESExample de = new DESExample();
+ System.err.println("Usage: java "+de.getClass().getName()+
+ " infile outfile [keyfile]");
+ System.exit(1);
+ }
+
+ keyfile = "deskey.dat";
+ infile = args[0];
+ outfile = args[1];
+
+ if (args.length > 2)
+ {
+ encrypt = false;
+ keyfile = args[2];
+ }
+
+ DESExample de = new DESExample(infile, outfile, keyfile, encrypt);
+ de.process();
+ }
+
+ // Default constructor, used for the usage message
+ public DESExample()
+ {
+ }
+
+ /*
+ * Constructor, that takes the arguments appropriate for
+ * processing the command line directives.
+ */
+ public DESExample(
+ String infile,
+ String outfile,
+ String keyfile,
+ boolean encrypt)
+ {
+ /*
+ * First, determine that infile & keyfile exist as appropriate.
+ *
+ * This will also create the BufferedInputStream as required
+ * for reading the input file. All input files are treated
+ * as if they are binary, even if they contain text, it's the
+ * bytes that are encrypted.
+ */
+ this.encrypt = encrypt;
+ try
+ {
+ in = new BufferedInputStream(new FileInputStream(infile));
+ }
+ catch (FileNotFoundException fnf)
+ {
+ System.err.println("Input file not found ["+infile+"]");
+ System.exit(1);
+ }
+
+ try
+ {
+ out = new BufferedOutputStream(new FileOutputStream(outfile));
+ }
+ catch (IOException fnf)
+ {
+ System.err.println("Output file not created ["+outfile+"]");
+ System.exit(1);
+ }
+
+ if (encrypt)
+ {
+ try
+ {
+ /*
+ * The process of creating a new key requires a
+ * number of steps.
+ *
+ * First, create the parameters for the key generator
+ * which are a secure random number generator, and
+ * the length of the key (in bits).
+ */
+ SecureRandom sr = null;
+ try
+ {
+ sr = new SecureRandom();
+ /*
+ * This following call to setSeed() makes the
+ * initialisation of the SecureRandom object
+ * _very_ fast, but not secure AT ALL.
+ *
+ * Remove the line, recreate the class file and
+ * then run DESExample again to see the difference.
+ *
+ * The initialisation of a SecureRandom object
+ * can take 5 or more seconds depending on the
+ * CPU that the program is running on. That can
+ * be annoying during unit testing.
+ * -- jon
+ */
+ sr.setSeed("www.bouncycastle.org".getBytes());
+ }
+ catch (Exception nsa)
+ {
+ System.err.println("Hmmm, no SHA1PRNG, you need the "+
+ "Sun implementation");
+ System.exit(1);
+ }
+ KeyGenerationParameters kgp = new KeyGenerationParameters(
+ sr,
+ DESedeParameters.DES_EDE_KEY_LENGTH*8);
+
+ /*
+ * Second, initialise the key generator with the parameters
+ */
+ DESedeKeyGenerator kg = new DESedeKeyGenerator();
+ kg.init(kgp);
+
+ /*
+ * Third, and finally, generate the key
+ */
+ key = kg.generateKey();
+
+ /*
+ * We can now output the key to the file, but first
+ * hex encode the key so that we can have a look
+ * at it with a text editor if we so desire
+ */
+ BufferedOutputStream keystream =
+ new BufferedOutputStream(new FileOutputStream(keyfile));
+ byte[] keyhex = Hex.encode(key);
+ keystream.write(keyhex, 0, keyhex.length);
+ keystream.flush();
+ keystream.close();
+ }
+ catch (IOException createKey)
+ {
+ System.err.println("Could not decryption create key file "+
+ "["+keyfile+"]");
+ System.exit(1);
+ }
+ }
+ else
+ {
+ try
+ {
+ // read the key, and decode from hex encoding
+ BufferedInputStream keystream =
+ new BufferedInputStream(new FileInputStream(keyfile));
+ int len = keystream.available();
+ byte[] keyhex = new byte[len];
+ keystream.read(keyhex, 0, len);
+ key = Hex.decode(keyhex);
+ }
+ catch (IOException ioe)
+ {
+ System.err.println("Decryption key file not found, "+
+ "or not valid ["+keyfile+"]");
+ System.exit(1);
+ }
+ }
+ }
+
+ private void process()
+ {
+ /*
+ * Setup the DESede cipher engine, create a PaddedBufferedBlockCipher
+ * in CBC mode.
+ */
+ cipher = new PaddedBufferedBlockCipher(
+ new CBCBlockCipher(new DESedeEngine()));
+
+ /*
+ * The input and output streams are currently set up
+ * appropriately, and the key bytes are ready to be
+ * used.
+ *
+ */
+
+ if (encrypt)
+ {
+ performEncrypt(key);
+ }
+ else
+ {
+ performDecrypt(key);
+ }
+
+ // after processing clean up the files
+ try
+ {
+ in.close();
+ out.flush();
+ out.close();
+ }
+ catch (IOException closing)
+ {
+
+ }
+ }
+
+ /*
+ * This method performs all the encryption and writes
+ * the cipher text to the buffered output stream created
+ * previously.
+ */
+ private void performEncrypt(byte[] key)
+ {
+ // initialise the cipher with the key bytes, for encryption
+ cipher.init(true, new KeyParameter(key));
+
+ /*
+ * Create some temporary byte arrays for use in
+ * encryption, make them a reasonable size so that
+ * we don't spend forever reading small chunks from
+ * a file.
+ *
+ * There is no particular reason for using getBlockSize()
+ * to determine the size of the input chunk. It just
+ * was a convenient number for the example.
+ */
+ // int inBlockSize = cipher.getBlockSize() * 5;
+ int inBlockSize = 47;
+ int outBlockSize = cipher.getOutputSize(inBlockSize);
+
+ byte[] inblock = new byte[inBlockSize];
+ byte[] outblock = new byte[outBlockSize];
+
+ /*
+ * now, read the file, and output the chunks
+ */
+ try
+ {
+ int inL;
+ int outL;
+ byte[] rv = null;
+ while ((inL=in.read(inblock, 0, inBlockSize)) > 0)
+ {
+ outL = cipher.processBytes(inblock, 0, inL, outblock, 0);
+ /*
+ * Before we write anything out, we need to make sure
+ * that we've got something to write out.
+ */
+ if (outL > 0)
+ {
+ rv = Hex.encode(outblock, 0, outL);
+ out.write(rv, 0, rv.length);
+ out.write('\n');
+ }
+ }
+
+ try
+ {
+ /*
+ * Now, process the bytes that are still buffered
+ * within the cipher.
+ */
+ outL = cipher.doFinal(outblock, 0);
+ if (outL > 0)
+ {
+ rv = Hex.encode(outblock, 0, outL);
+ out.write(rv, 0, rv.length);
+ out.write('\n');
+ }
+ }
+ catch (CryptoException ce)
+ {
+
+ }
+ }
+ catch (IOException ioeread)
+ {
+ ioeread.printStackTrace();
+ }
+ }
+
+ /*
+ * This method performs all the decryption and writes
+ * the plain text to the buffered output stream created
+ * previously.
+ */
+ private void performDecrypt(byte[] key)
+ {
+ // initialise the cipher for decryption
+ cipher.init(false, new KeyParameter(key));
+
+ /*
+ * As the decryption is from our preformatted file,
+ * and we know that it's a hex encoded format, then
+ * we wrap the InputStream with a BufferedReader
+ * so that we can read it easily.
+ */
+ BufferedReader br = new BufferedReader(new InputStreamReader(in));
+
+ /*
+ * now, read the file, and output the chunks
+ */
+ try
+ {
+ int outL;
+ byte[] inblock = null;
+ byte[] outblock = null;
+ String rv = null;
+ while ((rv = br.readLine()) != null)
+ {
+ inblock = Hex.decode(rv);
+ outblock = new byte[cipher.getOutputSize(inblock.length)];
+
+ outL = cipher.processBytes(inblock, 0, inblock.length,
+ outblock, 0);
+ /*
+ * Before we write anything out, we need to make sure
+ * that we've got something to write out.
+ */
+ if (outL > 0)
+ {
+ out.write(outblock, 0, outL);
+ }
+ }
+
+ try
+ {
+ /*
+ * Now, process the bytes that are still buffered
+ * within the cipher.
+ */
+ outL = cipher.doFinal(outblock, 0);
+ if (outL > 0)
+ {
+ out.write(outblock, 0, outL);
+ }
+ }
+ catch (CryptoException ce)
+ {
+
+ }
+ }
+ catch (IOException ioeread)
+ {
+ ioeread.printStackTrace();
+ }
+ }
+
+}
+
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/examples/JPAKEExample.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/examples/JPAKEExample.java
new file mode 100644
index 0000000..7c18b92
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/examples/JPAKEExample.java
@@ -0,0 +1,214 @@
+package org.bc.crypto.examples;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
+import org.bc.crypto.CryptoException;
+import org.bc.crypto.Digest;
+import org.bc.crypto.agreement.jpake.JPAKEParticipant;
+import org.bc.crypto.agreement.jpake.JPAKEPrimeOrderGroup;
+import org.bc.crypto.agreement.jpake.JPAKEPrimeOrderGroups;
+import org.bc.crypto.agreement.jpake.JPAKERound1Payload;
+import org.bc.crypto.agreement.jpake.JPAKERound2Payload;
+import org.bc.crypto.agreement.jpake.JPAKERound3Payload;
+import org.bc.crypto.digests.SHA256Digest;
+
+/**
+ * An example of a J-PAKE exchange.
+ *
+ *
+ * In this example, both Alice and Bob are on the same computer (in the same JVM, in fact).
+ * In reality, Alice and Bob would be in different locations,
+ * and would be sending their generated payloads to each other.
+ */
+public class JPAKEExample
+{
+
+ public static void main(String args[]) throws CryptoException
+ {
+ /*
+ * Initialization
+ *
+ * Pick an appropriate prime order group to use throughout the exchange.
+ * Note that both participants must use the same group.
+ */
+ JPAKEPrimeOrderGroup group = JPAKEPrimeOrderGroups.NIST_3072;
+
+ BigInteger p = group.getP();
+ BigInteger q = group.getQ();
+ BigInteger g = group.getG();
+
+ String alicePassword = "password";
+ String bobPassword = "password";
+
+ System.out.println("********* Initialization **********");
+ System.out.println("Public parameters for the cyclic group:");
+ System.out.println("p (" + p.bitLength() + " bits): " + p.toString(16));
+ System.out.println("q (" + q.bitLength() + " bits): " + q.toString(16));
+ System.out.println("g (" + p.bitLength() + " bits): " + g.toString(16));
+ System.out.println("p mod q = " + p.mod(q).toString(16));
+ System.out.println("g^{q} mod p = " + g.modPow(q, p).toString(16));
+ System.out.println("");
+
+ System.out.println("(Secret passwords used by Alice and Bob: " +
+ "\"" + alicePassword + "\" and \"" + bobPassword + "\")\n");
+
+ /*
+ * Both participants must use the same hashing algorithm.
+ */
+ Digest digest = new SHA256Digest();
+ SecureRandom random = new SecureRandom();
+
+ JPAKEParticipant alice = new JPAKEParticipant("alice", alicePassword.toCharArray(), group, digest, random);
+ JPAKEParticipant bob = new JPAKEParticipant("bob", bobPassword.toCharArray(), group, digest, random);
+
+ /*
+ * Round 1
+ *
+ * Alice and Bob each generate a round 1 payload, and send it to each other.
+ */
+
+ JPAKERound1Payload aliceRound1Payload = alice.createRound1PayloadToSend();
+ JPAKERound1Payload bobRound1Payload = bob.createRound1PayloadToSend();
+
+ System.out.println("************ Round 1 **************");
+ System.out.println("Alice sends to Bob: ");
+ System.out.println("g^{x1}=" + aliceRound1Payload.getGx1().toString(16));
+ System.out.println("g^{x2}=" + aliceRound1Payload.getGx2().toString(16));
+ System.out.println("KP{x1}={" + aliceRound1Payload.getKnowledgeProofForX1()[0].toString(16) + "};{" + aliceRound1Payload.getKnowledgeProofForX1()[1].toString(16) + "}");
+ System.out.println("KP{x2}={" + aliceRound1Payload.getKnowledgeProofForX2()[0].toString(16) + "};{" + aliceRound1Payload.getKnowledgeProofForX2()[1].toString(16) + "}");
+ System.out.println("");
+
+ System.out.println("Bob sends to Alice: ");
+ System.out.println("g^{x3}=" + bobRound1Payload.getGx1().toString(16));
+ System.out.println("g^{x4}=" + bobRound1Payload.getGx2().toString(16));
+ System.out.println("KP{x3}={" + bobRound1Payload.getKnowledgeProofForX1()[0].toString(16) + "};{" + bobRound1Payload.getKnowledgeProofForX1()[1].toString(16) + "}");
+ System.out.println("KP{x4}={" + bobRound1Payload.getKnowledgeProofForX2()[0].toString(16) + "};{" + bobRound1Payload.getKnowledgeProofForX2()[1].toString(16) + "}");
+ System.out.println("");
+
+ /*
+ * Each participant must then validate the received payload for round 1
+ */
+
+ alice.validateRound1PayloadReceived(bobRound1Payload);
+ System.out.println("Alice checks g^{x4}!=1: OK");
+ System.out.println("Alice checks KP{x3}: OK");
+ System.out.println("Alice checks KP{x4}: OK");
+ System.out.println("");
+
+ bob.validateRound1PayloadReceived(aliceRound1Payload);
+ System.out.println("Bob checks g^{x2}!=1: OK");
+ System.out.println("Bob checks KP{x1},: OK");
+ System.out.println("Bob checks KP{x2},: OK");
+ System.out.println("");
+
+ /*
+ * Round 2
+ *
+ * Alice and Bob each generate a round 2 payload, and send it to each other.
+ */
+
+ JPAKERound2Payload aliceRound2Payload = alice.createRound2PayloadToSend();
+ JPAKERound2Payload bobRound2Payload = bob.createRound2PayloadToSend();
+
+ System.out.println("************ Round 2 **************");
+ System.out.println("Alice sends to Bob: ");
+ System.out.println("A=" + aliceRound2Payload.getA().toString(16));
+ System.out.println("KP{x2*s}={" + aliceRound2Payload.getKnowledgeProofForX2s()[0].toString(16) + "},{" + aliceRound2Payload.getKnowledgeProofForX2s()[1].toString(16) + "}");
+ System.out.println("");
+
+ System.out.println("Bob sends to Alice");
+ System.out.println("B=" + bobRound2Payload.getA().toString(16));
+ System.out.println("KP{x4*s}={" + bobRound2Payload.getKnowledgeProofForX2s()[0].toString(16) + "},{" + bobRound2Payload.getKnowledgeProofForX2s()[1].toString(16) + "}");
+ System.out.println("");
+
+ /*
+ * Each participant must then validate the received payload for round 2
+ */
+
+ alice.validateRound2PayloadReceived(bobRound2Payload);
+ System.out.println("Alice checks KP{x4*s}: OK\n");
+
+ bob.validateRound2PayloadReceived(aliceRound2Payload);
+ System.out.println("Bob checks KP{x2*s}: OK\n");
+
+ /*
+ * After round 2, each participant computes the keying material.
+ */
+
+ BigInteger aliceKeyingMaterial = alice.calculateKeyingMaterial();
+ BigInteger bobKeyingMaterial = bob.calculateKeyingMaterial();
+
+ System.out.println("********* After round 2 ***********");
+ System.out.println("Alice computes key material \t K=" + aliceKeyingMaterial.toString(16));
+ System.out.println("Bob computes key material \t K=" + bobKeyingMaterial.toString(16));
+ System.out.println();
+
+
+ /*
+ * You must derive a session key from the keying material applicable
+ * to whatever encryption algorithm you want to use.
+ */
+
+ BigInteger aliceKey = deriveSessionKey(aliceKeyingMaterial);
+ BigInteger bobKey = deriveSessionKey(bobKeyingMaterial);
+
+ /*
+ * At this point, you can stop and use the session keys if you want.
+ * This is implicit key confirmation.
+ *
+ * If you want to explicitly confirm that the key material matches,
+ * you can continue on and perform round 3.
+ */
+
+ /*
+ * Round 3
+ *
+ * Alice and Bob each generate a round 3 payload, and send it to each other.
+ */
+
+ JPAKERound3Payload aliceRound3Payload = alice.createRound3PayloadToSend(aliceKeyingMaterial);
+ JPAKERound3Payload bobRound3Payload = bob.createRound3PayloadToSend(bobKeyingMaterial);
+
+ System.out.println("************ Round 3 **************");
+ System.out.println("Alice sends to Bob: ");
+ System.out.println("MacTag=" + aliceRound3Payload.getMacTag().toString(16));
+ System.out.println("");
+ System.out.println("Bob sends to Alice: ");
+ System.out.println("MacTag=" + bobRound3Payload.getMacTag().toString(16));
+ System.out.println("");
+
+ /*
+ * Each participant must then validate the received payload for round 3
+ */
+
+ alice.validateRound3PayloadReceived(bobRound3Payload, aliceKeyingMaterial);
+ System.out.println("Alice checks MacTag: OK\n");
+
+ bob.validateRound3PayloadReceived(aliceRound3Payload, bobKeyingMaterial);
+ System.out.println("Bob checks MacTag: OK\n");
+
+ System.out.println();
+ System.out.println("MacTags validated, therefore the keying material matches.");
+ }
+
+ private static BigInteger deriveSessionKey(BigInteger keyingMaterial)
+ {
+ /*
+ * You should use a secure key derivation function (KDF) to derive the session key.
+ *
+ * For the purposes of this example, I'm just going to use a hash of the keying material.
+ */
+ SHA256Digest digest = new SHA256Digest();
+
+ byte[] keyByteArray = keyingMaterial.toByteArray();
+
+ byte[] output = new byte[digest.getDigestSize()];
+
+ digest.update(keyByteArray, 0, keyByteArray.length);
+
+ digest.doFinal(output, 0);
+
+ return new BigInteger(output);
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/generators/BaseKDFBytesGenerator.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/generators/BaseKDFBytesGenerator.java
new file mode 100644
index 0000000..b355253
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/generators/BaseKDFBytesGenerator.java
@@ -0,0 +1,142 @@
+package org.bc.crypto.generators;
+
+import org.bc.crypto.DataLengthException;
+import org.bc.crypto.DerivationFunction;
+import org.bc.crypto.DerivationParameters;
+import org.bc.crypto.Digest;
+import org.bc.crypto.params.ISO18033KDFParameters;
+import org.bc.crypto.params.KDFParameters;
+
+/**
+ * Basic KDF generator for derived keys and ivs as defined by IEEE P1363a/ISO 18033
+ *
+ * @param counterStart value of counter.
+ * @param digest the digest to be used as the source of derived keys.
+ */
+ protected BaseKDFBytesGenerator(
+ int counterStart,
+ Digest digest)
+ {
+ this.counterStart = counterStart;
+ this.digest = digest;
+ }
+
+ public void init(
+ DerivationParameters param)
+ {
+ if (param instanceof KDFParameters)
+ {
+ KDFParameters p = (KDFParameters)param;
+
+ shared = p.getSharedSecret();
+ iv = p.getIV();
+ }
+ else if (param instanceof ISO18033KDFParameters)
+ {
+ ISO18033KDFParameters p = (ISO18033KDFParameters)param;
+
+ shared = p.getSeed();
+ iv = null;
+ }
+ else
+ {
+ throw new IllegalArgumentException("KDF parameters required for KDF2Generator");
+ }
+ }
+
+ /**
+ * return the underlying digest.
+ */
+ public Digest getDigest()
+ {
+ return digest;
+ }
+
+ /**
+ * fill len bytes of the output buffer with bytes generated from
+ * the derivation function.
+ *
+ * @throws IllegalArgumentException if the size of the request will cause an overflow.
+ * @throws DataLengthException if the out buffer is too small.
+ */
+ public int generateBytes(
+ byte[] out,
+ int outOff,
+ int len)
+ throws DataLengthException, IllegalArgumentException
+ {
+ if ((out.length - len) < outOff)
+ {
+ throw new DataLengthException("output buffer too small");
+ }
+
+ long oBytes = len;
+ int outLen = digest.getDigestSize();
+
+ //
+ // this is at odds with the standard implementation, the
+ // maximum value should be hBits * (2^32 - 1) where hBits
+ // is the digest output size in bits. We can't have an
+ // array with a long index at the moment...
+ //
+ if (oBytes > ((2L << 32) - 1))
+ {
+ throw new IllegalArgumentException("Output length too large");
+ }
+
+ int cThreshold = (int)((oBytes + outLen - 1) / outLen);
+
+ byte[] dig = null;
+
+ dig = new byte[digest.getDigestSize()];
+
+ int counter = counterStart;
+
+ for (int i = 0; i < cThreshold; i++)
+ {
+ digest.update(shared, 0, shared.length);
+
+ digest.update((byte)(counter >> 24));
+ digest.update((byte)(counter >> 16));
+ digest.update((byte)(counter >> 8));
+ digest.update((byte)counter);
+
+ if (iv != null)
+ {
+ digest.update(iv, 0, iv.length);
+ }
+
+ digest.doFinal(dig, 0);
+
+ if (len > outLen)
+ {
+ System.arraycopy(dig, 0, out, outOff, outLen);
+ outOff += outLen;
+ len -= outLen;
+ }
+ else
+ {
+ System.arraycopy(dig, 0, out, outOff, len);
+ }
+
+ counter++;
+ }
+
+ digest.reset();
+
+ return len;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/generators/DESKeyGenerator.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/generators/DESKeyGenerator.java
new file mode 100644
index 0000000..0e61fe8
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/generators/DESKeyGenerator.java
@@ -0,0 +1,48 @@
+package org.bc.crypto.generators;
+
+import org.bc.crypto.CipherKeyGenerator;
+import org.bc.crypto.KeyGenerationParameters;
+import org.bc.crypto.params.DESParameters;
+
+public class DESKeyGenerator
+ extends CipherKeyGenerator
+{
+ /**
+ * initialise the key generator - if strength is set to zero
+ * the key generated will be 64 bits in size, otherwise
+ * strength can be 64 or 56 bits (if you don't count the parity bits).
+ *
+ * @param param the parameters to be used for key generation
+ */
+ public void init(
+ KeyGenerationParameters param)
+ {
+ super.init(param);
+
+ if (strength == 0 || strength == (56 / 8))
+ {
+ strength = DESParameters.DES_KEY_LENGTH;
+ }
+ else if (strength != DESParameters.DES_KEY_LENGTH)
+ {
+ throw new IllegalArgumentException("DES key must be "
+ + (DESParameters.DES_KEY_LENGTH * 8)
+ + " bits long.");
+ }
+ }
+
+ public byte[] generateKey()
+ {
+ byte[] newKey = new byte[DESParameters.DES_KEY_LENGTH];
+
+ do
+ {
+ random.nextBytes(newKey);
+
+ DESParameters.setOddParity(newKey);
+ }
+ while (DESParameters.isWeakKey(newKey, 0));
+
+ return newKey;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/generators/DESedeKeyGenerator.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/generators/DESedeKeyGenerator.java
new file mode 100644
index 0000000..a511bb9
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/generators/DESedeKeyGenerator.java
@@ -0,0 +1,56 @@
+package org.bc.crypto.generators;
+
+import org.bc.crypto.KeyGenerationParameters;
+import org.bc.crypto.params.DESedeParameters;
+
+public class DESedeKeyGenerator
+ extends DESKeyGenerator
+{
+ /**
+ * initialise the key generator - if strength is set to zero
+ * the key generated will be 192 bits in size, otherwise
+ * strength can be 128 or 192 (or 112 or 168 if you don't count
+ * parity bits), depending on whether you wish to do 2-key or 3-key
+ * triple DES.
+ *
+ * @param param the parameters to be used for key generation
+ */
+ public void init(
+ KeyGenerationParameters param)
+ {
+ this.random = param.getRandom();
+ this.strength = (param.getStrength() + 7) / 8;
+
+ if (strength == 0 || strength == (168 / 8))
+ {
+ strength = DESedeParameters.DES_EDE_KEY_LENGTH;
+ }
+ else if (strength == (112 / 8))
+ {
+ strength = 2 * DESedeParameters.DES_KEY_LENGTH;
+ }
+ else if (strength != DESedeParameters.DES_EDE_KEY_LENGTH
+ && strength != (2 * DESedeParameters.DES_KEY_LENGTH))
+ {
+ throw new IllegalArgumentException("DESede key must be "
+ + (DESedeParameters.DES_EDE_KEY_LENGTH * 8) + " or "
+ + (2 * 8 * DESedeParameters.DES_KEY_LENGTH)
+ + " bits long.");
+ }
+ }
+
+ public byte[] generateKey()
+ {
+ byte[] newKey = new byte[strength];
+
+ do
+ {
+ random.nextBytes(newKey);
+
+ DESedeParameters.setOddParity(newKey);
+ }
+ while (DESedeParameters.isWeakKey(newKey, 0, newKey.length));
+
+ return newKey;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/generators/DHBasicKeyPairGenerator.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/generators/DHBasicKeyPairGenerator.java
new file mode 100644
index 0000000..32b59ab
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/generators/DHBasicKeyPairGenerator.java
@@ -0,0 +1,42 @@
+package org.bc.crypto.generators;
+
+import org.bc.crypto.AsymmetricCipherKeyPair;
+import org.bc.crypto.AsymmetricCipherKeyPairGenerator;
+import org.bc.crypto.KeyGenerationParameters;
+import org.bc.crypto.params.DHKeyGenerationParameters;
+import org.bc.crypto.params.DHParameters;
+import org.bc.crypto.params.DHPrivateKeyParameters;
+import org.bc.crypto.params.DHPublicKeyParameters;
+
+import java.math.BigInteger;
+
+/**
+ * a basic Diffie-Hellman key pair generator.
+ *
+ * This generates keys consistent for use with the basic algorithm for
+ * Diffie-Hellman.
+ */
+public class DHBasicKeyPairGenerator
+ implements AsymmetricCipherKeyPairGenerator
+{
+ private DHKeyGenerationParameters param;
+
+ public void init(
+ KeyGenerationParameters param)
+ {
+ this.param = (DHKeyGenerationParameters)param;
+ }
+
+ public AsymmetricCipherKeyPair generateKeyPair()
+ {
+ DHKeyGeneratorHelper helper = DHKeyGeneratorHelper.INSTANCE;
+ DHParameters dhp = param.getParameters();
+
+ BigInteger x = helper.calculatePrivate(dhp, param.getRandom());
+ BigInteger y = helper.calculatePublic(dhp, x);
+
+ return new AsymmetricCipherKeyPair(
+ new DHPublicKeyParameters(y, dhp),
+ new DHPrivateKeyParameters(x, dhp));
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/generators/DHKeyGeneratorHelper.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/generators/DHKeyGeneratorHelper.java
new file mode 100644
index 0000000..16e47a0
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/generators/DHKeyGeneratorHelper.java
@@ -0,0 +1,51 @@
+package org.bc.crypto.generators;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
+import org.bc.crypto.params.DHParameters;
+import org.bc.util.BigIntegers;
+
+class DHKeyGeneratorHelper
+{
+ static final DHKeyGeneratorHelper INSTANCE = new DHKeyGeneratorHelper();
+
+ private static final BigInteger ONE = BigInteger.valueOf(1);
+ private static final BigInteger TWO = BigInteger.valueOf(2);
+
+ private DHKeyGeneratorHelper()
+ {
+ }
+
+ BigInteger calculatePrivate(DHParameters dhParams, SecureRandom random)
+ {
+ BigInteger p = dhParams.getP();
+ int limit = dhParams.getL();
+
+ if (limit != 0)
+ {
+ return new BigInteger(limit, random).setBit(limit - 1);
+ }
+
+ BigInteger min = TWO;
+ int m = dhParams.getM();
+ if (m != 0)
+ {
+ min = ONE.shiftLeft(m - 1);
+ }
+
+ BigInteger max = p.subtract(TWO);
+ BigInteger q = dhParams.getQ();
+ if (q != null)
+ {
+ max = q.subtract(TWO);
+ }
+
+ return BigIntegers.createRandomInRange(min, max, random);
+ }
+
+ BigInteger calculatePublic(DHParameters dhParams, BigInteger x)
+ {
+ return dhParams.getG().modPow(x, dhParams.getP());
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/generators/DHKeyPairGenerator.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/generators/DHKeyPairGenerator.java
new file mode 100644
index 0000000..16a7715
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/generators/DHKeyPairGenerator.java
@@ -0,0 +1,42 @@
+package org.bc.crypto.generators;
+
+import org.bc.crypto.AsymmetricCipherKeyPair;
+import org.bc.crypto.AsymmetricCipherKeyPairGenerator;
+import org.bc.crypto.KeyGenerationParameters;
+import org.bc.crypto.params.DHKeyGenerationParameters;
+import org.bc.crypto.params.DHParameters;
+import org.bc.crypto.params.DHPrivateKeyParameters;
+import org.bc.crypto.params.DHPublicKeyParameters;
+
+import java.math.BigInteger;
+
+/**
+ * a Diffie-Hellman key pair generator.
+ *
+ * This generates keys consistent for use in the MTI/A0 key agreement protocol
+ * as described in "Handbook of Applied Cryptography", Pages 516-519.
+ */
+public class DHKeyPairGenerator
+ implements AsymmetricCipherKeyPairGenerator
+{
+ private DHKeyGenerationParameters param;
+
+ public void init(
+ KeyGenerationParameters param)
+ {
+ this.param = (DHKeyGenerationParameters)param;
+ }
+
+ public AsymmetricCipherKeyPair generateKeyPair()
+ {
+ DHKeyGeneratorHelper helper = DHKeyGeneratorHelper.INSTANCE;
+ DHParameters dhp = param.getParameters();
+
+ BigInteger x = helper.calculatePrivate(dhp, param.getRandom());
+ BigInteger y = helper.calculatePublic(dhp, x);
+
+ return new AsymmetricCipherKeyPair(
+ new DHPublicKeyParameters(y, dhp),
+ new DHPrivateKeyParameters(x, dhp));
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/generators/DHParametersGenerator.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/generators/DHParametersGenerator.java
new file mode 100644
index 0000000..4b3bfe9
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/generators/DHParametersGenerator.java
@@ -0,0 +1,52 @@
+package org.bc.crypto.generators;
+
+import org.bc.crypto.params.DHParameters;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
+public class DHParametersGenerator
+{
+ private int size;
+ private int certainty;
+ private SecureRandom random;
+
+ private static final BigInteger TWO = BigInteger.valueOf(2);
+
+ /**
+ * Initialise the parameters generator.
+ *
+ * @param size bit length for the prime p
+ * @param certainty level of certainty for the prime number tests
+ * @param random a source of randomness
+ */
+ public void init(
+ int size,
+ int certainty,
+ SecureRandom random)
+ {
+ this.size = size;
+ this.certainty = certainty;
+ this.random = random;
+ }
+
+ /**
+ * which generates the p and g values from the given parameters,
+ * returning the DHParameters object.
+ *
+ * Note: can take a while...
+ */
+ public DHParameters generateParameters()
+ {
+ //
+ // find a safe prime p where p = 2*q + 1, where p and q are prime.
+ //
+ BigInteger[] safePrimes = DHParametersHelper.generateSafePrimes(size, certainty, random);
+
+ BigInteger p = safePrimes[0];
+ BigInteger q = safePrimes[1];
+ BigInteger g = DHParametersHelper.selectGenerator(p, q, random);
+
+ return new DHParameters(p, g, q, TWO, null);
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/generators/DHParametersHelper.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/generators/DHParametersHelper.java
new file mode 100644
index 0000000..0d13c27
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/generators/DHParametersHelper.java
@@ -0,0 +1,73 @@
+package org.bc.crypto.generators;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
+import org.bc.util.BigIntegers;
+
+class DHParametersHelper
+{
+ private static final BigInteger ONE = BigInteger.valueOf(1);
+ private static final BigInteger TWO = BigInteger.valueOf(2);
+
+ /*
+ * Finds a pair of prime BigInteger's {p, q: p = 2q + 1}
+ *
+ * (see: Handbook of Applied Cryptography 4.86)
+ */
+ static BigInteger[] generateSafePrimes(int size, int certainty, SecureRandom random)
+ {
+ BigInteger p, q;
+ int qLength = size - 1;
+
+ for (;;)
+ {
+ q = new BigInteger(qLength, 2, random);
+
+ // p <- 2q + 1
+ p = q.shiftLeft(1).add(ONE);
+
+ if (p.isProbablePrime(certainty) && (certainty <= 2 || q.isProbablePrime(certainty)))
+ {
+ break;
+ }
+ }
+
+ return new BigInteger[] { p, q };
+ }
+
+ /*
+ * Select a high order element of the multiplicative group Zp*
+ *
+ * p and q must be s.t. p = 2*q + 1, where p and q are prime (see generateSafePrimes)
+ */
+ static BigInteger selectGenerator(BigInteger p, BigInteger q, SecureRandom random)
+ {
+ BigInteger pMinusTwo = p.subtract(TWO);
+ BigInteger g;
+
+ /*
+ * (see: Handbook of Applied Cryptography 4.80)
+ */
+// do
+// {
+// g = BigIntegers.createRandomInRange(TWO, pMinusTwo, random);
+// }
+// while (g.modPow(TWO, p).equals(ONE) || g.modPow(q, p).equals(ONE));
+
+
+ /*
+ * RFC 2631 2.2.1.2 (and see: Handbook of Applied Cryptography 4.81)
+ */
+ do
+ {
+ BigInteger h = BigIntegers.createRandomInRange(TWO, pMinusTwo, random);
+
+ g = h.modPow(TWO, p);
+ }
+ while (g.equals(ONE));
+
+
+ return g;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/generators/DSAKeyPairGenerator.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/generators/DSAKeyPairGenerator.java
new file mode 100644
index 0000000..7ebd3d6
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/generators/DSAKeyPairGenerator.java
@@ -0,0 +1,61 @@
+package org.bc.crypto.generators;
+
+import org.bc.crypto.AsymmetricCipherKeyPair;
+import org.bc.crypto.AsymmetricCipherKeyPairGenerator;
+import org.bc.crypto.KeyGenerationParameters;
+import org.bc.crypto.params.DSAKeyGenerationParameters;
+import org.bc.crypto.params.DSAParameters;
+import org.bc.crypto.params.DSAPrivateKeyParameters;
+import org.bc.crypto.params.DSAPublicKeyParameters;
+import org.bc.util.BigIntegers;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
+/**
+ * a DSA key pair generator.
+ *
+ * This generates DSA keys in line with the method described
+ * in FIPS 186-3 B.1 FFC Key Pair Generation.
+ */
+public class DSAKeyPairGenerator
+ implements AsymmetricCipherKeyPairGenerator
+{
+ private static final BigInteger ONE = BigInteger.valueOf(1);
+
+ private DSAKeyGenerationParameters param;
+
+ public void init(
+ KeyGenerationParameters param)
+ {
+ this.param = (DSAKeyGenerationParameters)param;
+ }
+
+ public AsymmetricCipherKeyPair generateKeyPair()
+ {
+ DSAParameters dsaParams = param.getParameters();
+
+ BigInteger x = generatePrivateKey(dsaParams.getQ(), param.getRandom());
+ BigInteger y = calculatePublicKey(dsaParams.getP(), dsaParams.getG(), x);
+
+ return new AsymmetricCipherKeyPair(
+ new DSAPublicKeyParameters(y, dsaParams),
+ new DSAPrivateKeyParameters(x, dsaParams));
+ }
+
+ private static BigInteger generatePrivateKey(BigInteger q, SecureRandom random)
+ {
+ // TODO Prefer this method? (change test cases that used fixed random)
+ // B.1.1 Key Pair Generation Using Extra Random Bits
+// BigInteger c = new BigInteger(q.bitLength() + 64, random);
+// return c.mod(q.subtract(ONE)).add(ONE);
+
+ // B.1.2 Key Pair Generation by Testing Candidates
+ return BigIntegers.createRandomInRange(ONE, q.subtract(ONE), random);
+ }
+
+ private static BigInteger calculatePublicKey(BigInteger p, BigInteger g, BigInteger x)
+ {
+ return g.modPow(x, p);
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/generators/DSAParametersGenerator.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/generators/DSAParametersGenerator.java
new file mode 100644
index 0000000..7451e22
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/generators/DSAParametersGenerator.java
@@ -0,0 +1,337 @@
+package org.bc.crypto.generators;
+
+import org.bc.crypto.Digest;
+import org.bc.crypto.digests.SHA1Digest;
+import org.bc.crypto.digests.SHA256Digest;
+import org.bc.crypto.params.DSAParameters;
+import org.bc.crypto.params.DSAValidationParameters;
+import org.bc.util.Arrays;
+import org.bc.util.BigIntegers;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
+// TODO Update javadoc to mention FIPS 186-3 when done
+/**
+ * generate suitable parameters for DSA, in line with FIPS 186-2.
+ */
+public class DSAParametersGenerator
+{
+ private int L, N;
+ private int certainty;
+ private SecureRandom random;
+
+ private static final BigInteger ZERO = BigInteger.valueOf(0);
+ private static final BigInteger ONE = BigInteger.valueOf(1);
+ private static final BigInteger TWO = BigInteger.valueOf(2);
+
+ /**
+ * initialise the key generator.
+ *
+ * @param size size of the key (range 2^512 -> 2^1024 - 64 bit increments)
+ * @param certainty measure of robustness of prime (for FIPS 186-2 compliance this should be at least 80).
+ * @param random random byte source.
+ */
+ public void init(
+ int size,
+ int certainty,
+ SecureRandom random)
+ {
+ init(size, getDefaultN(size), certainty, random);
+ }
+
+ // TODO Make public to enable support for DSA keys > 1024 bits
+ private void init(
+ int L,
+ int N,
+ int certainty,
+ SecureRandom random)
+ {
+ // TODO Check that the (L, N) pair is in the list of acceptable (L, N pairs) (see Section 4.2)
+ // TODO Should we enforce the minimum 'certainty' values as per C.3 Table C.1?
+
+ this.L = L;
+ this.N = N;
+ this.certainty = certainty;
+ this.random = random;
+ }
+
+ /**
+ * which generates the p and g values from the given parameters,
+ * returning the DSAParameters object.
+ *
+ * Note: can take a while...
+ */
+ public DSAParameters generateParameters()
+ {
+ return L > 1024
+ ? generateParameters_FIPS186_3()
+ : generateParameters_FIPS186_2();
+ }
+
+ private DSAParameters generateParameters_FIPS186_2()
+ {
+ byte[] seed = new byte[20];
+ byte[] part1 = new byte[20];
+ byte[] part2 = new byte[20];
+ byte[] u = new byte[20];
+ SHA1Digest sha1 = new SHA1Digest();
+ int n = (L - 1) / 160;
+ byte[] w = new byte[L / 8];
+
+ for (;;)
+ {
+ random.nextBytes(seed);
+
+ hash(sha1, seed, part1);
+ System.arraycopy(seed, 0, part2, 0, seed.length);
+ inc(part2);
+ hash(sha1, part2, part2);
+
+ for (int i = 0; i != u.length; i++)
+ {
+ u[i] = (byte)(part1[i] ^ part2[i]);
+ }
+
+ u[0] |= (byte)0x80;
+ u[19] |= (byte)0x01;
+
+ BigInteger q = new BigInteger(1, u);
+
+ if (!q.isProbablePrime(certainty))
+ {
+ continue;
+ }
+
+ byte[] offset = Arrays.clone(seed);
+ inc(offset);
+
+ for (int counter = 0; counter < 4096; ++counter)
+ {
+ for (int k = 0; k < n; k++)
+ {
+ inc(offset);
+ hash(sha1, offset, part1);
+ System.arraycopy(part1, 0, w, w.length - (k + 1) * part1.length, part1.length);
+ }
+
+ inc(offset);
+ hash(sha1, offset, part1);
+ System.arraycopy(part1, part1.length - ((w.length - (n) * part1.length)), w, 0, w.length - n * part1.length);
+
+ w[0] |= (byte)0x80;
+
+ BigInteger x = new BigInteger(1, w);
+
+ BigInteger c = x.mod(q.shiftLeft(1));
+
+ BigInteger p = x.subtract(c.subtract(ONE));
+
+ if (p.bitLength() != L)
+ {
+ continue;
+ }
+
+ if (p.isProbablePrime(certainty))
+ {
+ BigInteger g = calculateGenerator_FIPS186_2(p, q, random);
+
+ return new DSAParameters(p, q, g, new DSAValidationParameters(seed, counter));
+ }
+ }
+ }
+ }
+
+ private static BigInteger calculateGenerator_FIPS186_2(BigInteger p, BigInteger q, SecureRandom r)
+ {
+ BigInteger e = p.subtract(ONE).divide(q);
+ BigInteger pSub2 = p.subtract(TWO);
+
+ for (;;)
+ {
+ BigInteger h = BigIntegers.createRandomInRange(TWO, pSub2, r);
+ BigInteger g = h.modPow(e, p);
+ if (g.bitLength() > 1)
+ {
+ return g;
+ }
+ }
+ }
+
+ /**
+ * generate suitable parameters for DSA, in line with
+ * FIPS 186-3 A.1 Generation of the FFC Primes p and q.
+ */
+ private DSAParameters generateParameters_FIPS186_3()
+ {
+// A.1.1.2 Generation of the Probable Primes p and q Using an Approved Hash Function
+ // FIXME This should be configurable (digest size in bits must be >= N)
+ Digest d = new SHA256Digest();
+ int outlen = d.getDigestSize() * 8;
+
+// 1. Check that the (L, N) pair is in the list of acceptable (L, N pairs) (see Section 4.2). If
+// the pair is not in the list, then return INVALID.
+ // Note: checked at initialisation
+
+// 2. If (seedlen < N), then return INVALID.
+ // FIXME This should be configurable (must be >= N)
+ int seedlen = N;
+ byte[] seed = new byte[seedlen / 8];
+
+// 3. n = ceiling(L ℠outlen) – 1.
+ int n = (L - 1) / outlen;
+
+// 4. b = L – 1 – (n ∗ outlen).
+ int b = (L - 1) % outlen;
+
+ byte[] output = new byte[d.getDigestSize()];
+ for (;;)
+ {
+// 5. Get an arbitrary sequence of seedlen bits as the domain_parameter_seed.
+ random.nextBytes(seed);
+
+// 6. U = Hash (domain_parameter_seed) mod 2^(N–1).
+ hash(d, seed, output);
+ BigInteger U = new BigInteger(1, output).mod(ONE.shiftLeft(N - 1));
+
+// 7. q = 2^(N–1) + U + 1 – ( U mod 2).
+ BigInteger q = ONE.shiftLeft(N - 1).add(U).add(ONE).subtract(U.mod(TWO));
+
+// 8. Test whether or not q is prime as specified in Appendix C.3.
+ // TODO Review C.3 for primality checking
+ if (!q.isProbablePrime(certainty))
+ {
+// 9. If q is not a prime, then go to step 5.
+ continue;
+ }
+
+// 10. offset = 1.
+ // Note: 'offset' value managed incrementally
+ byte[] offset = Arrays.clone(seed);
+
+// 11. For counter = 0 to (4L – 1) do
+ int counterLimit = 4 * L;
+ for (int counter = 0; counter < counterLimit; ++counter)
+ {
+// 11.1 For j = 0 to n do
+// Vj = Hash ((domain_parameter_seed + offset + j) mod 2^seedlen).
+// 11.2 W = V0 + (V1 ∗ 2^outlen) + ... + (V^(n–1) ∗ 2^((n–1) ∗ outlen)) + ((Vn mod 2^b) ∗ 2^(n ∗ outlen)).
+ // TODO Assemble w as a byte array
+ BigInteger W = ZERO;
+ for (int j = 0, exp = 0; j <= n; ++j, exp += outlen)
+ {
+ inc(offset);
+ hash(d, offset, output);
+
+ BigInteger Vj = new BigInteger(1, output);
+ if (j == n)
+ {
+ Vj = Vj.mod(ONE.shiftLeft(b));
+ }
+
+ W = W.add(Vj.shiftLeft(exp));
+ }
+
+// 11.3 X = W + 2^(L–1). Comment: 0 ≤ W < 2L–1; hence, 2L–1 ≤ X < 2L.
+ BigInteger X = W.add(ONE.shiftLeft(L - 1));
+
+// 11.4 c = X mod 2q.
+ BigInteger c = X.mod(q.shiftLeft(1));
+
+// 11.5 p = X - (c - 1). Comment: p ≡ 1 (mod 2q).
+ BigInteger p = X.subtract(c.subtract(ONE));
+
+// 11.6 If (p < 2^(L - 1)), then go to step 11.9
+ if (p.bitLength() != L)
+ {
+ continue;
+ }
+
+// 11.7 Test whether or not p is prime as specified in Appendix C.3.
+ // TODO Review C.3 for primality checking
+ if (p.isProbablePrime(certainty))
+ {
+// 11.8 If p is determined to be prime, then return VALID and the values of p, q and
+// (optionally) the values of domain_parameter_seed and counter.
+ // TODO Make configurable (8-bit unsigned)?
+// int index = 1;
+// BigInteger g = calculateGenerator_FIPS186_3_Verifiable(d, p, q, seed, index);
+// if (g != null)
+// {
+// // TODO Should 'index' be a part of the validation parameters?
+// return new DSAParameters(p, q, g, new DSAValidationParameters(seed, counter));
+// }
+
+ BigInteger g = calculateGenerator_FIPS186_3_Unverifiable(p, q, random);
+ return new DSAParameters(p, q, g, new DSAValidationParameters(seed, counter));
+ }
+
+// 11.9 offset = offset + n + 1. Comment: Increment offset; then, as part of
+// the loop in step 11, increment counter; if
+// counter < 4L, repeat steps 11.1 through 11.8.
+ // Note: 'offset' value already incremented in inner loop
+ }
+// 12. Go to step 5.
+ }
+ }
+
+ private static BigInteger calculateGenerator_FIPS186_3_Unverifiable(BigInteger p, BigInteger q,
+ SecureRandom r)
+ {
+ return calculateGenerator_FIPS186_2(p, q, r);
+ }
+
+// private static BigInteger calculateGenerator_FIPS186_3_Verifiable(Digest d, BigInteger p, BigInteger q,
+// byte[] seed, int index)
+// {
+//// A.2.3 Verifiable Canonical Generation of the Generator g
+// BigInteger e = p.subtract(ONE).divide(q);
+// byte[] ggen = Hex.decode("6767656E");
+//
+// // 7. U = domain_parameter_seed || "ggen" || index || count.
+// byte[] U = new byte[seed.length + ggen.length + 1 + 2];
+// System.arraycopy(seed, 0, U, 0, seed.length);
+// System.arraycopy(ggen, 0, U, seed.length, ggen.length);
+// U[U.length - 3] = (byte)index;
+//
+// byte[] w = new byte[d.getDigestSize()];
+// for (int count = 1; count < (1 << 16); ++count)
+// {
+// inc(U);
+// hash(d, U, w);
+// BigInteger W = new BigInteger(1, w);
+// BigInteger g = W.modPow(e, p);
+// if (g.compareTo(TWO) >= 0)
+// {
+// return g;
+// }
+// }
+//
+// return null;
+// }
+
+ private static void hash(Digest d, byte[] input, byte[] output)
+ {
+ d.update(input, 0, input.length);
+ d.doFinal(output, 0);
+ }
+
+ private static int getDefaultN(int L)
+ {
+ return L > 1024 ? 256 : 160;
+ }
+
+ private static void inc(byte[] buf)
+ {
+ for (int i = buf.length - 1; i >= 0; --i)
+ {
+ byte b = (byte)((buf[i] + 1) & 0xff);
+ buf[i] = b;
+
+ if (b != 0)
+ {
+ break;
+ }
+ }
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/generators/DSTU4145KeyPairGenerator.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/generators/DSTU4145KeyPairGenerator.java
new file mode 100644
index 0000000..3673444
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/generators/DSTU4145KeyPairGenerator.java
@@ -0,0 +1,21 @@
+package org.bc.crypto.generators;
+
+import org.bc.crypto.AsymmetricCipherKeyPair;
+import org.bc.crypto.params.ECPrivateKeyParameters;
+import org.bc.crypto.params.ECPublicKeyParameters;
+
+public class DSTU4145KeyPairGenerator
+ extends ECKeyPairGenerator
+{
+ public AsymmetricCipherKeyPair generateKeyPair()
+ {
+ AsymmetricCipherKeyPair pair = super.generateKeyPair();
+
+ ECPublicKeyParameters pub = (ECPublicKeyParameters)pair.getPublic();
+ ECPrivateKeyParameters priv = (ECPrivateKeyParameters)pair.getPrivate();
+
+ pub = new ECPublicKeyParameters(pub.getQ().negate(), pub.getParameters());
+
+ return new AsymmetricCipherKeyPair(pub, priv);
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/generators/ECKeyPairGenerator.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/generators/ECKeyPairGenerator.java
new file mode 100644
index 0000000..49fab98
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/generators/ECKeyPairGenerator.java
@@ -0,0 +1,53 @@
+package org.bc.crypto.generators;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
+import org.bc.crypto.AsymmetricCipherKeyPair;
+import org.bc.crypto.AsymmetricCipherKeyPairGenerator;
+import org.bc.crypto.KeyGenerationParameters;
+import org.bc.crypto.params.ECDomainParameters;
+import org.bc.crypto.params.ECKeyGenerationParameters;
+import org.bc.crypto.params.ECPrivateKeyParameters;
+import org.bc.crypto.params.ECPublicKeyParameters;
+import org.bc.math.ec.ECConstants;
+import org.bc.math.ec.ECPoint;
+
+public class ECKeyPairGenerator
+ implements AsymmetricCipherKeyPairGenerator, ECConstants
+{
+ ECDomainParameters params;
+ SecureRandom random;
+
+ public void init(
+ KeyGenerationParameters param)
+ {
+ ECKeyGenerationParameters ecP = (ECKeyGenerationParameters)param;
+
+ this.random = ecP.getRandom();
+ this.params = ecP.getDomainParameters();
+ }
+
+ /**
+ * Given the domain parameters this routine generates an EC key
+ * pair in accordance with X9.62 section 5.2.1 pages 26, 27.
+ */
+ public AsymmetricCipherKeyPair generateKeyPair()
+ {
+ BigInteger n = params.getN();
+ int nBitLength = n.bitLength();
+ BigInteger d;
+
+ do
+ {
+ d = new BigInteger(nBitLength, random);
+ }
+ while (d.equals(ZERO) || (d.compareTo(n) >= 0));
+
+ ECPoint Q = params.getG().multiply(d);
+
+ return new AsymmetricCipherKeyPair(
+ new ECPublicKeyParameters(Q, params),
+ new ECPrivateKeyParameters(d, params));
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/generators/ElGamalKeyPairGenerator.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/generators/ElGamalKeyPairGenerator.java
new file mode 100644
index 0000000..bb6d1e6
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/generators/ElGamalKeyPairGenerator.java
@@ -0,0 +1,44 @@
+package org.bc.crypto.generators;
+
+import java.math.BigInteger;
+
+import org.bc.crypto.AsymmetricCipherKeyPair;
+import org.bc.crypto.AsymmetricCipherKeyPairGenerator;
+import org.bc.crypto.KeyGenerationParameters;
+import org.bc.crypto.params.DHParameters;
+import org.bc.crypto.params.ElGamalKeyGenerationParameters;
+import org.bc.crypto.params.ElGamalParameters;
+import org.bc.crypto.params.ElGamalPrivateKeyParameters;
+import org.bc.crypto.params.ElGamalPublicKeyParameters;
+
+/**
+ * a ElGamal key pair generator.
+ *
+ * This generates keys consistent for use with ElGamal as described in
+ * page 164 of "Handbook of Applied Cryptography".
+ */
+public class ElGamalKeyPairGenerator
+ implements AsymmetricCipherKeyPairGenerator
+{
+ private ElGamalKeyGenerationParameters param;
+
+ public void init(
+ KeyGenerationParameters param)
+ {
+ this.param = (ElGamalKeyGenerationParameters)param;
+ }
+
+ public AsymmetricCipherKeyPair generateKeyPair()
+ {
+ DHKeyGeneratorHelper helper = DHKeyGeneratorHelper.INSTANCE;
+ ElGamalParameters egp = param.getParameters();
+ DHParameters dhp = new DHParameters(egp.getP(), egp.getG(), null, egp.getL());
+
+ BigInteger x = helper.calculatePrivate(dhp, param.getRandom());
+ BigInteger y = helper.calculatePublic(dhp, x);
+
+ return new AsymmetricCipherKeyPair(
+ new ElGamalPublicKeyParameters(y, egp),
+ new ElGamalPrivateKeyParameters(x, egp));
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/generators/ElGamalParametersGenerator.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/generators/ElGamalParametersGenerator.java
new file mode 100644
index 0000000..7fd1d83
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/generators/ElGamalParametersGenerator.java
@@ -0,0 +1,43 @@
+package org.bc.crypto.generators;
+
+import org.bc.crypto.params.ElGamalParameters;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
+public class ElGamalParametersGenerator
+{
+ private int size;
+ private int certainty;
+ private SecureRandom random;
+
+ public void init(
+ int size,
+ int certainty,
+ SecureRandom random)
+ {
+ this.size = size;
+ this.certainty = certainty;
+ this.random = random;
+ }
+
+ /**
+ * which generates the p and g values from the given parameters,
+ * returning the ElGamalParameters object.
+ *
+ * Note: can take a while...
+ */
+ public ElGamalParameters generateParameters()
+ {
+ //
+ // find a safe prime p where p = 2*q + 1, where p and q are prime.
+ //
+ BigInteger[] safePrimes = DHParametersHelper.generateSafePrimes(size, certainty, random);
+
+ BigInteger p = safePrimes[0];
+ BigInteger q = safePrimes[1];
+ BigInteger g = DHParametersHelper.selectGenerator(p, q, random);
+
+ return new ElGamalParameters(p, g);
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/generators/EphemeralKeyPairGenerator.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/generators/EphemeralKeyPairGenerator.java
new file mode 100644
index 0000000..8b563f2
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/generators/EphemeralKeyPairGenerator.java
@@ -0,0 +1,26 @@
+package org.bc.crypto.generators;
+
+import org.bc.crypto.AsymmetricCipherKeyPair;
+import org.bc.crypto.AsymmetricCipherKeyPairGenerator;
+import org.bc.crypto.EphemeralKeyPair;
+import org.bc.crypto.KeyEncoder;
+
+public class EphemeralKeyPairGenerator
+{
+ private AsymmetricCipherKeyPairGenerator gen;
+ private KeyEncoder keyEncoder;
+
+ public EphemeralKeyPairGenerator(AsymmetricCipherKeyPairGenerator gen, KeyEncoder keyEncoder)
+ {
+ this.gen = gen;
+ this.keyEncoder = keyEncoder;
+ }
+
+ public EphemeralKeyPair generate()
+ {
+ AsymmetricCipherKeyPair eph = gen.generateKeyPair();
+
+ // Encode the ephemeral public key
+ return new EphemeralKeyPair(eph, keyEncoder);
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/generators/GOST3410KeyPairGenerator.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/generators/GOST3410KeyPairGenerator.java
new file mode 100644
index 0000000..a5cfcbf
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/generators/GOST3410KeyPairGenerator.java
@@ -0,0 +1,57 @@
+package org.bc.crypto.generators;
+
+import org.bc.crypto.AsymmetricCipherKeyPair;
+import org.bc.crypto.AsymmetricCipherKeyPairGenerator;
+import org.bc.crypto.KeyGenerationParameters;
+import org.bc.crypto.params.GOST3410KeyGenerationParameters;
+import org.bc.crypto.params.GOST3410Parameters;
+import org.bc.crypto.params.GOST3410PrivateKeyParameters;
+import org.bc.crypto.params.GOST3410PublicKeyParameters;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
+/**
+ * a GOST3410 key pair generator.
+ * This generates GOST3410 keys in line with the method described
+ * in GOST R 34.10-94.
+ */
+public class GOST3410KeyPairGenerator
+ implements AsymmetricCipherKeyPairGenerator
+ {
+ private static final BigInteger ZERO = BigInteger.valueOf(0);
+
+ private GOST3410KeyGenerationParameters param;
+
+ public void init(
+ KeyGenerationParameters param)
+ {
+ this.param = (GOST3410KeyGenerationParameters)param;
+ }
+
+ public AsymmetricCipherKeyPair generateKeyPair()
+ {
+ BigInteger p, q, a, x, y;
+ GOST3410Parameters GOST3410Params = param.getParameters();
+ SecureRandom random = param.getRandom();
+
+ q = GOST3410Params.getQ();
+ p = GOST3410Params.getP();
+ a = GOST3410Params.getA();
+
+ do
+ {
+ x = new BigInteger(256, random);
+ }
+ while (x.equals(ZERO) || x.compareTo(q) >= 0);
+
+ //
+ // calculate the public key.
+ //
+ y = a.modPow(x, p);
+
+ return new AsymmetricCipherKeyPair(
+ new GOST3410PublicKeyParameters(y, GOST3410Params),
+ new GOST3410PrivateKeyParameters(x, GOST3410Params));
+ }
+ }
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/generators/GOST3410ParametersGenerator.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/generators/GOST3410ParametersGenerator.java
new file mode 100644
index 0000000..e0f8440
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/generators/GOST3410ParametersGenerator.java
@@ -0,0 +1,541 @@
+package org.bc.crypto.generators;
+
+import org.bc.crypto.params.GOST3410Parameters;
+import org.bc.crypto.params.GOST3410ValidationParameters;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
+/**
+ * generate suitable parameters for GOST3410.
+ */
+public class GOST3410ParametersGenerator
+{
+ private int size;
+ private int typeproc;
+ private SecureRandom init_random;
+
+ private static final BigInteger ONE = BigInteger.valueOf(1);
+ private static final BigInteger TWO = BigInteger.valueOf(2);
+
+ /**
+ * initialise the key generator.
+ *
+ * @param size size of the key
+ * @param typeproc type procedure A,B = 1; A',B' - else
+ * @param random random byte source.
+ */
+ public void init(
+ int size,
+ int typeproc,
+ SecureRandom random)
+ {
+ this.size = size;
+ this.typeproc = typeproc;
+ this.init_random = random;
+ }
+
+ //Procedure A
+ private int procedure_A(int x0, int c, BigInteger[] pq, int size)
+ {
+ //Verify and perform condition: 0
+ * @param digest the digest to be used as the source of derived keys.
+ */
+ public KDF1BytesGenerator(
+ Digest digest)
+ {
+ super(0, digest);
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/generators/KDF2BytesGenerator.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/generators/KDF2BytesGenerator.java
new file mode 100644
index 0000000..3ad24c5
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/generators/KDF2BytesGenerator.java
@@ -0,0 +1,24 @@
+package org.bc.crypto.generators;
+
+import org.bc.crypto.Digest;
+
+/**
+ * KDF2 generator for derived keys and ivs as defined by IEEE P1363a/ISO 18033
+ *
+ * @param digest the digest to be used as the source of derived keys.
+ */
+ public KDF2BytesGenerator(
+ Digest digest)
+ {
+ super(1, digest);
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/generators/MGF1BytesGenerator.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/generators/MGF1BytesGenerator.java
new file mode 100644
index 0000000..9257dd1
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/generators/MGF1BytesGenerator.java
@@ -0,0 +1,114 @@
+package org.bc.crypto.generators;
+
+import org.bc.crypto.DataLengthException;
+import org.bc.crypto.DerivationFunction;
+import org.bc.crypto.DerivationParameters;
+import org.bc.crypto.Digest;
+import org.bc.crypto.params.MGFParameters;
+
+/**
+ * Generator for MGF1 as defined in PKCS 1v2
+ */
+public class MGF1BytesGenerator
+ implements DerivationFunction
+{
+ private Digest digest;
+ private byte[] seed;
+ private int hLen;
+
+ /**
+ * @param digest the digest to be used as the source of generated bytes
+ */
+ public MGF1BytesGenerator(
+ Digest digest)
+ {
+ this.digest = digest;
+ this.hLen = digest.getDigestSize();
+ }
+
+ public void init(
+ DerivationParameters param)
+ {
+ if (!(param instanceof MGFParameters))
+ {
+ throw new IllegalArgumentException("MGF parameters required for MGF1Generator");
+ }
+
+ MGFParameters p = (MGFParameters)param;
+
+ seed = p.getSeed();
+ }
+
+ /**
+ * return the underlying digest.
+ */
+ public Digest getDigest()
+ {
+ return digest;
+ }
+
+ /**
+ * int to octet string.
+ */
+ private void ItoOSP(
+ int i,
+ byte[] sp)
+ {
+ sp[0] = (byte)(i >>> 24);
+ sp[1] = (byte)(i >>> 16);
+ sp[2] = (byte)(i >>> 8);
+ sp[3] = (byte)(i >>> 0);
+ }
+
+ /**
+ * fill len bytes of the output buffer with bytes generated from
+ * the derivation function.
+ *
+ * @throws DataLengthException if the out buffer is too small.
+ */
+ public int generateBytes(
+ byte[] out,
+ int outOff,
+ int len)
+ throws DataLengthException, IllegalArgumentException
+ {
+ if ((out.length - len) < outOff)
+ {
+ throw new DataLengthException("output buffer too small");
+ }
+
+ byte[] hashBuf = new byte[hLen];
+ byte[] C = new byte[4];
+ int counter = 0;
+
+ digest.reset();
+
+ if (len > hLen)
+ {
+ do
+ {
+ ItoOSP(counter, C);
+
+ digest.update(seed, 0, seed.length);
+ digest.update(C, 0, C.length);
+ digest.doFinal(hashBuf, 0);
+
+ System.arraycopy(hashBuf, 0, out, outOff + counter * hLen, hLen);
+ }
+ while (++counter < (len / hLen));
+ }
+
+ if ((counter * hLen) < len)
+ {
+ ItoOSP(counter, C);
+
+ digest.update(seed, 0, seed.length);
+ digest.update(C, 0, C.length);
+ digest.doFinal(hashBuf, 0);
+
+ System.arraycopy(hashBuf, 0, out, outOff + counter * hLen, len - (counter * hLen));
+ }
+
+ return len;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/generators/NTRUEncryptionKeyPairGenerator.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/generators/NTRUEncryptionKeyPairGenerator.java
new file mode 100644
index 0000000..77bb40a
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/generators/NTRUEncryptionKeyPairGenerator.java
@@ -0,0 +1,117 @@
+package org.bc.crypto.generators;
+
+import org.bc.crypto.AsymmetricCipherKeyPair;
+import org.bc.crypto.AsymmetricCipherKeyPairGenerator;
+import org.bc.crypto.KeyGenerationParameters;
+import org.bc.crypto.params.NTRUEncryptionKeyGenerationParameters;
+import org.bc.crypto.params.NTRUEncryptionPrivateKeyParameters;
+import org.bc.crypto.params.NTRUEncryptionPublicKeyParameters;
+import org.bc.crypto.params.NTRUParameters;
+import org.bc.math.ntru.polynomial.DenseTernaryPolynomial;
+import org.bc.math.ntru.polynomial.IntegerPolynomial;
+import org.bc.math.ntru.polynomial.Polynomial;
+import org.bc.math.ntru.polynomial.ProductFormPolynomial;
+import org.bc.math.ntru.util.Util;
+
+/**
+ * Generates key pairs.
+ * The scheme is a simple extension of PKCS 5 V2.0 Scheme 1 using MD5 with an
+ * iteration count of 1.
+ *
+ */
+public class OpenSSLPBEParametersGenerator
+ extends PBEParametersGenerator
+{
+ private Digest digest = new MD5Digest();
+
+ /**
+ * Construct a OpenSSL Parameters generator.
+ */
+ public OpenSSLPBEParametersGenerator()
+ {
+ }
+
+ /**
+ * Initialise - note the iteration count for this algorithm is fixed at 1.
+ *
+ * @param password password to use.
+ * @param salt salt to use.
+ */
+ public void init(
+ byte[] password,
+ byte[] salt)
+ {
+ super.init(password, salt, 1);
+ }
+
+ /**
+ * the derived key function, the ith hash of the password and the salt.
+ */
+ private byte[] generateDerivedKey(
+ int bytesNeeded)
+ {
+ byte[] buf = new byte[digest.getDigestSize()];
+ byte[] key = new byte[bytesNeeded];
+ int offset = 0;
+
+ for (;;)
+ {
+ digest.update(password, 0, password.length);
+ digest.update(salt, 0, salt.length);
+
+ digest.doFinal(buf, 0);
+
+ int len = (bytesNeeded > buf.length) ? buf.length : bytesNeeded;
+ System.arraycopy(buf, 0, key, offset, len);
+ offset += len;
+
+ // check if we need any more
+ bytesNeeded -= len;
+ if (bytesNeeded == 0)
+ {
+ break;
+ }
+
+ // do another round
+ digest.reset();
+ digest.update(buf, 0, buf.length);
+ }
+
+ return key;
+ }
+
+ /**
+ * Generate a key parameter derived from the password, salt, and iteration
+ * count we are currently initialised with.
+ *
+ * @param keySize the size of the key we want (in bits)
+ * @return a KeyParameter object.
+ * @exception IllegalArgumentException if the key length larger than the base hash size.
+ */
+ public CipherParameters generateDerivedParameters(
+ int keySize)
+ {
+ keySize = keySize / 8;
+
+ byte[] dKey = generateDerivedKey(keySize);
+
+ return new KeyParameter(dKey, 0, keySize);
+ }
+
+ /**
+ * Generate a key with initialisation vector parameter derived from
+ * the password, salt, and iteration count we are currently initialised
+ * with.
+ *
+ * @param keySize the size of the key we want (in bits)
+ * @param ivSize the size of the iv we want (in bits)
+ * @return a ParametersWithIV object.
+ * @exception IllegalArgumentException if keySize + ivSize is larger than the base hash size.
+ */
+ public CipherParameters generateDerivedParameters(
+ int keySize,
+ int ivSize)
+ {
+ keySize = keySize / 8;
+ ivSize = ivSize / 8;
+
+ byte[] dKey = generateDerivedKey(keySize + ivSize);
+
+ return new ParametersWithIV(new KeyParameter(dKey, 0, keySize), dKey, keySize, ivSize);
+ }
+
+ /**
+ * Generate a key parameter for use with a MAC derived from the password,
+ * salt, and iteration count we are currently initialised with.
+ *
+ * @param keySize the size of the key we want (in bits)
+ * @return a KeyParameter object.
+ * @exception IllegalArgumentException if the key length larger than the base hash size.
+ */
+ public CipherParameters generateDerivedMacParameters(
+ int keySize)
+ {
+ return generateDerivedParameters(keySize);
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/generators/PKCS12ParametersGenerator.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/generators/PKCS12ParametersGenerator.java
new file mode 100644
index 0000000..760ea8c
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/generators/PKCS12ParametersGenerator.java
@@ -0,0 +1,221 @@
+package org.bc.crypto.generators;
+
+import org.bc.crypto.CipherParameters;
+import org.bc.crypto.Digest;
+import org.bc.crypto.ExtendedDigest;
+import org.bc.crypto.PBEParametersGenerator;
+import org.bc.crypto.params.KeyParameter;
+import org.bc.crypto.params.ParametersWithIV;
+
+/**
+ * Generator for PBE derived keys and ivs as defined by PKCS 12 V1.0.
+ *
+ * The document this implementation is based on can be found at
+ *
+ * RSA's PKCS12 Page
+ */
+public class PKCS12ParametersGenerator
+ extends PBEParametersGenerator
+{
+ public static final int KEY_MATERIAL = 1;
+ public static final int IV_MATERIAL = 2;
+ public static final int MAC_MATERIAL = 3;
+
+ private Digest digest;
+
+ private int u;
+ private int v;
+
+ /**
+ * Construct a PKCS 12 Parameters generator. This constructor will
+ * accept any digest which also implements ExtendedDigest.
+ *
+ * @param digest the digest to be used as the source of derived keys.
+ * @exception IllegalArgumentException if an unknown digest is passed in.
+ */
+ public PKCS12ParametersGenerator(
+ Digest digest)
+ {
+ this.digest = digest;
+ if (digest instanceof ExtendedDigest)
+ {
+ u = digest.getDigestSize();
+ v = ((ExtendedDigest)digest).getByteLength();
+ }
+ else
+ {
+ throw new IllegalArgumentException("Digest " + digest.getAlgorithmName() + " unsupported");
+ }
+ }
+
+ /**
+ * add a + b + 1, returning the result in a. The a value is treated
+ * as a BigInteger of length (b.length * 8) bits. The result is
+ * modulo 2^b.length in case of overflow.
+ */
+ private void adjust(
+ byte[] a,
+ int aOff,
+ byte[] b)
+ {
+ int x = (b[b.length - 1] & 0xff) + (a[aOff + b.length - 1] & 0xff) + 1;
+
+ a[aOff + b.length - 1] = (byte)x;
+ x >>>= 8;
+
+ for (int i = b.length - 2; i >= 0; i--)
+ {
+ x += (b[i] & 0xff) + (a[aOff + i] & 0xff);
+ a[aOff + i] = (byte)x;
+ x >>>= 8;
+ }
+ }
+
+ /**
+ * generation of a derived key ala PKCS12 V1.0.
+ */
+ private byte[] generateDerivedKey(
+ int idByte,
+ int n)
+ {
+ byte[] D = new byte[v];
+ byte[] dKey = new byte[n];
+
+ for (int i = 0; i != D.length; i++)
+ {
+ D[i] = (byte)idByte;
+ }
+
+ byte[] S;
+
+ if ((salt != null) && (salt.length != 0))
+ {
+ S = new byte[v * ((salt.length + v - 1) / v)];
+
+ for (int i = 0; i != S.length; i++)
+ {
+ S[i] = salt[i % salt.length];
+ }
+ }
+ else
+ {
+ S = new byte[0];
+ }
+
+ byte[] P;
+
+ if ((password != null) && (password.length != 0))
+ {
+ P = new byte[v * ((password.length + v - 1) / v)];
+
+ for (int i = 0; i != P.length; i++)
+ {
+ P[i] = password[i % password.length];
+ }
+ }
+ else
+ {
+ P = new byte[0];
+ }
+
+ byte[] I = new byte[S.length + P.length];
+
+ System.arraycopy(S, 0, I, 0, S.length);
+ System.arraycopy(P, 0, I, S.length, P.length);
+
+ byte[] B = new byte[v];
+ int c = (n + u - 1) / u;
+
+ for (int i = 1; i <= c; i++)
+ {
+ byte[] A = new byte[u];
+
+ digest.update(D, 0, D.length);
+ digest.update(I, 0, I.length);
+ digest.doFinal(A, 0);
+ for (int j = 1; j < iterationCount; j++)
+ {
+ digest.update(A, 0, A.length);
+ digest.doFinal(A, 0);
+ }
+
+ for (int j = 0; j != B.length; j++)
+ {
+ B[j] = A[j % A.length];
+ }
+
+ for (int j = 0; j != I.length / v; j++)
+ {
+ adjust(I, j * v, B);
+ }
+
+ if (i == c)
+ {
+ System.arraycopy(A, 0, dKey, (i - 1) * u, dKey.length - ((i - 1) * u));
+ }
+ else
+ {
+ System.arraycopy(A, 0, dKey, (i - 1) * u, A.length);
+ }
+ }
+
+ return dKey;
+ }
+
+ /**
+ * Generate a key parameter derived from the password, salt, and iteration
+ * count we are currently initialised with.
+ *
+ * @param keySize the size of the key we want (in bits)
+ * @return a KeyParameter object.
+ */
+ public CipherParameters generateDerivedParameters(
+ int keySize)
+ {
+ keySize = keySize / 8;
+
+ byte[] dKey = generateDerivedKey(KEY_MATERIAL, keySize);
+
+ return new KeyParameter(dKey, 0, keySize);
+ }
+
+ /**
+ * Generate a key with initialisation vector parameter derived from
+ * the password, salt, and iteration count we are currently initialised
+ * with.
+ *
+ * @param keySize the size of the key we want (in bits)
+ * @param ivSize the size of the iv we want (in bits)
+ * @return a ParametersWithIV object.
+ */
+ public CipherParameters generateDerivedParameters(
+ int keySize,
+ int ivSize)
+ {
+ keySize = keySize / 8;
+ ivSize = ivSize / 8;
+
+ byte[] dKey = generateDerivedKey(KEY_MATERIAL, keySize);
+
+ byte[] iv = generateDerivedKey(IV_MATERIAL, ivSize);
+
+ return new ParametersWithIV(new KeyParameter(dKey, 0, keySize), iv, 0, ivSize);
+ }
+
+ /**
+ * Generate a key parameter for use with a MAC derived from the password,
+ * salt, and iteration count we are currently initialised with.
+ *
+ * @param keySize the size of the key we want (in bits)
+ * @return a KeyParameter object.
+ */
+ public CipherParameters generateDerivedMacParameters(
+ int keySize)
+ {
+ keySize = keySize / 8;
+
+ byte[] dKey = generateDerivedKey(MAC_MATERIAL, keySize);
+
+ return new KeyParameter(dKey, 0, keySize);
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/generators/PKCS5S1ParametersGenerator.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/generators/PKCS5S1ParametersGenerator.java
new file mode 100644
index 0000000..2b9e4ef
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/generators/PKCS5S1ParametersGenerator.java
@@ -0,0 +1,119 @@
+package org.bc.crypto.generators;
+
+import org.bc.crypto.CipherParameters;
+import org.bc.crypto.Digest;
+import org.bc.crypto.PBEParametersGenerator;
+import org.bc.crypto.params.KeyParameter;
+import org.bc.crypto.params.ParametersWithIV;
+
+/**
+ * Generator for PBE derived keys and ivs as defined by PKCS 5 V2.0 Scheme 1.
+ * Note this generator is limited to the size of the hash produced by the
+ * digest used to drive it.
+ *
+ * The document this implementation is based on can be found at
+ *
+ * RSA's PKCS5 Page
+ */
+public class PKCS5S1ParametersGenerator
+ extends PBEParametersGenerator
+{
+ private Digest digest;
+
+ /**
+ * Construct a PKCS 5 Scheme 1 Parameters generator.
+ *
+ * @param digest the digest to be used as the source of derived keys.
+ */
+ public PKCS5S1ParametersGenerator(
+ Digest digest)
+ {
+ this.digest = digest;
+ }
+
+ /**
+ * the derived key function, the ith hash of the password and the salt.
+ */
+ private byte[] generateDerivedKey()
+ {
+ byte[] digestBytes = new byte[digest.getDigestSize()];
+
+ digest.update(password, 0, password.length);
+ digest.update(salt, 0, salt.length);
+
+ digest.doFinal(digestBytes, 0);
+ for (int i = 1; i < iterationCount; i++)
+ {
+ digest.update(digestBytes, 0, digestBytes.length);
+ digest.doFinal(digestBytes, 0);
+ }
+
+ return digestBytes;
+ }
+
+ /**
+ * Generate a key parameter derived from the password, salt, and iteration
+ * count we are currently initialised with.
+ *
+ * @param keySize the size of the key we want (in bits)
+ * @return a KeyParameter object.
+ * @exception IllegalArgumentException if the key length larger than the base hash size.
+ */
+ public CipherParameters generateDerivedParameters(
+ int keySize)
+ {
+ keySize = keySize / 8;
+
+ if (keySize > digest.getDigestSize())
+ {
+ throw new IllegalArgumentException(
+ "Can't generate a derived key " + keySize + " bytes long.");
+ }
+
+ byte[] dKey = generateDerivedKey();
+
+ return new KeyParameter(dKey, 0, keySize);
+ }
+
+ /**
+ * Generate a key with initialisation vector parameter derived from
+ * the password, salt, and iteration count we are currently initialised
+ * with.
+ *
+ * @param keySize the size of the key we want (in bits)
+ * @param ivSize the size of the iv we want (in bits)
+ * @return a ParametersWithIV object.
+ * @exception IllegalArgumentException if keySize + ivSize is larger than the base hash size.
+ */
+ public CipherParameters generateDerivedParameters(
+ int keySize,
+ int ivSize)
+ {
+ keySize = keySize / 8;
+ ivSize = ivSize / 8;
+
+ if ((keySize + ivSize) > digest.getDigestSize())
+ {
+ throw new IllegalArgumentException(
+ "Can't generate a derived key " + (keySize + ivSize) + " bytes long.");
+ }
+
+ byte[] dKey = generateDerivedKey();
+
+ return new ParametersWithIV(new KeyParameter(dKey, 0, keySize), dKey, keySize, ivSize);
+ }
+
+ /**
+ * Generate a key parameter for use with a MAC derived from the password,
+ * salt, and iteration count we are currently initialised with.
+ *
+ * @param keySize the size of the key we want (in bits)
+ * @return a KeyParameter object.
+ * @exception IllegalArgumentException if the key length larger than the base hash size.
+ */
+ public CipherParameters generateDerivedMacParameters(
+ int keySize)
+ {
+ return generateDerivedParameters(keySize);
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/generators/PKCS5S2ParametersGenerator.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/generators/PKCS5S2ParametersGenerator.java
new file mode 100644
index 0000000..bc467de
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/generators/PKCS5S2ParametersGenerator.java
@@ -0,0 +1,158 @@
+package org.bc.crypto.generators;
+
+import org.bc.crypto.CipherParameters;
+import org.bc.crypto.Digest;
+import org.bc.crypto.Mac;
+import org.bc.crypto.PBEParametersGenerator;
+import org.bc.crypto.digests.SHA1Digest;
+import org.bc.crypto.macs.HMac;
+import org.bc.crypto.params.KeyParameter;
+import org.bc.crypto.params.ParametersWithIV;
+
+/**
+ * Generator for PBE derived keys and ivs as defined by PKCS 5 V2.0 Scheme 2.
+ * This generator uses a SHA-1 HMac as the calculation function.
+ *
+ * The document this implementation is based on can be found at
+ *
+ * RSA's PKCS5 Page
+ */
+public class PKCS5S2ParametersGenerator
+ extends PBEParametersGenerator
+{
+ private Mac hMac;
+
+ /**
+ * construct a PKCS5 Scheme 2 Parameters generator.
+ */
+ public PKCS5S2ParametersGenerator()
+ {
+ this(new SHA1Digest());
+ }
+
+ public PKCS5S2ParametersGenerator(Digest digest)
+ {
+ hMac = new HMac(digest);
+ }
+
+ private void F(
+ byte[] P,
+ byte[] S,
+ int c,
+ byte[] iBuf,
+ byte[] out,
+ int outOff)
+ {
+ byte[] state = new byte[hMac.getMacSize()];
+ CipherParameters param = new KeyParameter(P);
+
+ hMac.init(param);
+
+ if (S != null)
+ {
+ hMac.update(S, 0, S.length);
+ }
+
+ hMac.update(iBuf, 0, iBuf.length);
+
+ hMac.doFinal(state, 0);
+
+ System.arraycopy(state, 0, out, outOff, state.length);
+
+ if (c == 0)
+ {
+ throw new IllegalArgumentException("iteration count must be at least 1.");
+ }
+
+ for (int count = 1; count < c; count++)
+ {
+ hMac.init(param);
+ hMac.update(state, 0, state.length);
+ hMac.doFinal(state, 0);
+
+ for (int j = 0; j != state.length; j++)
+ {
+ out[outOff + j] ^= state[j];
+ }
+ }
+ }
+
+ private void intToOctet(
+ byte[] buf,
+ int i)
+ {
+ buf[0] = (byte)(i >>> 24);
+ buf[1] = (byte)(i >>> 16);
+ buf[2] = (byte)(i >>> 8);
+ buf[3] = (byte)i;
+ }
+
+ private byte[] generateDerivedKey(
+ int dkLen)
+ {
+ int hLen = hMac.getMacSize();
+ int l = (dkLen + hLen - 1) / hLen;
+ byte[] iBuf = new byte[4];
+ byte[] out = new byte[l * hLen];
+
+ for (int i = 1; i <= l; i++)
+ {
+ intToOctet(iBuf, i);
+
+ F(password, salt, iterationCount, iBuf, out, (i - 1) * hLen);
+ }
+
+ return out;
+ }
+
+ /**
+ * Generate a key parameter derived from the password, salt, and iteration
+ * count we are currently initialised with.
+ *
+ * @param keySize the size of the key we want (in bits)
+ * @return a KeyParameter object.
+ */
+ public CipherParameters generateDerivedParameters(
+ int keySize)
+ {
+ keySize = keySize / 8;
+
+ byte[] dKey = generateDerivedKey(keySize);
+
+ return new KeyParameter(dKey, 0, keySize);
+ }
+
+ /**
+ * Generate a key with initialisation vector parameter derived from
+ * the password, salt, and iteration count we are currently initialised
+ * with.
+ *
+ * @param keySize the size of the key we want (in bits)
+ * @param ivSize the size of the iv we want (in bits)
+ * @return a ParametersWithIV object.
+ */
+ public CipherParameters generateDerivedParameters(
+ int keySize,
+ int ivSize)
+ {
+ keySize = keySize / 8;
+ ivSize = ivSize / 8;
+
+ byte[] dKey = generateDerivedKey(keySize + ivSize);
+
+ return new ParametersWithIV(new KeyParameter(dKey, 0, keySize), dKey, keySize, ivSize);
+ }
+
+ /**
+ * Generate a key parameter for use with a MAC derived from the password,
+ * salt, and iteration count we are currently initialised with.
+ *
+ * @param keySize the size of the key we want (in bits)
+ * @return a KeyParameter object.
+ */
+ public CipherParameters generateDerivedMacParameters(
+ int keySize)
+ {
+ return generateDerivedParameters(keySize);
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/generators/RSABlindingFactorGenerator.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/generators/RSABlindingFactorGenerator.java
new file mode 100644
index 0000000..1f098cf
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/generators/RSABlindingFactorGenerator.java
@@ -0,0 +1,77 @@
+package org.bc.crypto.generators;
+
+import org.bc.crypto.CipherParameters;
+import org.bc.crypto.params.ParametersWithRandom;
+import org.bc.crypto.params.RSAKeyParameters;
+import org.bc.crypto.params.RSAPrivateCrtKeyParameters;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
+/**
+ * Generate a random factor suitable for use with RSA blind signatures
+ * as outlined in Chaum's blinding and unblinding as outlined in
+ * "Handbook of Applied Cryptography", page 475.
+ */
+public class RSABlindingFactorGenerator
+{
+ private static BigInteger ZERO = BigInteger.valueOf(0);
+ private static BigInteger ONE = BigInteger.valueOf(1);
+
+ private RSAKeyParameters key;
+ private SecureRandom random;
+
+ /**
+ * Initialise the factor generator
+ *
+ * @param param the necessary RSA key parameters.
+ */
+ public void init(
+ CipherParameters param)
+ {
+ if (param instanceof ParametersWithRandom)
+ {
+ ParametersWithRandom rParam = (ParametersWithRandom)param;
+
+ key = (RSAKeyParameters)rParam.getParameters();
+ random = rParam.getRandom();
+ }
+ else
+ {
+ key = (RSAKeyParameters)param;
+ random = new SecureRandom();
+ }
+
+ if (key instanceof RSAPrivateCrtKeyParameters)
+ {
+ throw new IllegalArgumentException("generator requires RSA public key");
+ }
+ }
+
+ /**
+ * Generate a suitable blind factor for the public key the generator was initialised with.
+ *
+ * @return a random blind factor
+ */
+ public BigInteger generateBlindingFactor()
+ {
+ if (key == null)
+ {
+ throw new IllegalStateException("generator not initialised");
+ }
+
+ BigInteger m = key.getModulus();
+ int length = m.bitLength() - 1; // must be less than m.bitLength()
+ BigInteger factor;
+ BigInteger gcd;
+
+ do
+ {
+ factor = new BigInteger(length, random);
+ gcd = factor.gcd(m);
+ }
+ while (factor.equals(ZERO) || factor.equals(ONE) || !gcd.equals(ONE));
+
+ return factor;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/generators/RSAKeyPairGenerator.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/generators/RSAKeyPairGenerator.java
new file mode 100644
index 0000000..05509cc
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/generators/RSAKeyPairGenerator.java
@@ -0,0 +1,147 @@
+package org.bc.crypto.generators;
+
+import org.bc.crypto.AsymmetricCipherKeyPair;
+import org.bc.crypto.AsymmetricCipherKeyPairGenerator;
+import org.bc.crypto.KeyGenerationParameters;
+import org.bc.crypto.params.RSAKeyGenerationParameters;
+import org.bc.crypto.params.RSAKeyParameters;
+import org.bc.crypto.params.RSAPrivateCrtKeyParameters;
+
+import java.math.BigInteger;
+
+/**
+ * an RSA key pair generator.
+ */
+public class RSAKeyPairGenerator
+ implements AsymmetricCipherKeyPairGenerator
+{
+ private static final BigInteger ONE = BigInteger.valueOf(1);
+
+ private RSAKeyGenerationParameters param;
+
+ public void init(
+ KeyGenerationParameters param)
+ {
+ this.param = (RSAKeyGenerationParameters)param;
+ }
+
+ public AsymmetricCipherKeyPair generateKeyPair()
+ {
+ BigInteger p, q, n, d, e, pSub1, qSub1, phi;
+
+ //
+ // p and q values should have a length of half the strength in bits
+ //
+ int strength = param.getStrength();
+ int pbitlength = (strength + 1) / 2;
+ int qbitlength = strength - pbitlength;
+ int mindiffbits = strength / 3;
+
+ e = param.getPublicExponent();
+
+ // TODO Consider generating safe primes for p, q (see DHParametersHelper.generateSafePrimes)
+ // (then p-1 and q-1 will not consist of only small factors - see "Pollard's algorithm")
+
+ //
+ // generate p, prime and (p-1) relatively prime to e
+ //
+ for (;;)
+ {
+ p = new BigInteger(pbitlength, 1, param.getRandom());
+
+ if (p.mod(e).equals(ONE))
+ {
+ continue;
+ }
+
+ if (!p.isProbablePrime(param.getCertainty()))
+ {
+ continue;
+ }
+
+ if (e.gcd(p.subtract(ONE)).equals(ONE))
+ {
+ break;
+ }
+ }
+
+ //
+ // generate a modulus of the required length
+ //
+ for (;;)
+ {
+ // generate q, prime and (q-1) relatively prime to e,
+ // and not equal to p
+ //
+ for (;;)
+ {
+ q = new BigInteger(qbitlength, 1, param.getRandom());
+
+ if (q.subtract(p).abs().bitLength() < mindiffbits)
+ {
+ continue;
+ }
+
+ if (q.mod(e).equals(ONE))
+ {
+ continue;
+ }
+
+ if (!q.isProbablePrime(param.getCertainty()))
+ {
+ continue;
+ }
+
+ if (e.gcd(q.subtract(ONE)).equals(ONE))
+ {
+ break;
+ }
+ }
+
+ //
+ // calculate the modulus
+ //
+ n = p.multiply(q);
+
+ if (n.bitLength() == param.getStrength())
+ {
+ break;
+ }
+
+ //
+ // if we get here our primes aren't big enough, make the largest
+ // of the two p and try again
+ //
+ p = p.max(q);
+ }
+
+ if (p.compareTo(q) < 0)
+ {
+ phi = p;
+ p = q;
+ q = phi;
+ }
+
+ pSub1 = p.subtract(ONE);
+ qSub1 = q.subtract(ONE);
+ phi = pSub1.multiply(qSub1);
+
+ //
+ // calculate the private exponent
+ //
+ d = e.modInverse(phi);
+
+ //
+ // calculate the CRT factors
+ //
+ BigInteger dP, dQ, qInv;
+
+ dP = d.remainder(pSub1);
+ dQ = d.remainder(qSub1);
+ qInv = q.modInverse(p);
+
+ return new AsymmetricCipherKeyPair(
+ new RSAKeyParameters(false, n, e),
+ new RSAPrivateCrtKeyParameters(n, e, d, p, q, dP, dQ, qInv));
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/generators/SCrypt.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/generators/SCrypt.java
new file mode 100644
index 0000000..a7e76eb
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/generators/SCrypt.java
@@ -0,0 +1,147 @@
+package org.bc.crypto.generators;
+
+import org.bc.crypto.PBEParametersGenerator;
+import org.bc.crypto.digests.SHA256Digest;
+import org.bc.crypto.engines.Salsa20Engine;
+import org.bc.crypto.params.KeyParameter;
+import org.bc.crypto.util.Pack;
+import org.bc.util.Arrays;
+
+public class SCrypt
+{
+ // TODO Validate arguments
+ public static byte[] generate(byte[] P, byte[] S, int N, int r, int p, int dkLen)
+ {
+ return MFcrypt(P, S, N, r, p, dkLen);
+ }
+
+ private static byte[] MFcrypt(byte[] P, byte[] S, int N, int r, int p, int dkLen)
+ {
+ int MFLenBytes = r * 128;
+ byte[] bytes = SingleIterationPBKDF2(P, S, p * MFLenBytes);
+
+ int[] B = null;
+
+ try
+ {
+ int BLen = bytes.length >>> 2;
+ B = new int[BLen];
+
+ Pack.littleEndianToInt(bytes, 0, B);
+
+ int MFLenWords = MFLenBytes >>> 2;
+ for (int BOff = 0; BOff < BLen; BOff += MFLenWords)
+ {
+ // TODO These can be done in parallel threads
+ SMix(B, BOff, N, r);
+ }
+
+ Pack.intToLittleEndian(B, bytes, 0);
+
+ return SingleIterationPBKDF2(P, bytes, dkLen);
+ }
+ finally
+ {
+ Clear(bytes);
+ Clear(B);
+ }
+ }
+
+ private static byte[] SingleIterationPBKDF2(byte[] P, byte[] S, int dkLen)
+ {
+ PBEParametersGenerator pGen = new PKCS5S2ParametersGenerator(new SHA256Digest());
+ pGen.init(P, S, 1);
+ KeyParameter key = (KeyParameter) pGen.generateDerivedMacParameters(dkLen * 8);
+ return key.getKey();
+ }
+
+ private static void SMix(int[] B, int BOff, int N, int r)
+ {
+ int BCount = r * 32;
+
+ int[] blockX1 = new int[16];
+ int[] blockX2 = new int[16];
+ int[] blockY = new int[BCount];
+
+ int[] X = new int[BCount];
+ int[][] V = new int[N][];
+
+ try
+ {
+ System.arraycopy(B, BOff, X, 0, BCount);
+
+ for (int i = 0; i < N; ++i)
+ {
+ V[i] = Arrays.clone(X);
+ BlockMix(X, blockX1, blockX2, blockY, r);
+ }
+
+ int mask = N - 1;
+ for (int i = 0; i < N; ++i)
+ {
+ int j = X[BCount - 16] & mask;
+ Xor(X, V[j], 0, X);
+ BlockMix(X, blockX1, blockX2, blockY, r);
+ }
+
+ System.arraycopy(X, 0, B, BOff, BCount);
+ }
+ finally
+ {
+ ClearAll(V);
+ ClearAll(new int[][]{ X, blockX1, blockX2, blockY });
+ }
+ }
+
+ private static void BlockMix(int[] B, int[] X1, int[] X2, int[] Y, int r)
+ {
+ System.arraycopy(B, B.length - 16, X1, 0, 16);
+
+ int BOff = 0, YOff = 0, halfLen = B.length >>> 1;
+
+ for (int i = 2 * r; i > 0; --i)
+ {
+ Xor(X1, B, BOff, X2);
+
+ Salsa20Engine.salsaCore(8, X2, X1);
+ System.arraycopy(X1, 0, Y, YOff, 16);
+
+ YOff = halfLen + BOff - YOff;
+ BOff += 16;
+ }
+
+ System.arraycopy(Y, 0, B, 0, Y.length);
+ }
+
+ private static void Xor(int[] a, int[] b, int bOff, int[] output)
+ {
+ for (int i = output.length - 1; i >= 0; --i)
+ {
+ output[i] = a[i] ^ b[bOff + i];
+ }
+ }
+
+ private static void Clear(byte[] array)
+ {
+ if (array != null)
+ {
+ Arrays.fill(array, (byte)0);
+ }
+ }
+
+ private static void Clear(int[] array)
+ {
+ if (array != null)
+ {
+ Arrays.fill(array, 0);
+ }
+ }
+
+ private static void ClearAll(int[][] arrays)
+ {
+ for (int i = 0; i < arrays.length; ++i)
+ {
+ Clear(arrays[i]);
+ }
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/io/CipherInputStream.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/io/CipherInputStream.java
new file mode 100644
index 0000000..783559e
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/io/CipherInputStream.java
@@ -0,0 +1,244 @@
+package org.bc.crypto.io;
+
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.bc.crypto.BufferedBlockCipher;
+import org.bc.crypto.StreamCipher;
+
+/**
+ * A CipherInputStream is composed of an InputStream and a BufferedBlockCipher so
+ * that read() methods return data that are read in from the
+ * underlying InputStream but have been additionally processed by the
+ * Cipher. The Cipher must be fully initialized before being used by
+ * a CipherInputStream.
+ *
+ * For example, if the Cipher is initialized for decryption, the
+ * CipherInputStream will attempt to read in data and decrypt them,
+ * before returning the decrypted data.
+ */
+public class CipherInputStream
+ extends FilterInputStream
+{
+ private BufferedBlockCipher bufferedBlockCipher;
+ private StreamCipher streamCipher;
+
+ private byte[] buf;
+ private byte[] inBuf;
+
+ private int bufOff;
+ private int maxBuf;
+ private boolean finalized;
+
+ private static final int INPUT_BUF_SIZE = 2048;
+
+ /**
+ * Constructs a CipherInputStream from an InputStream and a
+ * BufferedBlockCipher.
+ */
+ public CipherInputStream(
+ InputStream is,
+ BufferedBlockCipher cipher)
+ {
+ super(is);
+
+ this.bufferedBlockCipher = cipher;
+
+ buf = new byte[cipher.getOutputSize(INPUT_BUF_SIZE)];
+ inBuf = new byte[INPUT_BUF_SIZE];
+ }
+
+ public CipherInputStream(
+ InputStream is,
+ StreamCipher cipher)
+ {
+ super(is);
+
+ this.streamCipher = cipher;
+
+ buf = new byte[INPUT_BUF_SIZE];
+ inBuf = new byte[INPUT_BUF_SIZE];
+ }
+
+ /**
+ * grab the next chunk of input from the underlying input stream
+ */
+ private int nextChunk()
+ throws IOException
+ {
+ int available = super.available();
+
+ // must always try to read 1 byte!
+ // some buggy InputStreams return < 0!
+ if (available <= 0)
+ {
+ available = 1;
+ }
+
+ if (available > inBuf.length)
+ {
+ available = super.read(inBuf, 0, inBuf.length);
+ }
+ else
+ {
+ available = super.read(inBuf, 0, available);
+ }
+
+ if (available < 0)
+ {
+ if (finalized)
+ {
+ return -1;
+ }
+
+ try
+ {
+ if (bufferedBlockCipher != null)
+ {
+ maxBuf = bufferedBlockCipher.doFinal(buf, 0);
+ }
+ else
+ {
+ maxBuf = 0; // a stream cipher
+ }
+ }
+ catch (Exception e)
+ {
+ throw new IOException("error processing stream: " + e.toString());
+ }
+
+ bufOff = 0;
+
+ finalized = true;
+
+ if (bufOff == maxBuf)
+ {
+ return -1;
+ }
+ }
+ else
+ {
+ bufOff = 0;
+
+ try
+ {
+ if (bufferedBlockCipher != null)
+ {
+ maxBuf = bufferedBlockCipher.processBytes(inBuf, 0, available, buf, 0);
+ }
+ else
+ {
+ streamCipher.processBytes(inBuf, 0, available, buf, 0);
+ maxBuf = available;
+ }
+ }
+ catch (Exception e)
+ {
+ throw new IOException("error processing stream: " + e.toString());
+ }
+
+ if (maxBuf == 0) // not enough bytes read for first block...
+ {
+ return nextChunk();
+ }
+ }
+
+ return maxBuf;
+ }
+
+ public int read()
+ throws IOException
+ {
+ if (bufOff == maxBuf)
+ {
+ if (nextChunk() < 0)
+ {
+ return -1;
+ }
+ }
+
+ return buf[bufOff++] & 0xff;
+ }
+
+ public int read(
+ byte[] b)
+ throws IOException
+ {
+ return read(b, 0, b.length);
+ }
+
+ public int read(
+ byte[] b,
+ int off,
+ int len)
+ throws IOException
+ {
+ if (bufOff == maxBuf)
+ {
+ if (nextChunk() < 0)
+ {
+ return -1;
+ }
+ }
+
+ int available = maxBuf - bufOff;
+
+ if (len > available)
+ {
+ System.arraycopy(buf, bufOff, b, off, available);
+ bufOff = maxBuf;
+
+ return available;
+ }
+ else
+ {
+ System.arraycopy(buf, bufOff, b, off, len);
+ bufOff += len;
+
+ return len;
+ }
+ }
+
+ public long skip(
+ long n)
+ throws IOException
+ {
+ if (n <= 0)
+ {
+ return 0;
+ }
+
+ int available = maxBuf - bufOff;
+
+ if (n > available)
+ {
+ bufOff = maxBuf;
+
+ return available;
+ }
+ else
+ {
+ bufOff += (int)n;
+
+ return (int)n;
+ }
+ }
+
+ public int available()
+ throws IOException
+ {
+ return maxBuf - bufOff;
+ }
+
+ public void close()
+ throws IOException
+ {
+ super.close();
+ }
+
+ public boolean markSupported()
+ {
+ return false;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/io/CipherOutputStream.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/io/CipherOutputStream.java
new file mode 100644
index 0000000..0282f55
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/io/CipherOutputStream.java
@@ -0,0 +1,188 @@
+package org.bc.crypto.io;
+
+import java.io.FilterOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.bc.crypto.BufferedBlockCipher;
+import org.bc.crypto.StreamCipher;
+
+public class CipherOutputStream
+ extends FilterOutputStream
+{
+ private BufferedBlockCipher bufferedBlockCipher;
+ private StreamCipher streamCipher;
+
+ private byte[] oneByte = new byte[1];
+ private byte[] buf;
+
+ /**
+ * Constructs a CipherOutputStream from an OutputStream and a
+ * BufferedBlockCipher.
+ */
+ public CipherOutputStream(
+ OutputStream os,
+ BufferedBlockCipher cipher)
+ {
+ super(os);
+ this.bufferedBlockCipher = cipher;
+ this.buf = new byte[cipher.getBlockSize()];
+ }
+
+ /**
+ * Constructs a CipherOutputStream from an OutputStream and a
+ * BufferedBlockCipher.
+ */
+ public CipherOutputStream(
+ OutputStream os,
+ StreamCipher cipher)
+ {
+ super(os);
+ this.streamCipher = cipher;
+ }
+
+ /**
+ * Writes the specified byte to this output stream.
+ *
+ * @param b the
+ * The
+ * Any bytes buffered by the encapsulated cipher
+ * and waiting to be processed by it will not be written out. For example,
+ * if the encapsulated cipher is a block cipher, and the total number of
+ * bytes written using one of the
+ * This method invokes the
+ * This method resets the encapsulated cipher object to its initial state
+ * and calls the
+ * Note: the size of the MAC must be at least 16 bits (FIPS Publication 113),
+ * and in general should be less than the size of the block cipher as it reduces
+ * the chance of an exhaustive attack (see Handbook of Applied Cryptography).
+ *
+ * @param cipher the cipher to be used as the basis of the MAC generation.
+ * @param macSizeInBits the size of the MAC in bits, must be a multiple of 8.
+ * @deprecated use CBCBlockCipherMac
+ */
+ public BlockCipherMac(
+ BlockCipher cipher,
+ int macSizeInBits)
+ {
+ if ((macSizeInBits % 8) != 0)
+ {
+ throw new IllegalArgumentException("MAC size must be multiple of 8");
+ }
+
+ this.cipher = new CBCBlockCipher(cipher);
+ this.macSize = macSizeInBits / 8;
+
+ mac = new byte[cipher.getBlockSize()];
+
+ buf = new byte[cipher.getBlockSize()];
+ bufOff = 0;
+ }
+
+ public String getAlgorithmName()
+ {
+ return cipher.getAlgorithmName();
+ }
+
+ public void init(
+ CipherParameters params)
+ {
+ reset();
+
+ cipher.init(true, params);
+ }
+
+ public int getMacSize()
+ {
+ return macSize;
+ }
+
+ public void update(
+ byte in)
+ {
+ if (bufOff == buf.length)
+ {
+ cipher.processBlock(buf, 0, mac, 0);
+ bufOff = 0;
+ }
+
+ buf[bufOff++] = in;
+ }
+
+ public void update(
+ byte[] in,
+ int inOff,
+ int len)
+ {
+ if (len < 0)
+ {
+ throw new IllegalArgumentException("Can't have a negative input length!");
+ }
+
+ int blockSize = cipher.getBlockSize();
+ int resultLen = 0;
+ int gapLen = blockSize - bufOff;
+
+ if (len > gapLen)
+ {
+ System.arraycopy(in, inOff, buf, bufOff, gapLen);
+
+ resultLen += cipher.processBlock(buf, 0, mac, 0);
+
+ bufOff = 0;
+ len -= gapLen;
+ inOff += gapLen;
+
+ while (len > blockSize)
+ {
+ resultLen += cipher.processBlock(in, inOff, mac, 0);
+
+ len -= blockSize;
+ inOff += blockSize;
+ }
+ }
+
+ System.arraycopy(in, inOff, buf, bufOff, len);
+
+ bufOff += len;
+ }
+
+ public int doFinal(
+ byte[] out,
+ int outOff)
+ {
+ int blockSize = cipher.getBlockSize();
+
+ //
+ // pad with zeroes
+ //
+ while (bufOff < blockSize)
+ {
+ buf[bufOff] = 0;
+ bufOff++;
+ }
+
+ cipher.processBlock(buf, 0, mac, 0);
+
+ System.arraycopy(mac, 0, out, outOff, macSize);
+
+ reset();
+
+ return macSize;
+ }
+
+ /**
+ * Reset the mac generator.
+ */
+ public void reset()
+ {
+ /*
+ * clean the buffer.
+ */
+ for (int i = 0; i < buf.length; i++)
+ {
+ buf[i] = 0;
+ }
+
+ bufOff = 0;
+
+ /*
+ * reset the underlying cipher.
+ */
+ cipher.reset();
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/macs/CBCBlockCipherMac.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/macs/CBCBlockCipherMac.java
new file mode 100644
index 0000000..d500a21
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/macs/CBCBlockCipherMac.java
@@ -0,0 +1,229 @@
+package org.bc.crypto.macs;
+
+import org.bc.crypto.BlockCipher;
+import org.bc.crypto.CipherParameters;
+import org.bc.crypto.Mac;
+import org.bc.crypto.modes.CBCBlockCipher;
+import org.bc.crypto.paddings.BlockCipherPadding;
+
+/**
+ * standard CBC Block Cipher MAC - if no padding is specified the default of
+ * pad of zeroes is used.
+ */
+public class CBCBlockCipherMac
+ implements Mac
+{
+ private byte[] mac;
+
+ private byte[] buf;
+ private int bufOff;
+ private BlockCipher cipher;
+ private BlockCipherPadding padding;
+
+ private int macSize;
+
+ /**
+ * create a standard MAC based on a CBC block cipher. This will produce an
+ * authentication code half the length of the block size of the cipher.
+ *
+ * @param cipher the cipher to be used as the basis of the MAC generation.
+ */
+ public CBCBlockCipherMac(
+ BlockCipher cipher)
+ {
+ this(cipher, (cipher.getBlockSize() * 8) / 2, null);
+ }
+
+ /**
+ * create a standard MAC based on a CBC block cipher. This will produce an
+ * authentication code half the length of the block size of the cipher.
+ *
+ * @param cipher the cipher to be used as the basis of the MAC generation.
+ * @param padding the padding to be used to complete the last block.
+ */
+ public CBCBlockCipherMac(
+ BlockCipher cipher,
+ BlockCipherPadding padding)
+ {
+ this(cipher, (cipher.getBlockSize() * 8) / 2, padding);
+ }
+
+ /**
+ * create a standard MAC based on a block cipher with the size of the
+ * MAC been given in bits. This class uses CBC mode as the basis for the
+ * MAC generation.
+ *
+ * Note: the size of the MAC must be at least 24 bits (FIPS Publication 81),
+ * or 16 bits if being used as a data authenticator (FIPS Publication 113),
+ * and in general should be less than the size of the block cipher as it reduces
+ * the chance of an exhaustive attack (see Handbook of Applied Cryptography).
+ *
+ * @param cipher the cipher to be used as the basis of the MAC generation.
+ * @param macSizeInBits the size of the MAC in bits, must be a multiple of 8.
+ */
+ public CBCBlockCipherMac(
+ BlockCipher cipher,
+ int macSizeInBits)
+ {
+ this(cipher, macSizeInBits, null);
+ }
+
+ /**
+ * create a standard MAC based on a block cipher with the size of the
+ * MAC been given in bits. This class uses CBC mode as the basis for the
+ * MAC generation.
+ *
+ * Note: the size of the MAC must be at least 24 bits (FIPS Publication 81),
+ * or 16 bits if being used as a data authenticator (FIPS Publication 113),
+ * and in general should be less than the size of the block cipher as it reduces
+ * the chance of an exhaustive attack (see Handbook of Applied Cryptography).
+ *
+ * @param cipher the cipher to be used as the basis of the MAC generation.
+ * @param macSizeInBits the size of the MAC in bits, must be a multiple of 8.
+ * @param padding the padding to be used to complete the last block.
+ */
+ public CBCBlockCipherMac(
+ BlockCipher cipher,
+ int macSizeInBits,
+ BlockCipherPadding padding)
+ {
+ if ((macSizeInBits % 8) != 0)
+ {
+ throw new IllegalArgumentException("MAC size must be multiple of 8");
+ }
+
+ this.cipher = new CBCBlockCipher(cipher);
+ this.padding = padding;
+ this.macSize = macSizeInBits / 8;
+
+ mac = new byte[cipher.getBlockSize()];
+
+ buf = new byte[cipher.getBlockSize()];
+ bufOff = 0;
+ }
+
+ public String getAlgorithmName()
+ {
+ return cipher.getAlgorithmName();
+ }
+
+ public void init(
+ CipherParameters params)
+ {
+ reset();
+
+ cipher.init(true, params);
+ }
+
+ public int getMacSize()
+ {
+ return macSize;
+ }
+
+ public void update(
+ byte in)
+ {
+ if (bufOff == buf.length)
+ {
+ cipher.processBlock(buf, 0, mac, 0);
+ bufOff = 0;
+ }
+
+ buf[bufOff++] = in;
+ }
+
+ public void update(
+ byte[] in,
+ int inOff,
+ int len)
+ {
+ if (len < 0)
+ {
+ throw new IllegalArgumentException("Can't have a negative input length!");
+ }
+
+ int blockSize = cipher.getBlockSize();
+ int gapLen = blockSize - bufOff;
+
+ if (len > gapLen)
+ {
+ System.arraycopy(in, inOff, buf, bufOff, gapLen);
+
+ cipher.processBlock(buf, 0, mac, 0);
+
+ bufOff = 0;
+ len -= gapLen;
+ inOff += gapLen;
+
+ while (len > blockSize)
+ {
+ cipher.processBlock(in, inOff, mac, 0);
+
+ len -= blockSize;
+ inOff += blockSize;
+ }
+ }
+
+ System.arraycopy(in, inOff, buf, bufOff, len);
+
+ bufOff += len;
+ }
+
+ public int doFinal(
+ byte[] out,
+ int outOff)
+ {
+ int blockSize = cipher.getBlockSize();
+
+ if (padding == null)
+ {
+ //
+ // pad with zeroes
+ //
+ while (bufOff < blockSize)
+ {
+ buf[bufOff] = 0;
+ bufOff++;
+ }
+ }
+ else
+ {
+ if (bufOff == blockSize)
+ {
+ cipher.processBlock(buf, 0, mac, 0);
+ bufOff = 0;
+ }
+
+ padding.addPadding(buf, bufOff);
+ }
+
+ cipher.processBlock(buf, 0, mac, 0);
+
+ System.arraycopy(mac, 0, out, outOff, macSize);
+
+ reset();
+
+ return macSize;
+ }
+
+ /**
+ * Reset the mac generator.
+ */
+ public void reset()
+ {
+ /*
+ * clean the buffer.
+ */
+ for (int i = 0; i < buf.length; i++)
+ {
+ buf[i] = 0;
+ }
+
+ bufOff = 0;
+
+ /*
+ * reset the underlying cipher.
+ */
+ cipher.reset();
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/macs/CFBBlockCipherMac.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/macs/CFBBlockCipherMac.java
new file mode 100644
index 0000000..85e2d7f
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/macs/CFBBlockCipherMac.java
@@ -0,0 +1,388 @@
+package org.bc.crypto.macs;
+
+import org.bc.crypto.BlockCipher;
+import org.bc.crypto.CipherParameters;
+import org.bc.crypto.DataLengthException;
+import org.bc.crypto.Mac;
+import org.bc.crypto.paddings.BlockCipherPadding;
+import org.bc.crypto.params.ParametersWithIV;
+
+/**
+ * implements a Cipher-FeedBack (CFB) mode on top of a simple cipher.
+ */
+class MacCFBBlockCipher
+{
+ private byte[] IV;
+ private byte[] cfbV;
+ private byte[] cfbOutV;
+
+ private int blockSize;
+ private BlockCipher cipher = null;
+
+ /**
+ * Basic constructor.
+ *
+ * @param cipher the block cipher to be used as the basis of the
+ * feedback mode.
+ * @param blockSize the block size in bits (note: a multiple of 8)
+ */
+ public MacCFBBlockCipher(
+ BlockCipher cipher,
+ int bitBlockSize)
+ {
+ this.cipher = cipher;
+ this.blockSize = bitBlockSize / 8;
+
+ this.IV = new byte[cipher.getBlockSize()];
+ this.cfbV = new byte[cipher.getBlockSize()];
+ this.cfbOutV = new byte[cipher.getBlockSize()];
+ }
+
+ /**
+ * Initialise the cipher and, possibly, the initialisation vector (IV).
+ * If an IV isn't passed as part of the parameter, the IV will be all zeros.
+ * An IV which is too short is handled in FIPS compliant fashion.
+ *
+ * @param param the key and other data required by the cipher.
+ * @exception IllegalArgumentException if the params argument is
+ * inappropriate.
+ */
+ public void init(
+ CipherParameters params)
+ throws IllegalArgumentException
+ {
+ if (params instanceof ParametersWithIV)
+ {
+ ParametersWithIV ivParam = (ParametersWithIV)params;
+ byte[] iv = ivParam.getIV();
+
+ if (iv.length < IV.length)
+ {
+ System.arraycopy(iv, 0, IV, IV.length - iv.length, iv.length);
+ }
+ else
+ {
+ System.arraycopy(iv, 0, IV, 0, IV.length);
+ }
+
+ reset();
+
+ cipher.init(true, ivParam.getParameters());
+ }
+ else
+ {
+ reset();
+
+ cipher.init(true, params);
+ }
+ }
+
+ /**
+ * return the algorithm name and mode.
+ *
+ * @return the name of the underlying algorithm followed by "/CFB"
+ * and the block size in bits.
+ */
+ public String getAlgorithmName()
+ {
+ return cipher.getAlgorithmName() + "/CFB" + (blockSize * 8);
+ }
+
+ /**
+ * return the block size we are operating at.
+ *
+ * @return the block size we are operating at (in bytes).
+ */
+ public int getBlockSize()
+ {
+ return blockSize;
+ }
+
+ /**
+ * Process one block of input from the array in and write it to
+ * the out array.
+ *
+ * @param in the array containing the input data.
+ * @param inOff offset into the in array the data starts at.
+ * @param out the array the output data will be copied into.
+ * @param outOff the offset into the out array the output will start at.
+ * @exception DataLengthException if there isn't enough data in in, or
+ * space in out.
+ * @exception IllegalStateException if the cipher isn't initialised.
+ * @return the number of bytes processed and produced.
+ */
+ public int processBlock(
+ byte[] in,
+ int inOff,
+ byte[] out,
+ int outOff)
+ throws DataLengthException, IllegalStateException
+ {
+ if ((inOff + blockSize) > in.length)
+ {
+ throw new DataLengthException("input buffer too short");
+ }
+
+ if ((outOff + blockSize) > out.length)
+ {
+ throw new DataLengthException("output buffer too short");
+ }
+
+ cipher.processBlock(cfbV, 0, cfbOutV, 0);
+
+ //
+ // XOR the cfbV with the plaintext producing the cipher text
+ //
+ for (int i = 0; i < blockSize; i++)
+ {
+ out[outOff + i] = (byte)(cfbOutV[i] ^ in[inOff + i]);
+ }
+
+ //
+ // change over the input block.
+ //
+ System.arraycopy(cfbV, blockSize, cfbV, 0, cfbV.length - blockSize);
+ System.arraycopy(out, outOff, cfbV, cfbV.length - blockSize, blockSize);
+
+ return blockSize;
+ }
+
+ /**
+ * reset the chaining vector back to the IV and reset the underlying
+ * cipher.
+ */
+ public void reset()
+ {
+ System.arraycopy(IV, 0, cfbV, 0, IV.length);
+
+ cipher.reset();
+ }
+
+ void getMacBlock(
+ byte[] mac)
+ {
+ cipher.processBlock(cfbV, 0, mac, 0);
+ }
+}
+
+public class CFBBlockCipherMac
+ implements Mac
+{
+ private byte[] mac;
+
+ private byte[] buf;
+ private int bufOff;
+ private MacCFBBlockCipher cipher;
+ private BlockCipherPadding padding = null;
+
+
+ private int macSize;
+
+ /**
+ * create a standard MAC based on a CFB block cipher. This will produce an
+ * authentication code half the length of the block size of the cipher, with
+ * the CFB mode set to 8 bits.
+ *
+ * @param cipher the cipher to be used as the basis of the MAC generation.
+ */
+ public CFBBlockCipherMac(
+ BlockCipher cipher)
+ {
+ this(cipher, 8, (cipher.getBlockSize() * 8) / 2, null);
+ }
+
+ /**
+ * create a standard MAC based on a CFB block cipher. This will produce an
+ * authentication code half the length of the block size of the cipher, with
+ * the CFB mode set to 8 bits.
+ *
+ * @param cipher the cipher to be used as the basis of the MAC generation.
+ * @param padding the padding to be used.
+ */
+ public CFBBlockCipherMac(
+ BlockCipher cipher,
+ BlockCipherPadding padding)
+ {
+ this(cipher, 8, (cipher.getBlockSize() * 8) / 2, padding);
+ }
+
+ /**
+ * create a standard MAC based on a block cipher with the size of the
+ * MAC been given in bits. This class uses CFB mode as the basis for the
+ * MAC generation.
+ *
+ * Note: the size of the MAC must be at least 24 bits (FIPS Publication 81),
+ * or 16 bits if being used as a data authenticator (FIPS Publication 113),
+ * and in general should be less than the size of the block cipher as it reduces
+ * the chance of an exhaustive attack (see Handbook of Applied Cryptography).
+ *
+ * @param cipher the cipher to be used as the basis of the MAC generation.
+ * @param cfbBitSize the size of an output block produced by the CFB mode.
+ * @param macSizeInBits the size of the MAC in bits, must be a multiple of 8.
+ */
+ public CFBBlockCipherMac(
+ BlockCipher cipher,
+ int cfbBitSize,
+ int macSizeInBits)
+ {
+ this(cipher, cfbBitSize, macSizeInBits, null);
+ }
+
+ /**
+ * create a standard MAC based on a block cipher with the size of the
+ * MAC been given in bits. This class uses CFB mode as the basis for the
+ * MAC generation.
+ *
+ * Note: the size of the MAC must be at least 24 bits (FIPS Publication 81),
+ * or 16 bits if being used as a data authenticator (FIPS Publication 113),
+ * and in general should be less than the size of the block cipher as it reduces
+ * the chance of an exhaustive attack (see Handbook of Applied Cryptography).
+ *
+ * @param cipher the cipher to be used as the basis of the MAC generation.
+ * @param cfbBitSize the size of an output block produced by the CFB mode.
+ * @param macSizeInBits the size of the MAC in bits, must be a multiple of 8.
+ * @param padding a padding to be used.
+ */
+ public CFBBlockCipherMac(
+ BlockCipher cipher,
+ int cfbBitSize,
+ int macSizeInBits,
+ BlockCipherPadding padding)
+ {
+ if ((macSizeInBits % 8) != 0)
+ {
+ throw new IllegalArgumentException("MAC size must be multiple of 8");
+ }
+
+ mac = new byte[cipher.getBlockSize()];
+
+ this.cipher = new MacCFBBlockCipher(cipher, cfbBitSize);
+ this.padding = padding;
+ this.macSize = macSizeInBits / 8;
+
+ buf = new byte[this.cipher.getBlockSize()];
+ bufOff = 0;
+ }
+
+ public String getAlgorithmName()
+ {
+ return cipher.getAlgorithmName();
+ }
+
+ public void init(
+ CipherParameters params)
+ {
+ reset();
+
+ cipher.init(params);
+ }
+
+ public int getMacSize()
+ {
+ return macSize;
+ }
+
+ public void update(
+ byte in)
+ {
+ if (bufOff == buf.length)
+ {
+ cipher.processBlock(buf, 0, mac, 0);
+ bufOff = 0;
+ }
+
+ buf[bufOff++] = in;
+ }
+
+ public void update(
+ byte[] in,
+ int inOff,
+ int len)
+ {
+ if (len < 0)
+ {
+ throw new IllegalArgumentException("Can't have a negative input length!");
+ }
+
+ int blockSize = cipher.getBlockSize();
+ int resultLen = 0;
+ int gapLen = blockSize - bufOff;
+
+ if (len > gapLen)
+ {
+ System.arraycopy(in, inOff, buf, bufOff, gapLen);
+
+ resultLen += cipher.processBlock(buf, 0, mac, 0);
+
+ bufOff = 0;
+ len -= gapLen;
+ inOff += gapLen;
+
+ while (len > blockSize)
+ {
+ resultLen += cipher.processBlock(in, inOff, mac, 0);
+
+ len -= blockSize;
+ inOff += blockSize;
+ }
+ }
+
+ System.arraycopy(in, inOff, buf, bufOff, len);
+
+ bufOff += len;
+ }
+
+ public int doFinal(
+ byte[] out,
+ int outOff)
+ {
+ int blockSize = cipher.getBlockSize();
+
+ //
+ // pad with zeroes
+ //
+ if (this.padding == null)
+ {
+ while (bufOff < blockSize)
+ {
+ buf[bufOff] = 0;
+ bufOff++;
+ }
+ }
+ else
+ {
+ padding.addPadding(buf, bufOff);
+ }
+
+ cipher.processBlock(buf, 0, mac, 0);
+
+ cipher.getMacBlock(mac);
+
+ System.arraycopy(mac, 0, out, outOff, macSize);
+
+ reset();
+
+ return macSize;
+ }
+
+ /**
+ * Reset the mac generator.
+ */
+ public void reset()
+ {
+ /*
+ * clean the buffer.
+ */
+ for (int i = 0; i < buf.length; i++)
+ {
+ buf[i] = 0;
+ }
+
+ bufOff = 0;
+
+ /*
+ * reset the underlying cipher.
+ */
+ cipher.reset();
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/macs/CMac.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/macs/CMac.java
new file mode 100644
index 0000000..5d94026
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/macs/CMac.java
@@ -0,0 +1,238 @@
+package org.bc.crypto.macs;
+
+import org.bc.crypto.BlockCipher;
+import org.bc.crypto.CipherParameters;
+import org.bc.crypto.Mac;
+import org.bc.crypto.modes.CBCBlockCipher;
+import org.bc.crypto.paddings.ISO7816d4Padding;
+
+/**
+ * CMAC - as specified at www.nuee.nagoya-u.ac.jp/labs/tiwata/omac/omac.html
+ *
+ * CMAC is analogous to OMAC1 - see also en.wikipedia.org/wiki/CMAC
+ *
+ * CMAC is a NIST recomendation - see
+ * csrc.nist.gov/CryptoToolkit/modes/800-38_Series_Publications/SP800-38B.pdf
+ *
+ * CMAC/OMAC1 is a blockcipher-based message authentication code designed and
+ * analyzed by Tetsu Iwata and Kaoru Kurosawa.
+ *
+ * CMAC/OMAC1 is a simple variant of the CBC MAC (Cipher Block Chaining Message
+ * Authentication Code). OMAC stands for One-Key CBC MAC.
+ *
+ * It supports 128- or 64-bits block ciphers, with any key size, and returns
+ * a MAC with dimension less or equal to the block size of the underlying
+ * cipher.
+ *
+ * Note: the size of the MAC must be at least 24 bits (FIPS Publication 81),
+ * or 16 bits if being used as a data authenticator (FIPS Publication 113),
+ * and in general should be less than the size of the block cipher as it reduces
+ * the chance of an exhaustive attack (see Handbook of Applied Cryptography).
+ *
+ * @param cipher the cipher to be used as the basis of the MAC generation.
+ * @param macSizeInBits the size of the MAC in bits, must be a multiple of 8.
+ */
+ public ISO9797Alg3Mac(
+ BlockCipher cipher,
+ int macSizeInBits)
+ {
+ this(cipher, macSizeInBits, null);
+ }
+
+ /**
+ * create a standard MAC based on a block cipher with the size of the
+ * MAC been given in bits. This class uses single DES CBC mode as the basis for the
+ * MAC generation. The final block is decrypted and then encrypted using the
+ * middle and right part of the key.
+ *
+ * Note: the size of the MAC must be at least 24 bits (FIPS Publication 81),
+ * or 16 bits if being used as a data authenticator (FIPS Publication 113),
+ * and in general should be less than the size of the block cipher as it reduces
+ * the chance of an exhaustive attack (see Handbook of Applied Cryptography).
+ *
+ * @param cipher the cipher to be used as the basis of the MAC generation.
+ * @param macSizeInBits the size of the MAC in bits, must be a multiple of 8.
+ * @param padding the padding to be used to complete the last block.
+ */
+ public ISO9797Alg3Mac(
+ BlockCipher cipher,
+ int macSizeInBits,
+ BlockCipherPadding padding)
+ {
+ if ((macSizeInBits % 8) != 0)
+ {
+ throw new IllegalArgumentException("MAC size must be multiple of 8");
+ }
+
+ if (!(cipher instanceof DESEngine))
+ {
+ throw new IllegalArgumentException("cipher must be instance of DESEngine");
+ }
+
+ this.cipher = new CBCBlockCipher(cipher);
+ this.padding = padding;
+ this.macSize = macSizeInBits / 8;
+
+ mac = new byte[cipher.getBlockSize()];
+
+ buf = new byte[cipher.getBlockSize()];
+ bufOff = 0;
+ }
+
+ public String getAlgorithmName()
+ {
+ return "ISO9797Alg3";
+ }
+
+ public void init(CipherParameters params)
+ {
+ reset();
+
+ if (!(params instanceof KeyParameter || params instanceof ParametersWithIV))
+ {
+ throw new IllegalArgumentException(
+ "params must be an instance of KeyParameter or ParametersWithIV");
+ }
+
+ // KeyParameter must contain a double or triple length DES key,
+ // however the underlying cipher is a single DES. The middle and
+ // right key are used only in the final step.
+
+ KeyParameter kp;
+
+ if (params instanceof KeyParameter)
+ {
+ kp = (KeyParameter)params;
+ }
+ else
+ {
+ kp = (KeyParameter)((ParametersWithIV)params).getParameters();
+ }
+
+ KeyParameter key1;
+ byte[] keyvalue = kp.getKey();
+
+ if (keyvalue.length == 16)
+ { // Double length DES key
+ key1 = new KeyParameter(keyvalue, 0, 8);
+ this.lastKey2 = new KeyParameter(keyvalue, 8, 8);
+ this.lastKey3 = key1;
+ }
+ else if (keyvalue.length == 24)
+ { // Triple length DES key
+ key1 = new KeyParameter(keyvalue, 0, 8);
+ this.lastKey2 = new KeyParameter(keyvalue, 8, 8);
+ this.lastKey3 = new KeyParameter(keyvalue, 16, 8);
+ }
+ else
+ {
+ throw new IllegalArgumentException(
+ "Key must be either 112 or 168 bit long");
+ }
+
+ if (params instanceof ParametersWithIV)
+ {
+ cipher.init(true, new ParametersWithIV(key1, ((ParametersWithIV)params).getIV()));
+ }
+ else
+ {
+ cipher.init(true, key1);
+ }
+ }
+
+ public int getMacSize()
+ {
+ return macSize;
+ }
+
+ public void update(
+ byte in)
+ {
+ if (bufOff == buf.length)
+ {
+ cipher.processBlock(buf, 0, mac, 0);
+ bufOff = 0;
+ }
+
+ buf[bufOff++] = in;
+ }
+
+
+ public void update(
+ byte[] in,
+ int inOff,
+ int len)
+ {
+ if (len < 0)
+ {
+ throw new IllegalArgumentException("Can't have a negative input length!");
+ }
+
+ int blockSize = cipher.getBlockSize();
+ int resultLen = 0;
+ int gapLen = blockSize - bufOff;
+
+ if (len > gapLen)
+ {
+ System.arraycopy(in, inOff, buf, bufOff, gapLen);
+
+ resultLen += cipher.processBlock(buf, 0, mac, 0);
+
+ bufOff = 0;
+ len -= gapLen;
+ inOff += gapLen;
+
+ while (len > blockSize)
+ {
+ resultLen += cipher.processBlock(in, inOff, mac, 0);
+
+ len -= blockSize;
+ inOff += blockSize;
+ }
+ }
+
+ System.arraycopy(in, inOff, buf, bufOff, len);
+
+ bufOff += len;
+ }
+
+ public int doFinal(
+ byte[] out,
+ int outOff)
+ {
+ int blockSize = cipher.getBlockSize();
+
+ if (padding == null)
+ {
+ //
+ // pad with zeroes
+ //
+ while (bufOff < blockSize)
+ {
+ buf[bufOff] = 0;
+ bufOff++;
+ }
+ }
+ else
+ {
+ if (bufOff == blockSize)
+ {
+ cipher.processBlock(buf, 0, mac, 0);
+ bufOff = 0;
+ }
+
+ padding.addPadding(buf, bufOff);
+ }
+
+ cipher.processBlock(buf, 0, mac, 0);
+
+ // Added to code from base class
+ DESEngine deseng = new DESEngine();
+
+ deseng.init(false, this.lastKey2);
+ deseng.processBlock(mac, 0, mac, 0);
+
+ deseng.init(true, this.lastKey3);
+ deseng.processBlock(mac, 0, mac, 0);
+ // ****
+
+ System.arraycopy(mac, 0, out, outOff, macSize);
+
+ reset();
+
+ return macSize;
+ }
+
+
+ /**
+ * Reset the mac generator.
+ */
+ public void reset()
+ {
+ /*
+ * clean the buffer.
+ */
+ for (int i = 0; i < buf.length; i++)
+ {
+ buf[i] = 0;
+ }
+
+ bufOff = 0;
+
+ /*
+ * reset the underlying cipher.
+ */
+ cipher.reset();
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/macs/OldHMac.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/macs/OldHMac.java
new file mode 100644
index 0000000..aeaeb9d
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/macs/OldHMac.java
@@ -0,0 +1,138 @@
+package org.bc.crypto.macs;
+
+import org.bc.crypto.CipherParameters;
+import org.bc.crypto.Digest;
+import org.bc.crypto.Mac;
+import org.bc.crypto.params.KeyParameter;
+
+/**
+ * HMAC implementation based on RFC2104
+ *
+ * H(K XOR opad, H(K XOR ipad, text))
+ */
+public class OldHMac
+implements Mac
+{
+ private final static int BLOCK_LENGTH = 64;
+
+ private final static byte IPAD = (byte)0x36;
+ private final static byte OPAD = (byte)0x5C;
+
+ private Digest digest;
+ private int digestSize;
+ private byte[] inputPad = new byte[BLOCK_LENGTH];
+ private byte[] outputPad = new byte[BLOCK_LENGTH];
+
+ /**
+ * @deprecated uses incorrect pad for SHA-512 and SHA-384 use HMac.
+ */
+ public OldHMac(
+ Digest digest)
+ {
+ this.digest = digest;
+ digestSize = digest.getDigestSize();
+ }
+
+ public String getAlgorithmName()
+ {
+ return digest.getAlgorithmName() + "/HMAC";
+ }
+
+ public Digest getUnderlyingDigest()
+ {
+ return digest;
+ }
+
+ public void init(
+ CipherParameters params)
+ {
+ digest.reset();
+
+ byte[] key = ((KeyParameter)params).getKey();
+
+ if (key.length > BLOCK_LENGTH)
+ {
+ digest.update(key, 0, key.length);
+ digest.doFinal(inputPad, 0);
+ for (int i = digestSize; i < inputPad.length; i++)
+ {
+ inputPad[i] = 0;
+ }
+ }
+ else
+ {
+ System.arraycopy(key, 0, inputPad, 0, key.length);
+ for (int i = key.length; i < inputPad.length; i++)
+ {
+ inputPad[i] = 0;
+ }
+ }
+
+ outputPad = new byte[inputPad.length];
+ System.arraycopy(inputPad, 0, outputPad, 0, inputPad.length);
+
+ for (int i = 0; i < inputPad.length; i++)
+ {
+ inputPad[i] ^= IPAD;
+ }
+
+ for (int i = 0; i < outputPad.length; i++)
+ {
+ outputPad[i] ^= OPAD;
+ }
+
+ digest.update(inputPad, 0, inputPad.length);
+ }
+
+ public int getMacSize()
+ {
+ return digestSize;
+ }
+
+ public void update(
+ byte in)
+ {
+ digest.update(in);
+ }
+
+ public void update(
+ byte[] in,
+ int inOff,
+ int len)
+ {
+ digest.update(in, inOff, len);
+ }
+
+ public int doFinal(
+ byte[] out,
+ int outOff)
+ {
+ byte[] tmp = new byte[digestSize];
+ digest.doFinal(tmp, 0);
+
+ digest.update(outputPad, 0, outputPad.length);
+ digest.update(tmp, 0, tmp.length);
+
+ int len = digest.doFinal(out, outOff);
+
+ reset();
+
+ return len;
+ }
+
+ /**
+ * Reset the mac generator.
+ */
+ public void reset()
+ {
+ /*
+ * reset the underlying digest.
+ */
+ digest.reset();
+
+ /*
+ * reinitialize the digest.
+ */
+ digest.update(inputPad, 0, inputPad.length);
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/macs/VMPCMac.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/macs/VMPCMac.java
new file mode 100644
index 0000000..8f1f616
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/macs/VMPCMac.java
@@ -0,0 +1,186 @@
+package org.bc.crypto.macs;
+
+import org.bc.crypto.CipherParameters;
+import org.bc.crypto.DataLengthException;
+import org.bc.crypto.Mac;
+import org.bc.crypto.params.KeyParameter;
+import org.bc.crypto.params.ParametersWithIV;
+
+public class VMPCMac implements Mac
+{
+ private byte g;
+
+ private byte n = 0;
+ private byte[] P = null;
+ private byte s = 0;
+
+ private byte[] T;
+ private byte[] workingIV;
+
+ private byte[] workingKey;
+
+ private byte x1, x2, x3, x4;
+
+ public int doFinal(byte[] out, int outOff)
+ throws DataLengthException, IllegalStateException
+ {
+ // Execute the Post-Processing Phase
+ for (int r = 1; r < 25; r++)
+ {
+ s = P[(s + P[n & 0xff]) & 0xff];
+
+ x4 = P[(x4 + x3 + r) & 0xff];
+ x3 = P[(x3 + x2 + r) & 0xff];
+ x2 = P[(x2 + x1 + r) & 0xff];
+ x1 = P[(x1 + s + r) & 0xff];
+ T[g & 0x1f] = (byte) (T[g & 0x1f] ^ x1);
+ T[(g + 1) & 0x1f] = (byte) (T[(g + 1) & 0x1f] ^ x2);
+ T[(g + 2) & 0x1f] = (byte) (T[(g + 2) & 0x1f] ^ x3);
+ T[(g + 3) & 0x1f] = (byte) (T[(g + 3) & 0x1f] ^ x4);
+ g = (byte) ((g + 4) & 0x1f);
+
+ byte temp = P[n & 0xff];
+ P[n & 0xff] = P[s & 0xff];
+ P[s & 0xff] = temp;
+ n = (byte) ((n + 1) & 0xff);
+ }
+
+ // Input T to the IV-phase of the VMPC KSA
+ for (int m = 0; m < 768; m++)
+ {
+ s = P[(s + P[m & 0xff] + T[m & 0x1f]) & 0xff];
+ byte temp = P[m & 0xff];
+ P[m & 0xff] = P[s & 0xff];
+ P[s & 0xff] = temp;
+ }
+
+ // Store 20 new outputs of the VMPC Stream Cipher in table M
+ byte[] M = new byte[20];
+ for (int i = 0; i < 20; i++)
+ {
+ s = P[(s + P[i & 0xff]) & 0xff];
+ M[i] = P[(P[(P[s & 0xff]) & 0xff] + 1) & 0xff];
+
+ byte temp = P[i & 0xff];
+ P[i & 0xff] = P[s & 0xff];
+ P[s & 0xff] = temp;
+ }
+
+ System.arraycopy(M, 0, out, outOff, M.length);
+ reset();
+
+ return M.length;
+ }
+
+ public String getAlgorithmName()
+ {
+ return "VMPC-MAC";
+ }
+
+ public int getMacSize()
+ {
+ return 20;
+ }
+
+ public void init(CipherParameters params) throws IllegalArgumentException
+ {
+ if (!(params instanceof ParametersWithIV))
+ {
+ throw new IllegalArgumentException(
+ "VMPC-MAC Init parameters must include an IV");
+ }
+
+ ParametersWithIV ivParams = (ParametersWithIV) params;
+ KeyParameter key = (KeyParameter) ivParams.getParameters();
+
+ if (!(ivParams.getParameters() instanceof KeyParameter))
+ {
+ throw new IllegalArgumentException(
+ "VMPC-MAC Init parameters must include a key");
+ }
+
+ this.workingIV = ivParams.getIV();
+
+ if (workingIV == null || workingIV.length < 1 || workingIV.length > 768)
+ {
+ throw new IllegalArgumentException(
+ "VMPC-MAC requires 1 to 768 bytes of IV");
+ }
+
+ this.workingKey = key.getKey();
+
+ reset();
+
+ }
+
+ private void initKey(byte[] keyBytes, byte[] ivBytes)
+ {
+ s = 0;
+ P = new byte[256];
+ for (int i = 0; i < 256; i++)
+ {
+ P[i] = (byte) i;
+ }
+ for (int m = 0; m < 768; m++)
+ {
+ s = P[(s + P[m & 0xff] + keyBytes[m % keyBytes.length]) & 0xff];
+ byte temp = P[m & 0xff];
+ P[m & 0xff] = P[s & 0xff];
+ P[s & 0xff] = temp;
+ }
+ for (int m = 0; m < 768; m++)
+ {
+ s = P[(s + P[m & 0xff] + ivBytes[m % ivBytes.length]) & 0xff];
+ byte temp = P[m & 0xff];
+ P[m & 0xff] = P[s & 0xff];
+ P[s & 0xff] = temp;
+ }
+ n = 0;
+ }
+
+ public void reset()
+ {
+ initKey(this.workingKey, this.workingIV);
+ g = x1 = x2 = x3 = x4 = n = 0;
+ T = new byte[32];
+ for (int i = 0; i < 32; i++)
+ {
+ T[i] = 0;
+ }
+ }
+
+ public void update(byte in) throws IllegalStateException
+ {
+ s = P[(s + P[n & 0xff]) & 0xff];
+ byte c = (byte) (in ^ P[(P[(P[s & 0xff]) & 0xff] + 1) & 0xff]);
+
+ x4 = P[(x4 + x3) & 0xff];
+ x3 = P[(x3 + x2) & 0xff];
+ x2 = P[(x2 + x1) & 0xff];
+ x1 = P[(x1 + s + c) & 0xff];
+ T[g & 0x1f] = (byte) (T[g & 0x1f] ^ x1);
+ T[(g + 1) & 0x1f] = (byte) (T[(g + 1) & 0x1f] ^ x2);
+ T[(g + 2) & 0x1f] = (byte) (T[(g + 2) & 0x1f] ^ x3);
+ T[(g + 3) & 0x1f] = (byte) (T[(g + 3) & 0x1f] ^ x4);
+ g = (byte) ((g + 4) & 0x1f);
+
+ byte temp = P[n & 0xff];
+ P[n & 0xff] = P[s & 0xff];
+ P[s & 0xff] = temp;
+ n = (byte) ((n + 1) & 0xff);
+ }
+
+ public void update(byte[] in, int inOff, int len)
+ throws DataLengthException, IllegalStateException
+ {
+ if ((inOff + len) > in.length)
+ {
+ throw new DataLengthException("input buffer too short");
+ }
+
+ for (int i = 0; i < len; i++)
+ {
+ update(in[i]);
+ }
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/modes/AEADBlockCipher.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/modes/AEADBlockCipher.java
new file mode 100644
index 0000000..0b715e9
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/modes/AEADBlockCipher.java
@@ -0,0 +1,126 @@
+package org.bc.crypto.modes;
+
+import org.bc.crypto.BlockCipher;
+import org.bc.crypto.CipherParameters;
+import org.bc.crypto.DataLengthException;
+import org.bc.crypto.InvalidCipherTextException;
+
+/**
+ * A block cipher mode that includes authenticated encryption with a streaming mode and optional associated data.
+ * @see org.bc.crypto.params.AEADParameters
+ */
+public interface AEADBlockCipher
+{
+ /**
+ * initialise the underlying cipher. Parameter can either be an AEADParameters or a ParametersWithIV object.
+ *
+ * @param forEncryption true if we are setting up for encryption, false otherwise.
+ * @param params the necessary parameters for the underlying cipher to be initialised.
+ * @exception IllegalArgumentException if the params argument is inappropriate.
+ */
+ public void init(boolean forEncryption, CipherParameters params)
+ throws IllegalArgumentException;
+
+ /**
+ * Return the name of the algorithm.
+ *
+ * @return the algorithm name.
+ */
+ public String getAlgorithmName();
+
+ /**
+ * return the cipher this object wraps.
+ *
+ * @return the cipher this object wraps.
+ */
+ public BlockCipher getUnderlyingCipher();
+
+ /**
+ * Add a single byte to the associated data check.
+ *
+ * Note: this mode is a packet mode - it needs all the data up front.
+ */
+public class CCMBlockCipher
+ implements AEADBlockCipher
+{
+ private BlockCipher cipher;
+ private int blockSize;
+ private boolean forEncryption;
+ private byte[] nonce;
+ private byte[] initialAssociatedText;
+ private int macSize;
+ private CipherParameters keyParam;
+ private byte[] macBlock;
+ private ByteArrayOutputStream associatedText = new ByteArrayOutputStream();
+ private ByteArrayOutputStream data = new ByteArrayOutputStream();
+
+ /**
+ * Basic constructor.
+ *
+ * @param c the block cipher to be used.
+ */
+ public CCMBlockCipher(BlockCipher c)
+ {
+ this.cipher = c;
+ this.blockSize = c.getBlockSize();
+ this.macBlock = new byte[blockSize];
+
+ if (blockSize != 16)
+ {
+ throw new IllegalArgumentException("cipher required with a block size of 16.");
+ }
+ }
+
+ /**
+ * return the underlying block cipher that we are wrapping.
+ *
+ * @return the underlying block cipher that we are wrapping.
+ */
+ public BlockCipher getUnderlyingCipher()
+ {
+ return cipher;
+ }
+
+
+ public void init(boolean forEncryption, CipherParameters params)
+ throws IllegalArgumentException
+ {
+ this.forEncryption = forEncryption;
+
+ if (params instanceof AEADParameters)
+ {
+ AEADParameters param = (AEADParameters)params;
+
+ nonce = param.getNonce();
+ initialAssociatedText = param.getAssociatedText();
+ macSize = param.getMacSize() / 8;
+ keyParam = param.getKey();
+ }
+ else if (params instanceof ParametersWithIV)
+ {
+ ParametersWithIV param = (ParametersWithIV)params;
+
+ nonce = param.getIV();
+ initialAssociatedText = null;
+ macSize = macBlock.length / 2;
+ keyParam = param.getParameters();
+ }
+ else
+ {
+ throw new IllegalArgumentException("invalid parameters passed to CCM");
+ }
+ }
+
+ public String getAlgorithmName()
+ {
+ return cipher.getAlgorithmName() + "/CCM";
+ }
+
+ public void processAADByte(byte in)
+ {
+ associatedText.write(in);
+ }
+
+ public void processAADBytes(byte[] in, int inOff, int len)
+ {
+ // TODO: Process AAD online
+ associatedText.write(in, inOff, len);
+ }
+
+ public int processByte(byte in, byte[] out, int outOff)
+ throws DataLengthException, IllegalStateException
+ {
+ data.write(in);
+
+ return 0;
+ }
+
+ public int processBytes(byte[] in, int inOff, int inLen, byte[] out, int outOff)
+ throws DataLengthException, IllegalStateException
+ {
+ data.write(in, inOff, inLen);
+
+ return 0;
+ }
+
+ public int doFinal(byte[] out, int outOff)
+ throws IllegalStateException, InvalidCipherTextException
+ {
+ byte[] text = data.toByteArray();
+ byte[] enc = processPacket(text, 0, text.length);
+
+ System.arraycopy(enc, 0, out, outOff, enc.length);
+
+ reset();
+
+ return enc.length;
+ }
+
+ public void reset()
+ {
+ cipher.reset();
+ associatedText.reset();
+ data.reset();
+ }
+
+ /**
+ * Returns a byte array containing the mac calculated as part of the
+ * last encrypt or decrypt operation.
+ *
+ * @return the last mac calculated.
+ */
+ public byte[] getMac()
+ {
+ byte[] mac = new byte[macSize];
+
+ System.arraycopy(macBlock, 0, mac, 0, mac.length);
+
+ return mac;
+ }
+
+ public int getUpdateOutputSize(int len)
+ {
+ return 0;
+ }
+
+ public int getOutputSize(int len)
+ {
+ int totalData = len + data.size();
+
+ if (forEncryption)
+ {
+ return totalData + macSize;
+ }
+
+ return totalData < macSize ? 0 : totalData - macSize;
+ }
+
+ public byte[] processPacket(byte[] in, int inOff, int inLen)
+ throws IllegalStateException, InvalidCipherTextException
+ {
+ // TODO: handle null keyParam (e.g. via RepeatedKeySpec)
+ // Need to keep the CTR and CBC Mac parts around and reset
+ if (keyParam == null)
+ {
+ throw new IllegalStateException("CCM cipher unitialized.");
+ }
+
+ BlockCipher ctrCipher = new SICBlockCipher(cipher);
+ byte[] iv = new byte[blockSize];
+ byte[] out;
+
+ iv[0] = (byte)(((15 - nonce.length) - 1) & 0x7);
+
+ System.arraycopy(nonce, 0, iv, 1, nonce.length);
+
+ ctrCipher.init(forEncryption, new ParametersWithIV(keyParam, iv));
+
+ if (forEncryption)
+ {
+ int index = inOff;
+ int outOff = 0;
+
+ out = new byte[inLen + macSize];
+
+ calculateMac(in, inOff, inLen, macBlock);
+
+ ctrCipher.processBlock(macBlock, 0, macBlock, 0); // S0
+
+ while (index < inLen - blockSize) // S1...
+ {
+ ctrCipher.processBlock(in, index, out, outOff);
+ outOff += blockSize;
+ index += blockSize;
+ }
+
+ byte[] block = new byte[blockSize];
+
+ System.arraycopy(in, index, block, 0, inLen - index);
+
+ ctrCipher.processBlock(block, 0, block, 0);
+
+ System.arraycopy(block, 0, out, outOff, inLen - index);
+
+ outOff += inLen - index;
+
+ System.arraycopy(macBlock, 0, out, outOff, out.length - outOff);
+ }
+ else
+ {
+ int index = inOff;
+ int outOff = 0;
+
+ out = new byte[inLen - macSize];
+
+ System.arraycopy(in, inOff + inLen - macSize, macBlock, 0, macSize);
+
+ ctrCipher.processBlock(macBlock, 0, macBlock, 0);
+
+ for (int i = macSize; i != macBlock.length; i++)
+ {
+ macBlock[i] = 0;
+ }
+
+ while (outOff < out.length - blockSize)
+ {
+ ctrCipher.processBlock(in, index, out, outOff);
+ outOff += blockSize;
+ index += blockSize;
+ }
+
+ byte[] block = new byte[blockSize];
+
+ System.arraycopy(in, index, block, 0, out.length - outOff);
+
+ ctrCipher.processBlock(block, 0, block, 0);
+
+ System.arraycopy(block, 0, out, outOff, out.length - outOff);
+
+ byte[] calculatedMacBlock = new byte[blockSize];
+
+ calculateMac(out, 0, out.length, calculatedMacBlock);
+
+ if (!Arrays.constantTimeAreEqual(macBlock, calculatedMacBlock))
+ {
+ throw new InvalidCipherTextException("mac check in CCM failed");
+ }
+ }
+
+ return out;
+ }
+
+ private int calculateMac(byte[] data, int dataOff, int dataLen, byte[] macBlock)
+ {
+ Mac cMac = new CBCBlockCipherMac(cipher, macSize * 8);
+
+ cMac.init(keyParam);
+
+ //
+ // build b0
+ //
+ byte[] b0 = new byte[16];
+
+ if (hasAssociatedText())
+ {
+ b0[0] |= 0x40;
+ }
+
+ b0[0] |= (((cMac.getMacSize() - 2) / 2) & 0x7) << 3;
+
+ b0[0] |= ((15 - nonce.length) - 1) & 0x7;
+
+ System.arraycopy(nonce, 0, b0, 1, nonce.length);
+
+ int q = dataLen;
+ int count = 1;
+ while (q > 0)
+ {
+ b0[b0.length - count] = (byte)(q & 0xff);
+ q >>>= 8;
+ count++;
+ }
+
+ cMac.update(b0, 0, b0.length);
+
+ //
+ // process associated text
+ //
+ if (hasAssociatedText())
+ {
+ int extra;
+
+ int textLength = getAssociatedTextLength();
+ if (textLength < ((1 << 16) - (1 << 8)))
+ {
+ cMac.update((byte)(textLength >> 8));
+ cMac.update((byte)textLength);
+
+ extra = 2;
+ }
+ else // can't go any higher than 2^32
+ {
+ cMac.update((byte)0xff);
+ cMac.update((byte)0xfe);
+ cMac.update((byte)(textLength >> 24));
+ cMac.update((byte)(textLength >> 16));
+ cMac.update((byte)(textLength >> 8));
+ cMac.update((byte)textLength);
+
+ extra = 6;
+ }
+
+ if (initialAssociatedText != null)
+ {
+ cMac.update(initialAssociatedText, 0, initialAssociatedText.length);
+ }
+ if (associatedText.size() > 0)
+ {
+ byte[] tmp = associatedText.toByteArray();
+ cMac.update(tmp, 0, tmp.length);
+ }
+
+ extra = (extra + textLength) % 16;
+ if (extra != 0)
+ {
+ for (int i = 0; i != 16 - extra; i++)
+ {
+ cMac.update((byte)0x00);
+ }
+ }
+ }
+
+ //
+ // add the text
+ //
+ cMac.update(data, dataOff, dataLen);
+
+ return cMac.doFinal(macBlock, 0);
+ }
+
+ private int getAssociatedTextLength()
+ {
+ return associatedText.size() + ((initialAssociatedText == null) ? 0 : initialAssociatedText.length);
+ }
+
+ private boolean hasAssociatedText()
+ {
+ return getAssociatedTextLength() > 0;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/modes/CFBBlockCipher.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/modes/CFBBlockCipher.java
new file mode 100644
index 0000000..eaec321
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/modes/CFBBlockCipher.java
@@ -0,0 +1,258 @@
+package org.bc.crypto.modes;
+
+import org.bc.crypto.BlockCipher;
+import org.bc.crypto.CipherParameters;
+import org.bc.crypto.DataLengthException;
+import org.bc.crypto.params.ParametersWithIV;
+
+/**
+ * implements a Cipher-FeedBack (CFB) mode on top of a simple cipher.
+ */
+public class CFBBlockCipher
+ implements BlockCipher
+{
+ private byte[] IV;
+ private byte[] cfbV;
+ private byte[] cfbOutV;
+
+ private int blockSize;
+ private BlockCipher cipher = null;
+ private boolean encrypting;
+
+ /**
+ * Basic constructor.
+ *
+ * @param cipher the block cipher to be used as the basis of the
+ * feedback mode.
+ * @param bitBlockSize the block size in bits (note: a multiple of 8)
+ */
+ public CFBBlockCipher(
+ BlockCipher cipher,
+ int bitBlockSize)
+ {
+ this.cipher = cipher;
+ this.blockSize = bitBlockSize / 8;
+
+ this.IV = new byte[cipher.getBlockSize()];
+ this.cfbV = new byte[cipher.getBlockSize()];
+ this.cfbOutV = new byte[cipher.getBlockSize()];
+ }
+
+ /**
+ * return the underlying block cipher that we are wrapping.
+ *
+ * @return the underlying block cipher that we are wrapping.
+ */
+ public BlockCipher getUnderlyingCipher()
+ {
+ return cipher;
+ }
+
+ /**
+ * Initialise the cipher and, possibly, the initialisation vector (IV).
+ * If an IV isn't passed as part of the parameter, the IV will be all zeros.
+ * An IV which is too short is handled in FIPS compliant fashion.
+ *
+ * @param encrypting if true the cipher is initialised for
+ * encryption, if false for decryption.
+ * @param params the key and other data required by the cipher.
+ * @exception IllegalArgumentException if the params argument is
+ * inappropriate.
+ */
+ public void init(
+ boolean encrypting,
+ CipherParameters params)
+ throws IllegalArgumentException
+ {
+ this.encrypting = encrypting;
+
+ if (params instanceof ParametersWithIV)
+ {
+ ParametersWithIV ivParam = (ParametersWithIV)params;
+ byte[] iv = ivParam.getIV();
+
+ if (iv.length < IV.length)
+ {
+ // prepend the supplied IV with zeros (per FIPS PUB 81)
+ System.arraycopy(iv, 0, IV, IV.length - iv.length, iv.length);
+ for (int i = 0; i < IV.length - iv.length; i++)
+ {
+ IV[i] = 0;
+ }
+ }
+ else
+ {
+ System.arraycopy(iv, 0, IV, 0, IV.length);
+ }
+
+ reset();
+
+ // if null it's an IV changed only.
+ if (ivParam.getParameters() != null)
+ {
+ cipher.init(true, ivParam.getParameters());
+ }
+ }
+ else
+ {
+ reset();
+
+ // if it's null, key is to be reused.
+ if (params != null)
+ {
+ cipher.init(true, params);
+ }
+ }
+ }
+
+ /**
+ * return the algorithm name and mode.
+ *
+ * @return the name of the underlying algorithm followed by "/CFB"
+ * and the block size in bits.
+ */
+ public String getAlgorithmName()
+ {
+ return cipher.getAlgorithmName() + "/CFB" + (blockSize * 8);
+ }
+
+ /**
+ * return the block size we are operating at.
+ *
+ * @return the block size we are operating at (in bytes).
+ */
+ public int getBlockSize()
+ {
+ return blockSize;
+ }
+
+ /**
+ * Process one block of input from the array in and write it to
+ * the out array.
+ *
+ * @param in the array containing the input data.
+ * @param inOff offset into the in array the data starts at.
+ * @param out the array the output data will be copied into.
+ * @param outOff the offset into the out array the output will start at.
+ * @exception DataLengthException if there isn't enough data in in, or
+ * space in out.
+ * @exception IllegalStateException if the cipher isn't initialised.
+ * @return the number of bytes processed and produced.
+ */
+ public int processBlock(
+ byte[] in,
+ int inOff,
+ byte[] out,
+ int outOff)
+ throws DataLengthException, IllegalStateException
+ {
+ return (encrypting) ? encryptBlock(in, inOff, out, outOff) : decryptBlock(in, inOff, out, outOff);
+ }
+
+ /**
+ * Do the appropriate processing for CFB mode encryption.
+ *
+ * @param in the array containing the data to be encrypted.
+ * @param inOff offset into the in array the data starts at.
+ * @param out the array the encrypted data will be copied into.
+ * @param outOff the offset into the out array the output will start at.
+ * @exception DataLengthException if there isn't enough data in in, or
+ * space in out.
+ * @exception IllegalStateException if the cipher isn't initialised.
+ * @return the number of bytes processed and produced.
+ */
+ public int encryptBlock(
+ byte[] in,
+ int inOff,
+ byte[] out,
+ int outOff)
+ throws DataLengthException, IllegalStateException
+ {
+ if ((inOff + blockSize) > in.length)
+ {
+ throw new DataLengthException("input buffer too short");
+ }
+
+ if ((outOff + blockSize) > out.length)
+ {
+ throw new DataLengthException("output buffer too short");
+ }
+
+ cipher.processBlock(cfbV, 0, cfbOutV, 0);
+
+ //
+ // XOR the cfbV with the plaintext producing the ciphertext
+ //
+ for (int i = 0; i < blockSize; i++)
+ {
+ out[outOff + i] = (byte)(cfbOutV[i] ^ in[inOff + i]);
+ }
+
+ //
+ // change over the input block.
+ //
+ System.arraycopy(cfbV, blockSize, cfbV, 0, cfbV.length - blockSize);
+ System.arraycopy(out, outOff, cfbV, cfbV.length - blockSize, blockSize);
+
+ return blockSize;
+ }
+
+ /**
+ * Do the appropriate processing for CFB mode decryption.
+ *
+ * @param in the array containing the data to be decrypted.
+ * @param inOff offset into the in array the data starts at.
+ * @param out the array the encrypted data will be copied into.
+ * @param outOff the offset into the out array the output will start at.
+ * @exception DataLengthException if there isn't enough data in in, or
+ * space in out.
+ * @exception IllegalStateException if the cipher isn't initialised.
+ * @return the number of bytes processed and produced.
+ */
+ public int decryptBlock(
+ byte[] in,
+ int inOff,
+ byte[] out,
+ int outOff)
+ throws DataLengthException, IllegalStateException
+ {
+ if ((inOff + blockSize) > in.length)
+ {
+ throw new DataLengthException("input buffer too short");
+ }
+
+ if ((outOff + blockSize) > out.length)
+ {
+ throw new DataLengthException("output buffer too short");
+ }
+
+ cipher.processBlock(cfbV, 0, cfbOutV, 0);
+
+ //
+ // change over the input block.
+ //
+ System.arraycopy(cfbV, blockSize, cfbV, 0, cfbV.length - blockSize);
+ System.arraycopy(in, inOff, cfbV, cfbV.length - blockSize, blockSize);
+
+ //
+ // XOR the cfbV with the ciphertext producing the plaintext
+ //
+ for (int i = 0; i < blockSize; i++)
+ {
+ out[outOff + i] = (byte)(cfbOutV[i] ^ in[inOff + i]);
+ }
+
+ return blockSize;
+ }
+
+ /**
+ * reset the chaining vector back to the IV and reset the underlying
+ * cipher.
+ */
+ public void reset()
+ {
+ System.arraycopy(IV, 0, cfbV, 0, IV.length);
+
+ cipher.reset();
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/modes/CTSBlockCipher.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/modes/CTSBlockCipher.java
new file mode 100644
index 0000000..edd4248
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/modes/CTSBlockCipher.java
@@ -0,0 +1,265 @@
+package org.bc.crypto.modes;
+
+import org.bc.crypto.BlockCipher;
+import org.bc.crypto.BufferedBlockCipher;
+import org.bc.crypto.DataLengthException;
+import org.bc.crypto.InvalidCipherTextException;
+
+/**
+ * A Cipher Text Stealing (CTS) mode cipher. CTS allows block ciphers to
+ * be used to produce cipher text which is the same length as the plain text.
+ */
+public class CTSBlockCipher
+ extends BufferedBlockCipher
+{
+ private int blockSize;
+
+ /**
+ * Create a buffered block cipher that uses Cipher Text Stealing
+ *
+ * @param cipher the underlying block cipher this buffering object wraps.
+ */
+ public CTSBlockCipher(
+ BlockCipher cipher)
+ {
+ if ((cipher instanceof OFBBlockCipher) || (cipher instanceof CFBBlockCipher))
+ {
+ throw new IllegalArgumentException("CTSBlockCipher can only accept ECB, or CBC ciphers");
+ }
+
+ this.cipher = cipher;
+
+ blockSize = cipher.getBlockSize();
+
+ buf = new byte[blockSize * 2];
+ bufOff = 0;
+ }
+
+ /**
+ * return the size of the output buffer required for an update
+ * an input of len bytes.
+ *
+ * @param len the length of the input.
+ * @return the space required to accommodate a call to update
+ * with len bytes of input.
+ */
+ public int getUpdateOutputSize(
+ int len)
+ {
+ int total = len + bufOff;
+ int leftOver = total % buf.length;
+
+ if (leftOver == 0)
+ {
+ return total - buf.length;
+ }
+
+ return total - leftOver;
+ }
+
+ /**
+ * return the size of the output buffer required for an update plus a
+ * doFinal with an input of len bytes.
+ *
+ * @param len the length of the input.
+ * @return the space required to accommodate a call to update and doFinal
+ * with len bytes of input.
+ */
+ public int getOutputSize(
+ int len)
+ {
+ return len + bufOff;
+ }
+
+ /**
+ * process a single byte, producing an output block if neccessary.
+ *
+ * @param in the input byte.
+ * @param out the space for any output that might be produced.
+ * @param outOff the offset from which the output will be copied.
+ * @return the number of output bytes copied to out.
+ * @exception DataLengthException if there isn't enough space in out.
+ * @exception IllegalStateException if the cipher isn't initialised.
+ */
+ public int processByte(
+ byte in,
+ byte[] out,
+ int outOff)
+ throws DataLengthException, IllegalStateException
+ {
+ int resultLen = 0;
+
+ if (bufOff == buf.length)
+ {
+ resultLen = cipher.processBlock(buf, 0, out, outOff);
+ System.arraycopy(buf, blockSize, buf, 0, blockSize);
+
+ bufOff = blockSize;
+ }
+
+ buf[bufOff++] = in;
+
+ return resultLen;
+ }
+
+ /**
+ * process an array of bytes, producing output if necessary.
+ *
+ * @param in the input byte array.
+ * @param inOff the offset at which the input data starts.
+ * @param len the number of bytes to be copied out of the input array.
+ * @param out the space for any output that might be produced.
+ * @param outOff the offset from which the output will be copied.
+ * @return the number of output bytes copied to out.
+ * @exception DataLengthException if there isn't enough space in out.
+ * @exception IllegalStateException if the cipher isn't initialised.
+ */
+ public int processBytes(
+ byte[] in,
+ int inOff,
+ int len,
+ byte[] out,
+ int outOff)
+ throws DataLengthException, IllegalStateException
+ {
+ if (len < 0)
+ {
+ throw new IllegalArgumentException("Can't have a negative input length!");
+ }
+
+ int blockSize = getBlockSize();
+ int length = getUpdateOutputSize(len);
+
+ if (length > 0)
+ {
+ if ((outOff + length) > out.length)
+ {
+ throw new DataLengthException("output buffer too short");
+ }
+ }
+
+ int resultLen = 0;
+ int gapLen = buf.length - bufOff;
+
+ if (len > gapLen)
+ {
+ System.arraycopy(in, inOff, buf, bufOff, gapLen);
+
+ resultLen += cipher.processBlock(buf, 0, out, outOff);
+ System.arraycopy(buf, blockSize, buf, 0, blockSize);
+
+ bufOff = blockSize;
+
+ len -= gapLen;
+ inOff += gapLen;
+
+ while (len > blockSize)
+ {
+ System.arraycopy(in, inOff, buf, bufOff, blockSize);
+ resultLen += cipher.processBlock(buf, 0, out, outOff + resultLen);
+ System.arraycopy(buf, blockSize, buf, 0, blockSize);
+
+ len -= blockSize;
+ inOff += blockSize;
+ }
+ }
+
+ System.arraycopy(in, inOff, buf, bufOff, len);
+
+ bufOff += len;
+
+ return resultLen;
+ }
+
+ /**
+ * Process the last block in the buffer.
+ *
+ * @param out the array the block currently being held is copied into.
+ * @param outOff the offset at which the copying starts.
+ * @return the number of output bytes copied to out.
+ * @exception DataLengthException if there is insufficient space in out for
+ * the output.
+ * @exception IllegalStateException if the underlying cipher is not
+ * initialised.
+ * @exception InvalidCipherTextException if cipher text decrypts wrongly (in
+ * case the exception will never get thrown).
+ */
+ public int doFinal(
+ byte[] out,
+ int outOff)
+ throws DataLengthException, IllegalStateException, InvalidCipherTextException
+ {
+ if (bufOff + outOff > out.length)
+ {
+ throw new DataLengthException("output buffer to small in doFinal");
+ }
+
+ int blockSize = cipher.getBlockSize();
+ int len = bufOff - blockSize;
+ byte[] block = new byte[blockSize];
+
+ if (forEncryption)
+ {
+ cipher.processBlock(buf, 0, block, 0);
+
+ if (bufOff < blockSize)
+ {
+ throw new DataLengthException("need at least one block of input for CTS");
+ }
+
+ for (int i = bufOff; i != buf.length; i++)
+ {
+ buf[i] = block[i - blockSize];
+ }
+
+ for (int i = blockSize; i != bufOff; i++)
+ {
+ buf[i] ^= block[i - blockSize];
+ }
+
+ if (cipher instanceof CBCBlockCipher)
+ {
+ BlockCipher c = ((CBCBlockCipher)cipher).getUnderlyingCipher();
+
+ c.processBlock(buf, blockSize, out, outOff);
+ }
+ else
+ {
+ cipher.processBlock(buf, blockSize, out, outOff);
+ }
+
+ System.arraycopy(block, 0, out, outOff + blockSize, len);
+ }
+ else
+ {
+ byte[] lastBlock = new byte[blockSize];
+
+ if (cipher instanceof CBCBlockCipher)
+ {
+ BlockCipher c = ((CBCBlockCipher)cipher).getUnderlyingCipher();
+
+ c.processBlock(buf, 0, block, 0);
+ }
+ else
+ {
+ cipher.processBlock(buf, 0, block, 0);
+ }
+
+ for (int i = blockSize; i != bufOff; i++)
+ {
+ lastBlock[i - blockSize] = (byte)(block[i - blockSize] ^ buf[i]);
+ }
+
+ System.arraycopy(buf, blockSize, block, 0, len);
+
+ cipher.processBlock(block, 0, out, outOff);
+ System.arraycopy(lastBlock, 0, out, outOff + blockSize, len);
+ }
+
+ int offset = bufOff;
+
+ reset();
+
+ return offset;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/modes/EAXBlockCipher.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/modes/EAXBlockCipher.java
new file mode 100644
index 0000000..1a1cd63
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/modes/EAXBlockCipher.java
@@ -0,0 +1,368 @@
+package org.bc.crypto.modes;
+
+import org.bc.crypto.BlockCipher;
+import org.bc.crypto.CipherParameters;
+import org.bc.crypto.DataLengthException;
+import org.bc.crypto.InvalidCipherTextException;
+import org.bc.crypto.Mac;
+import org.bc.crypto.macs.CMac;
+import org.bc.crypto.params.AEADParameters;
+import org.bc.crypto.params.ParametersWithIV;
+import org.bc.util.Arrays;
+
+/**
+ * A Two-Pass Authenticated-Encryption Scheme Optimized for Simplicity and
+ * Efficiency - by M. Bellare, P. Rogaway, D. Wagner.
+ *
+ * http://www.cs.ucdavis.edu/~rogaway/papers/eax.pdf
+ *
+ * EAX is an AEAD scheme based on CTR and OMAC1/CMAC, that uses a single block
+ * cipher to encrypt and authenticate data. It's on-line (the length of a
+ * message isn't needed to begin processing it), has good performances, it's
+ * simple and provably secure (provided the underlying block cipher is secure).
+ *
+ * Of course, this implementations is NOT thread-safe.
+ */
+public class EAXBlockCipher
+ implements AEADBlockCipher
+{
+ private static final byte nTAG = 0x0;
+
+ private static final byte hTAG = 0x1;
+
+ private static final byte cTAG = 0x2;
+
+ private SICBlockCipher cipher;
+
+ private boolean forEncryption;
+
+ private int blockSize;
+
+ private Mac mac;
+
+ private byte[] nonceMac;
+ private byte[] associatedTextMac;
+ private byte[] macBlock;
+
+ private int macSize;
+ private byte[] bufBlock;
+ private int bufOff;
+
+ private boolean cipherInitialized;
+ private byte[] initialAssociatedText;
+
+ /**
+ * Constructor that accepts an instance of a block cipher engine.
+ *
+ * @param cipher the engine to use
+ */
+ public EAXBlockCipher(BlockCipher cipher)
+ {
+ blockSize = cipher.getBlockSize();
+ mac = new CMac(cipher);
+ macBlock = new byte[blockSize];
+ bufBlock = new byte[blockSize * 2];
+ associatedTextMac = new byte[mac.getMacSize()];
+ nonceMac = new byte[mac.getMacSize()];
+ this.cipher = new SICBlockCipher(cipher);
+ }
+
+ public String getAlgorithmName()
+ {
+ return cipher.getUnderlyingCipher().getAlgorithmName() + "/EAX";
+ }
+
+ public BlockCipher getUnderlyingCipher()
+ {
+ return cipher.getUnderlyingCipher();
+ }
+
+ public int getBlockSize()
+ {
+ return cipher.getBlockSize();
+ }
+
+ public void init(boolean forEncryption, CipherParameters params)
+ throws IllegalArgumentException
+ {
+ this.forEncryption = forEncryption;
+
+ byte[] nonce;
+ CipherParameters keyParam;
+
+ if (params instanceof AEADParameters)
+ {
+ AEADParameters param = (AEADParameters)params;
+
+ nonce = param.getNonce();
+ initialAssociatedText = param.getAssociatedText();
+ macSize = param.getMacSize() / 8;
+ keyParam = param.getKey();
+ }
+ else if (params instanceof ParametersWithIV)
+ {
+ ParametersWithIV param = (ParametersWithIV)params;
+
+ nonce = param.getIV();
+ initialAssociatedText = null;
+ macSize = mac.getMacSize() / 2;
+ keyParam = param.getParameters();
+ }
+ else
+ {
+ throw new IllegalArgumentException("invalid parameters passed to EAX");
+ }
+
+ byte[] tag = new byte[blockSize];
+
+ // Key reuse implemented in CBC mode of underlying CMac
+ mac.init(keyParam);
+
+ tag[blockSize - 1] = nTAG;
+ mac.update(tag, 0, blockSize);
+ mac.update(nonce, 0, nonce.length);
+ mac.doFinal(nonceMac, 0);
+
+ tag[blockSize - 1] = hTAG;
+ mac.update(tag, 0, blockSize);
+
+ if (initialAssociatedText != null)
+ {
+ processAADBytes(initialAssociatedText, 0, initialAssociatedText.length);
+ }
+
+ // Same BlockCipher underlies this and the mac, so reuse last key on cipher
+ cipher.init(true, new ParametersWithIV(null, nonceMac));
+ }
+
+ private void initCipher()
+ {
+ if (cipherInitialized)
+ {
+ return;
+ }
+
+ cipherInitialized = true;
+
+ mac.doFinal(associatedTextMac, 0);
+
+ byte[] tag = new byte[blockSize];
+ tag[blockSize - 1] = cTAG;
+ mac.update(tag, 0, blockSize);
+ }
+
+ private void calculateMac()
+ {
+ byte[] outC = new byte[blockSize];
+ mac.doFinal(outC, 0);
+
+ for (int i = 0; i < macBlock.length; i++)
+ {
+ macBlock[i] = (byte)(nonceMac[i] ^ associatedTextMac[i] ^ outC[i]);
+ }
+ }
+
+ public void reset()
+ {
+ reset(true);
+ }
+
+ private void reset(
+ boolean clearMac)
+ {
+ cipher.reset(); // TODO Redundant since the mac will reset it?
+ mac.reset();
+
+ bufOff = 0;
+ Arrays.fill(bufBlock, (byte)0);
+
+ if (clearMac)
+ {
+ Arrays.fill(macBlock, (byte)0);
+ }
+
+ byte[] tag = new byte[blockSize];
+ tag[blockSize - 1] = hTAG;
+ mac.update(tag, 0, blockSize);
+
+ cipherInitialized = false;
+
+ if (initialAssociatedText != null)
+ {
+ processAADBytes(initialAssociatedText, 0, initialAssociatedText.length);
+ }
+ }
+
+ public void processAADByte(byte in)
+ {
+ if (cipherInitialized)
+ {
+ throw new IllegalStateException("AAD data cannot be added after encryption/decription processing has begun.");
+ }
+ mac.update(in);
+ }
+
+ public void processAADBytes(byte[] in, int inOff, int len)
+ {
+ if (cipherInitialized)
+ {
+ throw new IllegalStateException("AAD data cannot be added after encryption/decription processing has begun.");
+ }
+ mac.update(in, inOff, len);
+ }
+
+ public int processByte(byte in, byte[] out, int outOff)
+ throws DataLengthException
+ {
+ initCipher();
+
+ return process(in, out, outOff);
+ }
+
+ public int processBytes(byte[] in, int inOff, int len, byte[] out, int outOff)
+ throws DataLengthException
+ {
+ initCipher();
+
+ int resultLen = 0;
+
+ for (int i = 0; i != len; i++)
+ {
+ resultLen += process(in[inOff + i], out, outOff + resultLen);
+ }
+
+ return resultLen;
+ }
+
+ public int doFinal(byte[] out, int outOff)
+ throws IllegalStateException, InvalidCipherTextException
+ {
+ initCipher();
+
+ int extra = bufOff;
+ byte[] tmp = new byte[bufBlock.length];
+
+ bufOff = 0;
+
+ if (forEncryption)
+ {
+ cipher.processBlock(bufBlock, 0, tmp, 0);
+ cipher.processBlock(bufBlock, blockSize, tmp, blockSize);
+
+ System.arraycopy(tmp, 0, out, outOff, extra);
+
+ mac.update(tmp, 0, extra);
+
+ calculateMac();
+
+ System.arraycopy(macBlock, 0, out, outOff + extra, macSize);
+
+ reset(false);
+
+ return extra + macSize;
+ }
+ else
+ {
+ if (extra > macSize)
+ {
+ mac.update(bufBlock, 0, extra - macSize);
+
+ cipher.processBlock(bufBlock, 0, tmp, 0);
+ cipher.processBlock(bufBlock, blockSize, tmp, blockSize);
+
+ System.arraycopy(tmp, 0, out, outOff, extra - macSize);
+ }
+
+ calculateMac();
+
+ if (!verifyMac(bufBlock, extra - macSize))
+ {
+ throw new InvalidCipherTextException("mac check in EAX failed");
+ }
+
+ reset(false);
+
+ return extra - macSize;
+ }
+ }
+
+ public byte[] getMac()
+ {
+ byte[] mac = new byte[macSize];
+
+ System.arraycopy(macBlock, 0, mac, 0, macSize);
+
+ return mac;
+ }
+
+ public int getUpdateOutputSize(int len)
+ {
+ int totalData = len + bufOff;
+ if (!forEncryption)
+ {
+ if (totalData < macSize)
+ {
+ return 0;
+ }
+ totalData -= macSize;
+ }
+ return totalData - totalData % blockSize;
+ }
+
+ public int getOutputSize(int len)
+ {
+ int totalData = len + bufOff;
+
+ if (forEncryption)
+ {
+ return totalData + macSize;
+ }
+
+ return totalData < macSize ? 0 : totalData - macSize;
+ }
+
+ private int process(byte b, byte[] out, int outOff)
+ {
+ bufBlock[bufOff++] = b;
+
+ if (bufOff == bufBlock.length)
+ {
+ // TODO Could move the processByte(s) calls to here
+// initCipher();
+
+ int size;
+
+ if (forEncryption)
+ {
+ size = cipher.processBlock(bufBlock, 0, out, outOff);
+
+ mac.update(out, outOff, blockSize);
+ }
+ else
+ {
+ mac.update(bufBlock, 0, blockSize);
+
+ size = cipher.processBlock(bufBlock, 0, out, outOff);
+ }
+
+ bufOff = blockSize;
+ System.arraycopy(bufBlock, blockSize, bufBlock, 0, blockSize);
+
+ return size;
+ }
+
+ return 0;
+ }
+
+ private boolean verifyMac(byte[] mac, int off)
+ {
+ int nonEqual = 0;
+
+ for (int i = 0; i < macSize; i++)
+ {
+ nonEqual |= (macBlock[i] ^ mac[off + i]);
+ }
+
+ return nonEqual == 0;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/modes/GCMBlockCipher.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/modes/GCMBlockCipher.java
new file mode 100644
index 0000000..c868d51
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/modes/GCMBlockCipher.java
@@ -0,0 +1,574 @@
+package org.bc.crypto.modes;
+
+import org.bc.crypto.BlockCipher;
+import org.bc.crypto.CipherParameters;
+import org.bc.crypto.DataLengthException;
+import org.bc.crypto.InvalidCipherTextException;
+import org.bc.crypto.modes.gcm.GCMExponentiator;
+import org.bc.crypto.modes.gcm.GCMMultiplier;
+import org.bc.crypto.modes.gcm.Tables1kGCMExponentiator;
+import org.bc.crypto.modes.gcm.Tables8kGCMMultiplier;
+import org.bc.crypto.params.AEADParameters;
+import org.bc.crypto.params.KeyParameter;
+import org.bc.crypto.params.ParametersWithIV;
+import org.bc.crypto.util.Pack;
+import org.bc.util.Arrays;
+
+/**
+ * Implements the Galois/Counter mode (GCM) detailed in
+ * NIST Special Publication 800-38D.
+ */
+public class GCMBlockCipher
+ implements AEADBlockCipher
+{
+ private static final int BLOCK_SIZE = 16;
+
+ // not final due to a compiler bug
+ private BlockCipher cipher;
+ private GCMMultiplier multiplier;
+ private GCMExponentiator exp;
+
+ // These fields are set by init and not modified by processing
+ private boolean forEncryption;
+ private int macSize;
+ private byte[] nonce;
+ private byte[] initialAssociatedText;
+ private byte[] H;
+ private byte[] J0;
+
+ // These fields are modified during processing
+ private byte[] bufBlock;
+ private byte[] macBlock;
+ private byte[] S, S_at, S_atPre;
+ private byte[] counter;
+ private int bufOff;
+ private long totalLength;
+ private byte[] atBlock;
+ private int atBlockPos;
+ private long atLength;
+ private long atLengthPre;
+
+ public GCMBlockCipher(BlockCipher c)
+ {
+ this(c, null);
+ }
+
+ public GCMBlockCipher(BlockCipher c, GCMMultiplier m)
+ {
+ if (c.getBlockSize() != BLOCK_SIZE)
+ {
+ throw new IllegalArgumentException(
+ "cipher required with a block size of " + BLOCK_SIZE + ".");
+ }
+
+ if (m == null)
+ {
+ // TODO Consider a static property specifying default multiplier
+ m = new Tables8kGCMMultiplier();
+ }
+
+ this.cipher = c;
+ this.multiplier = m;
+ }
+
+ public BlockCipher getUnderlyingCipher()
+ {
+ return cipher;
+ }
+
+ public String getAlgorithmName()
+ {
+ return cipher.getAlgorithmName() + "/GCM";
+ }
+
+ public void init(boolean forEncryption, CipherParameters params)
+ throws IllegalArgumentException
+ {
+ this.forEncryption = forEncryption;
+ this.macBlock = null;
+
+ KeyParameter keyParam;
+
+ if (params instanceof AEADParameters)
+ {
+ AEADParameters param = (AEADParameters)params;
+
+ nonce = param.getNonce();
+ initialAssociatedText = param.getAssociatedText();
+
+ int macSizeBits = param.getMacSize();
+ if (macSizeBits < 96 || macSizeBits > 128 || macSizeBits % 8 != 0)
+ {
+ throw new IllegalArgumentException("Invalid value for MAC size: " + macSizeBits);
+ }
+
+ macSize = macSizeBits / 8;
+ keyParam = param.getKey();
+ }
+ else if (params instanceof ParametersWithIV)
+ {
+ ParametersWithIV param = (ParametersWithIV)params;
+
+ nonce = param.getIV();
+ initialAssociatedText = null;
+ macSize = 16;
+ keyParam = (KeyParameter)param.getParameters();
+ }
+ else
+ {
+ throw new IllegalArgumentException("invalid parameters passed to GCM");
+ }
+
+ int bufLength = forEncryption ? BLOCK_SIZE : (BLOCK_SIZE + macSize);
+ this.bufBlock = new byte[bufLength];
+
+ if (nonce == null || nonce.length < 1)
+ {
+ throw new IllegalArgumentException("IV must be at least 1 byte");
+ }
+
+ // TODO This should be configurable by init parameters
+ // (but must be 16 if nonce length not 12) (BLOCK_SIZE?)
+// this.tagLength = 16;
+
+ // Cipher always used in forward mode
+ // if keyParam is null we're reusing the last key.
+ if (keyParam != null)
+ {
+ cipher.init(true, keyParam);
+
+ this.H = new byte[BLOCK_SIZE];
+ cipher.processBlock(H, 0, H, 0);
+
+ // GCMMultiplier tables don't change unless the key changes (and are expensive to init)
+ multiplier.init(H);
+ exp = null;
+ }
+
+ this.J0 = new byte[BLOCK_SIZE];
+
+ if (nonce.length == 12)
+ {
+ System.arraycopy(nonce, 0, J0, 0, nonce.length);
+ this.J0[BLOCK_SIZE - 1] = 0x01;
+ }
+ else
+ {
+ gHASH(J0, nonce, nonce.length);
+ byte[] X = new byte[BLOCK_SIZE];
+ Pack.longToBigEndian((long)nonce.length * 8, X, 8);
+ gHASHBlock(J0, X);
+ }
+
+ this.S = new byte[BLOCK_SIZE];
+ this.S_at = new byte[BLOCK_SIZE];
+ this.S_atPre = new byte[BLOCK_SIZE];
+ this.atBlock = new byte[BLOCK_SIZE];
+ this.atBlockPos = 0;
+ this.atLength = 0;
+ this.atLengthPre = 0;
+ this.counter = Arrays.clone(J0);
+ this.bufOff = 0;
+ this.totalLength = 0;
+
+ if (initialAssociatedText != null)
+ {
+ processAADBytes(initialAssociatedText, 0, initialAssociatedText.length);
+ }
+ }
+
+ public byte[] getMac()
+ {
+ return Arrays.clone(macBlock);
+ }
+
+ public int getOutputSize(int len)
+ {
+ int totalData = len + bufOff;
+
+ if (forEncryption)
+ {
+ return totalData + macSize;
+ }
+
+ return totalData < macSize ? 0 : totalData - macSize;
+ }
+
+ public int getUpdateOutputSize(int len)
+ {
+ int totalData = len + bufOff;
+ if (!forEncryption)
+ {
+ if (totalData < macSize)
+ {
+ return 0;
+ }
+ totalData -= macSize;
+ }
+ return totalData - totalData % BLOCK_SIZE;
+ }
+
+ public void processAADByte(byte in)
+ {
+ atBlock[atBlockPos] = in;
+ if (++atBlockPos == BLOCK_SIZE)
+ {
+ // Hash each block as it fills
+ gHASHBlock(S_at, atBlock);
+ atBlockPos = 0;
+ atLength += BLOCK_SIZE;
+ }
+ }
+
+ public void processAADBytes(byte[] in, int inOff, int len)
+ {
+ for (int i = 0; i < len; ++i)
+ {
+ atBlock[atBlockPos] = in[inOff + i];
+ if (++atBlockPos == BLOCK_SIZE)
+ {
+ // Hash each block as it fills
+ gHASHBlock(S_at, atBlock);
+ atBlockPos = 0;
+ atLength += BLOCK_SIZE;
+ }
+ }
+ }
+
+ private void initCipher()
+ {
+ if (atLength > 0)
+ {
+ System.arraycopy(S_at, 0, S_atPre, 0, BLOCK_SIZE);
+ atLengthPre = atLength;
+ }
+
+ // Finish hash for partial AAD block
+ if (atBlockPos > 0)
+ {
+ gHASHPartial(S_atPre, atBlock, 0, atBlockPos);
+ atLengthPre += atBlockPos;
+ }
+
+ if (atLengthPre > 0)
+ {
+ System.arraycopy(S_atPre, 0, S, 0, BLOCK_SIZE);
+ }
+ }
+
+ public int processByte(byte in, byte[] out, int outOff)
+ throws DataLengthException
+ {
+ bufBlock[bufOff] = in;
+ if (++bufOff == bufBlock.length)
+ {
+ outputBlock(out, outOff);
+ return BLOCK_SIZE;
+ }
+ return 0;
+ }
+
+ public int processBytes(byte[] in, int inOff, int len, byte[] out, int outOff)
+ throws DataLengthException
+ {
+ int resultLen = 0;
+
+ for (int i = 0; i < len; ++i)
+ {
+ bufBlock[bufOff] = in[inOff + i];
+ if (++bufOff == bufBlock.length)
+ {
+ outputBlock(out, outOff + resultLen);
+ resultLen += BLOCK_SIZE;
+ }
+ }
+
+ return resultLen;
+ }
+
+ private void outputBlock(byte[] output, int offset)
+ {
+ if (totalLength == 0)
+ {
+ initCipher();
+ }
+ gCTRBlock(bufBlock, output, offset);
+ if (forEncryption)
+ {
+ bufOff = 0;
+ }
+ else
+ {
+ System.arraycopy(bufBlock, BLOCK_SIZE, bufBlock, 0, macSize);
+ bufOff = macSize;
+ }
+ }
+
+ public int doFinal(byte[] out, int outOff)
+ throws IllegalStateException, InvalidCipherTextException
+ {
+ if (totalLength == 0)
+ {
+ initCipher();
+ }
+
+ int extra = bufOff;
+ if (!forEncryption)
+ {
+ if (extra < macSize)
+ {
+ throw new InvalidCipherTextException("data too short");
+ }
+ extra -= macSize;
+ }
+
+ if (extra > 0)
+ {
+ gCTRPartial(bufBlock, 0, extra, out, outOff);
+ }
+
+ atLength += atBlockPos;
+
+ if (atLength > atLengthPre)
+ {
+ /*
+ * Some AAD was sent after the cipher started. We determine the difference b/w the hash value
+ * we actually used when the cipher started (S_atPre) and the final hash value calculated (S_at).
+ * Then we carry this difference forward by multiplying by H^c, where c is the number of (full or
+ * partial) cipher-text blocks produced, and adjust the current hash.
+ */
+
+ // Finish hash for partial AAD block
+ if (atBlockPos > 0)
+ {
+ gHASHPartial(S_at, atBlock, 0, atBlockPos);
+ }
+
+ // Find the difference between the AAD hashes
+ if (atLengthPre > 0)
+ {
+ xor(S_at, S_atPre);
+ }
+
+ // Number of cipher-text blocks produced
+ long c = ((totalLength * 8) + 127) >>> 7;
+
+ // Calculate the adjustment factor
+ byte[] H_c = new byte[16];
+ if (exp == null)
+ {
+ exp = new Tables1kGCMExponentiator();
+ exp.init(H);
+ }
+ exp.exponentiateX(c, H_c);
+
+ // Carry the difference forward
+ multiply(S_at, H_c);
+
+ // Adjust the current hash
+ xor(S, S_at);
+ }
+
+ // Final gHASH
+ byte[] X = new byte[BLOCK_SIZE];
+ Pack.longToBigEndian(atLength * 8, X, 0);
+ Pack.longToBigEndian(totalLength * 8, X, 8);
+
+ gHASHBlock(S, X);
+
+ // TODO Fix this if tagLength becomes configurable
+ // T = MSBt(GCTRk(J0,S))
+ byte[] tag = new byte[BLOCK_SIZE];
+ cipher.processBlock(J0, 0, tag, 0);
+ xor(tag, S);
+
+ int resultLen = extra;
+
+ // We place into macBlock our calculated value for T
+ this.macBlock = new byte[macSize];
+ System.arraycopy(tag, 0, macBlock, 0, macSize);
+
+ if (forEncryption)
+ {
+ // Append T to the message
+ System.arraycopy(macBlock, 0, out, outOff + bufOff, macSize);
+ resultLen += macSize;
+ }
+ else
+ {
+ // Retrieve the T value from the message and compare to calculated one
+ byte[] msgMac = new byte[macSize];
+ System.arraycopy(bufBlock, extra, msgMac, 0, macSize);
+ if (!Arrays.constantTimeAreEqual(this.macBlock, msgMac))
+ {
+ throw new InvalidCipherTextException("mac check in GCM failed");
+ }
+ }
+
+ reset(false);
+
+ return resultLen;
+ }
+
+ public void reset()
+ {
+ reset(true);
+ }
+
+ private void reset(
+ boolean clearMac)
+ {
+ cipher.reset();
+
+ S = new byte[BLOCK_SIZE];
+ S_at = new byte[BLOCK_SIZE];
+ S_atPre = new byte[BLOCK_SIZE];
+ atBlock = new byte[BLOCK_SIZE];
+ atBlockPos = 0;
+ atLength = 0;
+ atLengthPre = 0;
+ counter = Arrays.clone(J0);
+ bufOff = 0;
+ totalLength = 0;
+
+ if (bufBlock != null)
+ {
+ Arrays.fill(bufBlock, (byte)0);
+ }
+
+ if (clearMac)
+ {
+ macBlock = null;
+ }
+
+ if (initialAssociatedText != null)
+ {
+ processAADBytes(initialAssociatedText, 0, initialAssociatedText.length);
+ }
+ }
+
+ private void gCTRBlock(byte[] block, byte[] out, int outOff)
+ {
+ byte[] tmp = getNextCounterBlock();
+
+ xor(tmp, block);
+ System.arraycopy(tmp, 0, out, outOff, BLOCK_SIZE);
+
+ gHASHBlock(S, forEncryption ? tmp : block);
+
+ totalLength += BLOCK_SIZE;
+ }
+
+ private void gCTRPartial(byte[] buf, int off, int len, byte[] out, int outOff)
+ {
+ byte[] tmp = getNextCounterBlock();
+
+ xor(tmp, buf, off, len);
+ System.arraycopy(tmp, 0, out, outOff, len);
+
+ gHASHPartial(S, forEncryption ? tmp : buf, 0, len);
+
+ totalLength += len;
+ }
+
+ private void gHASH(byte[] Y, byte[] b, int len)
+ {
+ for (int pos = 0; pos < len; pos += BLOCK_SIZE)
+ {
+ int num = Math.min(len - pos, BLOCK_SIZE);
+ gHASHPartial(Y, b, pos, num);
+ }
+ }
+
+ private void gHASHBlock(byte[] Y, byte[] b)
+ {
+ xor(Y, b);
+ multiplier.multiplyH(Y);
+ }
+
+ private void gHASHPartial(byte[] Y, byte[] b, int off, int len)
+ {
+ xor(Y, b, off, len);
+ multiplier.multiplyH(Y);
+ }
+
+ private byte[] getNextCounterBlock()
+ {
+ for (int i = 15; i >= 12; --i)
+ {
+ byte b = (byte)((counter[i] + 1) & 0xff);
+ counter[i] = b;
+
+ if (b != 0)
+ {
+ break;
+ }
+ }
+
+ byte[] tmp = new byte[BLOCK_SIZE];
+ // TODO Sure would be nice if ciphers could operate on int[]
+ cipher.processBlock(counter, 0, tmp, 0);
+ return tmp;
+ }
+
+ private static void multiply(byte[] block, byte[] val)
+ {
+ byte[] tmp = Arrays.clone(block);
+ byte[] c = new byte[16];
+
+ for (int i = 0; i < 16; ++i)
+ {
+ byte bits = val[i];
+ for (int j = 7; j >= 0; --j)
+ {
+ if ((bits & (1 << j)) != 0)
+ {
+ xor(c, tmp);
+ }
+
+ boolean lsb = (tmp[15] & 1) != 0;
+ shiftRight(tmp);
+ if (lsb)
+ {
+ // R = new byte[]{ 0xe1, ... };
+// xor(v, R);
+ tmp[0] ^= (byte)0xe1;
+ }
+ }
+ }
+
+ System.arraycopy(c, 0, block, 0, 16);
+ }
+
+ private static void shiftRight(byte[] block)
+ {
+ int i = 0;
+ int bit = 0;
+ for (;;)
+ {
+ int b = block[i] & 0xff;
+ block[i] = (byte) ((b >>> 1) | bit);
+ if (++i == 16)
+ {
+ break;
+ }
+ bit = (b & 1) << 7;
+ }
+ }
+
+ private static void xor(byte[] block, byte[] val)
+ {
+ for (int i = 15; i >= 0; --i)
+ {
+ block[i] ^= val[i];
+ }
+ }
+
+ private static void xor(byte[] block, byte[] val, int off, int len)
+ {
+ while (len-- > 0)
+ {
+ block[len] ^= val[off + len];
+ }
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/modes/GOFBBlockCipher.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/modes/GOFBBlockCipher.java
new file mode 100644
index 0000000..a7d84e1
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/modes/GOFBBlockCipher.java
@@ -0,0 +1,234 @@
+package org.bc.crypto.modes;
+
+import org.bc.crypto.BlockCipher;
+import org.bc.crypto.CipherParameters;
+import org.bc.crypto.DataLengthException;
+import org.bc.crypto.params.ParametersWithIV;
+
+/**
+ * implements the GOST 28147 OFB counter mode (GCTR).
+ */
+public class GOFBBlockCipher
+ implements BlockCipher
+{
+ private byte[] IV;
+ private byte[] ofbV;
+ private byte[] ofbOutV;
+
+ private final int blockSize;
+ private final BlockCipher cipher;
+
+ boolean firstStep = true;
+ int N3;
+ int N4;
+ static final int C1 = 16843012; //00000001000000010000000100000100
+ static final int C2 = 16843009; //00000001000000010000000100000001
+
+
+ /**
+ * Basic constructor.
+ *
+ * @param cipher the block cipher to be used as the basis of the
+ * counter mode (must have a 64 bit block size).
+ */
+ public GOFBBlockCipher(
+ BlockCipher cipher)
+ {
+ this.cipher = cipher;
+ this.blockSize = cipher.getBlockSize();
+
+ if (blockSize != 8)
+ {
+ throw new IllegalArgumentException("GCTR only for 64 bit block ciphers");
+ }
+
+ this.IV = new byte[cipher.getBlockSize()];
+ this.ofbV = new byte[cipher.getBlockSize()];
+ this.ofbOutV = new byte[cipher.getBlockSize()];
+ }
+
+ /**
+ * return the underlying block cipher that we are wrapping.
+ *
+ * @return the underlying block cipher that we are wrapping.
+ */
+ public BlockCipher getUnderlyingCipher()
+ {
+ return cipher;
+ }
+
+ /**
+ * Initialise the cipher and, possibly, the initialisation vector (IV).
+ * If an IV isn't passed as part of the parameter, the IV will be all zeros.
+ * An IV which is too short is handled in FIPS compliant fashion.
+ *
+ * @param encrypting if true the cipher is initialised for
+ * encryption, if false for decryption.
+ * @param params the key and other data required by the cipher.
+ * @exception IllegalArgumentException if the params argument is
+ * inappropriate.
+ */
+ public void init(
+ boolean encrypting, //ignored by this CTR mode
+ CipherParameters params)
+ throws IllegalArgumentException
+ {
+ firstStep = true;
+ N3 = 0;
+ N4 = 0;
+
+ if (params instanceof ParametersWithIV)
+ {
+ ParametersWithIV ivParam = (ParametersWithIV)params;
+ byte[] iv = ivParam.getIV();
+
+ if (iv.length < IV.length)
+ {
+ // prepend the supplied IV with zeros (per FIPS PUB 81)
+ System.arraycopy(iv, 0, IV, IV.length - iv.length, iv.length);
+ for (int i = 0; i < IV.length - iv.length; i++)
+ {
+ IV[i] = 0;
+ }
+ }
+ else
+ {
+ System.arraycopy(iv, 0, IV, 0, IV.length);
+ }
+
+ reset();
+
+ // if params is null we reuse the current working key.
+ if (ivParam.getParameters() != null)
+ {
+ cipher.init(true, ivParam.getParameters());
+ }
+ }
+ else
+ {
+ reset();
+
+ // if params is null we reuse the current working key.
+ if (params != null)
+ {
+ cipher.init(true, params);
+ }
+ }
+ }
+
+ /**
+ * return the algorithm name and mode.
+ *
+ * @return the name of the underlying algorithm followed by "/GCTR"
+ * and the block size in bits
+ */
+ public String getAlgorithmName()
+ {
+ return cipher.getAlgorithmName() + "/GCTR";
+ }
+
+
+ /**
+ * return the block size we are operating at (in bytes).
+ *
+ * @return the block size we are operating at (in bytes).
+ */
+ public int getBlockSize()
+ {
+ return blockSize;
+ }
+
+ /**
+ * Process one block of input from the array in and write it to
+ * the out array.
+ *
+ * @param in the array containing the input data.
+ * @param inOff offset into the in array the data starts at.
+ * @param out the array the output data will be copied into.
+ * @param outOff the offset into the out array the output will start at.
+ * @exception DataLengthException if there isn't enough data in in, or
+ * space in out.
+ * @exception IllegalStateException if the cipher isn't initialised.
+ * @return the number of bytes processed and produced.
+ */
+ public int processBlock(
+ byte[] in,
+ int inOff,
+ byte[] out,
+ int outOff)
+ throws DataLengthException, IllegalStateException
+ {
+ if ((inOff + blockSize) > in.length)
+ {
+ throw new DataLengthException("input buffer too short");
+ }
+
+ if ((outOff + blockSize) > out.length)
+ {
+ throw new DataLengthException("output buffer too short");
+ }
+
+ if (firstStep)
+ {
+ firstStep = false;
+ cipher.processBlock(ofbV, 0, ofbOutV, 0);
+ N3 = bytesToint(ofbOutV, 0);
+ N4 = bytesToint(ofbOutV, 4);
+ }
+ N3 += C2;
+ N4 += C1;
+ intTobytes(N3, ofbV, 0);
+ intTobytes(N4, ofbV, 4);
+
+ cipher.processBlock(ofbV, 0, ofbOutV, 0);
+
+ //
+ // XOR the ofbV with the plaintext producing the cipher text (and
+ // the next input block).
+ //
+ for (int i = 0; i < blockSize; i++)
+ {
+ out[outOff + i] = (byte)(ofbOutV[i] ^ in[inOff + i]);
+ }
+
+ //
+ // change over the input block.
+ //
+ System.arraycopy(ofbV, blockSize, ofbV, 0, ofbV.length - blockSize);
+ System.arraycopy(ofbOutV, 0, ofbV, ofbV.length - blockSize, blockSize);
+
+ return blockSize;
+ }
+
+ /**
+ * reset the feedback vector back to the IV and reset the underlying
+ * cipher.
+ */
+ public void reset()
+ {
+ System.arraycopy(IV, 0, ofbV, 0, IV.length);
+
+ cipher.reset();
+ }
+
+ //array of bytes to type int
+ private int bytesToint(
+ byte[] in,
+ int inOff)
+ {
+ return ((in[inOff + 3] << 24) & 0xff000000) + ((in[inOff + 2] << 16) & 0xff0000) +
+ ((in[inOff + 1] << 8) & 0xff00) + (in[inOff] & 0xff);
+ }
+
+ //int to array of bytes
+ private void intTobytes(
+ int num,
+ byte[] out,
+ int outOff)
+ {
+ out[outOff + 3] = (byte)(num >>> 24);
+ out[outOff + 2] = (byte)(num >>> 16);
+ out[outOff + 1] = (byte)(num >>> 8);
+ out[outOff] = (byte)num;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/modes/OFBBlockCipher.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/modes/OFBBlockCipher.java
new file mode 100644
index 0000000..20970ee
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/modes/OFBBlockCipher.java
@@ -0,0 +1,187 @@
+package org.bc.crypto.modes;
+
+import org.bc.crypto.BlockCipher;
+import org.bc.crypto.CipherParameters;
+import org.bc.crypto.DataLengthException;
+import org.bc.crypto.params.ParametersWithIV;
+
+/**
+ * implements a Output-FeedBack (OFB) mode on top of a simple cipher.
+ */
+public class OFBBlockCipher
+ implements BlockCipher
+{
+ private byte[] IV;
+ private byte[] ofbV;
+ private byte[] ofbOutV;
+
+ private final int blockSize;
+ private final BlockCipher cipher;
+
+ /**
+ * Basic constructor.
+ *
+ * @param cipher the block cipher to be used as the basis of the
+ * feedback mode.
+ * @param blockSize the block size in bits (note: a multiple of 8)
+ */
+ public OFBBlockCipher(
+ BlockCipher cipher,
+ int blockSize)
+ {
+ this.cipher = cipher;
+ this.blockSize = blockSize / 8;
+
+ this.IV = new byte[cipher.getBlockSize()];
+ this.ofbV = new byte[cipher.getBlockSize()];
+ this.ofbOutV = new byte[cipher.getBlockSize()];
+ }
+
+ /**
+ * return the underlying block cipher that we are wrapping.
+ *
+ * @return the underlying block cipher that we are wrapping.
+ */
+ public BlockCipher getUnderlyingCipher()
+ {
+ return cipher;
+ }
+
+ /**
+ * Initialise the cipher and, possibly, the initialisation vector (IV).
+ * If an IV isn't passed as part of the parameter, the IV will be all zeros.
+ * An IV which is too short is handled in FIPS compliant fashion.
+ *
+ * @param encrypting if true the cipher is initialised for
+ * encryption, if false for decryption.
+ * @param params the key and other data required by the cipher.
+ * @exception IllegalArgumentException if the params argument is
+ * inappropriate.
+ */
+ public void init(
+ boolean encrypting, //ignored by this OFB mode
+ CipherParameters params)
+ throws IllegalArgumentException
+ {
+ if (params instanceof ParametersWithIV)
+ {
+ ParametersWithIV ivParam = (ParametersWithIV)params;
+ byte[] iv = ivParam.getIV();
+
+ if (iv.length < IV.length)
+ {
+ // prepend the supplied IV with zeros (per FIPS PUB 81)
+ System.arraycopy(iv, 0, IV, IV.length - iv.length, iv.length);
+ for (int i = 0; i < IV.length - iv.length; i++)
+ {
+ IV[i] = 0;
+ }
+ }
+ else
+ {
+ System.arraycopy(iv, 0, IV, 0, IV.length);
+ }
+
+ reset();
+
+ // if null it's an IV changed only.
+ if (ivParam.getParameters() != null)
+ {
+ cipher.init(true, ivParam.getParameters());
+ }
+ }
+ else
+ {
+ reset();
+
+ // if it's null, key is to be reused.
+ if (params != null)
+ {
+ cipher.init(true, params);
+ }
+ }
+ }
+
+ /**
+ * return the algorithm name and mode.
+ *
+ * @return the name of the underlying algorithm followed by "/OFB"
+ * and the block size in bits
+ */
+ public String getAlgorithmName()
+ {
+ return cipher.getAlgorithmName() + "/OFB" + (blockSize * 8);
+ }
+
+
+ /**
+ * return the block size we are operating at (in bytes).
+ *
+ * @return the block size we are operating at (in bytes).
+ */
+ public int getBlockSize()
+ {
+ return blockSize;
+ }
+
+ /**
+ * Process one block of input from the array in and write it to
+ * the out array.
+ *
+ * @param in the array containing the input data.
+ * @param inOff offset into the in array the data starts at.
+ * @param out the array the output data will be copied into.
+ * @param outOff the offset into the out array the output will start at.
+ * @exception DataLengthException if there isn't enough data in in, or
+ * space in out.
+ * @exception IllegalStateException if the cipher isn't initialised.
+ * @return the number of bytes processed and produced.
+ */
+ public int processBlock(
+ byte[] in,
+ int inOff,
+ byte[] out,
+ int outOff)
+ throws DataLengthException, IllegalStateException
+ {
+ if ((inOff + blockSize) > in.length)
+ {
+ throw new DataLengthException("input buffer too short");
+ }
+
+ if ((outOff + blockSize) > out.length)
+ {
+ throw new DataLengthException("output buffer too short");
+ }
+
+ cipher.processBlock(ofbV, 0, ofbOutV, 0);
+
+ //
+ // XOR the ofbV with the plaintext producing the cipher text (and
+ // the next input block).
+ //
+ for (int i = 0; i < blockSize; i++)
+ {
+ out[outOff + i] = (byte)(ofbOutV[i] ^ in[inOff + i]);
+ }
+
+ //
+ // change over the input block.
+ //
+ System.arraycopy(ofbV, blockSize, ofbV, 0, ofbV.length - blockSize);
+ System.arraycopy(ofbOutV, 0, ofbV, ofbV.length - blockSize, blockSize);
+
+ return blockSize;
+ }
+
+ /**
+ * reset the feedback vector back to the IV and reset the underlying
+ * cipher.
+ */
+ public void reset()
+ {
+ System.arraycopy(IV, 0, ofbV, 0, IV.length);
+
+ cipher.reset();
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/modes/OpenPGPCFBBlockCipher.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/modes/OpenPGPCFBBlockCipher.java
new file mode 100644
index 0000000..e5b426e
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/modes/OpenPGPCFBBlockCipher.java
@@ -0,0 +1,312 @@
+package org.bc.crypto.modes;
+
+import org.bc.crypto.BlockCipher;
+import org.bc.crypto.CipherParameters;
+import org.bc.crypto.DataLengthException;
+
+/**
+ * Implements OpenPGP's rather strange version of Cipher-FeedBack (CFB) mode
+ * on top of a simple cipher. This class assumes the IV has been prepended
+ * to the data stream already, and just accomodates the reset after
+ * (blockSize + 2) bytes have been read.
+ *
+ * For further info see RFC 2440.
+ */
+public class OpenPGPCFBBlockCipher
+ implements BlockCipher
+{
+ private byte[] IV;
+ private byte[] FR;
+ private byte[] FRE;
+
+ private BlockCipher cipher;
+
+ private int count;
+ private int blockSize;
+ private boolean forEncryption;
+
+ /**
+ * Basic constructor.
+ *
+ * @param cipher the block cipher to be used as the basis of the
+ * feedback mode.
+ */
+ public OpenPGPCFBBlockCipher(
+ BlockCipher cipher)
+ {
+ this.cipher = cipher;
+
+ this.blockSize = cipher.getBlockSize();
+ this.IV = new byte[blockSize];
+ this.FR = new byte[blockSize];
+ this.FRE = new byte[blockSize];
+ }
+
+ /**
+ * return the underlying block cipher that we are wrapping.
+ *
+ * @return the underlying block cipher that we are wrapping.
+ */
+ public BlockCipher getUnderlyingCipher()
+ {
+ return cipher;
+ }
+
+ /**
+ * return the algorithm name and mode.
+ *
+ * @return the name of the underlying algorithm followed by "/PGPCFB"
+ * and the block size in bits.
+ */
+ public String getAlgorithmName()
+ {
+ return cipher.getAlgorithmName() + "/OpenPGPCFB";
+ }
+
+ /**
+ * return the block size we are operating at.
+ *
+ * @return the block size we are operating at (in bytes).
+ */
+ public int getBlockSize()
+ {
+ return cipher.getBlockSize();
+ }
+
+ /**
+ * Process one block of input from the array in and write it to
+ * the out array.
+ *
+ * @param in the array containing the input data.
+ * @param inOff offset into the in array the data starts at.
+ * @param out the array the output data will be copied into.
+ * @param outOff the offset into the out array the output will start at.
+ * @exception DataLengthException if there isn't enough data in in, or
+ * space in out.
+ * @exception IllegalStateException if the cipher isn't initialised.
+ * @return the number of bytes processed and produced.
+ */
+ public int processBlock(
+ byte[] in,
+ int inOff,
+ byte[] out,
+ int outOff)
+ throws DataLengthException, IllegalStateException
+ {
+ return (forEncryption) ? encryptBlock(in, inOff, out, outOff) : decryptBlock(in, inOff, out, outOff);
+ }
+
+ /**
+ * reset the chaining vector back to the IV and reset the underlying
+ * cipher.
+ */
+ public void reset()
+ {
+ count = 0;
+
+ System.arraycopy(IV, 0, FR, 0, FR.length);
+
+ cipher.reset();
+ }
+
+ /**
+ * Initialise the cipher and, possibly, the initialisation vector (IV).
+ * If an IV isn't passed as part of the parameter, the IV will be all zeros.
+ * An IV which is too short is handled in FIPS compliant fashion.
+ *
+ * @param forEncryption if true the cipher is initialised for
+ * encryption, if false for decryption.
+ * @param params the key and other data required by the cipher.
+ * @exception IllegalArgumentException if the params argument is
+ * inappropriate.
+ */
+ public void init(
+ boolean forEncryption,
+ CipherParameters params)
+ throws IllegalArgumentException
+ {
+ this.forEncryption = forEncryption;
+
+ reset();
+
+ cipher.init(true, params);
+ }
+
+ /**
+ * Encrypt one byte of data according to CFB mode.
+ * @param data the byte to encrypt
+ * @param blockOff offset in the current block
+ * @return the encrypted byte
+ */
+ private byte encryptByte(byte data, int blockOff)
+ {
+ return (byte)(FRE[blockOff] ^ data);
+ }
+
+ /**
+ * Do the appropriate processing for CFB IV mode encryption.
+ *
+ * @param in the array containing the data to be encrypted.
+ * @param inOff offset into the in array the data starts at.
+ * @param out the array the encrypted data will be copied into.
+ * @param outOff the offset into the out array the output will start at.
+ * @exception DataLengthException if there isn't enough data in in, or
+ * space in out.
+ * @exception IllegalStateException if the cipher isn't initialised.
+ * @return the number of bytes processed and produced.
+ */
+ private int encryptBlock(
+ byte[] in,
+ int inOff,
+ byte[] out,
+ int outOff)
+ throws DataLengthException, IllegalStateException
+ {
+ if ((inOff + blockSize) > in.length)
+ {
+ throw new DataLengthException("input buffer too short");
+ }
+
+ if ((outOff + blockSize) > out.length)
+ {
+ throw new DataLengthException("output buffer too short");
+ }
+
+ if (count > blockSize)
+ {
+ FR[blockSize - 2] = out[outOff] = encryptByte(in[inOff], blockSize - 2);
+ FR[blockSize - 1] = out[outOff + 1] = encryptByte(in[inOff + 1], blockSize - 1);
+
+ cipher.processBlock(FR, 0, FRE, 0);
+
+ for (int n = 2; n < blockSize; n++)
+ {
+ FR[n - 2] = out[outOff + n] = encryptByte(in[inOff + n], n - 2);
+ }
+ }
+ else if (count == 0)
+ {
+ cipher.processBlock(FR, 0, FRE, 0);
+
+ for (int n = 0; n < blockSize; n++)
+ {
+ FR[n] = out[outOff + n] = encryptByte(in[inOff + n], n);
+ }
+
+ count += blockSize;
+ }
+ else if (count == blockSize)
+ {
+ cipher.processBlock(FR, 0, FRE, 0);
+
+ out[outOff] = encryptByte(in[inOff], 0);
+ out[outOff + 1] = encryptByte(in[inOff + 1], 1);
+
+ //
+ // do reset
+ //
+ System.arraycopy(FR, 2, FR, 0, blockSize - 2);
+ System.arraycopy(out, outOff, FR, blockSize - 2, 2);
+
+ cipher.processBlock(FR, 0, FRE, 0);
+
+ for (int n = 2; n < blockSize; n++)
+ {
+ FR[n - 2] = out[outOff + n] = encryptByte(in[inOff + n], n - 2);
+ }
+
+ count += blockSize;
+ }
+
+ return blockSize;
+ }
+
+ /**
+ * Do the appropriate processing for CFB IV mode decryption.
+ *
+ * @param in the array containing the data to be decrypted.
+ * @param inOff offset into the in array the data starts at.
+ * @param out the array the encrypted data will be copied into.
+ * @param outOff the offset into the out array the output will start at.
+ * @exception DataLengthException if there isn't enough data in in, or
+ * space in out.
+ * @exception IllegalStateException if the cipher isn't initialised.
+ * @return the number of bytes processed and produced.
+ */
+ private int decryptBlock(
+ byte[] in,
+ int inOff,
+ byte[] out,
+ int outOff)
+ throws DataLengthException, IllegalStateException
+ {
+ if ((inOff + blockSize) > in.length)
+ {
+ throw new DataLengthException("input buffer too short");
+ }
+
+ if ((outOff + blockSize) > out.length)
+ {
+ throw new DataLengthException("output buffer too short");
+ }
+
+ if (count > blockSize)
+ {
+ byte inVal = in[inOff];
+ FR[blockSize - 2] = inVal;
+ out[outOff] = encryptByte(inVal, blockSize - 2);
+
+ inVal = in[inOff + 1];
+ FR[blockSize - 1] = inVal;
+ out[outOff + 1] = encryptByte(inVal, blockSize - 1);
+
+ cipher.processBlock(FR, 0, FRE, 0);
+
+ for (int n = 2; n < blockSize; n++)
+ {
+ inVal = in[inOff + n];
+ FR[n - 2] = inVal;
+ out[outOff + n] = encryptByte(inVal, n - 2);
+ }
+ }
+ else if (count == 0)
+ {
+ cipher.processBlock(FR, 0, FRE, 0);
+
+ for (int n = 0; n < blockSize; n++)
+ {
+ FR[n] = in[inOff + n];
+ out[n] = encryptByte(in[inOff + n], n);
+ }
+
+ count += blockSize;
+ }
+ else if (count == blockSize)
+ {
+ cipher.processBlock(FR, 0, FRE, 0);
+
+ byte inVal1 = in[inOff];
+ byte inVal2 = in[inOff + 1];
+ out[outOff ] = encryptByte(inVal1, 0);
+ out[outOff + 1] = encryptByte(inVal2, 1);
+
+ System.arraycopy(FR, 2, FR, 0, blockSize - 2);
+
+ FR[blockSize - 2] = inVal1;
+ FR[blockSize - 1] = inVal2;
+
+ cipher.processBlock(FR, 0, FRE, 0);
+
+ for (int n = 2; n < blockSize; n++)
+ {
+ byte inVal = in[inOff + n];
+ FR[n - 2] = inVal;
+ out[outOff + n] = encryptByte(inVal, n - 2);
+ }
+
+ count += blockSize;
+ }
+
+ return blockSize;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/modes/PGPCFBBlockCipher.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/modes/PGPCFBBlockCipher.java
new file mode 100644
index 0000000..16db7f9
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/modes/PGPCFBBlockCipher.java
@@ -0,0 +1,450 @@
+package org.bc.crypto.modes;
+
+import org.bc.crypto.BlockCipher;
+import org.bc.crypto.CipherParameters;
+import org.bc.crypto.DataLengthException;
+import org.bc.crypto.params.ParametersWithIV;
+
+/**
+ * Implements OpenPGP's rather strange version of Cipher-FeedBack (CFB) mode on top of a simple cipher. For further info see RFC 2440.
+ */
+public class PGPCFBBlockCipher
+ implements BlockCipher
+{
+ private byte[] IV;
+ private byte[] FR;
+ private byte[] FRE;
+ private byte[] tmp;
+
+ private BlockCipher cipher;
+
+ private int count;
+ private int blockSize;
+ private boolean forEncryption;
+
+ private boolean inlineIv; // if false we don't need to prepend an IV
+
+ /**
+ * Basic constructor.
+ *
+ * @param cipher the block cipher to be used as the basis of the
+ * feedback mode.
+ * @param inlineIv if true this is for PGP CFB with a prepended iv.
+ */
+ public PGPCFBBlockCipher(
+ BlockCipher cipher,
+ boolean inlineIv)
+ {
+ this.cipher = cipher;
+ this.inlineIv = inlineIv;
+
+ this.blockSize = cipher.getBlockSize();
+ this.IV = new byte[blockSize];
+ this.FR = new byte[blockSize];
+ this.FRE = new byte[blockSize];
+ this.tmp = new byte[blockSize];
+ }
+
+ /**
+ * return the underlying block cipher that we are wrapping.
+ *
+ * @return the underlying block cipher that we are wrapping.
+ */
+ public BlockCipher getUnderlyingCipher()
+ {
+ return cipher;
+ }
+
+ /**
+ * return the algorithm name and mode.
+ *
+ * @return the name of the underlying algorithm followed by "/PGPCFB"
+ * and the block size in bits.
+ */
+ public String getAlgorithmName()
+ {
+ if (inlineIv)
+ {
+ return cipher.getAlgorithmName() + "/PGPCFBwithIV";
+ }
+ else
+ {
+ return cipher.getAlgorithmName() + "/PGPCFB";
+ }
+ }
+
+ /**
+ * return the block size we are operating at.
+ *
+ * @return the block size we are operating at (in bytes).
+ */
+ public int getBlockSize()
+ {
+ return cipher.getBlockSize();
+ }
+
+ /**
+ * Process one block of input from the array in and write it to
+ * the out array.
+ *
+ * @param in the array containing the input data.
+ * @param inOff offset into the in array the data starts at.
+ * @param out the array the output data will be copied into.
+ * @param outOff the offset into the out array the output will start at.
+ * @exception DataLengthException if there isn't enough data in in, or
+ * space in out.
+ * @exception IllegalStateException if the cipher isn't initialised.
+ * @return the number of bytes processed and produced.
+ */
+ public int processBlock(
+ byte[] in,
+ int inOff,
+ byte[] out,
+ int outOff)
+ throws DataLengthException, IllegalStateException
+ {
+ if (inlineIv)
+ {
+ return (forEncryption) ? encryptBlockWithIV(in, inOff, out, outOff) : decryptBlockWithIV(in, inOff, out, outOff);
+ }
+ else
+ {
+ return (forEncryption) ? encryptBlock(in, inOff, out, outOff) : decryptBlock(in, inOff, out, outOff);
+ }
+ }
+
+ /**
+ * reset the chaining vector back to the IV and reset the underlying
+ * cipher.
+ */
+ public void reset()
+ {
+ count = 0;
+
+ for (int i = 0; i != FR.length; i++)
+ {
+ if (inlineIv)
+ {
+ FR[i] = 0;
+ }
+ else
+ {
+ FR[i] = IV[i]; // if simple mode, key is IV (even if this is zero)
+ }
+ }
+
+ cipher.reset();
+ }
+
+ /**
+ * Initialise the cipher and, possibly, the initialisation vector (IV).
+ * If an IV isn't passed as part of the parameter, the IV will be all zeros.
+ * An IV which is too short is handled in FIPS compliant fashion.
+ *
+ * @param forEncryption if true the cipher is initialised for
+ * encryption, if false for decryption.
+ * @param params the key and other data required by the cipher.
+ * @exception IllegalArgumentException if the params argument is
+ * inappropriate.
+ */
+ public void init(
+ boolean forEncryption,
+ CipherParameters params)
+ throws IllegalArgumentException
+ {
+ this.forEncryption = forEncryption;
+
+ if (params instanceof ParametersWithIV)
+ {
+ ParametersWithIV ivParam = (ParametersWithIV)params;
+ byte[] iv = ivParam.getIV();
+
+ if (iv.length < IV.length)
+ {
+ // prepend the supplied IV with zeros (per FIPS PUB 81)
+ System.arraycopy(iv, 0, IV, IV.length - iv.length, iv.length);
+ for (int i = 0; i < IV.length - iv.length; i++)
+ {
+ IV[i] = 0;
+ }
+ }
+ else
+ {
+ System.arraycopy(iv, 0, IV, 0, IV.length);
+ }
+
+ reset();
+
+ cipher.init(true, ivParam.getParameters());
+ }
+ else
+ {
+ reset();
+
+ cipher.init(true, params);
+ }
+ }
+
+ /**
+ * Encrypt one byte of data according to CFB mode.
+ * @param data the byte to encrypt
+ * @param blockOff where am i in the current block, determines when to resync the block
+ * @returns the encrypted byte
+ */
+ private byte encryptByte(byte data, int blockOff)
+ {
+ return (byte)(FRE[blockOff] ^ data);
+ }
+
+ /**
+ * Do the appropriate processing for CFB IV mode encryption.
+ *
+ * @param in the array containing the data to be encrypted.
+ * @param inOff offset into the in array the data starts at.
+ * @param out the array the encrypted data will be copied into.
+ * @param outOff the offset into the out array the output will start at.
+ * @exception DataLengthException if there isn't enough data in in, or
+ * space in out.
+ * @exception IllegalStateException if the cipher isn't initialised.
+ * @return the number of bytes processed and produced.
+ */
+ private int encryptBlockWithIV(
+ byte[] in,
+ int inOff,
+ byte[] out,
+ int outOff)
+ throws DataLengthException, IllegalStateException
+ {
+ if ((inOff + blockSize) > in.length)
+ {
+ throw new DataLengthException("input buffer too short");
+ }
+
+ if ((outOff + blockSize) > out.length)
+ {
+ throw new DataLengthException("output buffer too short");
+ }
+
+ if (count == 0)
+ {
+ cipher.processBlock(FR, 0, FRE, 0);
+
+ for (int n = 0; n < blockSize; n++)
+ {
+ out[outOff + n] = encryptByte(IV[n], n);
+ }
+
+ System.arraycopy(out, outOff, FR, 0, blockSize);
+
+ cipher.processBlock(FR, 0, FRE, 0);
+
+ out[outOff + blockSize] = encryptByte(IV[blockSize - 2], 0);
+ out[outOff + blockSize + 1] = encryptByte(IV[blockSize - 1], 1);
+
+ System.arraycopy(out, outOff + 2, FR, 0, blockSize);
+
+ cipher.processBlock(FR, 0, FRE, 0);
+
+ for (int n = 0; n < blockSize; n++)
+ {
+ out[outOff + blockSize + 2 + n] = encryptByte(in[inOff + n], n);
+ }
+
+ System.arraycopy(out, outOff + blockSize + 2, FR, 0, blockSize);
+
+ count += 2 * blockSize + 2;
+
+ return 2 * blockSize + 2;
+ }
+ else if (count >= blockSize + 2)
+ {
+ cipher.processBlock(FR, 0, FRE, 0);
+
+ for (int n = 0; n < blockSize; n++)
+ {
+ out[outOff + n] = encryptByte(in[inOff + n], n);
+ }
+
+ System.arraycopy(out, outOff, FR, 0, blockSize);
+ }
+
+ return blockSize;
+ }
+
+ /**
+ * Do the appropriate processing for CFB IV mode decryption.
+ *
+ * @param in the array containing the data to be decrypted.
+ * @param inOff offset into the in array the data starts at.
+ * @param out the array the encrypted data will be copied into.
+ * @param outOff the offset into the out array the output will start at.
+ * @exception DataLengthException if there isn't enough data in in, or
+ * space in out.
+ * @exception IllegalStateException if the cipher isn't initialised.
+ * @return the number of bytes processed and produced.
+ */
+ private int decryptBlockWithIV(
+ byte[] in,
+ int inOff,
+ byte[] out,
+ int outOff)
+ throws DataLengthException, IllegalStateException
+ {
+ if ((inOff + blockSize) > in.length)
+ {
+ throw new DataLengthException("input buffer too short");
+ }
+
+ if ((outOff + blockSize) > out.length)
+ {
+ throw new DataLengthException("output buffer too short");
+ }
+
+ if (count == 0)
+ {
+ for (int n = 0; n < blockSize; n++)
+ {
+ FR[n] = in[inOff + n];
+ }
+
+ cipher.processBlock(FR, 0, FRE, 0);
+
+ count += blockSize;
+
+ return 0;
+ }
+ else if (count == blockSize)
+ {
+ // copy in buffer so that this mode works if in and out are the same
+ System.arraycopy(in, inOff, tmp, 0, blockSize);
+
+ System.arraycopy(FR, 2, FR, 0, blockSize - 2);
+
+ FR[blockSize - 2] = tmp[0];
+ FR[blockSize - 1] = tmp[1];
+
+ cipher.processBlock(FR, 0, FRE, 0);
+
+ for (int n = 0; n < blockSize - 2; n++)
+ {
+ out[outOff + n] = encryptByte(tmp[n + 2], n);
+ }
+
+ System.arraycopy(tmp, 2, FR, 0, blockSize - 2);
+
+ count += 2;
+
+ return blockSize - 2;
+ }
+ else if (count >= blockSize + 2)
+ {
+ // copy in buffer so that this mode works if in and out are the same
+ System.arraycopy(in, inOff, tmp, 0, blockSize);
+
+ out[outOff + 0] = encryptByte(tmp[0], blockSize - 2);
+ out[outOff + 1] = encryptByte(tmp[1], blockSize - 1);
+
+ System.arraycopy(tmp, 0, FR, blockSize - 2, 2);
+
+ cipher.processBlock(FR, 0, FRE, 0);
+
+ for (int n = 0; n < blockSize - 2; n++)
+ {
+ out[outOff + n + 2] = encryptByte(tmp[n + 2], n);
+ }
+
+ System.arraycopy(tmp, 2, FR, 0, blockSize - 2);
+
+ }
+
+ return blockSize;
+ }
+
+ /**
+ * Do the appropriate processing for CFB mode encryption.
+ *
+ * @param in the array containing the data to be encrypted.
+ * @param inOff offset into the in array the data starts at.
+ * @param out the array the encrypted data will be copied into.
+ * @param outOff the offset into the out array the output will start at.
+ * @exception DataLengthException if there isn't enough data in in, or
+ * space in out.
+ * @exception IllegalStateException if the cipher isn't initialised.
+ * @return the number of bytes processed and produced.
+ */
+ private int encryptBlock(
+ byte[] in,
+ int inOff,
+ byte[] out,
+ int outOff)
+ throws DataLengthException, IllegalStateException
+ {
+ if ((inOff + blockSize) > in.length)
+ {
+ throw new DataLengthException("input buffer too short");
+ }
+
+ if ((outOff + blockSize) > out.length)
+ {
+ throw new DataLengthException("output buffer too short");
+ }
+
+ cipher.processBlock(FR, 0, FRE, 0);
+ for (int n = 0; n < blockSize; n++)
+ {
+ out[outOff + n] = encryptByte(in[inOff + n], n);
+ }
+
+ for (int n = 0; n < blockSize; n++)
+ {
+ FR[n] = out[outOff + n];
+ }
+
+ return blockSize;
+
+ }
+
+ /**
+ * Do the appropriate processing for CFB mode decryption.
+ *
+ * @param in the array containing the data to be decrypted.
+ * @param inOff offset into the in array the data starts at.
+ * @param out the array the encrypted data will be copied into.
+ * @param outOff the offset into the out array the output will start at.
+ * @exception DataLengthException if there isn't enough data in in, or
+ * space in out.
+ * @exception IllegalStateException if the cipher isn't initialised.
+ * @return the number of bytes processed and produced.
+ */
+ private int decryptBlock(
+ byte[] in,
+ int inOff,
+ byte[] out,
+ int outOff)
+ throws DataLengthException, IllegalStateException
+ {
+ if ((inOff + blockSize) > in.length)
+ {
+ throw new DataLengthException("input buffer too short");
+ }
+
+ if ((outOff + blockSize) > out.length)
+ {
+ throw new DataLengthException("output buffer too short");
+ }
+
+ cipher.processBlock(FR, 0, FRE, 0);
+ for (int n = 0; n < blockSize; n++)
+ {
+ out[outOff + n] = encryptByte(in[inOff + n], n);
+ }
+
+ for (int n = 0; n < blockSize; n++)
+ {
+ FR[n] = in[inOff + n];
+ }
+
+ return blockSize;
+
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/modes/PaddedBlockCipher.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/modes/PaddedBlockCipher.java
new file mode 100644
index 0000000..03a7bfb
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/modes/PaddedBlockCipher.java
@@ -0,0 +1,253 @@
+package org.bc.crypto.modes;
+
+import org.bc.crypto.BlockCipher;
+import org.bc.crypto.BufferedBlockCipher;
+import org.bc.crypto.DataLengthException;
+import org.bc.crypto.InvalidCipherTextException;
+
+/**
+ * A wrapper class that allows block ciphers to be used to process data in
+ * a piecemeal fashion with PKCS5/PKCS7 padding. The PaddedBlockCipher
+ * outputs a block only when the buffer is full and more data is being added,
+ * or on a doFinal (unless the current block in the buffer is a pad block).
+ * The padding mechanism used is the one outlined in PKCS5/PKCS7.
+ *
+ * @deprecated use org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher instead.
+ */
+public class PaddedBlockCipher
+ extends BufferedBlockCipher
+{
+ /**
+ * Create a buffered block cipher with, or without, padding.
+ *
+ * @param cipher the underlying block cipher this buffering object wraps.
+ */
+ public PaddedBlockCipher(
+ BlockCipher cipher)
+ {
+ this.cipher = cipher;
+
+ buf = new byte[cipher.getBlockSize()];
+ bufOff = 0;
+ }
+
+ /**
+ * return the size of the output buffer required for an update plus a
+ * doFinal with an input of len bytes.
+ *
+ * @param len the length of the input.
+ * @return the space required to accommodate a call to update and doFinal
+ * with len bytes of input.
+ */
+ public int getOutputSize(
+ int len)
+ {
+ int total = len + bufOff;
+ int leftOver = total % buf.length;
+
+ if (leftOver == 0)
+ {
+ if (forEncryption)
+ {
+ return total + buf.length;
+ }
+
+ return total;
+ }
+
+ return total - leftOver + buf.length;
+ }
+
+ /**
+ * return the size of the output buffer required for an update
+ * an input of len bytes.
+ *
+ * @param len the length of the input.
+ * @return the space required to accommodate a call to update
+ * with len bytes of input.
+ */
+ public int getUpdateOutputSize(
+ int len)
+ {
+ int total = len + bufOff;
+ int leftOver = total % buf.length;
+
+ if (leftOver == 0)
+ {
+ return total - buf.length;
+ }
+
+ return total - leftOver;
+ }
+
+ /**
+ * process a single byte, producing an output block if neccessary.
+ *
+ * @param in the input byte.
+ * @param out the space for any output that might be produced.
+ * @param outOff the offset from which the output will be copied.
+ * @exception DataLengthException if there isn't enough space in out.
+ * @exception IllegalStateException if the cipher isn't initialised.
+ */
+ public int processByte(
+ byte in,
+ byte[] out,
+ int outOff)
+ throws DataLengthException, IllegalStateException
+ {
+ int resultLen = 0;
+
+ if (bufOff == buf.length)
+ {
+ resultLen = cipher.processBlock(buf, 0, out, outOff);
+ bufOff = 0;
+ }
+
+ buf[bufOff++] = in;
+
+ return resultLen;
+ }
+
+ /**
+ * process an array of bytes, producing output if necessary.
+ *
+ * @param in the input byte array.
+ * @param inOff the offset at which the input data starts.
+ * @param len the number of bytes to be copied out of the input array.
+ * @param out the space for any output that might be produced.
+ * @param outOff the offset from which the output will be copied.
+ * @exception DataLengthException if there isn't enough space in out.
+ * @exception IllegalStateException if the cipher isn't initialised.
+ */
+ public int processBytes(
+ byte[] in,
+ int inOff,
+ int len,
+ byte[] out,
+ int outOff)
+ throws DataLengthException, IllegalStateException
+ {
+ if (len < 0)
+ {
+ throw new IllegalArgumentException("Can't have a negative input length!");
+ }
+
+ int blockSize = getBlockSize();
+ int length = getUpdateOutputSize(len);
+
+ if (length > 0)
+ {
+ if ((outOff + length) > out.length)
+ {
+ throw new DataLengthException("output buffer too short");
+ }
+ }
+
+ int resultLen = 0;
+ int gapLen = buf.length - bufOff;
+
+ if (len > gapLen)
+ {
+ System.arraycopy(in, inOff, buf, bufOff, gapLen);
+
+ resultLen += cipher.processBlock(buf, 0, out, outOff);
+
+ bufOff = 0;
+ len -= gapLen;
+ inOff += gapLen;
+
+ while (len > buf.length)
+ {
+ resultLen += cipher.processBlock(in, inOff, out, outOff + resultLen);
+
+ len -= blockSize;
+ inOff += blockSize;
+ }
+ }
+
+ System.arraycopy(in, inOff, buf, bufOff, len);
+
+ bufOff += len;
+
+ return resultLen;
+ }
+
+ /**
+ * Process the last block in the buffer. If the buffer is currently
+ * full and padding needs to be added a call to doFinal will produce
+ * 2 * getBlockSize() bytes.
+ *
+ * @param out the array the block currently being held is copied into.
+ * @param outOff the offset at which the copying starts.
+ * @exception DataLengthException if there is insufficient space in out for
+ * the output or we are decrypting and the input is not block size aligned.
+ * @exception IllegalStateException if the underlying cipher is not
+ * initialised.
+ * @exception InvalidCipherTextException if padding is expected and not found.
+ */
+ public int doFinal(
+ byte[] out,
+ int outOff)
+ throws DataLengthException, IllegalStateException, InvalidCipherTextException
+ {
+ int blockSize = cipher.getBlockSize();
+ int resultLen = 0;
+
+ if (forEncryption)
+ {
+ if (bufOff == blockSize)
+ {
+ if ((outOff + 2 * blockSize) > out.length)
+ {
+ throw new DataLengthException("output buffer too short");
+ }
+
+ resultLen = cipher.processBlock(buf, 0, out, outOff);
+ bufOff = 0;
+ }
+
+ //
+ // add PKCS7 padding
+ //
+ byte code = (byte)(blockSize - bufOff);
+
+ while (bufOff < blockSize)
+ {
+ buf[bufOff] = code;
+ bufOff++;
+ }
+
+ resultLen += cipher.processBlock(buf, 0, out, outOff + resultLen);
+ }
+ else
+ {
+ if (bufOff == blockSize)
+ {
+ resultLen = cipher.processBlock(buf, 0, buf, 0);
+ bufOff = 0;
+ }
+ else
+ {
+ throw new DataLengthException("last block incomplete in decryption");
+ }
+
+ //
+ // remove PKCS7 padding
+ //
+ int count = buf[blockSize - 1] & 0xff;
+
+ if ((count < 0) || (count > blockSize))
+ {
+ throw new InvalidCipherTextException("pad block corrupted");
+ }
+
+ resultLen -= count;
+
+ System.arraycopy(buf, 0, out, outOff, resultLen);
+ }
+
+ reset();
+
+ return resultLen;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/modes/SICBlockCipher.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/modes/SICBlockCipher.java
new file mode 100644
index 0000000..f0631f9
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/modes/SICBlockCipher.java
@@ -0,0 +1,113 @@
+package org.bc.crypto.modes;
+
+import org.bc.crypto.BlockCipher;
+import org.bc.crypto.CipherParameters;
+import org.bc.crypto.DataLengthException;
+import org.bc.crypto.params.ParametersWithIV;
+
+/**
+ * Implements the Segmented Integer Counter (SIC) mode on top of a simple
+ * block cipher. This mode is also known as CTR mode.
+ */
+public class SICBlockCipher
+ implements BlockCipher
+{
+ private final BlockCipher cipher;
+ private final int blockSize;
+
+ private byte[] IV;
+ private byte[] counter;
+ private byte[] counterOut;
+
+
+ /**
+ * Basic constructor.
+ *
+ * @param c the block cipher to be used.
+ */
+ public SICBlockCipher(BlockCipher c)
+ {
+ this.cipher = c;
+ this.blockSize = cipher.getBlockSize();
+ this.IV = new byte[blockSize];
+ this.counter = new byte[blockSize];
+ this.counterOut = new byte[blockSize];
+ }
+
+
+ /**
+ * return the underlying block cipher that we are wrapping.
+ *
+ * @return the underlying block cipher that we are wrapping.
+ */
+ public BlockCipher getUnderlyingCipher()
+ {
+ return cipher;
+ }
+
+
+ public void init(
+ boolean forEncryption, //ignored by this CTR mode
+ CipherParameters params)
+ throws IllegalArgumentException
+ {
+ if (params instanceof ParametersWithIV)
+ {
+ ParametersWithIV ivParam = (ParametersWithIV)params;
+ byte[] iv = ivParam.getIV();
+ System.arraycopy(iv, 0, IV, 0, IV.length);
+
+ reset();
+
+ // if null it's an IV changed only.
+ if (ivParam.getParameters() != null)
+ {
+ cipher.init(true, ivParam.getParameters());
+ }
+ }
+ else
+ {
+ throw new IllegalArgumentException("SIC mode requires ParametersWithIV");
+ }
+ }
+
+ public String getAlgorithmName()
+ {
+ return cipher.getAlgorithmName() + "/SIC";
+ }
+
+ public int getBlockSize()
+ {
+ return cipher.getBlockSize();
+ }
+
+
+ public int processBlock(byte[] in, int inOff, byte[] out, int outOff)
+ throws DataLengthException, IllegalStateException
+ {
+ cipher.processBlock(counter, 0, counterOut, 0);
+
+ //
+ // XOR the counterOut with the plaintext producing the cipher text
+ //
+ for (int i = 0; i < counterOut.length; i++)
+ {
+ out[outOff + i] = (byte)(counterOut[i] ^ in[inOff + i]);
+ }
+
+ // increment counter by 1.
+ for (int i = counter.length - 1; i >= 0 && ++counter[i] == 0; i--)
+ {
+ ; // do nothing - pre-increment and test for 0 in counter does the job.
+ }
+
+ return counter.length;
+ }
+
+
+ public void reset()
+ {
+ System.arraycopy(IV, 0, counter, 0, counter.length);
+ cipher.reset();
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/modes/gcm/BasicGCMExponentiator.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/modes/gcm/BasicGCMExponentiator.java
new file mode 100644
index 0000000..c6e17f0
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/modes/gcm/BasicGCMExponentiator.java
@@ -0,0 +1,36 @@
+package org.bc.crypto.modes.gcm;
+
+import org.bc.util.Arrays;
+
+public class BasicGCMExponentiator implements GCMExponentiator
+{
+ private byte[] x;
+
+ public void init(byte[] x)
+ {
+ this.x = Arrays.clone(x);
+ }
+
+ public void exponentiateX(long pow, byte[] output)
+ {
+ // Initial value is little-endian 1
+ byte[] y = GCMUtil.oneAsBytes();
+
+ if (pow > 0)
+ {
+ byte[] powX = Arrays.clone(x);
+ do
+ {
+ if ((pow & 1L) != 0)
+ {
+ GCMUtil.multiply(y, powX);
+ }
+ GCMUtil.multiply(powX, powX);
+ pow >>>= 1;
+ }
+ while (pow > 0);
+ }
+
+ System.arraycopy(y, 0, output, 0, 16);
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/modes/gcm/BasicGCMMultiplier.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/modes/gcm/BasicGCMMultiplier.java
new file mode 100644
index 0000000..3733b13
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/modes/gcm/BasicGCMMultiplier.java
@@ -0,0 +1,18 @@
+package org.bc.crypto.modes.gcm;
+
+import org.bc.util.Arrays;
+
+public class BasicGCMMultiplier implements GCMMultiplier
+{
+ private byte[] H;
+
+ public void init(byte[] H)
+ {
+ this.H = Arrays.clone(H);
+ }
+
+ public void multiplyH(byte[] x)
+ {
+ GCMUtil.multiply(x, H);
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/modes/gcm/GCMExponentiator.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/modes/gcm/GCMExponentiator.java
new file mode 100644
index 0000000..c1cc4c7
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/modes/gcm/GCMExponentiator.java
@@ -0,0 +1,7 @@
+package org.bc.crypto.modes.gcm;
+
+public interface GCMExponentiator
+{
+ void init(byte[] x);
+ void exponentiateX(long pow, byte[] output);
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/modes/gcm/GCMMultiplier.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/modes/gcm/GCMMultiplier.java
new file mode 100644
index 0000000..0a0d30f
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/modes/gcm/GCMMultiplier.java
@@ -0,0 +1,7 @@
+package org.bc.crypto.modes.gcm;
+
+public interface GCMMultiplier
+{
+ void init(byte[] H);
+ void multiplyH(byte[] x);
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/modes/gcm/GCMUtil.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/modes/gcm/GCMUtil.java
new file mode 100644
index 0000000..5893f72
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/modes/gcm/GCMUtil.java
@@ -0,0 +1,260 @@
+package org.bc.crypto.modes.gcm;
+
+import org.bc.crypto.util.Pack;
+import org.bc.util.Arrays;
+
+abstract class GCMUtil
+{
+ static byte[] oneAsBytes()
+ {
+ byte[] tmp = new byte[16];
+ tmp[0] = (byte)0x80;
+ return tmp;
+ }
+
+ static int[] oneAsInts()
+ {
+ int[] tmp = new int[4];
+ tmp[0] = 0x80000000;
+ return tmp;
+ }
+
+ static byte[] asBytes(int[] ns)
+ {
+ byte[] output = new byte[16];
+ Pack.intToBigEndian(ns, output, 0);
+ return output;
+ }
+
+ static int[] asInts(byte[] bs)
+ {
+ int[] output = new int[4];
+ Pack.bigEndianToInt(bs, 0, output);
+ return output;
+ }
+
+ static void asInts(byte[] bs, int[] output)
+ {
+ Pack.bigEndianToInt(bs, 0, output);
+ }
+
+ static void multiply(byte[] block, byte[] val)
+ {
+ byte[] tmp = Arrays.clone(block);
+ byte[] c = new byte[16];
+
+ for (int i = 0; i < 16; ++i)
+ {
+ byte bits = val[i];
+ for (int j = 7; j >= 0; --j)
+ {
+ if ((bits & (1 << j)) != 0)
+ {
+ xor(c, tmp);
+ }
+
+ boolean lsb = (tmp[15] & 1) != 0;
+ shiftRight(tmp);
+ if (lsb)
+ {
+ // R = new byte[]{ 0xe1, ... };
+// GCMUtil.xor(v, R);
+ tmp[0] ^= (byte)0xe1;
+ }
+ }
+ }
+
+ System.arraycopy(c, 0, block, 0, 16);
+ }
+
+ // P is the value with only bit i=1 set
+ static void multiplyP(int[] x)
+ {
+ boolean lsb = (x[3] & 1) != 0;
+ shiftRight(x);
+ if (lsb)
+ {
+ // R = new int[]{ 0xe1000000, 0, 0, 0 };
+// xor(v, R);
+ x[0] ^= 0xe1000000;
+ }
+ }
+
+ static void multiplyP(int[] x, int[] output)
+ {
+ boolean lsb = (x[3] & 1) != 0;
+ shiftRight(x, output);
+ if (lsb)
+ {
+ output[0] ^= 0xe1000000;
+ }
+ }
+
+ // P is the value with only bit i=1 set
+ static void multiplyP8(int[] x)
+ {
+// for (int i = 8; i != 0; --i)
+// {
+// multiplyP(x);
+// }
+
+ int lsw = x[3];
+ shiftRightN(x, 8);
+ for (int i = 7; i >= 0; --i)
+ {
+ if ((lsw & (1 << i)) != 0)
+ {
+ x[0] ^= (0xe1000000 >>> (7 - i));
+ }
+ }
+ }
+
+ static void multiplyP8(int[] x, int[] output)
+ {
+ int lsw = x[3];
+ shiftRightN(x, 8, output);
+ for (int i = 7; i >= 0; --i)
+ {
+ if ((lsw & (1 << i)) != 0)
+ {
+ output[0] ^= (0xe1000000 >>> (7 - i));
+ }
+ }
+ }
+
+ static void shiftRight(byte[] block)
+ {
+ int i = 0;
+ int bit = 0;
+ for (;;)
+ {
+ int b = block[i] & 0xff;
+ block[i] = (byte) ((b >>> 1) | bit);
+ if (++i == 16)
+ {
+ break;
+ }
+ bit = (b & 1) << 7;
+ }
+ }
+
+ static void shiftRight(byte[] block, byte[] output)
+ {
+ int i = 0;
+ int bit = 0;
+ for (;;)
+ {
+ int b = block[i] & 0xff;
+ output[i] = (byte) ((b >>> 1) | bit);
+ if (++i == 16)
+ {
+ break;
+ }
+ bit = (b & 1) << 7;
+ }
+ }
+
+ static void shiftRight(int[] block)
+ {
+ int i = 0;
+ int bit = 0;
+ for (;;)
+ {
+ int b = block[i];
+ block[i] = (b >>> 1) | bit;
+ if (++i == 4)
+ {
+ break;
+ }
+ bit = b << 31;
+ }
+ }
+
+ static void shiftRight(int[] block, int[] output)
+ {
+ int i = 0;
+ int bit = 0;
+ for (;;)
+ {
+ int b = block[i];
+ output[i] = (b >>> 1) | bit;
+ if (++i == 4)
+ {
+ break;
+ }
+ bit = b << 31;
+ }
+ }
+
+ static void shiftRightN(int[] block, int n)
+ {
+ int i = 0;
+ int bits = 0;
+ for (;;)
+ {
+ int b = block[i];
+ block[i] = (b >>> n) | bits;
+ if (++i == 4)
+ {
+ break;
+ }
+ bits = b << (32 - n);
+ }
+ }
+
+ static void shiftRightN(int[] block, int n, int[] output)
+ {
+ int i = 0;
+ int bits = 0;
+ for (;;)
+ {
+ int b = block[i];
+ output[i] = (b >>> n) | bits;
+ if (++i == 4)
+ {
+ break;
+ }
+ bits = b << (32 - n);
+ }
+ }
+
+ static void xor(byte[] block, byte[] val)
+ {
+ for (int i = 15; i >= 0; --i)
+ {
+ block[i] ^= val[i];
+ }
+ }
+
+ static void xor(byte[] block, byte[] val, int off, int len)
+ {
+ while (len-- > 0)
+ {
+ block[len] ^= val[off + len];
+ }
+ }
+
+ static void xor(byte[] block, byte[] val, byte[] output)
+ {
+ for (int i = 15; i >= 0; --i)
+ {
+ output[i] = (byte)(block[i] ^ val[i]);
+ }
+ }
+
+ static void xor(int[] block, int[] val)
+ {
+ for (int i = 3; i >= 0; --i)
+ {
+ block[i] ^= val[i];
+ }
+ }
+
+ static void xor(int[] block, int[] val, int[] output)
+ {
+ for (int i = 3; i >= 0; --i)
+ {
+ output[i] = block[i] ^ val[i];
+ }
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/modes/gcm/Tables1kGCMExponentiator.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/modes/gcm/Tables1kGCMExponentiator.java
new file mode 100644
index 0000000..69dff12
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/modes/gcm/Tables1kGCMExponentiator.java
@@ -0,0 +1,57 @@
+package org.bc.crypto.modes.gcm;
+
+import java.util.Vector;
+
+import org.bc.util.Arrays;
+
+public class Tables1kGCMExponentiator implements GCMExponentiator
+{
+ // A lookup table of the power-of-two powers of 'x'
+ // - lookupPowX2[i] = x^(2^i)
+ private Vector lookupPowX2;
+
+ public void init(byte[] x)
+ {
+ if (lookupPowX2 != null && Arrays.areEqual(x, (byte[])lookupPowX2.elementAt(0)))
+ {
+ return;
+ }
+
+ lookupPowX2 = new Vector(8);
+ lookupPowX2.addElement(Arrays.clone(x));
+ }
+
+ public void exponentiateX(long pow, byte[] output)
+ {
+ byte[] y = GCMUtil.oneAsBytes();
+ int bit = 0;
+ while (pow > 0)
+ {
+ if ((pow & 1L) != 0)
+ {
+ ensureAvailable(bit);
+ GCMUtil.multiply(y, (byte[])lookupPowX2.elementAt(bit));
+ }
+ ++bit;
+ pow >>>= 1;
+ }
+
+ System.arraycopy(y, 0, output, 0, 16);
+ }
+
+ private void ensureAvailable(int bit)
+ {
+ int count = lookupPowX2.size();
+ if (count <= bit)
+ {
+ byte[] tmp = (byte[])lookupPowX2.elementAt(count - 1);
+ do
+ {
+ tmp = Arrays.clone(tmp);
+ GCMUtil.multiply(tmp, tmp);
+ lookupPowX2.addElement(tmp);
+ }
+ while (++count <= bit);
+ }
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/modes/gcm/Tables64kGCMMultiplier.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/modes/gcm/Tables64kGCMMultiplier.java
new file mode 100644
index 0000000..e32acd3
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/modes/gcm/Tables64kGCMMultiplier.java
@@ -0,0 +1,73 @@
+package org.bc.crypto.modes.gcm;
+
+import org.bc.crypto.util.Pack;
+import org.bc.util.Arrays;
+
+public class Tables64kGCMMultiplier implements GCMMultiplier
+{
+ private byte[] H;
+ private int[][][] M;
+
+ public void init(byte[] H)
+ {
+ if (M == null)
+ {
+ M = new int[16][256][4];
+ }
+ else if (Arrays.areEqual(this.H, H))
+ {
+ return;
+ }
+
+ this.H = Arrays.clone(H);
+
+ // M[0][0] is ZEROES;
+ GCMUtil.asInts(H, M[0][128]);
+
+ for (int j = 64; j >= 1; j >>= 1)
+ {
+ GCMUtil.multiplyP(M[0][j + j], M[0][j]);
+ }
+
+ int i = 0;
+ for (;;)
+ {
+ for (int j = 2; j < 256; j += j)
+ {
+ for (int k = 1; k < j; ++k)
+ {
+ GCMUtil.xor(M[i][j], M[i][k], M[i][j + k]);
+ }
+ }
+
+ if (++i == 16)
+ {
+ return;
+ }
+
+ // M[i][0] is ZEROES;
+ for (int j = 128; j > 0; j >>= 1)
+ {
+ GCMUtil.multiplyP8(M[i - 1][j], M[i][j]);
+ }
+ }
+ }
+
+ public void multiplyH(byte[] x)
+ {
+// assert x.Length == 16;
+
+ int[] z = new int[4];
+ for (int i = 15; i >= 0; --i)
+ {
+// GCMUtil.xor(z, M[i][x[i] & 0xff]);
+ int[] m = M[i][x[i] & 0xff];
+ z[0] ^= m[0];
+ z[1] ^= m[1];
+ z[2] ^= m[2];
+ z[3] ^= m[3];
+ }
+
+ Pack.intToBigEndian(z, x, 0);
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/modes/gcm/Tables8kGCMMultiplier.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/modes/gcm/Tables8kGCMMultiplier.java
new file mode 100644
index 0000000..674f230
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/modes/gcm/Tables8kGCMMultiplier.java
@@ -0,0 +1,90 @@
+package org.bc.crypto.modes.gcm;
+
+import org.bc.crypto.util.Pack;
+import org.bc.util.Arrays;
+
+public class Tables8kGCMMultiplier implements GCMMultiplier
+{
+ private byte[] H;
+ private int[][][] M;
+
+ public void init(byte[] H)
+ {
+ if (M == null)
+ {
+ M = new int[32][16][4];
+ }
+ else if (Arrays.areEqual(this.H, H))
+ {
+ return;
+ }
+
+ this.H = Arrays.clone(H);
+
+ // M[0][0] is ZEROES;
+ // M[1][0] is ZEROES;
+ GCMUtil.asInts(H, M[1][8]);
+
+ for (int j = 4; j >= 1; j >>= 1)
+ {
+ GCMUtil.multiplyP(M[1][j + j], M[1][j]);
+ }
+
+ GCMUtil.multiplyP(M[1][1], M[0][8]);
+
+ for (int j = 4; j >= 1; j >>= 1)
+ {
+ GCMUtil.multiplyP(M[0][j + j], M[0][j]);
+ }
+
+ int i = 0;
+ for (;;)
+ {
+ for (int j = 2; j < 16; j += j)
+ {
+ for (int k = 1; k < j; ++k)
+ {
+ GCMUtil.xor(M[i][j], M[i][k], M[i][j + k]);
+ }
+ }
+
+ if (++i == 32)
+ {
+ return;
+ }
+
+ if (i > 1)
+ {
+ // M[i][0] is ZEROES;
+ for(int j = 8; j > 0; j >>= 1)
+ {
+ GCMUtil.multiplyP8(M[i - 2][j], M[i][j]);
+ }
+ }
+ }
+ }
+
+ public void multiplyH(byte[] x)
+ {
+// assert x.Length == 16;
+
+ int[] z = new int[4];
+ for (int i = 15; i >= 0; --i)
+ {
+// GCMUtil.xor(z, M[i + i][x[i] & 0x0f]);
+ int[] m = M[i + i][x[i] & 0x0f];
+ z[0] ^= m[0];
+ z[1] ^= m[1];
+ z[2] ^= m[2];
+ z[3] ^= m[3];
+// GCMUtil.xor(z, M[i + i + 1][(x[i] & 0xf0) >>> 4]);
+ m = M[i + i + 1][(x[i] & 0xf0) >>> 4];
+ z[0] ^= m[0];
+ z[1] ^= m[1];
+ z[2] ^= m[2];
+ z[3] ^= m[3];
+ }
+
+ Pack.intToBigEndian(z, x, 0);
+ }
+}
\ No newline at end of file
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/paddings/BlockCipherPadding.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/paddings/BlockCipherPadding.java
new file mode 100644
index 0000000..0432277
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/paddings/BlockCipherPadding.java
@@ -0,0 +1,48 @@
+package org.bc.crypto.paddings;
+
+import java.security.SecureRandom;
+
+import org.bc.crypto.InvalidCipherTextException;
+
+/**
+ * Block cipher padders are expected to conform to this interface
+ */
+public interface BlockCipherPadding
+{
+ /**
+ * Initialise the padder.
+ *
+ * @param random the source of randomness for the padding, if required.
+ */
+ public void init(SecureRandom random)
+ throws IllegalArgumentException;
+
+ /**
+ * Return the name of the algorithm the cipher implements.
+ *
+ * @return the name of the algorithm the cipher implements.
+ */
+ public String getPaddingName();
+
+ /**
+ * add the pad bytes to the passed in block, returning the
+ * number of bytes added.
+ *
+ * Note: this assumes that the last block of plain text is always
+ * passed to it inside in. i.e. if inOff is zero, indicating the
+ * entire block is to be overwritten with padding the value of in
+ * should be the same as the last block of plain text. The reason
+ * for this is that some modes such as "trailing bit compliment"
+ * base the padding on the last byte of plain text.
+ *
+ * This padding pads the block out with the compliment of the last bit
+ * of the plain text.
+ *
+ * Note: this assumes that the last block of plain text is always
+ * passed to it inside in. i.e. if inOff is zero, indicating the
+ * entire block is to be overwritten with padding the value of in
+ * should be the same as the last block of plain text.
+ *
+ * See "Applied
+ * Cryptography" by Bruce Schneier for more information.
+ *
+ * @return true if the given DES key material is weak or semi-weak,
+ * false otherwise.
+ */
+ public static boolean isWeakKey(
+ byte[] key,
+ int offset)
+ {
+ if (key.length - offset < DES_KEY_LENGTH)
+ {
+ throw new IllegalArgumentException("key material too short.");
+ }
+
+ nextkey: for (int i = 0; i < N_DES_WEAK_KEYS; i++)
+ {
+ for (int j = 0; j < DES_KEY_LENGTH; j++)
+ {
+ if (key[j + offset] != DES_weak_keys[i * DES_KEY_LENGTH + j])
+ {
+ continue nextkey;
+ }
+ }
+
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * DES Keys use the LSB as the odd parity bit. This can
+ * be used to check for corrupt keys.
+ *
+ * @param bytes the byte array to set the parity on.
+ */
+ public static void setOddParity(
+ byte[] bytes)
+ {
+ for (int i = 0; i < bytes.length; i++)
+ {
+ int b = bytes[i];
+ bytes[i] = (byte)((b & 0xfe) |
+ ((((b >> 1) ^
+ (b >> 2) ^
+ (b >> 3) ^
+ (b >> 4) ^
+ (b >> 5) ^
+ (b >> 6) ^
+ (b >> 7)) ^ 0x01) & 0x01));
+ }
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/DESedeParameters.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/DESedeParameters.java
new file mode 100644
index 0000000..fddfaa6
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/DESedeParameters.java
@@ -0,0 +1,57 @@
+package org.bc.crypto.params;
+
+public class DESedeParameters
+ extends DESParameters
+{
+ /*
+ * DES-EDE Key length in bytes.
+ */
+ static public final int DES_EDE_KEY_LENGTH = 24;
+
+ public DESedeParameters(
+ byte[] key)
+ {
+ super(key);
+
+ if (isWeakKey(key, 0, key.length))
+ {
+ throw new IllegalArgumentException("attempt to create weak DESede key");
+ }
+ }
+
+ /**
+ * return true if the passed in key is a DES-EDE weak key.
+ *
+ * @param key bytes making up the key
+ * @param offset offset into the byte array the key starts at
+ * @param length number of bytes making up the key
+ */
+ public static boolean isWeakKey(
+ byte[] key,
+ int offset,
+ int length)
+ {
+ for (int i = offset; i < length; i += DES_KEY_LENGTH)
+ {
+ if (DESParameters.isWeakKey(key, i))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * return true if the passed in key is a DES-EDE weak key.
+ *
+ * @param key bytes making up the key
+ * @param offset offset into the byte array the key starts at
+ */
+ public static boolean isWeakKey(
+ byte[] key,
+ int offset)
+ {
+ return isWeakKey(key, offset, key.length - offset);
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/DHKeyGenerationParameters.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/DHKeyGenerationParameters.java
new file mode 100644
index 0000000..68e5d45
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/DHKeyGenerationParameters.java
@@ -0,0 +1,30 @@
+package org.bc.crypto.params;
+
+import java.security.SecureRandom;
+
+import org.bc.crypto.KeyGenerationParameters;
+
+public class DHKeyGenerationParameters
+ extends KeyGenerationParameters
+{
+ private DHParameters params;
+
+ public DHKeyGenerationParameters(
+ SecureRandom random,
+ DHParameters params)
+ {
+ super(random, getStrength(params));
+
+ this.params = params;
+ }
+
+ public DHParameters getParameters()
+ {
+ return params;
+ }
+
+ static int getStrength(DHParameters params)
+ {
+ return params.getL() != 0 ? params.getL() : params.getP().bitLength();
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/DHKeyParameters.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/DHKeyParameters.java
new file mode 100644
index 0000000..021f4a9
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/DHKeyParameters.java
@@ -0,0 +1,54 @@
+package org.bc.crypto.params;
+
+
+public class DHKeyParameters
+ extends AsymmetricKeyParameter
+{
+ private DHParameters params;
+
+ protected DHKeyParameters(
+ boolean isPrivate,
+ DHParameters params)
+ {
+ super(isPrivate);
+
+ this.params = params;
+ }
+
+ public DHParameters getParameters()
+ {
+ return params;
+ }
+
+ public boolean equals(
+ Object obj)
+ {
+ if (!(obj instanceof DHKeyParameters))
+ {
+ return false;
+ }
+
+ DHKeyParameters dhKey = (DHKeyParameters)obj;
+
+ if (params == null)
+ {
+ return dhKey.getParameters() == null;
+ }
+ else
+ {
+ return params.equals(dhKey.getParameters());
+ }
+ }
+
+ public int hashCode()
+ {
+ int code = isPrivate() ? 0 : 1;
+
+ if (params != null)
+ {
+ code ^= params.hashCode();
+ }
+
+ return code;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/DHParameters.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/DHParameters.java
new file mode 100644
index 0000000..a9b2144
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/DHParameters.java
@@ -0,0 +1,189 @@
+package org.bc.crypto.params;
+
+import java.math.BigInteger;
+
+import org.bc.crypto.CipherParameters;
+
+public class DHParameters
+ implements CipherParameters
+{
+ private static final int DEFAULT_MINIMUM_LENGTH = 160;
+
+ // not final due to compiler bug in "simpler" JDKs
+ private BigInteger g;
+ private BigInteger p;
+ private BigInteger q;
+ private BigInteger j;
+ private int m;
+ private int l;
+ private DHValidationParameters validation;
+
+ private static int getDefaultMParam(
+ int lParam)
+ {
+ if (lParam == 0)
+ {
+ return DEFAULT_MINIMUM_LENGTH;
+ }
+
+ return lParam < DEFAULT_MINIMUM_LENGTH ? lParam : DEFAULT_MINIMUM_LENGTH;
+ }
+
+ public DHParameters(
+ BigInteger p,
+ BigInteger g)
+ {
+ this(p, g, null, 0);
+ }
+
+ public DHParameters(
+ BigInteger p,
+ BigInteger g,
+ BigInteger q)
+ {
+ this(p, g, q, 0);
+ }
+
+ public DHParameters(
+ BigInteger p,
+ BigInteger g,
+ BigInteger q,
+ int l)
+ {
+ this(p, g, q, getDefaultMParam(l), l, null, null);
+ }
+
+ public DHParameters(
+ BigInteger p,
+ BigInteger g,
+ BigInteger q,
+ int m,
+ int l)
+ {
+ this(p, g, q, m, l, null, null);
+ }
+
+ public DHParameters(
+ BigInteger p,
+ BigInteger g,
+ BigInteger q,
+ BigInteger j,
+ DHValidationParameters validation)
+ {
+ this(p, g, q, DEFAULT_MINIMUM_LENGTH, 0, j, validation);
+ }
+
+ public DHParameters(
+ BigInteger p,
+ BigInteger g,
+ BigInteger q,
+ int m,
+ int l,
+ BigInteger j,
+ DHValidationParameters validation)
+ {
+ if (l != 0)
+ {
+ BigInteger bigL = BigInteger.valueOf(2L ^ (l - 1));
+ if (bigL.compareTo(p) == 1)
+ {
+ throw new IllegalArgumentException("when l value specified, it must satisfy 2^(l-1) <= p");
+ }
+ if (l < m)
+ {
+ throw new IllegalArgumentException("when l value specified, it may not be less than m value");
+ }
+ }
+
+ this.g = g;
+ this.p = p;
+ this.q = q;
+ this.m = m;
+ this.l = l;
+ this.j = j;
+ this.validation = validation;
+ }
+
+ public BigInteger getP()
+ {
+ return p;
+ }
+
+ public BigInteger getG()
+ {
+ return g;
+ }
+
+ public BigInteger getQ()
+ {
+ return q;
+ }
+
+ /**
+ * Return the subgroup factor J.
+ *
+ * @return subgroup factor
+ */
+ public BigInteger getJ()
+ {
+ return j;
+ }
+
+ /**
+ * Return the minimum length of the private value.
+ *
+ * @return the minimum length of the private value in bits.
+ */
+ public int getM()
+ {
+ return m;
+ }
+
+ /**
+ * Return the private value length in bits - if set, zero otherwise
+ *
+ * @return the private value length in bits, zero otherwise.
+ */
+ public int getL()
+ {
+ return l;
+ }
+
+ public DHValidationParameters getValidationParameters()
+ {
+ return validation;
+ }
+
+ public boolean equals(
+ Object obj)
+ {
+ if (!(obj instanceof DHParameters))
+ {
+ return false;
+ }
+
+ DHParameters pm = (DHParameters)obj;
+
+ if (this.getQ() != null)
+ {
+ if (!this.getQ().equals(pm.getQ()))
+ {
+ return false;
+ }
+ }
+ else
+ {
+ if (pm.getQ() != null)
+ {
+ return false;
+ }
+ }
+
+ return pm.getP().equals(p) && pm.getG().equals(g);
+ }
+
+ public int hashCode()
+ {
+ return getP().hashCode() ^ getG().hashCode() ^ (getQ() != null ? getQ().hashCode() : 0);
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/DHPrivateKeyParameters.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/DHPrivateKeyParameters.java
new file mode 100644
index 0000000..2e4f7ee
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/DHPrivateKeyParameters.java
@@ -0,0 +1,41 @@
+package org.bc.crypto.params;
+
+import java.math.BigInteger;
+
+public class DHPrivateKeyParameters
+ extends DHKeyParameters
+{
+ private BigInteger x;
+
+ public DHPrivateKeyParameters(
+ BigInteger x,
+ DHParameters params)
+ {
+ super(true, params);
+
+ this.x = x;
+ }
+
+ public BigInteger getX()
+ {
+ return x;
+ }
+
+ public int hashCode()
+ {
+ return x.hashCode() ^ super.hashCode();
+ }
+
+ public boolean equals(
+ Object obj)
+ {
+ if (!(obj instanceof DHPrivateKeyParameters))
+ {
+ return false;
+ }
+
+ DHPrivateKeyParameters other = (DHPrivateKeyParameters)obj;
+
+ return other.getX().equals(this.x) && super.equals(obj);
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/DHPublicKeyParameters.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/DHPublicKeyParameters.java
new file mode 100644
index 0000000..900f1a7
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/DHPublicKeyParameters.java
@@ -0,0 +1,41 @@
+package org.bc.crypto.params;
+
+import java.math.BigInteger;
+
+public class DHPublicKeyParameters
+ extends DHKeyParameters
+{
+ private BigInteger y;
+
+ public DHPublicKeyParameters(
+ BigInteger y,
+ DHParameters params)
+ {
+ super(false, params);
+
+ this.y = y;
+ }
+
+ public BigInteger getY()
+ {
+ return y;
+ }
+
+ public int hashCode()
+ {
+ return y.hashCode() ^ super.hashCode();
+ }
+
+ public boolean equals(
+ Object obj)
+ {
+ if (!(obj instanceof DHPublicKeyParameters))
+ {
+ return false;
+ }
+
+ DHPublicKeyParameters other = (DHPublicKeyParameters)obj;
+
+ return other.getY().equals(y) && super.equals(obj);
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/DHValidationParameters.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/DHValidationParameters.java
new file mode 100644
index 0000000..af66f07
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/DHValidationParameters.java
@@ -0,0 +1,50 @@
+package org.bc.crypto.params;
+
+import org.bc.util.Arrays;
+
+public class DHValidationParameters
+{
+ private byte[] seed;
+ private int counter;
+
+ public DHValidationParameters(
+ byte[] seed,
+ int counter)
+ {
+ this.seed = seed;
+ this.counter = counter;
+ }
+
+ public int getCounter()
+ {
+ return counter;
+ }
+
+ public byte[] getSeed()
+ {
+ return seed;
+ }
+
+ public boolean equals(
+ Object o)
+ {
+ if (!(o instanceof DHValidationParameters))
+ {
+ return false;
+ }
+
+ DHValidationParameters other = (DHValidationParameters)o;
+
+ if (other.counter != this.counter)
+ {
+ return false;
+ }
+
+ return Arrays.areEqual(this.seed, other.seed);
+ }
+
+ public int hashCode()
+ {
+ return counter ^ Arrays.hashCode(seed);
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/DSAKeyGenerationParameters.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/DSAKeyGenerationParameters.java
new file mode 100644
index 0000000..56a222a
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/DSAKeyGenerationParameters.java
@@ -0,0 +1,25 @@
+package org.bc.crypto.params;
+
+import java.security.SecureRandom;
+
+import org.bc.crypto.KeyGenerationParameters;
+
+public class DSAKeyGenerationParameters
+ extends KeyGenerationParameters
+{
+ private DSAParameters params;
+
+ public DSAKeyGenerationParameters(
+ SecureRandom random,
+ DSAParameters params)
+ {
+ super(random, params.getP().bitLength() - 1);
+
+ this.params = params;
+ }
+
+ public DSAParameters getParameters()
+ {
+ return params;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/DSAKeyParameters.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/DSAKeyParameters.java
new file mode 100644
index 0000000..fc0d3e9
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/DSAKeyParameters.java
@@ -0,0 +1,21 @@
+package org.bc.crypto.params;
+
+public class DSAKeyParameters
+ extends AsymmetricKeyParameter
+{
+ private DSAParameters params;
+
+ public DSAKeyParameters(
+ boolean isPrivate,
+ DSAParameters params)
+ {
+ super(isPrivate);
+
+ this.params = params;
+ }
+
+ public DSAParameters getParameters()
+ {
+ return params;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/DSAParameters.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/DSAParameters.java
new file mode 100644
index 0000000..1db720d
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/DSAParameters.java
@@ -0,0 +1,74 @@
+package org.bc.crypto.params;
+
+import java.math.BigInteger;
+
+import org.bc.crypto.CipherParameters;
+
+public class DSAParameters
+ implements CipherParameters
+{
+ private BigInteger g;
+ private BigInteger q;
+ private BigInteger p;
+ private DSAValidationParameters validation;
+
+ public DSAParameters(
+ BigInteger p,
+ BigInteger q,
+ BigInteger g)
+ {
+ this.g = g;
+ this.p = p;
+ this.q = q;
+ }
+
+ public DSAParameters(
+ BigInteger p,
+ BigInteger q,
+ BigInteger g,
+ DSAValidationParameters params)
+ {
+ this.g = g;
+ this.p = p;
+ this.q = q;
+ this.validation = params;
+ }
+
+ public BigInteger getP()
+ {
+ return p;
+ }
+
+ public BigInteger getQ()
+ {
+ return q;
+ }
+
+ public BigInteger getG()
+ {
+ return g;
+ }
+
+ public DSAValidationParameters getValidationParameters()
+ {
+ return validation;
+ }
+
+ public boolean equals(
+ Object obj)
+ {
+ if (!(obj instanceof DSAParameters))
+ {
+ return false;
+ }
+
+ DSAParameters pm = (DSAParameters)obj;
+
+ return (pm.getP().equals(p) && pm.getQ().equals(q) && pm.getG().equals(g));
+ }
+
+ public int hashCode()
+ {
+ return getP().hashCode() ^ getQ().hashCode() ^ getG().hashCode();
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/DSAPrivateKeyParameters.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/DSAPrivateKeyParameters.java
new file mode 100644
index 0000000..da62537
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/DSAPrivateKeyParameters.java
@@ -0,0 +1,23 @@
+package org.bc.crypto.params;
+
+import java.math.BigInteger;
+
+public class DSAPrivateKeyParameters
+ extends DSAKeyParameters
+{
+ private BigInteger x;
+
+ public DSAPrivateKeyParameters(
+ BigInteger x,
+ DSAParameters params)
+ {
+ super(true, params);
+
+ this.x = x;
+ }
+
+ public BigInteger getX()
+ {
+ return x;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/DSAPublicKeyParameters.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/DSAPublicKeyParameters.java
new file mode 100644
index 0000000..3337768
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/DSAPublicKeyParameters.java
@@ -0,0 +1,23 @@
+package org.bc.crypto.params;
+
+import java.math.BigInteger;
+
+public class DSAPublicKeyParameters
+ extends DSAKeyParameters
+{
+ private BigInteger y;
+
+ public DSAPublicKeyParameters(
+ BigInteger y,
+ DSAParameters params)
+ {
+ super(false, params);
+
+ this.y = y;
+ }
+
+ public BigInteger getY()
+ {
+ return y;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/DSAValidationParameters.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/DSAValidationParameters.java
new file mode 100644
index 0000000..fce829a
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/DSAValidationParameters.java
@@ -0,0 +1,50 @@
+package org.bc.crypto.params;
+
+import org.bc.util.Arrays;
+
+public class DSAValidationParameters
+{
+ private byte[] seed;
+ private int counter;
+
+ public DSAValidationParameters(
+ byte[] seed,
+ int counter)
+ {
+ this.seed = seed;
+ this.counter = counter;
+ }
+
+ public int getCounter()
+ {
+ return counter;
+ }
+
+ public byte[] getSeed()
+ {
+ return seed;
+ }
+
+ public int hashCode()
+ {
+ return counter ^ Arrays.hashCode(seed);
+ }
+
+ public boolean equals(
+ Object o)
+ {
+ if (!(o instanceof DSAValidationParameters))
+ {
+ return false;
+ }
+
+ DSAValidationParameters other = (DSAValidationParameters)o;
+
+ if (other.counter != this.counter)
+ {
+ return false;
+ }
+
+ return Arrays.areEqual(this.seed, other.seed);
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/ECDomainParameters.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/ECDomainParameters.java
new file mode 100644
index 0000000..6fa6a55
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/ECDomainParameters.java
@@ -0,0 +1,81 @@
+package org.bc.crypto.params;
+
+import java.math.BigInteger;
+
+import org.bc.math.ec.ECConstants;
+import org.bc.math.ec.ECCurve;
+import org.bc.math.ec.ECPoint;
+
+public class ECDomainParameters
+ implements ECConstants
+{
+ ECCurve curve;
+ byte[] seed;
+ ECPoint G;
+ BigInteger n;
+ BigInteger h;
+
+ public ECDomainParameters(
+ ECCurve curve,
+ ECPoint G,
+ BigInteger n)
+ {
+ this.curve = curve;
+ this.G = G;
+ this.n = n;
+ this.h = ONE;
+ this.seed = null;
+ }
+
+ public ECDomainParameters(
+ ECCurve curve,
+ ECPoint G,
+ BigInteger n,
+ BigInteger h)
+ {
+ this.curve = curve;
+ this.G = G;
+ this.n = n;
+ this.h = h;
+ this.seed = null;
+ }
+
+ public ECDomainParameters(
+ ECCurve curve,
+ ECPoint G,
+ BigInteger n,
+ BigInteger h,
+ byte[] seed)
+ {
+ this.curve = curve;
+ this.G = G;
+ this.n = n;
+ this.h = h;
+ this.seed = seed;
+ }
+
+ public ECCurve getCurve()
+ {
+ return curve;
+ }
+
+ public ECPoint getG()
+ {
+ return G;
+ }
+
+ public BigInteger getN()
+ {
+ return n;
+ }
+
+ public BigInteger getH()
+ {
+ return h;
+ }
+
+ public byte[] getSeed()
+ {
+ return seed;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/ECKeyGenerationParameters.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/ECKeyGenerationParameters.java
new file mode 100644
index 0000000..785b766
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/ECKeyGenerationParameters.java
@@ -0,0 +1,25 @@
+package org.bc.crypto.params;
+
+import java.security.SecureRandom;
+
+import org.bc.crypto.KeyGenerationParameters;
+
+public class ECKeyGenerationParameters
+ extends KeyGenerationParameters
+{
+ private ECDomainParameters domainParams;
+
+ public ECKeyGenerationParameters(
+ ECDomainParameters domainParams,
+ SecureRandom random)
+ {
+ super(random, domainParams.getN().bitLength());
+
+ this.domainParams = domainParams;
+ }
+
+ public ECDomainParameters getDomainParameters()
+ {
+ return domainParams;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/ECKeyParameters.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/ECKeyParameters.java
new file mode 100644
index 0000000..a95ea6b
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/ECKeyParameters.java
@@ -0,0 +1,21 @@
+package org.bc.crypto.params;
+
+public class ECKeyParameters
+ extends AsymmetricKeyParameter
+{
+ ECDomainParameters params;
+
+ protected ECKeyParameters(
+ boolean isPrivate,
+ ECDomainParameters params)
+ {
+ super(isPrivate);
+
+ this.params = params;
+ }
+
+ public ECDomainParameters getParameters()
+ {
+ return params;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/ECPrivateKeyParameters.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/ECPrivateKeyParameters.java
new file mode 100644
index 0000000..6166e9b
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/ECPrivateKeyParameters.java
@@ -0,0 +1,22 @@
+package org.bc.crypto.params;
+
+import java.math.BigInteger;
+
+public class ECPrivateKeyParameters
+ extends ECKeyParameters
+{
+ BigInteger d;
+
+ public ECPrivateKeyParameters(
+ BigInteger d,
+ ECDomainParameters params)
+ {
+ super(true, params);
+ this.d = d;
+ }
+
+ public BigInteger getD()
+ {
+ return d;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/ECPublicKeyParameters.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/ECPublicKeyParameters.java
new file mode 100644
index 0000000..7e63ad0
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/ECPublicKeyParameters.java
@@ -0,0 +1,22 @@
+package org.bc.crypto.params;
+
+import org.bc.math.ec.ECPoint;
+
+public class ECPublicKeyParameters
+ extends ECKeyParameters
+{
+ ECPoint Q;
+
+ public ECPublicKeyParameters(
+ ECPoint Q,
+ ECDomainParameters params)
+ {
+ super(false, params);
+ this.Q = Q;
+ }
+
+ public ECPoint getQ()
+ {
+ return Q;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/ElGamalKeyGenerationParameters.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/ElGamalKeyGenerationParameters.java
new file mode 100644
index 0000000..23bfbe7
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/ElGamalKeyGenerationParameters.java
@@ -0,0 +1,30 @@
+package org.bc.crypto.params;
+
+import java.security.SecureRandom;
+
+import org.bc.crypto.KeyGenerationParameters;
+
+public class ElGamalKeyGenerationParameters
+ extends KeyGenerationParameters
+{
+ private ElGamalParameters params;
+
+ public ElGamalKeyGenerationParameters(
+ SecureRandom random,
+ ElGamalParameters params)
+ {
+ super(random, getStrength(params));
+
+ this.params = params;
+ }
+
+ public ElGamalParameters getParameters()
+ {
+ return params;
+ }
+
+ static int getStrength(ElGamalParameters params)
+ {
+ return params.getL() != 0 ? params.getL() : params.getP().bitLength();
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/ElGamalKeyParameters.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/ElGamalKeyParameters.java
new file mode 100644
index 0000000..4f0a4a9
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/ElGamalKeyParameters.java
@@ -0,0 +1,47 @@
+package org.bc.crypto.params;
+
+
+public class ElGamalKeyParameters
+ extends AsymmetricKeyParameter
+{
+ private ElGamalParameters params;
+
+ protected ElGamalKeyParameters(
+ boolean isPrivate,
+ ElGamalParameters params)
+ {
+ super(isPrivate);
+
+ this.params = params;
+ }
+
+ public ElGamalParameters getParameters()
+ {
+ return params;
+ }
+
+ public int hashCode()
+ {
+ return (params != null) ? params.hashCode() : 0;
+ }
+
+ public boolean equals(
+ Object obj)
+ {
+ if (!(obj instanceof ElGamalKeyParameters))
+ {
+ return false;
+ }
+
+ ElGamalKeyParameters dhKey = (ElGamalKeyParameters)obj;
+
+ if (params == null)
+ {
+ return dhKey.getParameters() == null;
+ }
+ else
+ {
+ return params.equals(dhKey.getParameters());
+ }
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/ElGamalParameters.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/ElGamalParameters.java
new file mode 100644
index 0000000..1ba523a
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/ElGamalParameters.java
@@ -0,0 +1,69 @@
+package org.bc.crypto.params;
+
+import java.math.BigInteger;
+
+import org.bc.crypto.CipherParameters;
+
+public class ElGamalParameters
+ implements CipherParameters
+{
+ private BigInteger g;
+ private BigInteger p;
+ private int l;
+
+ public ElGamalParameters(
+ BigInteger p,
+ BigInteger g)
+ {
+ this(p, g, 0);
+ }
+
+ public ElGamalParameters(
+ BigInteger p,
+ BigInteger g,
+ int l)
+ {
+ this.g = g;
+ this.p = p;
+ this.l = l;
+ }
+
+ public BigInteger getP()
+ {
+ return p;
+ }
+
+ /**
+ * return the generator - g
+ */
+ public BigInteger getG()
+ {
+ return g;
+ }
+
+ /**
+ * return private value limit - l
+ */
+ public int getL()
+ {
+ return l;
+ }
+
+ public boolean equals(
+ Object obj)
+ {
+ if (!(obj instanceof ElGamalParameters))
+ {
+ return false;
+ }
+
+ ElGamalParameters pm = (ElGamalParameters)obj;
+
+ return pm.getP().equals(p) && pm.getG().equals(g) && pm.getL() == l;
+ }
+
+ public int hashCode()
+ {
+ return (getP().hashCode() ^ getG().hashCode()) + l;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/ElGamalPrivateKeyParameters.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/ElGamalPrivateKeyParameters.java
new file mode 100644
index 0000000..8bec291
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/ElGamalPrivateKeyParameters.java
@@ -0,0 +1,46 @@
+package org.bc.crypto.params;
+
+import java.math.BigInteger;
+
+public class ElGamalPrivateKeyParameters
+ extends ElGamalKeyParameters
+{
+ private BigInteger x;
+
+ public ElGamalPrivateKeyParameters(
+ BigInteger x,
+ ElGamalParameters params)
+ {
+ super(true, params);
+
+ this.x = x;
+ }
+
+ public BigInteger getX()
+ {
+ return x;
+ }
+
+ public boolean equals(
+ Object obj)
+ {
+ if (!(obj instanceof ElGamalPrivateKeyParameters))
+ {
+ return false;
+ }
+
+ ElGamalPrivateKeyParameters pKey = (ElGamalPrivateKeyParameters)obj;
+
+ if (!pKey.getX().equals(x))
+ {
+ return false;
+ }
+
+ return super.equals(obj);
+ }
+
+ public int hashCode()
+ {
+ return getX().hashCode();
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/ElGamalPublicKeyParameters.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/ElGamalPublicKeyParameters.java
new file mode 100644
index 0000000..fc26be7
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/ElGamalPublicKeyParameters.java
@@ -0,0 +1,41 @@
+package org.bc.crypto.params;
+
+import java.math.BigInteger;
+
+public class ElGamalPublicKeyParameters
+ extends ElGamalKeyParameters
+{
+ private BigInteger y;
+
+ public ElGamalPublicKeyParameters(
+ BigInteger y,
+ ElGamalParameters params)
+ {
+ super(false, params);
+
+ this.y = y;
+ }
+
+ public BigInteger getY()
+ {
+ return y;
+ }
+
+ public int hashCode()
+ {
+ return y.hashCode() ^ super.hashCode();
+ }
+
+ public boolean equals(
+ Object obj)
+ {
+ if (!(obj instanceof ElGamalPublicKeyParameters))
+ {
+ return false;
+ }
+
+ ElGamalPublicKeyParameters other = (ElGamalPublicKeyParameters)obj;
+
+ return other.getY().equals(y) && super.equals(obj);
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/GOST3410KeyGenerationParameters.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/GOST3410KeyGenerationParameters.java
new file mode 100644
index 0000000..066efe7
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/GOST3410KeyGenerationParameters.java
@@ -0,0 +1,25 @@
+package org.bc.crypto.params;
+
+import org.bc.crypto.KeyGenerationParameters;
+
+import java.security.SecureRandom;
+
+public class GOST3410KeyGenerationParameters
+ extends KeyGenerationParameters
+{
+ private GOST3410Parameters params;
+
+ public GOST3410KeyGenerationParameters(
+ SecureRandom random,
+ GOST3410Parameters params)
+ {
+ super(random, params.getP().bitLength() - 1);
+
+ this.params = params;
+ }
+
+ public GOST3410Parameters getParameters()
+ {
+ return params;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/GOST3410KeyParameters.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/GOST3410KeyParameters.java
new file mode 100644
index 0000000..ece2238
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/GOST3410KeyParameters.java
@@ -0,0 +1,21 @@
+package org.bc.crypto.params;
+
+public class GOST3410KeyParameters
+ extends AsymmetricKeyParameter
+{
+ private GOST3410Parameters params;
+
+ public GOST3410KeyParameters(
+ boolean isPrivate,
+ GOST3410Parameters params)
+ {
+ super(isPrivate);
+
+ this.params = params;
+ }
+
+ public GOST3410Parameters getParameters()
+ {
+ return params;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/GOST3410Parameters.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/GOST3410Parameters.java
new file mode 100644
index 0000000..0413297
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/GOST3410Parameters.java
@@ -0,0 +1,74 @@
+package org.bc.crypto.params;
+
+import org.bc.crypto.CipherParameters;
+
+import java.math.BigInteger;
+
+public class GOST3410Parameters
+ implements CipherParameters
+{
+ private BigInteger p;
+ private BigInteger q;
+ private BigInteger a;
+ private GOST3410ValidationParameters validation;
+
+ public GOST3410Parameters(
+ BigInteger p,
+ BigInteger q,
+ BigInteger a)
+ {
+ this.p = p;
+ this.q = q;
+ this.a = a;
+ }
+
+ public GOST3410Parameters(
+ BigInteger p,
+ BigInteger q,
+ BigInteger a,
+ GOST3410ValidationParameters params)
+ {
+ this.a = a;
+ this.p = p;
+ this.q = q;
+ this.validation = params;
+ }
+
+ public BigInteger getP()
+ {
+ return p;
+ }
+
+ public BigInteger getQ()
+ {
+ return q;
+ }
+
+ public BigInteger getA()
+ {
+ return a;
+ }
+
+ public GOST3410ValidationParameters getValidationParameters()
+ {
+ return validation;
+ }
+
+ public int hashCode()
+ {
+ return p.hashCode() ^ q.hashCode() ^ a.hashCode();
+ }
+
+ public boolean equals(
+ Object obj)
+ {
+ if (!(obj instanceof GOST3410Parameters))
+ {
+ return false;
+ }
+
+ GOST3410Parameters pm = (GOST3410Parameters)obj;
+
+ return (pm.getP().equals(p) && pm.getQ().equals(q) && pm.getA().equals(a));
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/GOST3410PrivateKeyParameters.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/GOST3410PrivateKeyParameters.java
new file mode 100644
index 0000000..27a4fe7
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/GOST3410PrivateKeyParameters.java
@@ -0,0 +1,23 @@
+package org.bc.crypto.params;
+
+import java.math.BigInteger;
+
+public class GOST3410PrivateKeyParameters
+ extends GOST3410KeyParameters
+{
+ private BigInteger x;
+
+ public GOST3410PrivateKeyParameters(
+ BigInteger x,
+ GOST3410Parameters params)
+ {
+ super(true, params);
+
+ this.x = x;
+ }
+
+ public BigInteger getX()
+ {
+ return x;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/GOST3410PublicKeyParameters.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/GOST3410PublicKeyParameters.java
new file mode 100644
index 0000000..a184c5f
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/GOST3410PublicKeyParameters.java
@@ -0,0 +1,23 @@
+package org.bc.crypto.params;
+
+import java.math.BigInteger;
+
+public class GOST3410PublicKeyParameters
+ extends GOST3410KeyParameters
+{
+ private BigInteger y;
+
+ public GOST3410PublicKeyParameters(
+ BigInteger y,
+ GOST3410Parameters params)
+ {
+ super(false, params);
+
+ this.y = y;
+ }
+
+ public BigInteger getY()
+ {
+ return y;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/GOST3410ValidationParameters.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/GOST3410ValidationParameters.java
new file mode 100644
index 0000000..2fa8dea
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/GOST3410ValidationParameters.java
@@ -0,0 +1,84 @@
+package org.bc.crypto.params;
+
+public class GOST3410ValidationParameters
+{
+ private int x0;
+ private int c;
+ private long x0L;
+ private long cL;
+
+
+ public GOST3410ValidationParameters(
+ int x0,
+ int c)
+ {
+ this.x0 = x0;
+ this.c = c;
+ }
+
+ public GOST3410ValidationParameters(
+ long x0L,
+ long cL)
+ {
+ this.x0L = x0L;
+ this.cL = cL;
+ }
+
+ public int getC()
+ {
+ return c;
+ }
+
+ public int getX0()
+ {
+ return x0;
+ }
+
+ public long getCL()
+ {
+ return cL;
+ }
+
+ public long getX0L()
+ {
+ return x0L;
+ }
+
+ public boolean equals(
+ Object o)
+ {
+ if (!(o instanceof GOST3410ValidationParameters))
+ {
+ return false;
+ }
+
+ GOST3410ValidationParameters other = (GOST3410ValidationParameters)o;
+
+ if (other.c != this.c)
+ {
+ return false;
+ }
+
+ if (other.x0 != this.x0)
+ {
+ return false;
+ }
+
+ if (other.cL != this.cL)
+ {
+ return false;
+ }
+
+ if (other.x0L != this.x0L)
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ public int hashCode()
+ {
+ return x0 ^ c ^ (int) x0L ^ (int)(x0L >> 32) ^ (int) cL ^ (int)(cL >> 32);
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/HKDFParameters.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/HKDFParameters.java
new file mode 100644
index 0000000..5e1f2c7
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/HKDFParameters.java
@@ -0,0 +1,123 @@
+package org.bc.crypto.params;
+
+import org.bc.crypto.DerivationParameters;
+import org.bc.util.Arrays;
+
+/**
+ * Parameter class for the HKDFBytesGenerator class.
+ */
+public class HKDFParameters
+ implements DerivationParameters
+{
+ private final byte[] ikm;
+ private final boolean skipExpand;
+ private final byte[] salt;
+ private final byte[] info;
+
+ private HKDFParameters(final byte[] ikm, final boolean skip,
+ final byte[] salt, final byte[] info)
+ {
+ if (ikm == null)
+ {
+ throw new IllegalArgumentException(
+ "IKM (input keying material) should not be null");
+ }
+
+ this.ikm = Arrays.clone(ikm);
+
+ this.skipExpand = skip;
+
+ if (salt == null || salt.length == 0)
+ {
+ this.salt = null;
+ }
+ else
+ {
+ this.salt = Arrays.clone(salt);
+ }
+
+ if (info == null)
+ {
+ this.info = new byte[0];
+ }
+ else
+ {
+ this.info = Arrays.clone(info);
+ }
+ }
+
+ /**
+ * Generates parameters for HKDF, specifying both the optional salt and
+ * optional info. Step 1: Extract won't be skipped.
+ *
+ * @param ikm the input keying material or seed
+ * @param salt the salt to use, may be null for a salt for hashLen zeros
+ * @param info the info to use, may be null for an info field of zero bytes
+ */
+ public HKDFParameters(final byte[] ikm, final byte[] salt, final byte[] info)
+ {
+ this(ikm, false, salt, info);
+ }
+
+ /**
+ * Factory method that makes the HKDF skip the extract part of the key
+ * derivation function.
+ *
+ * @param ikm the input keying material or seed, directly used for step 2:
+ * Expand
+ * @param info the info to use, may be null for an info field of zero bytes
+ * @return HKDFParameters that makes the implementation skip step 1
+ */
+ public static HKDFParameters skipExtractParameters(final byte[] ikm,
+ final byte[] info)
+ {
+
+ return new HKDFParameters(ikm, true, null, info);
+ }
+
+ public static HKDFParameters defaultParameters(final byte[] ikm)
+ {
+ return new HKDFParameters(ikm, false, null, null);
+ }
+
+ /**
+ * Returns the input keying material or seed.
+ *
+ * @return the keying material
+ */
+ public byte[] getIKM()
+ {
+ return Arrays.clone(ikm);
+ }
+
+ /**
+ * Returns if step 1: extract has to be skipped or not
+ *
+ * @return true for skipping, false for no skipping of step 1
+ */
+ public boolean skipExtract()
+ {
+ return skipExpand;
+ }
+
+ /**
+ * Returns the salt, or null if the salt should be generated as a byte array
+ * of HashLen zeros.
+ *
+ * @return the salt, or null
+ */
+ public byte[] getSalt()
+ {
+ return Arrays.clone(salt);
+ }
+
+ /**
+ * Returns the info field, which may be empty (null is converted to empty).
+ *
+ * @return the info field, never null
+ */
+ public byte[] getInfo()
+ {
+ return Arrays.clone(info);
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/IESParameters.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/IESParameters.java
new file mode 100644
index 0000000..a496e5c
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/IESParameters.java
@@ -0,0 +1,44 @@
+package org.bc.crypto.params;
+
+import org.bc.crypto.CipherParameters;
+
+/**
+ * parameters for using an integrated cipher in stream mode.
+ */
+public class IESParameters
+ implements CipherParameters
+{
+ private byte[] derivation;
+ private byte[] encoding;
+ private int macKeySize;
+
+ /**
+ * @param derivation the derivation parameter for the KDF function.
+ * @param encoding the encoding parameter for the KDF function.
+ * @param macKeySize the size of the MAC key (in bits).
+ */
+ public IESParameters(
+ byte[] derivation,
+ byte[] encoding,
+ int macKeySize)
+ {
+ this.derivation = derivation;
+ this.encoding = encoding;
+ this.macKeySize = macKeySize;
+ }
+
+ public byte[] getDerivationV()
+ {
+ return derivation;
+ }
+
+ public byte[] getEncodingV()
+ {
+ return encoding;
+ }
+
+ public int getMacKeySize()
+ {
+ return macKeySize;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/IESWithCipherParameters.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/IESWithCipherParameters.java
new file mode 100644
index 0000000..9b7f9d9
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/IESWithCipherParameters.java
@@ -0,0 +1,30 @@
+package org.bc.crypto.params;
+
+
+public class IESWithCipherParameters
+ extends IESParameters
+{
+ private int cipherKeySize;
+
+ /**
+ * @param derivation the derivation parameter for the KDF function.
+ * @param encoding the encoding parameter for the KDF function.
+ * @param macKeySize the size of the MAC key (in bits).
+ * @param cipherKeySize the size of the associated Cipher key (in bits).
+ */
+ public IESWithCipherParameters(
+ byte[] derivation,
+ byte[] encoding,
+ int macKeySize,
+ int cipherKeySize)
+ {
+ super(derivation, encoding, macKeySize);
+
+ this.cipherKeySize = cipherKeySize;
+ }
+
+ public int getCipherKeySize()
+ {
+ return cipherKeySize;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/ISO18033KDFParameters.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/ISO18033KDFParameters.java
new file mode 100644
index 0000000..071b46a
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/ISO18033KDFParameters.java
@@ -0,0 +1,23 @@
+package org.bc.crypto.params;
+
+import org.bc.crypto.DerivationParameters;
+
+/**
+ * parameters for Key derivation functions for ISO-18033
+ */
+public class ISO18033KDFParameters
+ implements DerivationParameters
+{
+ byte[] seed;
+
+ public ISO18033KDFParameters(
+ byte[] seed)
+ {
+ this.seed = seed;
+ }
+
+ public byte[] getSeed()
+ {
+ return seed;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/KDFParameters.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/KDFParameters.java
new file mode 100644
index 0000000..3ff305d
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/KDFParameters.java
@@ -0,0 +1,31 @@
+package org.bc.crypto.params;
+
+import org.bc.crypto.DerivationParameters;
+
+/**
+ * parameters for Key derivation functions for IEEE P1363a
+ */
+public class KDFParameters
+ implements DerivationParameters
+{
+ byte[] iv;
+ byte[] shared;
+
+ public KDFParameters(
+ byte[] shared,
+ byte[] iv)
+ {
+ this.shared = shared;
+ this.iv = iv;
+ }
+
+ public byte[] getSharedSecret()
+ {
+ return shared;
+ }
+
+ public byte[] getIV()
+ {
+ return iv;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/KeyParameter.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/KeyParameter.java
new file mode 100644
index 0000000..cab4b82
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/KeyParameter.java
@@ -0,0 +1,30 @@
+package org.bc.crypto.params;
+
+import org.bc.crypto.CipherParameters;
+
+public class KeyParameter
+ implements CipherParameters
+{
+ private byte[] key;
+
+ public KeyParameter(
+ byte[] key)
+ {
+ this(key, 0, key.length);
+ }
+
+ public KeyParameter(
+ byte[] key,
+ int keyOff,
+ int keyLen)
+ {
+ this.key = new byte[keyLen];
+
+ System.arraycopy(key, keyOff, this.key, 0, keyLen);
+ }
+
+ public byte[] getKey()
+ {
+ return key;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/MGFParameters.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/MGFParameters.java
new file mode 100644
index 0000000..753af93
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/MGFParameters.java
@@ -0,0 +1,32 @@
+package org.bc.crypto.params;
+
+import org.bc.crypto.DerivationParameters;
+
+/**
+ * parameters for mask derivation functions.
+ */
+public class MGFParameters
+ implements DerivationParameters
+{
+ byte[] seed;
+
+ public MGFParameters(
+ byte[] seed)
+ {
+ this(seed, 0, seed.length);
+ }
+
+ public MGFParameters(
+ byte[] seed,
+ int off,
+ int len)
+ {
+ this.seed = new byte[len];
+ System.arraycopy(seed, off, this.seed, 0, len);
+ }
+
+ public byte[] getSeed()
+ {
+ return seed;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/MQVPrivateParameters.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/MQVPrivateParameters.java
new file mode 100644
index 0000000..3b32378
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/MQVPrivateParameters.java
@@ -0,0 +1,43 @@
+package org.bc.crypto.params;
+
+import org.bc.crypto.CipherParameters;
+
+public class MQVPrivateParameters
+ implements CipherParameters
+{
+ private ECPrivateKeyParameters staticPrivateKey;
+ private ECPrivateKeyParameters ephemeralPrivateKey;
+ private ECPublicKeyParameters ephemeralPublicKey;
+
+ public MQVPrivateParameters(
+ ECPrivateKeyParameters staticPrivateKey,
+ ECPrivateKeyParameters ephemeralPrivateKey)
+ {
+ this(staticPrivateKey, ephemeralPrivateKey, null);
+ }
+
+ public MQVPrivateParameters(
+ ECPrivateKeyParameters staticPrivateKey,
+ ECPrivateKeyParameters ephemeralPrivateKey,
+ ECPublicKeyParameters ephemeralPublicKey)
+ {
+ this.staticPrivateKey = staticPrivateKey;
+ this.ephemeralPrivateKey = ephemeralPrivateKey;
+ this.ephemeralPublicKey = ephemeralPublicKey;
+ }
+
+ public ECPrivateKeyParameters getStaticPrivateKey()
+ {
+ return staticPrivateKey;
+ }
+
+ public ECPrivateKeyParameters getEphemeralPrivateKey()
+ {
+ return ephemeralPrivateKey;
+ }
+
+ public ECPublicKeyParameters getEphemeralPublicKey()
+ {
+ return ephemeralPublicKey;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/MQVPublicParameters.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/MQVPublicParameters.java
new file mode 100644
index 0000000..a5b1f61
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/MQVPublicParameters.java
@@ -0,0 +1,28 @@
+package org.bc.crypto.params;
+
+import org.bc.crypto.CipherParameters;
+
+public class MQVPublicParameters
+ implements CipherParameters
+{
+ private ECPublicKeyParameters staticPublicKey;
+ private ECPublicKeyParameters ephemeralPublicKey;
+
+ public MQVPublicParameters(
+ ECPublicKeyParameters staticPublicKey,
+ ECPublicKeyParameters ephemeralPublicKey)
+ {
+ this.staticPublicKey = staticPublicKey;
+ this.ephemeralPublicKey = ephemeralPublicKey;
+ }
+
+ public ECPublicKeyParameters getStaticPublicKey()
+ {
+ return staticPublicKey;
+ }
+
+ public ECPublicKeyParameters getEphemeralPublicKey()
+ {
+ return ephemeralPublicKey;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/NTRUEncryptionKeyGenerationParameters.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/NTRUEncryptionKeyGenerationParameters.java
new file mode 100644
index 0000000..85402f7
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/NTRUEncryptionKeyGenerationParameters.java
@@ -0,0 +1,463 @@
+package org.bc.crypto.params;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.security.SecureRandom;
+import java.util.Arrays;
+
+import org.bc.crypto.Digest;
+import org.bc.crypto.KeyGenerationParameters;
+import org.bc.crypto.digests.SHA256Digest;
+import org.bc.crypto.digests.SHA512Digest;
+
+/**
+ * A set of parameters for NtruEncrypt. Several predefined parameter sets are available and new ones can be created as well.
+ */
+public class NTRUEncryptionKeyGenerationParameters
+ extends KeyGenerationParameters
+ implements Cloneable
+{
+ /**
+ * A conservative (in terms of security) parameter set that gives 256 bits of security and is optimized for key size.
+ */
+ public static final NTRUEncryptionKeyGenerationParameters EES1087EP2 = new NTRUEncryptionKeyGenerationParameters(1087, 2048, 120, 120, 256, 13, 25, 14, true, new byte[]{0, 6, 3}, true, false, new SHA512Digest());
+
+ /**
+ * A conservative (in terms of security) parameter set that gives 256 bits of security and is a tradeoff between key size and encryption/decryption speed.
+ */
+ public static final NTRUEncryptionKeyGenerationParameters EES1171EP1 = new NTRUEncryptionKeyGenerationParameters(1171, 2048, 106, 106, 256, 13, 20, 15, true, new byte[]{0, 6, 4}, true, false, new SHA512Digest());
+
+ /**
+ * A conservative (in terms of security) parameter set that gives 256 bits of security and is optimized for encryption/decryption speed.
+ */
+ public static final NTRUEncryptionKeyGenerationParameters EES1499EP1 = new NTRUEncryptionKeyGenerationParameters(1499, 2048, 79, 79, 256, 13, 17, 19, true, new byte[]{0, 6, 5}, true, false, new SHA512Digest());
+
+ /**
+ * A parameter set that gives 128 bits of security and uses simple ternary polynomials.
+ */
+ public static final NTRUEncryptionKeyGenerationParameters APR2011_439 = new NTRUEncryptionKeyGenerationParameters(439, 2048, 146, 130, 128, 9, 32, 9, true, new byte[]{0, 7, 101}, true, false, new SHA256Digest());
+
+ /**
+ * Like
+ * Internal access to the digest is synchronized so a single one of these can be shared.
+ *
+ * Access to internals is synchronized so a single one of these can be shared.
+ *
+ * Based on an idea from Marcus Lippert.
+ *
+ * If fast is set to true, the code should be round about 8 times faster when
+ * generating a long sequence of random bytes. 20 bytes of random values using
+ * the fast mode take less than half a second on a Nokia e70. If fast is set to false,
+ * it takes round about 2500 ms.
+ *
+ * National Ukrainian standard of digital signature based on elliptic curves (DSTU 4145-2002).
+ *
+ * Note: the usual length for the salt is the length of the hash
+ * function used in bytes.
+ */
+public class ISO9796d2PSSSigner
+ implements SignerWithRecovery
+{
+ static final public int TRAILER_IMPLICIT = 0xBC;
+ static final public int TRAILER_RIPEMD160 = 0x31CC;
+ static final public int TRAILER_RIPEMD128 = 0x32CC;
+ static final public int TRAILER_SHA1 = 0x33CC;
+
+ private Digest digest;
+ private AsymmetricBlockCipher cipher;
+
+ private SecureRandom random;
+ private byte[] standardSalt;
+
+ private int hLen;
+ private int trailer;
+ private int keyBits;
+ private byte[] block;
+ private byte[] mBuf;
+ private int messageLength;
+ private int saltLength;
+ private boolean fullMessage;
+ private byte[] recoveredMessage;
+
+ /**
+ * Generate a signer for the with either implicit or explicit trailers
+ * for ISO9796-2, scheme 2 or 3.
+ *
+ * @param cipher base cipher to use for signature creation/verification
+ * @param digest digest to use.
+ * @param saltLength length of salt in bytes.
+ * @param implicit whether or not the trailer is implicit or gives the hash.
+ */
+ public ISO9796d2PSSSigner(
+ AsymmetricBlockCipher cipher,
+ Digest digest,
+ int saltLength,
+ boolean implicit)
+ {
+ this.cipher = cipher;
+ this.digest = digest;
+ this.hLen = digest.getDigestSize();
+ this.saltLength = saltLength;
+
+ if (implicit)
+ {
+ trailer = TRAILER_IMPLICIT;
+ }
+ else
+ {
+ if (digest instanceof SHA1Digest)
+ {
+ trailer = TRAILER_SHA1;
+ }
+ else if (digest instanceof RIPEMD160Digest)
+ {
+ trailer = TRAILER_RIPEMD160;
+ }
+ else if (digest instanceof RIPEMD128Digest)
+ {
+ trailer = TRAILER_RIPEMD128;
+ }
+ else
+ {
+ throw new IllegalArgumentException("no valid trailer for digest");
+ }
+ }
+ }
+
+ /**
+ * Constructor for a signer with an explicit digest trailer.
+ *
+ * @param cipher cipher to use.
+ * @param digest digest to sign with.
+ * @param saltLength length of salt in bytes.
+ */
+ public ISO9796d2PSSSigner(
+ AsymmetricBlockCipher cipher,
+ Digest digest,
+ int saltLength)
+ {
+ this(cipher, digest, saltLength, false);
+ }
+
+ /**
+ * Initialise the signer.
+ *
+ * @param forSigning true if for signing, false if for verification.
+ * @param param parameters for signature generation/verification. If the
+ * parameters are for generation they should be a ParametersWithRandom,
+ * a ParametersWithSalt, or just an RSAKeyParameters object. If RSAKeyParameters
+ * are passed in a SecureRandom will be created.
+ * @exception IllegalArgumentException if wrong parameter type or a fixed
+ * salt is passed in which is the wrong length.
+ */
+ public void init(
+ boolean forSigning,
+ CipherParameters param)
+ {
+ RSAKeyParameters kParam;
+ int lengthOfSalt = saltLength;
+
+ if (param instanceof ParametersWithRandom)
+ {
+ ParametersWithRandom p = (ParametersWithRandom)param;
+
+ kParam = (RSAKeyParameters)p.getParameters();
+ if (forSigning)
+ {
+ random = p.getRandom();
+ }
+ }
+ else if (param instanceof ParametersWithSalt)
+ {
+ ParametersWithSalt p = (ParametersWithSalt)param;
+
+ kParam = (RSAKeyParameters)p.getParameters();
+ standardSalt = p.getSalt();
+ lengthOfSalt = standardSalt.length;
+ if (standardSalt.length != saltLength)
+ {
+ throw new IllegalArgumentException("Fixed salt is of wrong length");
+ }
+ }
+ else
+ {
+ kParam = (RSAKeyParameters)param;
+ if (forSigning)
+ {
+ random = new SecureRandom();
+ }
+ }
+
+ cipher.init(forSigning, kParam);
+
+ keyBits = kParam.getModulus().bitLength();
+
+ block = new byte[(keyBits + 7) / 8];
+
+ if (trailer == TRAILER_IMPLICIT)
+ {
+ mBuf = new byte[block.length - digest.getDigestSize() - lengthOfSalt - 1 - 1];
+ }
+ else
+ {
+ mBuf = new byte[block.length - digest.getDigestSize() - lengthOfSalt - 1 - 2];
+ }
+
+ reset();
+ }
+
+ /**
+ * compare two byte arrays - constant time
+ */
+ private boolean isSameAs(
+ byte[] a,
+ byte[] b)
+ {
+ boolean isOkay = true;
+
+ if (messageLength != b.length)
+ {
+ isOkay = false;
+ }
+
+ for (int i = 0; i != b.length; i++)
+ {
+ if (a[i] != b[i])
+ {
+ isOkay = false;
+ }
+ }
+
+ return isOkay;
+ }
+
+ /**
+ * clear possible sensitive data
+ */
+ private void clearBlock(
+ byte[] block)
+ {
+ for (int i = 0; i != block.length; i++)
+ {
+ block[i] = 0;
+ }
+ }
+
+ public void updateWithRecoveredMessage(byte[] signature)
+ throws InvalidCipherTextException
+ {
+ throw new RuntimeException("not implemented"); // TODO:
+ }
+
+ /**
+ * update the internal digest with the byte b
+ */
+ public void update(
+ byte b)
+ {
+ if (messageLength < mBuf.length)
+ {
+ mBuf[messageLength++] = b;
+ }
+ else
+ {
+ digest.update(b);
+ }
+ }
+
+ /**
+ * update the internal digest with the byte array in
+ */
+ public void update(
+ byte[] in,
+ int off,
+ int len)
+ {
+ while (len > 0 && messageLength < mBuf.length)
+ {
+ this.update(in[off]);
+ off++;
+ len--;
+ }
+
+ if (len > 0)
+ {
+ digest.update(in, off, len);
+ }
+ }
+
+ /**
+ * reset the internal state
+ */
+ public void reset()
+ {
+ digest.reset();
+ messageLength = 0;
+ if (mBuf != null)
+ {
+ clearBlock(mBuf);
+ }
+ if (recoveredMessage != null)
+ {
+ clearBlock(recoveredMessage);
+ recoveredMessage = null;
+ }
+ fullMessage = false;
+ }
+
+ /**
+ * generate a signature for the loaded message using the key we were
+ * initialised with.
+ */
+ public byte[] generateSignature()
+ throws CryptoException
+ {
+ int digSize = digest.getDigestSize();
+
+ byte[] m2Hash = new byte[digSize];
+
+ digest.doFinal(m2Hash, 0);
+
+ byte[] C = new byte[8];
+ LtoOSP(messageLength * 8, C);
+
+ digest.update(C, 0, C.length);
+
+ digest.update(mBuf, 0, messageLength);
+
+ digest.update(m2Hash, 0, m2Hash.length);
+
+ byte[] salt;
+
+ if (standardSalt != null)
+ {
+ salt = standardSalt;
+ }
+ else
+ {
+ salt = new byte[saltLength];
+ random.nextBytes(salt);
+ }
+
+ digest.update(salt, 0, salt.length);
+
+ byte[] hash = new byte[digest.getDigestSize()];
+
+ digest.doFinal(hash, 0);
+
+ int tLength = 2;
+ if (trailer == TRAILER_IMPLICIT)
+ {
+ tLength = 1;
+ }
+
+ int off = block.length - messageLength - salt.length - hLen - tLength - 1;
+
+ block[off] = 0x01;
+
+ System.arraycopy(mBuf, 0, block, off + 1, messageLength);
+ System.arraycopy(salt, 0, block, off + 1 + messageLength, salt.length);
+
+ byte[] dbMask = maskGeneratorFunction1(hash, 0, hash.length, block.length - hLen - tLength);
+ for (int i = 0; i != dbMask.length; i++)
+ {
+ block[i] ^= dbMask[i];
+ }
+
+ System.arraycopy(hash, 0, block, block.length - hLen - tLength, hLen);
+
+ if (trailer == TRAILER_IMPLICIT)
+ {
+ block[block.length - 1] = (byte)TRAILER_IMPLICIT;
+ }
+ else
+ {
+ block[block.length - 2] = (byte)(trailer >>> 8);
+ block[block.length - 1] = (byte)trailer;
+ }
+
+ block[0] &= 0x7f;
+
+ byte[] b = cipher.processBlock(block, 0, block.length);
+
+ clearBlock(mBuf);
+ clearBlock(block);
+ messageLength = 0;
+
+ return b;
+ }
+
+ /**
+ * return true if the signature represents a ISO9796-2 signature
+ * for the passed in message.
+ */
+ public boolean verifySignature(
+ byte[] signature)
+ {
+ byte[] block;
+
+ try
+ {
+ block = cipher.processBlock(signature, 0, signature.length);
+ }
+ catch (Exception e)
+ {
+ return false;
+ }
+
+ //
+ // adjust block size for leading zeroes if necessary
+ //
+ if (block.length < (keyBits + 7) / 8)
+ {
+ byte[] tmp = new byte[(keyBits + 7) / 8];
+
+ System.arraycopy(block, 0, tmp, tmp.length - block.length, block.length);
+ clearBlock(block);
+ block = tmp;
+ }
+
+ int tLength;
+
+ if (((block[block.length - 1] & 0xFF) ^ 0xBC) == 0)
+ {
+ tLength = 1;
+ }
+ else
+ {
+ int sigTrail = ((block[block.length - 2] & 0xFF) << 8) | (block[block.length - 1] & 0xFF);
+
+ switch (sigTrail)
+ {
+ case TRAILER_RIPEMD160:
+ if (!(digest instanceof RIPEMD160Digest))
+ {
+ throw new IllegalStateException("signer should be initialised with RIPEMD160");
+ }
+ break;
+ case TRAILER_SHA1:
+ if (!(digest instanceof SHA1Digest))
+ {
+ throw new IllegalStateException("signer should be initialised with SHA1");
+ }
+ break;
+ case TRAILER_RIPEMD128:
+ if (!(digest instanceof RIPEMD128Digest))
+ {
+ throw new IllegalStateException("signer should be initialised with RIPEMD128");
+ }
+ break;
+ default:
+ throw new IllegalArgumentException("unrecognised hash in signature");
+ }
+
+ tLength = 2;
+ }
+
+ //
+ // calculate H(m2)
+ //
+ byte[] m2Hash = new byte[hLen];
+ digest.doFinal(m2Hash, 0);
+
+ //
+ // remove the mask
+ //
+ byte[] dbMask = maskGeneratorFunction1(block, block.length - hLen - tLength, hLen, block.length - hLen - tLength);
+ for (int i = 0; i != dbMask.length; i++)
+ {
+ block[i] ^= dbMask[i];
+ }
+
+ block[0] &= 0x7f;
+
+ //
+ // find out how much padding we've got
+ //
+ int mStart = 0;
+ for (; mStart != block.length; mStart++)
+ {
+ if (block[mStart] == 0x01)
+ {
+ break;
+ }
+ }
+
+ mStart++;
+
+ if (mStart >= block.length)
+ {
+ clearBlock(block);
+ return false;
+ }
+
+ fullMessage = (mStart > 1);
+
+ recoveredMessage = new byte[dbMask.length - mStart - saltLength];
+
+ System.arraycopy(block, mStart, recoveredMessage, 0, recoveredMessage.length);
+
+ //
+ // check the hashes
+ //
+ byte[] C = new byte[8];
+ LtoOSP(recoveredMessage.length * 8, C);
+
+ digest.update(C, 0, C.length);
+
+ if (recoveredMessage.length != 0)
+ {
+ digest.update(recoveredMessage, 0, recoveredMessage.length);
+ }
+
+ digest.update(m2Hash, 0, m2Hash.length);
+
+ // Update for the salt
+ digest.update(block, mStart + recoveredMessage.length, saltLength);
+
+ byte[] hash = new byte[digest.getDigestSize()];
+ digest.doFinal(hash, 0);
+
+ int off = block.length - tLength - hash.length;
+
+ boolean isOkay = true;
+
+ for (int i = 0; i != hash.length; i++)
+ {
+ if (hash[i] != block[off + i])
+ {
+ isOkay = false;
+ }
+ }
+
+ clearBlock(block);
+ clearBlock(hash);
+
+ if (!isOkay)
+ {
+ fullMessage = false;
+ clearBlock(recoveredMessage);
+ return false;
+ }
+
+ //
+ // if they've input a message check what we've recovered against
+ // what was input.
+ //
+ if (messageLength != 0)
+ {
+ if (!isSameAs(mBuf, recoveredMessage))
+ {
+ clearBlock(mBuf);
+ return false;
+ }
+
+ messageLength = 0;
+ }
+
+ clearBlock(mBuf);
+ return true;
+ }
+
+ /**
+ * Return true if the full message was recoveredMessage.
+ *
+ * @return true on full message recovery, false otherwise, or if not sure.
+ * @see org.bc.crypto.SignerWithRecovery#hasFullMessage()
+ */
+ public boolean hasFullMessage()
+ {
+ return fullMessage;
+ }
+
+ /**
+ * Return a reference to the recoveredMessage message.
+ *
+ * @return the full/partial recoveredMessage message.
+ * @see org.bc.crypto.SignerWithRecovery#getRecoveredMessage()
+ */
+ public byte[] getRecoveredMessage()
+ {
+ return recoveredMessage;
+ }
+
+ /**
+ * int to octet string.
+ */
+ private void ItoOSP(
+ int i,
+ byte[] sp)
+ {
+ sp[0] = (byte)(i >>> 24);
+ sp[1] = (byte)(i >>> 16);
+ sp[2] = (byte)(i >>> 8);
+ sp[3] = (byte)(i >>> 0);
+ }
+
+ /**
+ * long to octet string.
+ */
+ private void LtoOSP(
+ long l,
+ byte[] sp)
+ {
+ sp[0] = (byte)(l >>> 56);
+ sp[1] = (byte)(l >>> 48);
+ sp[2] = (byte)(l >>> 40);
+ sp[3] = (byte)(l >>> 32);
+ sp[4] = (byte)(l >>> 24);
+ sp[5] = (byte)(l >>> 16);
+ sp[6] = (byte)(l >>> 8);
+ sp[7] = (byte)(l >>> 0);
+ }
+ /**
+ * mask generator function, as described in PKCS1v2.
+ */
+ private byte[] maskGeneratorFunction1(
+ byte[] Z,
+ int zOff,
+ int zLen,
+ int length)
+ {
+ byte[] mask = new byte[length];
+ byte[] hashBuf = new byte[hLen];
+ byte[] C = new byte[4];
+ int counter = 0;
+
+ digest.reset();
+
+ while (counter < (length / hLen))
+ {
+ ItoOSP(counter, C);
+
+ digest.update(Z, zOff, zLen);
+ digest.update(C, 0, C.length);
+ digest.doFinal(hashBuf, 0);
+
+ System.arraycopy(hashBuf, 0, mask, counter * hLen, hLen);
+
+ counter++;
+ }
+
+ if ((counter * hLen) < length)
+ {
+ ItoOSP(counter, C);
+
+ digest.update(Z, zOff, zLen);
+ digest.update(C, 0, C.length);
+ digest.doFinal(hashBuf, 0);
+
+ System.arraycopy(hashBuf, 0, mask, counter * hLen, mask.length - (counter * hLen));
+ }
+
+ return mask;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/signers/ISO9796d2Signer.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/signers/ISO9796d2Signer.java
new file mode 100644
index 0000000..b10beab
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/signers/ISO9796d2Signer.java
@@ -0,0 +1,615 @@
+package org.bc.crypto.signers;
+
+import java.util.Hashtable;
+
+import org.bc.crypto.AsymmetricBlockCipher;
+import org.bc.crypto.CipherParameters;
+import org.bc.crypto.CryptoException;
+import org.bc.crypto.Digest;
+import org.bc.crypto.InvalidCipherTextException;
+import org.bc.crypto.SignerWithRecovery;
+import org.bc.crypto.params.RSAKeyParameters;
+import org.bc.util.Arrays;
+import org.bc.util.Integers;
+
+/**
+ * ISO9796-2 - mechanism using a hash function with recovery (scheme 1)
+ */
+public class ISO9796d2Signer
+ implements SignerWithRecovery
+{
+ static final public int TRAILER_IMPLICIT = 0xBC;
+ static final public int TRAILER_RIPEMD160 = 0x31CC;
+ static final public int TRAILER_RIPEMD128 = 0x32CC;
+ static final public int TRAILER_SHA1 = 0x33CC;
+ static final public int TRAILER_SHA256 = 0x34CC;
+ static final public int TRAILER_SHA512 = 0x35CC;
+ static final public int TRAILER_SHA384 = 0x36CC;
+ static final public int TRAILER_WHIRLPOOL = 0x37CC;
+
+ private static Hashtable trailerMap = new Hashtable();
+
+ static
+ {
+ trailerMap.put("RIPEMD128", Integers.valueOf(TRAILER_RIPEMD128));
+ trailerMap.put("RIPEMD160", Integers.valueOf(TRAILER_RIPEMD160));
+
+ trailerMap.put("SHA-1", Integers.valueOf(TRAILER_SHA1));
+ trailerMap.put("SHA-256", Integers.valueOf(TRAILER_SHA256));
+ trailerMap.put("SHA-384", Integers.valueOf(TRAILER_SHA384));
+ trailerMap.put("SHA-512", Integers.valueOf(TRAILER_SHA512));
+
+ trailerMap.put("Whirlpool", Integers.valueOf(TRAILER_WHIRLPOOL));
+ }
+
+ private Digest digest;
+ private AsymmetricBlockCipher cipher;
+
+ private int trailer;
+ private int keyBits;
+ private byte[] block;
+ private byte[] mBuf;
+ private int messageLength;
+ private boolean fullMessage;
+ private byte[] recoveredMessage;
+
+ private byte[] preSig;
+ private byte[] preBlock;
+
+ /**
+ * Generate a signer for the with either implicit or explicit trailers
+ * for ISO9796-2.
+ *
+ * @param cipher base cipher to use for signature creation/verification
+ * @param digest digest to use.
+ * @param implicit whether or not the trailer is implicit or gives the hash.
+ */
+ public ISO9796d2Signer(
+ AsymmetricBlockCipher cipher,
+ Digest digest,
+ boolean implicit)
+ {
+ this.cipher = cipher;
+ this.digest = digest;
+
+ if (implicit)
+ {
+ trailer = TRAILER_IMPLICIT;
+ }
+ else
+ {
+ Integer trailerObj = (Integer)trailerMap.get(digest.getAlgorithmName());
+
+ if (trailerObj != null)
+ {
+ trailer = trailerObj.intValue();
+ }
+ else
+ {
+ throw new IllegalArgumentException("no valid trailer for digest");
+ }
+ }
+ }
+
+ /**
+ * Constructor for a signer with an explicit digest trailer.
+ *
+ * @param cipher cipher to use.
+ * @param digest digest to sign with.
+ */
+ public ISO9796d2Signer(
+ AsymmetricBlockCipher cipher,
+ Digest digest)
+ {
+ this(cipher, digest, false);
+ }
+
+ public void init(
+ boolean forSigning,
+ CipherParameters param)
+ {
+ RSAKeyParameters kParam = (RSAKeyParameters)param;
+
+ cipher.init(forSigning, kParam);
+
+ keyBits = kParam.getModulus().bitLength();
+
+ block = new byte[(keyBits + 7) / 8];
+
+ if (trailer == TRAILER_IMPLICIT)
+ {
+ mBuf = new byte[block.length - digest.getDigestSize() - 2];
+ }
+ else
+ {
+ mBuf = new byte[block.length - digest.getDigestSize() - 3];
+ }
+
+ reset();
+ }
+
+ /**
+ * compare two byte arrays - constant time
+ */
+ private boolean isSameAs(
+ byte[] a,
+ byte[] b)
+ {
+ boolean isOkay = true;
+
+ if (messageLength > mBuf.length)
+ {
+ if (mBuf.length > b.length)
+ {
+ isOkay = false;
+ }
+
+ for (int i = 0; i != mBuf.length; i++)
+ {
+ if (a[i] != b[i])
+ {
+ isOkay = false;
+ }
+ }
+ }
+ else
+ {
+ if (messageLength != b.length)
+ {
+ isOkay = false;
+ }
+
+ for (int i = 0; i != b.length; i++)
+ {
+ if (a[i] != b[i])
+ {
+ isOkay = false;
+ }
+ }
+ }
+
+ return isOkay;
+ }
+
+ /**
+ * clear possible sensitive data
+ */
+ private void clearBlock(
+ byte[] block)
+ {
+ for (int i = 0; i != block.length; i++)
+ {
+ block[i] = 0;
+ }
+ }
+
+ public void updateWithRecoveredMessage(byte[] signature)
+ throws InvalidCipherTextException
+ {
+ byte[] block = cipher.processBlock(signature, 0, signature.length);
+
+ if (((block[0] & 0xC0) ^ 0x40) != 0)
+ {
+ throw new InvalidCipherTextException("malformed signature");
+ }
+
+ if (((block[block.length - 1] & 0xF) ^ 0xC) != 0)
+ {
+ throw new InvalidCipherTextException("malformed signature");
+ }
+
+ int delta = 0;
+
+ if (((block[block.length - 1] & 0xFF) ^ 0xBC) == 0)
+ {
+ delta = 1;
+ }
+ else
+ {
+ int sigTrail = ((block[block.length - 2] & 0xFF) << 8) | (block[block.length - 1] & 0xFF);
+ Integer trailerObj = (Integer)trailerMap.get(digest.getAlgorithmName());
+
+ if (trailerObj != null)
+ {
+ if (sigTrail != trailerObj.intValue())
+ {
+ throw new IllegalStateException("signer initialised with wrong digest for trailer " + sigTrail);
+ }
+ }
+ else
+ {
+ throw new IllegalArgumentException("unrecognised hash in signature");
+ }
+
+ delta = 2;
+ }
+
+ //
+ // find out how much padding we've got
+ //
+ int mStart = 0;
+
+ for (mStart = 0; mStart != block.length; mStart++)
+ {
+ if (((block[mStart] & 0x0f) ^ 0x0a) == 0)
+ {
+ break;
+ }
+ }
+
+ mStart++;
+
+ int off = block.length - delta - digest.getDigestSize();
+
+ //
+ // there must be at least one byte of message string
+ //
+ if ((off - mStart) <= 0)
+ {
+ throw new InvalidCipherTextException("malformed block");
+ }
+
+ //
+ // if we contain the whole message as well, check the hash of that.
+ //
+ if ((block[0] & 0x20) == 0)
+ {
+ fullMessage = true;
+
+ recoveredMessage = new byte[off - mStart];
+ System.arraycopy(block, mStart, recoveredMessage, 0, recoveredMessage.length);
+ }
+ else
+ {
+ fullMessage = false;
+
+ recoveredMessage = new byte[off - mStart];
+ System.arraycopy(block, mStart, recoveredMessage, 0, recoveredMessage.length);
+ }
+
+ preSig = signature;
+ preBlock = block;
+
+ digest.update(recoveredMessage, 0, recoveredMessage.length);
+ messageLength = recoveredMessage.length;
+ }
+
+ /**
+ * update the internal digest with the byte b
+ */
+ public void update(
+ byte b)
+ {
+ digest.update(b);
+
+ if (preSig == null && messageLength < mBuf.length)
+ {
+ mBuf[messageLength] = b;
+ }
+
+ messageLength++;
+ }
+
+ /**
+ * update the internal digest with the byte array in
+ */
+ public void update(
+ byte[] in,
+ int off,
+ int len)
+ {
+ digest.update(in, off, len);
+
+ if (preSig == null && messageLength < mBuf.length)
+ {
+ for (int i = 0; i < len && (i + messageLength) < mBuf.length; i++)
+ {
+ mBuf[messageLength + i] = in[off + i];
+ }
+ }
+
+ messageLength += len;
+ }
+
+ /**
+ * reset the internal state
+ */
+ public void reset()
+ {
+ digest.reset();
+ messageLength = 0;
+ clearBlock(mBuf);
+
+ if (recoveredMessage != null)
+ {
+ clearBlock(recoveredMessage);
+ }
+
+ recoveredMessage = null;
+ fullMessage = false;
+ }
+
+ /**
+ * generate a signature for the loaded message using the key we were
+ * initialised with.
+ */
+ public byte[] generateSignature()
+ throws CryptoException
+ {
+ int digSize = digest.getDigestSize();
+
+ int t = 0;
+ int delta = 0;
+
+ if (trailer == TRAILER_IMPLICIT)
+ {
+ t = 8;
+ delta = block.length - digSize - 1;
+ digest.doFinal(block, delta);
+ block[block.length - 1] = (byte)TRAILER_IMPLICIT;
+ }
+ else
+ {
+ t = 16;
+ delta = block.length - digSize - 2;
+ digest.doFinal(block, delta);
+ block[block.length - 2] = (byte)(trailer >>> 8);
+ block[block.length - 1] = (byte)trailer;
+ }
+
+ byte header = 0;
+ int x = (digSize + messageLength) * 8 + t + 4 - keyBits;
+
+ if (x > 0)
+ {
+ int mR = messageLength - ((x + 7) / 8);
+ header = 0x60;
+
+ delta -= mR;
+
+ System.arraycopy(mBuf, 0, block, delta, mR);
+ }
+ else
+ {
+ header = 0x40;
+ delta -= messageLength;
+
+ System.arraycopy(mBuf, 0, block, delta, messageLength);
+ }
+
+ if ((delta - 1) > 0)
+ {
+ for (int i = delta - 1; i != 0; i--)
+ {
+ block[i] = (byte)0xbb;
+ }
+ block[delta - 1] ^= (byte)0x01;
+ block[0] = (byte)0x0b;
+ block[0] |= header;
+ }
+ else
+ {
+ block[0] = (byte)0x0a;
+ block[0] |= header;
+ }
+
+ byte[] b = cipher.processBlock(block, 0, block.length);
+
+ clearBlock(mBuf);
+ clearBlock(block);
+
+ return b;
+ }
+
+ /**
+ * return true if the signature represents a ISO9796-2 signature
+ * for the passed in message.
+ */
+ public boolean verifySignature(
+ byte[] signature)
+ {
+ byte[] block = null;
+ boolean updateWithRecoveredCalled;
+
+ if (preSig == null)
+ {
+ updateWithRecoveredCalled = false;
+ try
+ {
+ block = cipher.processBlock(signature, 0, signature.length);
+ }
+ catch (Exception e)
+ {
+ return false;
+ }
+ }
+ else
+ {
+ if (!Arrays.areEqual(preSig, signature))
+ {
+ throw new IllegalStateException("updateWithRecoveredMessage called on different signature");
+ }
+
+ updateWithRecoveredCalled = true;
+ block = preBlock;
+
+ preSig = null;
+ preBlock = null;
+ }
+
+ if (((block[0] & 0xC0) ^ 0x40) != 0)
+ {
+ return returnFalse(block);
+ }
+
+ if (((block[block.length - 1] & 0xF) ^ 0xC) != 0)
+ {
+ return returnFalse(block);
+ }
+
+ int delta = 0;
+
+ if (((block[block.length - 1] & 0xFF) ^ 0xBC) == 0)
+ {
+ delta = 1;
+ }
+ else
+ {
+ int sigTrail = ((block[block.length - 2] & 0xFF) << 8) | (block[block.length - 1] & 0xFF);
+ Integer trailerObj = (Integer)trailerMap.get(digest.getAlgorithmName());
+
+ if (trailerObj != null)
+ {
+ if (sigTrail != trailerObj.intValue())
+ {
+ throw new IllegalStateException("signer initialised with wrong digest for trailer " + sigTrail);
+ }
+ }
+ else
+ {
+ throw new IllegalArgumentException("unrecognised hash in signature");
+ }
+
+ delta = 2;
+ }
+
+ //
+ // find out how much padding we've got
+ //
+ int mStart = 0;
+
+ for (mStart = 0; mStart != block.length; mStart++)
+ {
+ if (((block[mStart] & 0x0f) ^ 0x0a) == 0)
+ {
+ break;
+ }
+ }
+
+ mStart++;
+
+ //
+ // check the hashes
+ //
+ byte[] hash = new byte[digest.getDigestSize()];
+
+ int off = block.length - delta - hash.length;
+
+ //
+ // there must be at least one byte of message string
+ //
+ if ((off - mStart) <= 0)
+ {
+ return returnFalse(block);
+ }
+
+ //
+ // if we contain the whole message as well, check the hash of that.
+ //
+ if ((block[0] & 0x20) == 0)
+ {
+ fullMessage = true;
+
+ // check right number of bytes passed in.
+ if (messageLength > off - mStart)
+ {
+ return returnFalse(block);
+ }
+
+ digest.reset();
+ digest.update(block, mStart, off - mStart);
+ digest.doFinal(hash, 0);
+
+ boolean isOkay = true;
+
+ for (int i = 0; i != hash.length; i++)
+ {
+ block[off + i] ^= hash[i];
+ if (block[off + i] != 0)
+ {
+ isOkay = false;
+ }
+ }
+
+ if (!isOkay)
+ {
+ return returnFalse(block);
+ }
+
+ recoveredMessage = new byte[off - mStart];
+ System.arraycopy(block, mStart, recoveredMessage, 0, recoveredMessage.length);
+ }
+ else
+ {
+ fullMessage = false;
+
+ digest.doFinal(hash, 0);
+
+ boolean isOkay = true;
+
+ for (int i = 0; i != hash.length; i++)
+ {
+ block[off + i] ^= hash[i];
+ if (block[off + i] != 0)
+ {
+ isOkay = false;
+ }
+ }
+
+ if (!isOkay)
+ {
+ return returnFalse(block);
+ }
+
+ recoveredMessage = new byte[off - mStart];
+ System.arraycopy(block, mStart, recoveredMessage, 0, recoveredMessage.length);
+ }
+
+ //
+ // if they've input a message check what we've recovered against
+ // what was input.
+ //
+ if (messageLength != 0 && !updateWithRecoveredCalled)
+ {
+ if (!isSameAs(mBuf, recoveredMessage))
+ {
+ return returnFalse(block);
+ }
+ }
+
+ clearBlock(mBuf);
+ clearBlock(block);
+
+ return true;
+ }
+
+ private boolean returnFalse(byte[] block)
+ {
+ clearBlock(mBuf);
+ clearBlock(block);
+
+ return false;
+ }
+
+ /**
+ * Return true if the full message was recoveredMessage.
+ *
+ * @return true on full message recovery, false otherwise.
+ * @see org.bc.crypto.SignerWithRecovery#hasFullMessage()
+ */
+ public boolean hasFullMessage()
+ {
+ return fullMessage;
+ }
+
+ /**
+ * Return a reference to the recoveredMessage message.
+ *
+ * @return the full/partial recoveredMessage message.
+ * @see org.bc.crypto.SignerWithRecovery#getRecoveredMessage()
+ */
+ public byte[] getRecoveredMessage()
+ {
+ return recoveredMessage;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/signers/NTRUSigner.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/signers/NTRUSigner.java
new file mode 100644
index 0000000..64d3f6c
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/signers/NTRUSigner.java
@@ -0,0 +1,262 @@
+package org.bc.crypto.signers;
+
+import java.nio.ByteBuffer;
+
+import org.bc.crypto.CipherParameters;
+import org.bc.crypto.Digest;
+import org.bc.crypto.params.NTRUSigningParameters;
+import org.bc.crypto.params.NTRUSigningPrivateKeyParameters;
+import org.bc.crypto.params.NTRUSigningPublicKeyParameters;
+import org.bc.math.ntru.polynomial.IntegerPolynomial;
+import org.bc.math.ntru.polynomial.Polynomial;
+
+/**
+ * Signs, verifies data and generates key pairs.
+ */
+public class NTRUSigner
+{
+ private NTRUSigningParameters params;
+ private Digest hashAlg;
+ private NTRUSigningPrivateKeyParameters signingKeyPair;
+ private NTRUSigningPublicKeyParameters verificationKey;
+
+ /**
+ * Constructs a new instance with a set of signature parameters.
+ *
+ * @param params signature parameters
+ */
+ public NTRUSigner(NTRUSigningParameters params)
+ {
+ this.params = params;
+ }
+
+ /**
+ * Resets the engine for signing a message.
+ *
+ * @param forSigning
+ * @param params
+ */
+ public void init(boolean forSigning, CipherParameters params)
+ {
+ if (forSigning)
+ {
+ this.signingKeyPair = (NTRUSigningPrivateKeyParameters)params;
+ }
+ else
+ {
+ this.verificationKey = (NTRUSigningPublicKeyParameters)params;
+ }
+ hashAlg = this.params.hashAlg;
+ hashAlg.reset();
+ }
+
+ /**
+ * Adds data to sign or verify.
+ *
+ * @param b data
+ */
+ public void update(byte b)
+ {
+ if (hashAlg == null)
+ {
+ throw new IllegalStateException("Call initSign or initVerify first!");
+ }
+
+ hashAlg.update(b);
+ }
+
+ /**
+ * Adds data to sign or verify.
+ *
+ * @param m data
+ * @param off offset
+ * @param length number of bytes
+ */
+ public void update(byte[] m, int off, int length)
+ {
+ if (hashAlg == null)
+ {
+ throw new IllegalStateException("Call initSign or initVerify first!");
+ }
+
+ hashAlg.update(m, off, length);
+ }
+
+ /**
+ * Adds data to sign and computes a signature over this data and any data previously added via {@link #update(byte[], int, int)}.
+ *
+ * @return a signature
+ * @throws IllegalStateException if
+ * Note: the usual value for the salt length is the number of
+ * bytes in the hash function.
+ */
+public class PSSSigner
+ implements Signer
+{
+ static final public byte TRAILER_IMPLICIT = (byte)0xBC;
+
+ private Digest contentDigest;
+ private Digest mgfDigest;
+ private AsymmetricBlockCipher cipher;
+ private SecureRandom random;
+
+ private int hLen;
+ private int mgfhLen;
+ private int sLen;
+ private int emBits;
+ private byte[] salt;
+ private byte[] mDash;
+ private byte[] block;
+ private byte trailer;
+
+ /**
+ * basic constructor
+ *
+ * @param cipher the asymmetric cipher to use.
+ * @param digest the digest to use.
+ * @param sLen the length of the salt to use (in bytes).
+ */
+ public PSSSigner(
+ AsymmetricBlockCipher cipher,
+ Digest digest,
+ int sLen)
+ {
+ this(cipher, digest, sLen, TRAILER_IMPLICIT);
+ }
+
+ public PSSSigner(
+ AsymmetricBlockCipher cipher,
+ Digest contentDigest,
+ Digest mgfDigest,
+ int sLen)
+ {
+ this(cipher, contentDigest, mgfDigest, sLen, TRAILER_IMPLICIT);
+ }
+
+ public PSSSigner(
+ AsymmetricBlockCipher cipher,
+ Digest digest,
+ int sLen,
+ byte trailer)
+ {
+ this(cipher, digest, digest, sLen, trailer);
+ }
+
+ public PSSSigner(
+ AsymmetricBlockCipher cipher,
+ Digest contentDigest,
+ Digest mgfDigest,
+ int sLen,
+ byte trailer)
+ {
+ this.cipher = cipher;
+ this.contentDigest = contentDigest;
+ this.mgfDigest = mgfDigest;
+ this.hLen = contentDigest.getDigestSize();
+ this.mgfhLen = mgfDigest.getDigestSize();
+ this.sLen = sLen;
+ this.salt = new byte[sLen];
+ this.mDash = new byte[8 + sLen + hLen];
+ this.trailer = trailer;
+ }
+
+ public void init(
+ boolean forSigning,
+ CipherParameters param)
+ {
+ CipherParameters params;
+
+ if (param instanceof ParametersWithRandom)
+ {
+ ParametersWithRandom p = (ParametersWithRandom)param;
+
+ params = p.getParameters();
+ random = p.getRandom();
+ }
+ else
+ {
+ params = param;
+ if (forSigning)
+ {
+ random = new SecureRandom();
+ }
+ }
+
+ cipher.init(forSigning, params);
+
+ RSAKeyParameters kParam;
+
+ if (params instanceof RSABlindingParameters)
+ {
+ kParam = ((RSABlindingParameters)params).getPublicKey();
+ }
+ else
+ {
+ kParam = (RSAKeyParameters)params;
+ }
+
+ emBits = kParam.getModulus().bitLength() - 1;
+
+ if (emBits < (8 * hLen + 8 * sLen + 9))
+ {
+ throw new IllegalArgumentException("key too small for specified hash and salt lengths");
+ }
+
+ block = new byte[(emBits + 7) / 8];
+
+ reset();
+ }
+
+ /**
+ * clear possible sensitive data
+ */
+ private void clearBlock(
+ byte[] block)
+ {
+ for (int i = 0; i != block.length; i++)
+ {
+ block[i] = 0;
+ }
+ }
+
+ /**
+ * update the internal digest with the byte b
+ */
+ public void update(
+ byte b)
+ {
+ contentDigest.update(b);
+ }
+
+ /**
+ * update the internal digest with the byte array in
+ */
+ public void update(
+ byte[] in,
+ int off,
+ int len)
+ {
+ contentDigest.update(in, off, len);
+ }
+
+ /**
+ * reset the internal state
+ */
+ public void reset()
+ {
+ contentDigest.reset();
+ }
+
+ /**
+ * generate a signature for the message we've been loaded with using
+ * the key we were initialised with.
+ */
+ public byte[] generateSignature()
+ throws CryptoException, DataLengthException
+ {
+ contentDigest.doFinal(mDash, mDash.length - hLen - sLen);
+
+ if (sLen != 0)
+ {
+ random.nextBytes(salt);
+
+ System.arraycopy(salt, 0, mDash, mDash.length - sLen, sLen);
+ }
+
+ byte[] h = new byte[hLen];
+
+ contentDigest.update(mDash, 0, mDash.length);
+
+ contentDigest.doFinal(h, 0);
+
+ block[block.length - sLen - 1 - hLen - 1] = 0x01;
+ System.arraycopy(salt, 0, block, block.length - sLen - hLen - 1, sLen);
+
+ byte[] dbMask = maskGeneratorFunction1(h, 0, h.length, block.length - hLen - 1);
+ for (int i = 0; i != dbMask.length; i++)
+ {
+ block[i] ^= dbMask[i];
+ }
+
+ block[0] &= (0xff >> ((block.length * 8) - emBits));
+
+ System.arraycopy(h, 0, block, block.length - hLen - 1, hLen);
+
+ block[block.length - 1] = trailer;
+
+ byte[] b = cipher.processBlock(block, 0, block.length);
+
+ clearBlock(block);
+
+ return b;
+ }
+
+ /**
+ * return true if the internal state represents the signature described
+ * in the passed in array.
+ */
+ public boolean verifySignature(
+ byte[] signature)
+ {
+ contentDigest.doFinal(mDash, mDash.length - hLen - sLen);
+
+ try
+ {
+ byte[] b = cipher.processBlock(signature, 0, signature.length);
+ System.arraycopy(b, 0, block, block.length - b.length, b.length);
+ }
+ catch (Exception e)
+ {
+ return false;
+ }
+
+ if (block[block.length - 1] != trailer)
+ {
+ clearBlock(block);
+ return false;
+ }
+
+ byte[] dbMask = maskGeneratorFunction1(block, block.length - hLen - 1, hLen, block.length - hLen - 1);
+
+ for (int i = 0; i != dbMask.length; i++)
+ {
+ block[i] ^= dbMask[i];
+ }
+
+ block[0] &= (0xff >> ((block.length * 8) - emBits));
+
+ for (int i = 0; i != block.length - hLen - sLen - 2; i++)
+ {
+ if (block[i] != 0)
+ {
+ clearBlock(block);
+ return false;
+ }
+ }
+
+ if (block[block.length - hLen - sLen - 2] != 0x01)
+ {
+ clearBlock(block);
+ return false;
+ }
+
+ System.arraycopy(block, block.length - sLen - hLen - 1, mDash, mDash.length - sLen, sLen);
+
+ contentDigest.update(mDash, 0, mDash.length);
+ contentDigest.doFinal(mDash, mDash.length - hLen);
+
+ for (int i = block.length - hLen - 1, j = mDash.length - hLen;
+ j != mDash.length; i++, j++)
+ {
+ if ((block[i] ^ mDash[j]) != 0)
+ {
+ clearBlock(mDash);
+ clearBlock(block);
+ return false;
+ }
+ }
+
+ clearBlock(mDash);
+ clearBlock(block);
+
+ return true;
+ }
+
+ /**
+ * int to octet string.
+ */
+ private void ItoOSP(
+ int i,
+ byte[] sp)
+ {
+ sp[0] = (byte)(i >>> 24);
+ sp[1] = (byte)(i >>> 16);
+ sp[2] = (byte)(i >>> 8);
+ sp[3] = (byte)(i >>> 0);
+ }
+
+ /**
+ * mask generator function, as described in PKCS1v2.
+ */
+ private byte[] maskGeneratorFunction1(
+ byte[] Z,
+ int zOff,
+ int zLen,
+ int length)
+ {
+ byte[] mask = new byte[length];
+ byte[] hashBuf = new byte[mgfhLen];
+ byte[] C = new byte[4];
+ int counter = 0;
+
+ mgfDigest.reset();
+
+ while (counter < (length / mgfhLen))
+ {
+ ItoOSP(counter, C);
+
+ mgfDigest.update(Z, zOff, zLen);
+ mgfDigest.update(C, 0, C.length);
+ mgfDigest.doFinal(hashBuf, 0);
+
+ System.arraycopy(hashBuf, 0, mask, counter * mgfhLen, mgfhLen);
+
+ counter++;
+ }
+
+ if ((counter * mgfhLen) < length)
+ {
+ ItoOSP(counter, C);
+
+ mgfDigest.update(Z, zOff, zLen);
+ mgfDigest.update(C, 0, C.length);
+ mgfDigest.doFinal(hashBuf, 0);
+
+ System.arraycopy(hashBuf, 0, mask, counter * mgfhLen, mask.length - (counter * mgfhLen));
+ }
+
+ return mask;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/signers/RSADigestSigner.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/signers/RSADigestSigner.java
new file mode 100644
index 0000000..9f30a8e
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/signers/RSADigestSigner.java
@@ -0,0 +1,232 @@
+package org.bc.crypto.signers;
+
+import java.io.IOException;
+import java.util.Hashtable;
+
+import org.bc.asn1.ASN1Encoding;
+import org.bc.asn1.ASN1ObjectIdentifier;
+import org.bc.asn1.DERNull;
+import org.bc.asn1.nist.NISTObjectIdentifiers;
+import org.bc.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bc.asn1.teletrust.TeleTrusTObjectIdentifiers;
+import org.bc.asn1.x509.AlgorithmIdentifier;
+import org.bc.asn1.x509.DigestInfo;
+import org.bc.asn1.x509.X509ObjectIdentifiers;
+import org.bc.crypto.AsymmetricBlockCipher;
+import org.bc.crypto.CipherParameters;
+import org.bc.crypto.CryptoException;
+import org.bc.crypto.DataLengthException;
+import org.bc.crypto.Digest;
+import org.bc.crypto.Signer;
+import org.bc.crypto.encodings.PKCS1Encoding;
+import org.bc.crypto.engines.RSABlindedEngine;
+import org.bc.crypto.params.AsymmetricKeyParameter;
+import org.bc.crypto.params.ParametersWithRandom;
+import org.bc.util.Arrays;
+
+public class RSADigestSigner
+ implements Signer
+{
+ private final AsymmetricBlockCipher rsaEngine = new PKCS1Encoding(new RSABlindedEngine());
+ private final AlgorithmIdentifier algId;
+ private final Digest digest;
+ private boolean forSigning;
+
+ private static final Hashtable oidMap = new Hashtable();
+
+ /*
+ * Load OID table.
+ */
+ static
+ {
+ oidMap.put("RIPEMD128", TeleTrusTObjectIdentifiers.ripemd128);
+ oidMap.put("RIPEMD160", TeleTrusTObjectIdentifiers.ripemd160);
+ oidMap.put("RIPEMD256", TeleTrusTObjectIdentifiers.ripemd256);
+
+ oidMap.put("SHA-1", X509ObjectIdentifiers.id_SHA1);
+ oidMap.put("SHA-224", NISTObjectIdentifiers.id_sha224);
+ oidMap.put("SHA-256", NISTObjectIdentifiers.id_sha256);
+ oidMap.put("SHA-384", NISTObjectIdentifiers.id_sha384);
+ oidMap.put("SHA-512", NISTObjectIdentifiers.id_sha512);
+
+ oidMap.put("MD2", PKCSObjectIdentifiers.md2);
+ oidMap.put("MD4", PKCSObjectIdentifiers.md4);
+ oidMap.put("MD5", PKCSObjectIdentifiers.md5);
+ }
+
+ public RSADigestSigner(
+ Digest digest)
+ {
+ this.digest = digest;
+
+ algId = new AlgorithmIdentifier((ASN1ObjectIdentifier)oidMap.get(digest.getAlgorithmName()), DERNull.INSTANCE);
+ }
+
+ /**
+ * @deprecated
+ */
+ public String getAlgorithmName()
+ {
+ return digest.getAlgorithmName() + "withRSA";
+ }
+
+ /**
+ * initialise the signer for signing or verification.
+ *
+ * @param forSigning
+ * true if for signing, false otherwise
+ * @param parameters
+ * necessary parameters.
+ */
+ public void init(
+ boolean forSigning,
+ CipherParameters parameters)
+ {
+ this.forSigning = forSigning;
+ AsymmetricKeyParameter k;
+
+ if (parameters instanceof ParametersWithRandom)
+ {
+ k = (AsymmetricKeyParameter)((ParametersWithRandom)parameters).getParameters();
+ }
+ else
+ {
+ k = (AsymmetricKeyParameter)parameters;
+ }
+
+ if (forSigning && !k.isPrivate())
+ {
+ throw new IllegalArgumentException("signing requires private key");
+ }
+
+ if (!forSigning && k.isPrivate())
+ {
+ throw new IllegalArgumentException("verification requires public key");
+ }
+
+ reset();
+
+ rsaEngine.init(forSigning, parameters);
+ }
+
+ /**
+ * update the internal digest with the byte b
+ */
+ public void update(
+ byte input)
+ {
+ digest.update(input);
+ }
+
+ /**
+ * update the internal digest with the byte array in
+ */
+ public void update(
+ byte[] input,
+ int inOff,
+ int length)
+ {
+ digest.update(input, inOff, length);
+ }
+
+ /**
+ * Generate a signature for the message we've been loaded with using the key
+ * we were initialised with.
+ */
+ public byte[] generateSignature()
+ throws CryptoException, DataLengthException
+ {
+ if (!forSigning)
+ {
+ throw new IllegalStateException("RSADigestSigner not initialised for signature generation.");
+ }
+
+ byte[] hash = new byte[digest.getDigestSize()];
+ digest.doFinal(hash, 0);
+
+ try
+ {
+ byte[] data = derEncode(hash);
+ return rsaEngine.processBlock(data, 0, data.length);
+ }
+ catch (IOException e)
+ {
+ throw new CryptoException("unable to encode signature: " + e.getMessage(), e);
+ }
+ }
+
+ /**
+ * return true if the internal state represents the signature described in
+ * the passed in array.
+ */
+ public boolean verifySignature(
+ byte[] signature)
+ {
+ if (forSigning)
+ {
+ throw new IllegalStateException("RSADigestSigner not initialised for verification");
+ }
+
+ byte[] hash = new byte[digest.getDigestSize()];
+
+ digest.doFinal(hash, 0);
+
+ byte[] sig;
+ byte[] expected;
+
+ try
+ {
+ sig = rsaEngine.processBlock(signature, 0, signature.length);
+ expected = derEncode(hash);
+ }
+ catch (Exception e)
+ {
+ return false;
+ }
+
+ if (sig.length == expected.length)
+ {
+ return Arrays.constantTimeAreEqual(sig, expected);
+ }
+ else if (sig.length == expected.length - 2) // NULL left out
+ {
+ int sigOffset = sig.length - hash.length - 2;
+ int expectedOffset = expected.length - hash.length - 2;
+
+ expected[1] -= 2; // adjust lengths
+ expected[3] -= 2;
+
+ int nonEqual = 0;
+
+ for (int i = 0; i < hash.length; i++)
+ {
+ nonEqual |= (sig[sigOffset + i] ^ expected[expectedOffset + i]);
+ }
+
+ for (int i = 0; i < sigOffset; i++)
+ {
+ nonEqual |= (sig[i] ^ expected[i]); // check header less NULL
+ }
+
+ return nonEqual == 0;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ public void reset()
+ {
+ digest.reset();
+ }
+
+ private byte[] derEncode(
+ byte[] hash)
+ throws IOException
+ {
+ DigestInfo dInfo = new DigestInfo(algId, hash);
+
+ return dInfo.getEncoded(ASN1Encoding.DER);
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/AlertDescription.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/AlertDescription.java
new file mode 100644
index 0000000..a097b4b
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/AlertDescription.java
@@ -0,0 +1,47 @@
+package org.bc.crypto.tls;
+
+/**
+ * RFC 2246 7.2
+ */
+public class AlertDescription
+{
+ public static final short close_notify = 0;
+ public static final short unexpected_message = 10;
+ public static final short bad_record_mac = 20;
+ public static final short decryption_failed = 21;
+ public static final short record_overflow = 22;
+ public static final short decompression_failure = 30;
+ public static final short handshake_failure = 40;
+ /* no_certificate(41) is specific to SSLv3 */
+ public static final short no_certificate = 41;
+ public static final short bad_certificate = 42;
+ public static final short unsupported_certificate = 43;
+ public static final short certificate_revoked = 44;
+ public static final short certificate_expired = 45;
+ public static final short certificate_unknown = 46;
+ public static final short illegal_parameter = 47;
+ public static final short unknown_ca = 48;
+ public static final short access_denied = 49;
+ public static final short decode_error = 50;
+ public static final short decrypt_error = 51;
+ public static final short export_restriction = 60;
+ public static final short protocol_version = 70;
+ public static final short insufficient_security = 71;
+ public static final short internal_error = 80;
+ public static final short user_canceled = 90;
+ public static final short no_renegotiation = 100;
+
+ /*
+ * RFC 3546
+ */
+ public static final short unsupported_extension = 110;
+ public static final short certificate_unobtainable = 111;
+ public static final short unrecognized_name = 112;
+ public static final short bad_certificate_status_response = 113;
+ public static final short bad_certificate_hash_value = 114;
+
+ /*
+ * RFC 4279
+ */
+ public static final short unknown_psk_identity = 115;
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/AlertLevel.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/AlertLevel.java
new file mode 100644
index 0000000..ed3b794
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/AlertLevel.java
@@ -0,0 +1,10 @@
+package org.bc.crypto.tls;
+
+/**
+ * RFC 2246 7.2
+ */
+public class AlertLevel
+{
+ public static final short warning = 1;
+ public static final short fatal = 2;
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/AlwaysValidVerifyer.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/AlwaysValidVerifyer.java
new file mode 100644
index 0000000..51420d1
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/AlwaysValidVerifyer.java
@@ -0,0 +1,23 @@
+package org.bc.crypto.tls;
+
+/**
+ * A certificate verifyer, that will always return true.
+ *
+ *
+ v.add(new DEROctetString(encP));
+
+ // encode
+ * The purpose of UrlBase64 encoding is to provide a compact encoding of binary
+ * data that is safe for use as an URL parameter. Base64 encoding does not
+ * produce encoded values that are safe for use in URLs, since "/" can be
+ * interpreted as a path delimiter; "+" is the encoded form of a space; and
+ * "=" is used to separate a name from the corresponding value in an URL
+ * parameter.
+ */
+public class UrlBase64
+{
+ private static final Encoder encoder = new UrlBase64Encoder();
+
+ /**
+ * Encode the input data producing a URL safe base 64 encoded byte array.
+ *
+ * @return a byte array containing the URL safe base 64 encoded data.
+ */
+ public static byte[] encode(
+ byte[] data)
+ {
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ try
+ {
+ encoder.encode(data, 0, data.length, bOut);
+ }
+ catch (Exception e)
+ {
+ throw new EncoderException("exception encoding URL safe base64 data: " + e.getMessage(), e);
+ }
+
+ return bOut.toByteArray();
+ }
+
+ /**
+ * Encode the byte data writing it to the given output stream.
+ *
+ * @return the number of bytes produced.
+ */
+ public static int encode(
+ byte[] data,
+ OutputStream out)
+ throws IOException
+ {
+ return encoder.encode(data, 0, data.length, out);
+ }
+
+ /**
+ * Decode the URL safe base 64 encoded input data - white space will be ignored.
+ *
+ * @return a byte array representing the decoded data.
+ */
+ public static byte[] decode(
+ byte[] data)
+ {
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ try
+ {
+ encoder.decode(data, 0, data.length, bOut);
+ }
+ catch (Exception e)
+ {
+ throw new DecoderException("exception decoding URL safe base64 string: " + e.getMessage(), e);
+ }
+
+ return bOut.toByteArray();
+ }
+
+ /**
+ * decode the URL safe base 64 encoded byte data writing it to the given output stream,
+ * whitespace characters will be ignored.
+ *
+ * @return the number of bytes produced.
+ */
+ public static int decode(
+ byte[] data,
+ OutputStream out)
+ throws IOException
+ {
+ return encoder.decode(data, 0, data.length, out);
+ }
+
+ /**
+ * decode the URL safe base 64 encoded String data - whitespace will be ignored.
+ *
+ * @return a byte array representing the decoded data.
+ */
+ public static byte[] decode(
+ String data)
+ {
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ try
+ {
+ encoder.decode(data, bOut);
+ }
+ catch (Exception e)
+ {
+ throw new DecoderException("exception decoding URL safe base64 string: " + e.getMessage(), e);
+ }
+
+ return bOut.toByteArray();
+ }
+
+ /**
+ * Decode the URL safe base 64 encoded String data writing it to the given output stream,
+ * whitespace characters will be ignored.
+ *
+ * @return the number of bytes produced.
+ */
+ public static int decode(
+ String data,
+ OutputStream out)
+ throws IOException
+ {
+ return encoder.decode(data, out);
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/util/encoders/UrlBase64Encoder.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/util/encoders/UrlBase64Encoder.java
new file mode 100644
index 0000000..7748e81
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/util/encoders/UrlBase64Encoder.java
@@ -0,0 +1,25 @@
+package org.bc.util.encoders;
+
+/**
+ * Convert binary data to and from UrlBase64 encoding. This is identical to
+ * Base64 encoding, except that the padding character is "." and the other
+ * non-alphanumeric characters are "-" and "_" instead of "+" and "/".
+ *
+ * The purpose of UrlBase64 encoding is to provide a compact encoding of binary
+ * data that is safe for use as an URL parameter. Base64 encoding does not
+ * produce encoded values that are safe for use in URLs, since "/" can be
+ * interpreted as a path delimiter; "+" is the encoded form of a space; and
+ * "=" is used to separate a name from the corresponding value in an URL
+ * parameter.
+ */
+public class UrlBase64Encoder extends Base64Encoder
+{
+ public UrlBase64Encoder()
+ {
+ encodingTable[encodingTable.length - 2] = (byte) '-';
+ encodingTable[encodingTable.length - 1] = (byte) '_';
+ padding = (byte) '.';
+ // we must re-create the decoding table with the new encoded values.
+ initialiseDecodingTable();
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/util/io/StreamOverflowException.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/util/io/StreamOverflowException.java
new file mode 100644
index 0000000..a755e10
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/util/io/StreamOverflowException.java
@@ -0,0 +1,12 @@
+package org.bc.util.io;
+
+import java.io.IOException;
+
+public class StreamOverflowException
+ extends IOException
+{
+ public StreamOverflowException(String msg)
+ {
+ super(msg);
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/util/io/Streams.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/util/io/Streams.java
new file mode 100644
index 0000000..c3f504a
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/util/io/Streams.java
@@ -0,0 +1,87 @@
+package org.bc.util.io;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+public final class Streams
+{
+ private static int BUFFER_SIZE = 512;
+
+ public static void drain(InputStream inStr)
+ throws IOException
+ {
+ byte[] bs = new byte[BUFFER_SIZE];
+ while (inStr.read(bs, 0, bs.length) >= 0)
+ {
+ }
+ }
+
+ public static byte[] readAll(InputStream inStr)
+ throws IOException
+ {
+ ByteArrayOutputStream buf = new ByteArrayOutputStream();
+ pipeAll(inStr, buf);
+ return buf.toByteArray();
+ }
+
+ public static byte[] readAllLimited(InputStream inStr, int limit)
+ throws IOException
+ {
+ ByteArrayOutputStream buf = new ByteArrayOutputStream();
+ pipeAllLimited(inStr, limit, buf);
+ return buf.toByteArray();
+ }
+
+ public static int readFully(InputStream inStr, byte[] buf)
+ throws IOException
+ {
+ return readFully(inStr, buf, 0, buf.length);
+ }
+
+ public static int readFully(InputStream inStr, byte[] buf, int off, int len)
+ throws IOException
+ {
+ int totalRead = 0;
+ while (totalRead < len)
+ {
+ int numRead = inStr.read(buf, off + totalRead, len - totalRead);
+ if (numRead < 0)
+ {
+ break;
+ }
+ totalRead += numRead;
+ }
+ return totalRead;
+ }
+
+ public static void pipeAll(InputStream inStr, OutputStream outStr)
+ throws IOException
+ {
+ byte[] bs = new byte[BUFFER_SIZE];
+ int numRead;
+ while ((numRead = inStr.read(bs, 0, bs.length)) >= 0)
+ {
+ outStr.write(bs, 0, numRead);
+ }
+ }
+
+ public static long pipeAllLimited(InputStream inStr, long limit, OutputStream outStr)
+ throws IOException
+ {
+ long total = 0;
+ byte[] bs = new byte[BUFFER_SIZE];
+ int numRead;
+ while ((numRead = inStr.read(bs, 0, bs.length)) >= 0)
+ {
+ total += numRead;
+ if (total > limit)
+ {
+ throw new StreamOverflowException("Data Overflow");
+ }
+ outStr.write(bs, 0, numRead);
+ }
+ return total;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/util/io/TeeInputStream.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/util/io/TeeInputStream.java
new file mode 100644
index 0000000..00c2b6d
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/util/io/TeeInputStream.java
@@ -0,0 +1,62 @@
+package org.bc.util.io;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+public class TeeInputStream
+ extends InputStream
+{
+ private final InputStream input;
+ private final OutputStream output;
+
+ public TeeInputStream(InputStream input, OutputStream output)
+ {
+ this.input = input;
+ this.output = output;
+ }
+
+ public int read(byte[] buf)
+ throws IOException
+ {
+ return read(buf, 0, buf.length);
+ }
+
+ public int read(byte[] buf, int off, int len)
+ throws IOException
+ {
+ int i = input.read(buf, off, len);
+
+ if (i > 0)
+ {
+ output.write(buf, off, i);
+ }
+
+ return i;
+ }
+
+ public int read()
+ throws IOException
+ {
+ int i = input.read();
+
+ if (i >= 0)
+ {
+ output.write(i);
+ }
+
+ return i;
+ }
+
+ public void close()
+ throws IOException
+ {
+ this.input.close();
+ this.output.close();
+ }
+
+ public OutputStream getOutputStream()
+ {
+ return output;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/util/io/TeeOutputStream.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/util/io/TeeOutputStream.java
new file mode 100644
index 0000000..28edd60
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/util/io/TeeOutputStream.java
@@ -0,0 +1,52 @@
+package org.bc.util.io;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+public class TeeOutputStream
+ extends OutputStream
+{
+ private OutputStream output1;
+ private OutputStream output2;
+
+ public TeeOutputStream(OutputStream output1, OutputStream output2)
+ {
+ this.output1 = output1;
+ this.output2 = output2;
+ }
+
+ public void write(byte[] buf)
+ throws IOException
+ {
+ this.output1.write(buf);
+ this.output2.write(buf);
+ }
+
+ public void write(byte[] buf, int off, int len)
+ throws IOException
+ {
+ this.output1.write(buf, off, len);
+ this.output2.write(buf, off, len);
+ }
+
+ public void write(int b)
+ throws IOException
+ {
+ this.output1.write(b);
+ this.output2.write(b);
+ }
+
+ public void flush()
+ throws IOException
+ {
+ this.output1.flush();
+ this.output2.flush();
+ }
+
+ public void close()
+ throws IOException
+ {
+ this.output1.close();
+ this.output2.close();
+ }
+}
\ No newline at end of file
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/util/io/pem/PemGenerationException.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/util/io/pem/PemGenerationException.java
new file mode 100644
index 0000000..19f8a0b
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/util/io/pem/PemGenerationException.java
@@ -0,0 +1,25 @@
+package org.bc.util.io.pem;
+
+import java.io.IOException;
+
+public class PemGenerationException
+ extends IOException
+{
+ private Throwable cause;
+
+ public PemGenerationException(String message, Throwable cause)
+ {
+ super(message);
+ this.cause = cause;
+ }
+
+ public PemGenerationException(String message)
+ {
+ super(message);
+ }
+
+ public Throwable getCause()
+ {
+ return cause;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/util/io/pem/PemHeader.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/util/io/pem/PemHeader.java
new file mode 100644
index 0000000..29c3f29
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/util/io/pem/PemHeader.java
@@ -0,0 +1,66 @@
+package org.bc.util.io.pem;
+
+public class PemHeader
+{
+ private String name;
+ private String value;
+
+ public PemHeader(String name, String value)
+ {
+ this.name = name;
+ this.value = value;
+ }
+
+ public String getName()
+ {
+ return name;
+ }
+
+ public String getValue()
+ {
+ return value;
+ }
+
+ public int hashCode()
+ {
+ return getHashCode(this.name) + 31 * getHashCode(this.value);
+ }
+
+ public boolean equals(Object o)
+ {
+ if (!(o instanceof PemHeader))
+ {
+ return false;
+ }
+
+ PemHeader other = (PemHeader)o;
+
+ return other == this || (isEqual(this.name, other.name) && isEqual(this.value, other.value));
+ }
+
+ private int getHashCode(String s)
+ {
+ if (s == null)
+ {
+ return 1;
+ }
+
+ return s.hashCode();
+ }
+
+ private boolean isEqual(String s1, String s2)
+ {
+ if (s1 == s2)
+ {
+ return true;
+ }
+
+ if (s1 == null || s2 == null)
+ {
+ return false;
+ }
+
+ return s1.equals(s2);
+ }
+
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/util/io/pem/PemObject.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/util/io/pem/PemObject.java
new file mode 100644
index 0000000..2f2c5f2
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/util/io/pem/PemObject.java
@@ -0,0 +1,61 @@
+package org.bc.util.io.pem;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public class PemObject
+ implements PemObjectGenerator
+{
+ private static final List EMPTY_LIST = Collections.unmodifiableList(new ArrayList());
+
+ private String type;
+ private List headers;
+ private byte[] content;
+
+ /**
+ * Generic constructor for object without headers.
+ *
+ * @param type pem object type.
+ * @param content the binary content of the object.
+ */
+ public PemObject(String type, byte[] content)
+ {
+ this(type, EMPTY_LIST, content);
+ }
+
+ /**
+ * Generic constructor for object with headers.
+ *
+ * @param type pem object type.
+ * @param headers a list of PemHeader objects.
+ * @param content the binary content of the object.
+ */
+ public PemObject(String type, List headers, byte[] content)
+ {
+ this.type = type;
+ this.headers = Collections.unmodifiableList(headers);
+ this.content = content;
+ }
+
+ public String getType()
+ {
+ return type;
+ }
+
+ public List getHeaders()
+ {
+ return headers;
+ }
+
+ public byte[] getContent()
+ {
+ return content;
+ }
+
+ public PemObject generate()
+ throws PemGenerationException
+ {
+ return this;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/util/io/pem/PemObjectGenerator.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/util/io/pem/PemObjectGenerator.java
new file mode 100644
index 0000000..347230f
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/util/io/pem/PemObjectGenerator.java
@@ -0,0 +1,7 @@
+package org.bc.util.io.pem;
+
+public interface PemObjectGenerator
+{
+ PemObject generate()
+ throws PemGenerationException;
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/util/io/pem/PemObjectParser.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/util/io/pem/PemObjectParser.java
new file mode 100644
index 0000000..b4dbf85
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/util/io/pem/PemObjectParser.java
@@ -0,0 +1,9 @@
+package org.bc.util.io.pem;
+
+import java.io.IOException;
+
+public interface PemObjectParser
+{
+ Object parseObject(PemObject obj)
+ throws IOException;
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/util/io/pem/PemReader.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/util/io/pem/PemReader.java
new file mode 100644
index 0000000..3298a9c
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/util/io/pem/PemReader.java
@@ -0,0 +1,84 @@
+package org.bc.util.io.pem;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.Reader;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.bc.util.encoders.Base64;
+
+public class PemReader
+ extends BufferedReader
+{
+ private static final String BEGIN = "-----BEGIN ";
+ private static final String END = "-----END ";
+
+ public PemReader(Reader reader)
+ {
+ super(reader);
+ }
+
+ public PemObject readPemObject()
+ throws IOException
+ {
+ String line = readLine();
+
+ while (line != null && !line.startsWith(BEGIN))
+ {
+ line = readLine();
+ }
+
+ if (line != null)
+ {
+ line = line.substring(BEGIN.length());
+ int index = line.indexOf('-');
+ String type = line.substring(0, index);
+
+ if (index > 0)
+ {
+ return loadObject(type);
+ }
+ }
+
+ return null;
+ }
+
+ private PemObject loadObject(String type)
+ throws IOException
+ {
+ String line;
+ String endMarker = END + type;
+ StringBuffer buf = new StringBuffer();
+ List headers = new ArrayList();
+
+ while ((line = readLine()) != null)
+ {
+ if (line.indexOf(":") >= 0)
+ {
+ int index = line.indexOf(':');
+ String hdr = line.substring(0, index);
+ String value = line.substring(index + 1).trim();
+
+ headers.add(new PemHeader(hdr, value));
+
+ continue;
+ }
+
+ if (line.indexOf(endMarker) != -1)
+ {
+ break;
+ }
+
+ buf.append(line.trim());
+ }
+
+ if (line == null)
+ {
+ throw new IOException(endMarker + " not found");
+ }
+
+ return new PemObject(type, headers, Base64.decode(buf.toString()));
+ }
+
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/util/io/pem/PemWriter.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/util/io/pem/PemWriter.java
new file mode 100644
index 0000000..0d2f5a4
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/util/io/pem/PemWriter.java
@@ -0,0 +1,137 @@
+package org.bc.util.io.pem;
+
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.io.Writer;
+import java.util.Iterator;
+
+import org.bc.util.encoders.Base64;
+
+/**
+ * A generic PEM writer, based on RFC 1421
+ */
+public class PemWriter
+ extends BufferedWriter
+{
+ private static final int LINE_LENGTH = 64;
+
+ private final int nlLength;
+ private char[] buf = new char[LINE_LENGTH];
+
+ /**
+ * Base constructor.
+ *
+ * @param out output stream to use.
+ */
+ public PemWriter(Writer out)
+ {
+ super(out);
+
+ String nl = System.getProperty("line.separator");
+ if (nl != null)
+ {
+ nlLength = nl.length();
+ }
+ else
+ {
+ nlLength = 2;
+ }
+ }
+
+ /**
+ * Return the number of bytes or characters required to contain the
+ * passed in object if it is PEM encoded.
+ *
+ * @param obj pem object to be output
+ * @return an estimate of the number of bytes
+ */
+ public int getOutputSize(PemObject obj)
+ {
+ // BEGIN and END boundaries.
+ int size = (2 * (obj.getType().length() + 10 + nlLength)) + 6 + 4;
+
+ if (!obj.getHeaders().isEmpty())
+ {
+ for (Iterator it = obj.getHeaders().iterator(); it.hasNext();)
+ {
+ PemHeader hdr = (PemHeader)it.next();
+
+ size += hdr.getName().length() + ": ".length() + hdr.getValue().length() + nlLength;
+ }
+
+ size += nlLength;
+ }
+
+ // base64 encoding
+ int dataLen = ((obj.getContent().length + 2) / 3) * 4;
+
+ size += dataLen + (((dataLen + LINE_LENGTH - 1) / LINE_LENGTH) * nlLength);
+
+ return size;
+ }
+
+ public void writeObject(PemObjectGenerator objGen)
+ throws IOException
+ {
+ PemObject obj = objGen.generate();
+
+ writePreEncapsulationBoundary(obj.getType());
+
+ if (!obj.getHeaders().isEmpty())
+ {
+ for (Iterator it = obj.getHeaders().iterator(); it.hasNext();)
+ {
+ PemHeader hdr = (PemHeader)it.next();
+
+ this.write(hdr.getName());
+ this.write(": ");
+ this.write(hdr.getValue());
+ this.newLine();
+ }
+
+ this.newLine();
+ }
+
+ writeEncoded(obj.getContent());
+ writePostEncapsulationBoundary(obj.getType());
+ }
+
+ private void writeEncoded(byte[] bytes)
+ throws IOException
+ {
+ bytes = Base64.encode(bytes);
+
+ for (int i = 0; i < bytes.length; i += buf.length)
+ {
+ int index = 0;
+
+ while (index != buf.length)
+ {
+ if ((i + index) >= bytes.length)
+ {
+ break;
+ }
+ buf[index] = (char)bytes[i + index];
+ index++;
+ }
+ this.write(buf, 0, index);
+ this.newLine();
+ }
+ }
+
+ private void writePreEncapsulationBoundary(
+ String type)
+ throws IOException
+ {
+ this.write("-----BEGIN " + type + "-----");
+ this.newLine();
+ }
+
+ private void writePostEncapsulationBoundary(
+ String type)
+ throws IOException
+ {
+ this.write("-----END " + type + "-----");
+ this.newLine();
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/util/test/FixedSecureRandom.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/util/test/FixedSecureRandom.java
new file mode 100644
index 0000000..5f0a9a3
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/util/test/FixedSecureRandom.java
@@ -0,0 +1,135 @@
+package org.bc.util.test;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.security.SecureRandom;
+
+public class FixedSecureRandom
+ extends SecureRandom
+{
+ private byte[] _data;
+
+ private int _index;
+ private int _intPad;
+
+ public FixedSecureRandom(byte[] value)
+ {
+ this(false, new byte[][] { value });
+ }
+
+ public FixedSecureRandom(
+ byte[][] values)
+ {
+ this(false, values);
+ }
+
+ /**
+ * Pad the data on integer boundaries. This is necessary for the classpath project's BigInteger
+ * implementation.
+ */
+ public FixedSecureRandom(
+ boolean intPad,
+ byte[] value)
+ {
+ this(intPad, new byte[][] { value });
+ }
+
+ /**
+ * Pad the data on integer boundaries. This is necessary for the classpath project's BigInteger
+ * implementation.
+ */
+ public FixedSecureRandom(
+ boolean intPad,
+ byte[][] values)
+ {
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ for (int i = 0; i != values.length; i++)
+ {
+ try
+ {
+ bOut.write(values[i]);
+ }
+ catch (IOException e)
+ {
+ throw new IllegalArgumentException("can't save value array.");
+ }
+ }
+
+ _data = bOut.toByteArray();
+
+ if (intPad)
+ {
+ _intPad = _data.length % 4;
+ }
+ }
+
+ public void nextBytes(byte[] bytes)
+ {
+ System.arraycopy(_data, _index, bytes, 0, bytes.length);
+
+ _index += bytes.length;
+ }
+
+ //
+ // classpath's implementation of SecureRandom doesn't currently go back to nextBytes
+ // when next is called. We can't override next as it's a final method.
+ //
+ public int nextInt()
+ {
+ int val = 0;
+
+ val |= nextValue() << 24;
+ val |= nextValue() << 16;
+
+ if (_intPad == 2)
+ {
+ _intPad--;
+ }
+ else
+ {
+ val |= nextValue() << 8;
+ }
+
+ if (_intPad == 1)
+ {
+ _intPad--;
+ }
+ else
+ {
+ val |= nextValue();
+ }
+
+ return val;
+ }
+
+ //
+ // classpath's implementation of SecureRandom doesn't currently go back to nextBytes
+ // when next is called. We can't override next as it's a final method.
+ //
+ public long nextLong()
+ {
+ long val = 0;
+
+ val |= (long)nextValue() << 56;
+ val |= (long)nextValue() << 48;
+ val |= (long)nextValue() << 40;
+ val |= (long)nextValue() << 32;
+ val |= (long)nextValue() << 24;
+ val |= (long)nextValue() << 16;
+ val |= (long)nextValue() << 8;
+ val |= (long)nextValue();
+
+ return val;
+ }
+
+ public boolean isExhausted()
+ {
+ return _index == _data.length;
+ }
+
+ private int nextValue()
+ {
+ return _data[_index++] & 0xff;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/util/test/NumberParsing.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/util/test/NumberParsing.java
new file mode 100644
index 0000000..a6085b9
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/util/test/NumberParsing.java
@@ -0,0 +1,34 @@
+package org.bc.util.test;
+
+/**
+ * Parsing
+ */
+public final class NumberParsing
+{
+ private NumberParsing()
+ {
+ // Hide constructor
+ }
+
+ public static long decodeLongFromHex(String longAsString)
+ {
+ if ((longAsString.charAt(1) == 'x')
+ || (longAsString.charAt(1) == 'X'))
+ {
+ return Long.parseLong(longAsString.substring(2), 16);
+ }
+
+ return Long.parseLong(longAsString, 16);
+ }
+
+ public static int decodeIntFromHex(String intAsString)
+ {
+ if ((intAsString.charAt(1) == 'x')
+ || (intAsString.charAt(1) == 'X'))
+ {
+ return Integer.parseInt(intAsString.substring(2), 16);
+ }
+
+ return Integer.parseInt(intAsString, 16);
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/util/test/SimpleTest.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/util/test/SimpleTest.java
new file mode 100644
index 0000000..cccdb2b
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/util/test/SimpleTest.java
@@ -0,0 +1,84 @@
+package org.bc.util.test;
+
+import java.io.PrintStream;
+
+import org.bc.util.Arrays;
+
+public abstract class SimpleTest
+ implements Test
+{
+ public abstract String getName();
+
+ private TestResult success()
+ {
+ return SimpleTestResult.successful(this, "Okay");
+ }
+
+ protected void fail(
+ String message)
+ {
+ throw new TestFailedException(SimpleTestResult.failed(this, message));
+ }
+
+ protected void fail(
+ String message,
+ Throwable throwable)
+ {
+ throw new TestFailedException(SimpleTestResult.failed(this, message, throwable));
+ }
+
+ protected void fail(
+ String message,
+ Object expected,
+ Object found)
+ {
+ throw new TestFailedException(SimpleTestResult.failed(this, message, expected, found));
+ }
+
+ protected boolean areEqual(
+ byte[] a,
+ byte[] b)
+ {
+ return Arrays.areEqual(a, b);
+ }
+
+ public TestResult perform()
+ {
+ try
+ {
+ performTest();
+
+ return success();
+ }
+ catch (TestFailedException e)
+ {
+ return e.getResult();
+ }
+ catch (Exception e)
+ {
+ return SimpleTestResult.failed(this, "Exception: " + e, e);
+ }
+ }
+
+ protected static void runTest(
+ Test test)
+ {
+ runTest(test, System.out);
+ }
+
+ protected static void runTest(
+ Test test,
+ PrintStream out)
+ {
+ TestResult result = test.perform();
+
+ out.println(result.toString());
+ if (result.getException() != null)
+ {
+ result.getException().printStackTrace(out);
+ }
+ }
+
+ public abstract void performTest()
+ throws Exception;
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/util/test/SimpleTestResult.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/util/test/SimpleTestResult.java
new file mode 100644
index 0000000..a31e02a
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/util/test/SimpleTestResult.java
@@ -0,0 +1,80 @@
+package org.bc.util.test;
+
+public class SimpleTestResult implements TestResult
+{
+ private static final String SEPARATOR = System.getProperty("line.separator");
+
+ private boolean success;
+ private String message;
+ private Throwable exception;
+
+ public SimpleTestResult(boolean success, String message)
+ {
+ this.success = success;
+ this.message = message;
+ }
+
+ public SimpleTestResult(boolean success, String message, Throwable exception)
+ {
+ this.success = success;
+ this.message = message;
+ this.exception = exception;
+ }
+
+ public static TestResult successful(
+ Test test,
+ String message)
+ {
+ return new SimpleTestResult(true, test.getName() + ": " + message);
+ }
+
+ public static TestResult failed(
+ Test test,
+ String message)
+ {
+ return new SimpleTestResult(false, test.getName() + ": " + message);
+ }
+
+ public static TestResult failed(
+ Test test,
+ String message,
+ Throwable t)
+ {
+ return new SimpleTestResult(false, test.getName() + ": " + message, t);
+ }
+
+ public static TestResult failed(
+ Test test,
+ String message,
+ Object expected,
+ Object found)
+ {
+ return failed(test, message + SEPARATOR + "Expected: " + expected + SEPARATOR + "Found : " + found);
+ }
+
+ public static String failedMessage(String algorithm, String testName, String expected,
+ String actual)
+ {
+ StringBuffer sb = new StringBuffer(algorithm);
+ sb.append(" failing ").append(testName);
+ sb.append(SEPARATOR).append(" expected: ").append(expected);
+ sb.append(SEPARATOR).append(" got : ").append(actual);
+
+ return sb.toString();
+ }
+
+ public boolean isSuccessful()
+ {
+ return success;
+ }
+
+ public String toString()
+ {
+ return message;
+ }
+
+ public Throwable getException()
+ {
+ return exception;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/util/test/Test.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/util/test/Test.java
new file mode 100644
index 0000000..58036a2
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/util/test/Test.java
@@ -0,0 +1,8 @@
+package org.bc.util.test;
+
+public interface Test
+{
+ String getName();
+
+ TestResult perform();
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/util/test/TestFailedException.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/util/test/TestFailedException.java
new file mode 100644
index 0000000..6dbb985
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/util/test/TestFailedException.java
@@ -0,0 +1,18 @@
+package org.bc.util.test;
+
+public class TestFailedException
+ extends RuntimeException
+{
+ private TestResult _result;
+
+ public TestFailedException(
+ TestResult result)
+ {
+ _result = result;
+ }
+
+ public TestResult getResult()
+ {
+ return _result;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/util/test/TestResult.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/util/test/TestResult.java
new file mode 100644
index 0000000..b68e91e
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/util/test/TestResult.java
@@ -0,0 +1,10 @@
+package org.bc.util.test;
+
+public interface TestResult
+{
+ public boolean isSuccessful();
+
+ public Throwable getException();
+
+ public String toString();
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/util/test/UncloseableOutputStream.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/util/test/UncloseableOutputStream.java
new file mode 100644
index 0000000..4fd302a
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/util/test/UncloseableOutputStream.java
@@ -0,0 +1,23 @@
+package org.bc.util.test;
+
+import java.io.FilterOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+public class UncloseableOutputStream extends FilterOutputStream
+{
+ public UncloseableOutputStream(OutputStream s)
+ {
+ super(s);
+ }
+
+ public void close()
+ {
+ throw new RuntimeException("close() called on UncloseableOutputStream");
+ }
+
+ public void write(byte[] b, int off, int len) throws IOException
+ {
+ out.write(b, off, len);
+ }
+ }
+ * g(x) = x^4 + (a+1/a)x^3 + ax^2 + (a+1/a)x + 1
+ *
+ * where a = primitive root of field generator 0x14D
+ */
+ private int RS_rem(int x)
+ {
+ int b = (x >>> 24) & 0xff;
+ int g2 = ((b << 1) ^
+ ((b & 0x80) != 0 ? RS_GF_FDBK : 0)) & 0xff;
+ int g3 = ((b >>> 1) ^
+ ((b & 0x01) != 0 ? (RS_GF_FDBK >>> 1) : 0)) ^ g2 ;
+ return ((x << 8) ^ (g3 << 24) ^ (g2 << 16) ^ (g3 << 8) ^ b);
+ }
+
+ private int LFSR1(int x)
+ {
+ return (x >> 1) ^
+ (((x & 0x01) != 0) ? GF256_FDBK_2 : 0);
+ }
+
+ private int LFSR2(int x)
+ {
+ return (x >> 2) ^
+ (((x & 0x02) != 0) ? GF256_FDBK_2 : 0) ^
+ (((x & 0x01) != 0) ? GF256_FDBK_4 : 0);
+ }
+
+ private int Mx_X(int x)
+ {
+ return x ^ LFSR2(x);
+ } // 5B
+
+ private int Mx_Y(int x)
+ {
+ return x ^ LFSR1(x) ^ LFSR2(x);
+ } // EF
+
+ private int b0(int x)
+ {
+ return x & 0xff;
+ }
+
+ private int b1(int x)
+ {
+ return (x >>> 8) & 0xff;
+ }
+
+ private int b2(int x)
+ {
+ return (x >>> 16) & 0xff;
+ }
+
+ private int b3(int x)
+ {
+ return (x >>> 24) & 0xff;
+ }
+
+ private int Fe32_0(int x)
+ {
+ return gSBox[ 0x000 + 2*(x & 0xff) ] ^
+ gSBox[ 0x001 + 2*((x >>> 8) & 0xff) ] ^
+ gSBox[ 0x200 + 2*((x >>> 16) & 0xff) ] ^
+ gSBox[ 0x201 + 2*((x >>> 24) & 0xff) ];
+ }
+
+ private int Fe32_3(int x)
+ {
+ return gSBox[ 0x000 + 2*((x >>> 24) & 0xff) ] ^
+ gSBox[ 0x001 + 2*(x & 0xff) ] ^
+ gSBox[ 0x200 + 2*((x >>> 8) & 0xff) ] ^
+ gSBox[ 0x201 + 2*((x >>> 16) & 0xff) ];
+ }
+
+ private int BytesTo32Bits(byte[] b, int p)
+ {
+ return ((b[p] & 0xff)) |
+ ((b[p+1] & 0xff) << 8) |
+ ((b[p+2] & 0xff) << 16) |
+ ((b[p+3] & 0xff) << 24);
+ }
+
+ private void Bits32ToBytes(int in, byte[] b, int offset)
+ {
+ b[offset] = (byte)in;
+ b[offset + 1] = (byte)(in >> 8);
+ b[offset + 2] = (byte)(in >> 16);
+ b[offset + 3] = (byte)(in >> 24);
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/VMPCEngine.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/VMPCEngine.java
new file mode 100644
index 0000000..ca9e6d9
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/VMPCEngine.java
@@ -0,0 +1,138 @@
+package org.bc.crypto.engines;
+
+import org.bc.crypto.CipherParameters;
+import org.bc.crypto.DataLengthException;
+import org.bc.crypto.StreamCipher;
+import org.bc.crypto.params.KeyParameter;
+import org.bc.crypto.params.ParametersWithIV;
+
+public class VMPCEngine implements StreamCipher
+{
+ /*
+ * variables to hold the state of the VMPC engine during encryption and
+ * decryption
+ */
+ protected byte n = 0;
+ protected byte[] P = null;
+ protected byte s = 0;
+
+ protected byte[] workingIV;
+ protected byte[] workingKey;
+
+ public String getAlgorithmName()
+ {
+ return "VMPC";
+ }
+
+ /**
+ * initialise a VMPC cipher.
+ *
+ * @param forEncryption
+ * whether or not we are for encryption.
+ * @param params
+ * the parameters required to set up the cipher.
+ * @exception IllegalArgumentException
+ * if the params argument is inappropriate.
+ */
+ public void init(boolean forEncryption, CipherParameters params)
+ {
+ if (!(params instanceof ParametersWithIV))
+ {
+ throw new IllegalArgumentException(
+ "VMPC init parameters must include an IV");
+ }
+
+ ParametersWithIV ivParams = (ParametersWithIV) params;
+ KeyParameter key = (KeyParameter) ivParams.getParameters();
+
+ if (!(ivParams.getParameters() instanceof KeyParameter))
+ {
+ throw new IllegalArgumentException(
+ "VMPC init parameters must include a key");
+ }
+
+ this.workingIV = ivParams.getIV();
+
+ if (workingIV == null || workingIV.length < 1 || workingIV.length > 768)
+ {
+ throw new IllegalArgumentException("VMPC requires 1 to 768 bytes of IV");
+ }
+
+ this.workingKey = key.getKey();
+
+ initKey(this.workingKey, this.workingIV);
+ }
+
+ protected void initKey(byte[] keyBytes, byte[] ivBytes)
+ {
+ s = 0;
+ P = new byte[256];
+ for (int i = 0; i < 256; i++)
+ {
+ P[i] = (byte) i;
+ }
+
+ for (int m = 0; m < 768; m++)
+ {
+ s = P[(s + P[m & 0xff] + keyBytes[m % keyBytes.length]) & 0xff];
+ byte temp = P[m & 0xff];
+ P[m & 0xff] = P[s & 0xff];
+ P[s & 0xff] = temp;
+ }
+ for (int m = 0; m < 768; m++)
+ {
+ s = P[(s + P[m & 0xff] + ivBytes[m % ivBytes.length]) & 0xff];
+ byte temp = P[m & 0xff];
+ P[m & 0xff] = P[s & 0xff];
+ P[s & 0xff] = temp;
+ }
+ n = 0;
+ }
+
+ public void processBytes(byte[] in, int inOff, int len, byte[] out,
+ int outOff)
+ {
+ if ((inOff + len) > in.length)
+ {
+ throw new DataLengthException("input buffer too short");
+ }
+
+ if ((outOff + len) > out.length)
+ {
+ throw new DataLengthException("output buffer too short");
+ }
+
+ for (int i = 0; i < len; i++)
+ {
+ s = P[(s + P[n & 0xff]) & 0xff];
+ byte z = P[(P[(P[s & 0xff]) & 0xff] + 1) & 0xff];
+ // encryption
+ byte temp = P[n & 0xff];
+ P[n & 0xff] = P[s & 0xff];
+ P[s & 0xff] = temp;
+ n = (byte) ((n + 1) & 0xff);
+
+ // xor
+ out[i + outOff] = (byte) (in[i + inOff] ^ z);
+ }
+ }
+
+ public void reset()
+ {
+ initKey(this.workingKey, this.workingIV);
+ }
+
+ public byte returnByte(byte in)
+ {
+ s = P[(s + P[n & 0xff]) & 0xff];
+ byte z = P[(P[(P[s & 0xff]) & 0xff] + 1) & 0xff];
+ // encryption
+ byte temp = P[n & 0xff];
+ P[n & 0xff] = P[s & 0xff];
+ P[s & 0xff] = temp;
+ n = (byte) ((n + 1) & 0xff);
+
+ // xor
+ return (byte) (in ^ z);
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/VMPCKSA3Engine.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/VMPCKSA3Engine.java
new file mode 100644
index 0000000..bf7bdf0
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/VMPCKSA3Engine.java
@@ -0,0 +1,45 @@
+package org.bc.crypto.engines;
+
+public class VMPCKSA3Engine extends VMPCEngine
+{
+ public String getAlgorithmName()
+ {
+ return "VMPC-KSA3";
+ }
+
+ protected void initKey(byte[] keyBytes, byte[] ivBytes)
+ {
+ s = 0;
+ P = new byte[256];
+ for (int i = 0; i < 256; i++)
+ {
+ P[i] = (byte) i;
+ }
+
+ for (int m = 0; m < 768; m++)
+ {
+ s = P[(s + P[m & 0xff] + keyBytes[m % keyBytes.length]) & 0xff];
+ byte temp = P[m & 0xff];
+ P[m & 0xff] = P[s & 0xff];
+ P[s & 0xff] = temp;
+ }
+
+ for (int m = 0; m < 768; m++)
+ {
+ s = P[(s + P[m & 0xff] + ivBytes[m % ivBytes.length]) & 0xff];
+ byte temp = P[m & 0xff];
+ P[m & 0xff] = P[s & 0xff];
+ P[s & 0xff] = temp;
+ }
+
+ for (int m = 0; m < 768; m++)
+ {
+ s = P[(s + P[m & 0xff] + keyBytes[m % keyBytes.length]) & 0xff];
+ byte temp = P[m & 0xff];
+ P[m & 0xff] = P[s & 0xff];
+ P[s & 0xff] = temp;
+ }
+
+ n = 0;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/XTEAEngine.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/XTEAEngine.java
new file mode 100644
index 0000000..44b2e25
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/engines/XTEAEngine.java
@@ -0,0 +1,182 @@
+package org.bc.crypto.engines;
+
+import org.bc.crypto.BlockCipher;
+import org.bc.crypto.CipherParameters;
+import org.bc.crypto.DataLengthException;
+import org.bc.crypto.params.KeyParameter;
+
+/**
+ * An XTEA engine.
+ */
+public class XTEAEngine
+ implements BlockCipher
+{
+ private static final int rounds = 32,
+ block_size = 8,
+// key_size = 16,
+ delta = 0x9E3779B9;
+
+ /*
+ * the expanded key array of 4 subkeys
+ */
+ private int[] _S = new int[4],
+ _sum0 = new int[32],
+ _sum1 = new int[32];
+ private boolean _initialised,
+ _forEncryption;
+
+ /**
+ * Create an instance of the TEA encryption algorithm
+ * and set some defaults
+ */
+ public XTEAEngine()
+ {
+ _initialised = false;
+ }
+
+ public String getAlgorithmName()
+ {
+ return "XTEA";
+ }
+
+ public int getBlockSize()
+ {
+ return block_size;
+ }
+
+ /**
+ * initialise
+ *
+ * @param forEncryption whether or not we are for encryption.
+ * @param params the parameters required to set up the cipher.
+ * @exception IllegalArgumentException if the params argument is
+ * inappropriate.
+ */
+ public void init(
+ boolean forEncryption,
+ CipherParameters params)
+ {
+ if (!(params instanceof KeyParameter))
+ {
+ throw new IllegalArgumentException("invalid parameter passed to TEA init - " + params.getClass().getName());
+ }
+
+ _forEncryption = forEncryption;
+ _initialised = true;
+
+ KeyParameter p = (KeyParameter)params;
+
+ setKey(p.getKey());
+ }
+
+ public int processBlock(
+ byte[] in,
+ int inOff,
+ byte[] out,
+ int outOff)
+ {
+ if (!_initialised)
+ {
+ throw new IllegalStateException(getAlgorithmName()+" not initialised");
+ }
+
+ if ((inOff + block_size) > in.length)
+ {
+ throw new DataLengthException("input buffer too short");
+ }
+
+ if ((outOff + block_size) > out.length)
+ {
+ throw new DataLengthException("output buffer too short");
+ }
+
+ return (_forEncryption) ? encryptBlock(in, inOff, out, outOff)
+ : decryptBlock(in, inOff, out, outOff);
+ }
+
+ public void reset()
+ {
+ }
+
+ /**
+ * Re-key the cipher.
+ *
+ * java org.bouncycastle.crypto.examples.DESExample infile outfile [keyfile]
+ *
+ * A new key is generated for each encryption, if key is not specified,
+ * then the example will assume encryption is required, and as output
+ * create deskey.dat in the current directory. This key is a hex
+ * encoded byte-stream that is used for the decryption. The output
+ * file is Hex encoded, 60 characters wide text file.
+ *
+ *
+ *
+ * This implementation is based on ISO 18033/P1363a.
+ */
+public class BaseKDFBytesGenerator
+ implements DerivationFunction
+{
+ private int counterStart;
+ private Digest digest;
+ private byte[] shared;
+ private byte[] iv;
+
+ /**
+ * Construct a KDF Parameters generator.
+ * =0)
+ {
+ break; //step 14
+ }
+ else
+ {
+ pq[0] = p[0];
+ pq[1] = p[1];
+ return y[0].intValue(); //return for procedure B step 2
+ }
+ }
+ }
+ return y[0].intValue();
+ }
+
+ //Procedure A'
+ private long procedure_Aa(long x0, long c, BigInteger[] pq, int size)
+ {
+ //Verify and perform condition: 0=0)
+ {
+ break; //step 14
+ }
+ else
+ {
+ pq[0] = p[0];
+ pq[1] = p[1];
+ return y[0].longValue(); //return for procedure B' step 2
+ }
+ }
+ }
+ return y[0].longValue();
+ }
+
+ //Procedure B
+ private void procedure_B(int x0, int c, BigInteger[] pq)
+ {
+ //Verify and perform condition: 0
+ * This implementation is based on ISO 18033/IEEE P1363a.
+ */
+public class KDF1BytesGenerator
+ extends BaseKDFBytesGenerator
+{
+ /**
+ * Construct a KDF1 byte generator.
+ *
+ * This implementation is based on IEEE P1363/ISO 18033.
+ */
+public class KDF2BytesGenerator
+ extends BaseKDFBytesGenerator
+{
+ /**
+ * Construct a KDF2 bytes generator. Generates key material
+ * according to IEEE P1363 or ISO 18033 depending on the initialisation.
+ *
+ * The parameter p is hardcoded to 3.
+ */
+public class NTRUEncryptionKeyPairGenerator
+ implements AsymmetricCipherKeyPairGenerator
+{
+ private NTRUEncryptionKeyGenerationParameters params;
+
+ /**
+ * Constructs a new instance with a set of encryption parameters.
+ *
+ * @param param encryption parameters
+ */
+ public void init(KeyGenerationParameters param)
+ {
+ this.params = (NTRUEncryptionKeyGenerationParameters)param;
+ }
+
+ /**
+ * Generates a new encryption key pair.
+ *
+ * @return a key pair
+ */
+ public AsymmetricCipherKeyPair generateKeyPair()
+ {
+ int N = params.N;
+ int q = params.q;
+ int df = params.df;
+ int df1 = params.df1;
+ int df2 = params.df2;
+ int df3 = params.df3;
+ int dg = params.dg;
+ boolean fastFp = params.fastFp;
+ boolean sparse = params.sparse;
+
+ Polynomial t;
+ IntegerPolynomial fq;
+ IntegerPolynomial fp = null;
+
+ // choose a random f that is invertible mod 3 and q
+ while (true)
+ {
+ IntegerPolynomial f;
+
+ // choose random t, calculate f and fp
+ if (fastFp)
+ {
+ // if fastFp=true, f is always invertible mod 3
+ t = params.polyType == NTRUParameters.TERNARY_POLYNOMIAL_TYPE_SIMPLE ? Util.generateRandomTernary(N, df, df, sparse, params.getRandom()) : ProductFormPolynomial.generateRandom(N, df1, df2, df3, df3, params.getRandom());
+ f = t.toIntegerPolynomial();
+ f.mult(3);
+ f.coeffs[0] += 1;
+ }
+ else
+ {
+ t = params.polyType == NTRUParameters.TERNARY_POLYNOMIAL_TYPE_SIMPLE ? Util.generateRandomTernary(N, df, df - 1, sparse, params.getRandom()) : ProductFormPolynomial.generateRandom(N, df1, df2, df3, df3 - 1, params.getRandom());
+ f = t.toIntegerPolynomial();
+ fp = f.invertF3();
+ if (fp == null)
+ {
+ continue;
+ }
+ }
+
+ fq = f.invertFq(q);
+ if (fq == null)
+ {
+ continue;
+ }
+ break;
+ }
+
+ // if fastFp=true, fp=1
+ if (fastFp)
+ {
+ fp = new IntegerPolynomial(N);
+ fp.coeffs[0] = 1;
+ }
+
+ // choose a random g that is invertible mod q
+ DenseTernaryPolynomial g;
+ while (true)
+ {
+ g = DenseTernaryPolynomial.generateRandom(N, dg, dg - 1, params.getRandom());
+ if (g.invertFq(q) != null)
+ {
+ break;
+ }
+ }
+
+ IntegerPolynomial h = g.mult(fq, q);
+ h.mult3(q);
+ h.ensurePositive(q);
+ g.clear();
+ fq.clear();
+
+ NTRUEncryptionPrivateKeyParameters priv = new NTRUEncryptionPrivateKeyParameters(h, t, fp, params.getEncryptionParameters());
+ NTRUEncryptionPublicKeyParameters pub = new NTRUEncryptionPublicKeyParameters(h, params.getEncryptionParameters());
+ return new AsymmetricCipherKeyPair(pub, priv);
+ }
+}
\ No newline at end of file
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/generators/NTRUSigningKeyPairGenerator.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/generators/NTRUSigningKeyPairGenerator.java
new file mode 100644
index 0000000..4ebe4be
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/generators/NTRUSigningKeyPairGenerator.java
@@ -0,0 +1,361 @@
+package org.bc.crypto.generators;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.security.SecureRandom;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+
+import org.bc.crypto.AsymmetricCipherKeyPair;
+import org.bc.crypto.AsymmetricCipherKeyPairGenerator;
+import org.bc.crypto.KeyGenerationParameters;
+import org.bc.crypto.params.NTRUParameters;
+import org.bc.crypto.params.NTRUSigningKeyGenerationParameters;
+import org.bc.crypto.params.NTRUSigningPrivateKeyParameters;
+import org.bc.crypto.params.NTRUSigningPublicKeyParameters;
+import org.bc.math.ntru.euclid.BigIntEuclidean;
+import org.bc.math.ntru.polynomial.BigDecimalPolynomial;
+import org.bc.math.ntru.polynomial.BigIntPolynomial;
+import org.bc.math.ntru.polynomial.DenseTernaryPolynomial;
+import org.bc.math.ntru.polynomial.IntegerPolynomial;
+import org.bc.math.ntru.polynomial.Polynomial;
+import org.bc.math.ntru.polynomial.ProductFormPolynomial;
+import org.bc.math.ntru.polynomial.Resultant;
+
+import static java.math.BigInteger.ONE;
+import static java.math.BigInteger.ZERO;
+
+public class NTRUSigningKeyPairGenerator
+ implements AsymmetricCipherKeyPairGenerator
+{
+ private NTRUSigningKeyGenerationParameters params;
+
+ public void init(KeyGenerationParameters param)
+ {
+ this.params = (NTRUSigningKeyGenerationParameters)param;
+ }
+
+ /**
+ * Generates a new signature key pair. Starts B+1
threads.
+ *
+ * @return a key pair
+ */
+ public AsymmetricCipherKeyPair generateKeyPair()
+ {
+ NTRUSigningPublicKeyParameters pub = null;
+ ExecutorService executor = Executors.newCachedThreadPool();
+ List
+ * This method changes F
and g
but leaves f
and
+ * g
unchanged.
+ *
+ * @param f
+ * @param g
+ * @param F
+ * @param G
+ * @param N
+ */
+ private void minimizeFG(IntegerPolynomial f, IntegerPolynomial g, IntegerPolynomial F, IntegerPolynomial G, int N)
+ {
+ int E = 0;
+ for (int j = 0; j < N; j++)
+ {
+ E += 2 * N * (f.coeffs[j] * f.coeffs[j] + g.coeffs[j] * g.coeffs[j]);
+ }
+
+ // [f(1)+g(1)]^2 = 4
+ E -= 4;
+
+ IntegerPolynomial u = (IntegerPolynomial)f.clone();
+ IntegerPolynomial v = (IntegerPolynomial)g.clone();
+ int j = 0;
+ int k = 0;
+ int maxAdjustment = N;
+ while (k < maxAdjustment && j < N)
+ {
+ int D = 0;
+ int i = 0;
+ while (i < N)
+ {
+ int D1 = F.coeffs[i] * f.coeffs[i];
+ int D2 = G.coeffs[i] * g.coeffs[i];
+ int D3 = 4 * N * (D1 + D2);
+ D += D3;
+ i++;
+ }
+ // f(1)+g(1) = 2
+ int D1 = 4 * (F.sumCoeffs() + G.sumCoeffs());
+ D -= D1;
+
+ if (D > E)
+ {
+ F.sub(u);
+ G.sub(v);
+ k++;
+ j = 0;
+ }
+ else if (D < -E)
+ {
+ F.add(u);
+ G.add(v);
+ k++;
+ j = 0;
+ }
+ j++;
+ u.rotate1();
+ v.rotate1();
+ }
+ }
+
+ /**
+ * Creates a NTRUSigner basis consisting of polynomials f, g, F, G, h
.
+ * If KeyGenAlg=FLOAT
, the basis may not be valid and this method must be rerun if that is the case.
+ *
+ * @see #generateBoundedBasis()
+ */
+ private FGBasis generateBasis()
+ {
+ int N = params.N;
+ int q = params.q;
+ int d = params.d;
+ int d1 = params.d1;
+ int d2 = params.d2;
+ int d3 = params.d3;
+ int basisType = params.basisType;
+
+ Polynomial f;
+ IntegerPolynomial fInt;
+ Polynomial g;
+ IntegerPolynomial gInt;
+ IntegerPolynomial fq;
+ Resultant rf;
+ Resultant rg;
+ BigIntEuclidean r;
+
+ int _2n1 = 2 * N + 1;
+ boolean primeCheck = params.primeCheck;
+
+ do
+ {
+ do
+ {
+ f = params.polyType== NTRUParameters.TERNARY_POLYNOMIAL_TYPE_SIMPLE ? DenseTernaryPolynomial.generateRandom(N, d + 1, d, new SecureRandom()) : ProductFormPolynomial.generateRandom(N, d1, d2, d3 + 1, d3, new SecureRandom());
+ fInt = f.toIntegerPolynomial();
+ }
+ while (primeCheck && fInt.resultant(_2n1).res.equals(ZERO));
+ fq = fInt.invertFq(q);
+ }
+ while (fq == null);
+ rf = fInt.resultant();
+
+ do
+ {
+ do
+ {
+ do
+ {
+ g = params.polyType == NTRUParameters.TERNARY_POLYNOMIAL_TYPE_SIMPLE ? DenseTernaryPolynomial.generateRandom(N, d + 1, d, new SecureRandom()) : ProductFormPolynomial.generateRandom(N, d1, d2, d3 + 1, d3, new SecureRandom());
+ gInt = g.toIntegerPolynomial();
+ }
+ while (primeCheck && gInt.resultant(_2n1).res.equals(ZERO));
+ }
+ while (gInt.invertFq(q) == null);
+ rg = gInt.resultant();
+ r = BigIntEuclidean.calculate(rf.res, rg.res);
+ }
+ while (!r.gcd.equals(ONE));
+
+ BigIntPolynomial A = (BigIntPolynomial)rf.rho.clone();
+ A.mult(r.x.multiply(BigInteger.valueOf(q)));
+ BigIntPolynomial B = (BigIntPolynomial)rg.rho.clone();
+ B.mult(r.y.multiply(BigInteger.valueOf(-q)));
+
+ BigIntPolynomial C;
+ if (params.keyGenAlg == NTRUSigningKeyGenerationParameters.KEY_GEN_ALG_RESULTANT)
+ {
+ int[] fRevCoeffs = new int[N];
+ int[] gRevCoeffs = new int[N];
+ fRevCoeffs[0] = fInt.coeffs[0];
+ gRevCoeffs[0] = gInt.coeffs[0];
+ for (int i = 1; i < N; i++)
+ {
+ fRevCoeffs[i] = fInt.coeffs[N - i];
+ gRevCoeffs[i] = gInt.coeffs[N - i];
+ }
+ IntegerPolynomial fRev = new IntegerPolynomial(fRevCoeffs);
+ IntegerPolynomial gRev = new IntegerPolynomial(gRevCoeffs);
+
+ IntegerPolynomial t = f.mult(fRev);
+ t.add(g.mult(gRev));
+ Resultant rt = t.resultant();
+ C = fRev.mult(B); // fRev.mult(B) is actually faster than new SparseTernaryPolynomial(fRev).mult(B), possibly due to cache locality?
+ C.add(gRev.mult(A));
+ C = C.mult(rt.rho);
+ C.div(rt.res);
+ }
+ else
+ { // KeyGenAlg.FLOAT
+ // calculate ceil(log10(N))
+ int log10N = 0;
+ for (int i = 1; i < N; i *= 10)
+ {
+ log10N++;
+ }
+
+ // * Cdec needs to be accurate to 1 decimal place so it can be correctly rounded;
+ // * fInv loses up to (#digits of longest coeff of B) places in fInv.mult(B);
+ // * multiplying fInv by B also multiplies the rounding error by a factor of N;
+ // so make #decimal places of fInv the sum of the above.
+ BigDecimalPolynomial fInv = rf.rho.div(new BigDecimal(rf.res), B.getMaxCoeffLength() + 1 + log10N);
+ BigDecimalPolynomial gInv = rg.rho.div(new BigDecimal(rg.res), A.getMaxCoeffLength() + 1 + log10N);
+
+ BigDecimalPolynomial Cdec = fInv.mult(B);
+ Cdec.add(gInv.mult(A));
+ Cdec.halve();
+ C = Cdec.round();
+ }
+
+ BigIntPolynomial F = (BigIntPolynomial)B.clone();
+ F.sub(f.mult(C));
+ BigIntPolynomial G = (BigIntPolynomial)A.clone();
+ G.sub(g.mult(C));
+
+ IntegerPolynomial FInt = new IntegerPolynomial(F);
+ IntegerPolynomial GInt = new IntegerPolynomial(G);
+ minimizeFG(fInt, gInt, FInt, GInt, N);
+
+ Polynomial fPrime;
+ IntegerPolynomial h;
+ if (basisType == NTRUSigningKeyGenerationParameters.BASIS_TYPE_STANDARD)
+ {
+ fPrime = FInt;
+ h = g.mult(fq, q);
+ }
+ else
+ {
+ fPrime = g;
+ h = FInt.mult(fq, q);
+ }
+ h.modPositive(q);
+
+ return new FGBasis(f, fPrime, h, FInt, GInt, params);
+ }
+
+ /**
+ * Creates a basis such that |F| < keyNormBound
and |G| < keyNormBound
+ *
+ * @return a NTRUSigner basis
+ */
+ public NTRUSigningPrivateKeyParameters.Basis generateBoundedBasis()
+ {
+ while (true)
+ {
+ FGBasis basis = generateBasis();
+ if (basis.isNormOk())
+ {
+ return basis;
+ }
+ }
+ }
+
+ private class BasisGenerationTask
+ implements CallableF
and G
.
+ */
+ public class FGBasis
+ extends NTRUSigningPrivateKeyParameters.Basis
+ {
+ public IntegerPolynomial F;
+ public IntegerPolynomial G;
+
+ FGBasis(Polynomial f, Polynomial fPrime, IntegerPolynomial h, IntegerPolynomial F, IntegerPolynomial G, NTRUSigningKeyGenerationParameters params)
+ {
+ super(f, fPrime, h, params);
+ this.F = F;
+ this.G = G;
+ }
+
+ /**
+ * Returns true
if the norms of the polynomials F
and G
+ * are within {@link NTRUSigningKeyGenerationParameters#keyNormBound}.
+ *
+ * @return
+ */
+ boolean isNormOk()
+ {
+ double keyNormBoundSq = params.keyNormBoundSq;
+ int q = params.q;
+ return (F.centeredNormSq(q) < keyNormBoundSq && G.centeredNormSq(q) < keyNormBoundSq);
+ }
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/generators/NaccacheSternKeyPairGenerator.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/generators/NaccacheSternKeyPairGenerator.java
new file mode 100644
index 0000000..da50b98
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/generators/NaccacheSternKeyPairGenerator.java
@@ -0,0 +1,365 @@
+package org.bc.crypto.generators;
+
+import org.bc.crypto.AsymmetricCipherKeyPair;
+import org.bc.crypto.AsymmetricCipherKeyPairGenerator;
+import org.bc.crypto.KeyGenerationParameters;
+import org.bc.crypto.params.NaccacheSternKeyGenerationParameters;
+import org.bc.crypto.params.NaccacheSternKeyParameters;
+import org.bc.crypto.params.NaccacheSternPrivateKeyParameters;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+import java.util.Vector;
+
+/**
+ * Key generation parameters for NaccacheStern cipher. For details on this cipher, please see
+ *
+ * http://www.gemplus.com/smart/rd/publications/pdf/NS98pkcs.pdf
+ */
+public class NaccacheSternKeyPairGenerator
+ implements AsymmetricCipherKeyPairGenerator
+{
+
+ private static int[] smallPrimes =
+ {
+ 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67,
+ 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149,
+ 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233,
+ 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331,
+ 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431,
+ 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523,
+ 541, 547, 557
+ };
+
+ private NaccacheSternKeyGenerationParameters param;
+
+ private static final BigInteger ONE = BigInteger.valueOf(1); // JDK 1.1 compatibility
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator#init(org.bouncycastle.crypto.KeyGenerationParameters)
+ */
+ public void init(KeyGenerationParameters param)
+ {
+ this.param = (NaccacheSternKeyGenerationParameters)param;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator#generateKeyPair()
+ */
+ public AsymmetricCipherKeyPair generateKeyPair()
+ {
+ int strength = param.getStrength();
+ SecureRandom rand = param.getRandom();
+ int certainty = param.getCertainty();
+ boolean debug = param.isDebug();
+
+ if (debug)
+ {
+ System.out.println("Fetching first " + param.getCntSmallPrimes() + " primes.");
+ }
+
+ Vector smallPrimes = findFirstPrimes(param.getCntSmallPrimes());
+ smallPrimes = permuteList(smallPrimes, rand);
+
+ BigInteger u = ONE;
+ BigInteger v = ONE;
+
+ for (int i = 0; i < smallPrimes.size() / 2; i++)
+ {
+ u = u.multiply((BigInteger)smallPrimes.elementAt(i));
+ }
+ for (int i = smallPrimes.size() / 2; i < smallPrimes.size(); i++)
+ {
+ v = v.multiply((BigInteger)smallPrimes.elementAt(i));
+ }
+
+ BigInteger sigma = u.multiply(v);
+
+ // n = (2 a u p_ + 1 ) ( 2 b v q_ + 1)
+ // -> |n| = strength
+ // |2| = 1 in bits
+ // -> |a| * |b| = |n| - |u| - |v| - |p_| - |q_| - |2| -|2|
+ // remainingStrength = strength - sigma.bitLength() - p_.bitLength() -
+ // q_.bitLength() - 1 -1
+ int remainingStrength = strength - sigma.bitLength() - 48;
+ BigInteger a = generatePrime(remainingStrength / 2 + 1, certainty, rand);
+ BigInteger b = generatePrime(remainingStrength / 2 + 1, certainty, rand);
+
+ BigInteger p_;
+ BigInteger q_;
+ BigInteger p;
+ BigInteger q;
+ long tries = 0;
+ if (debug)
+ {
+ System.out.println("generating p and q");
+ }
+
+ BigInteger _2au = a.multiply(u).shiftLeft(1);
+ BigInteger _2bv = b.multiply(v).shiftLeft(1);
+
+ for (;;)
+ {
+ tries++;
+
+ p_ = generatePrime(24, certainty, rand);
+
+ p = p_.multiply(_2au).add(ONE);
+
+ if (!p.isProbablePrime(certainty))
+ {
+ continue;
+ }
+
+ for (;;)
+ {
+ q_ = generatePrime(24, certainty, rand);
+
+ if (p_.equals(q_))
+ {
+ continue;
+ }
+
+ q = q_.multiply(_2bv).add(ONE);
+
+ if (q.isProbablePrime(certainty))
+ {
+ break;
+ }
+ }
+
+ if (!sigma.gcd(p_.multiply(q_)).equals(ONE))
+ {
+ // System.out.println("sigma.gcd(p_.mult(q_)) != 1!\n p_: " + p_
+ // +"\n q_: "+ q_ );
+ continue;
+ }
+
+ if (p.multiply(q).bitLength() < strength)
+ {
+ if (debug)
+ {
+ System.out.println("key size too small. Should be " + strength + " but is actually "
+ + p.multiply(q).bitLength());
+ }
+ continue;
+ }
+ break;
+ }
+
+ if (debug)
+ {
+ System.out.println("needed " + tries + " tries to generate p and q.");
+ }
+
+ BigInteger n = p.multiply(q);
+ BigInteger phi_n = p.subtract(ONE).multiply(q.subtract(ONE));
+ BigInteger g;
+ tries = 0;
+ if (debug)
+ {
+ System.out.println("generating g");
+ }
+ for (;;)
+ {
+
+ Vector gParts = new Vector();
+ for (int ind = 0; ind != smallPrimes.size(); ind++)
+ {
+ BigInteger i = (BigInteger)smallPrimes.elementAt(ind);
+ BigInteger e = phi_n.divide(i);
+
+ for (;;)
+ {
+ tries++;
+ g = new BigInteger(strength, certainty, rand);
+ if (g.modPow(e, n).equals(ONE))
+ {
+ continue;
+ }
+ gParts.addElement(g);
+ break;
+ }
+ }
+ g = ONE;
+ for (int i = 0; i < smallPrimes.size(); i++)
+ {
+ g = g.multiply(((BigInteger)gParts.elementAt(i)).modPow(sigma.divide((BigInteger)smallPrimes.elementAt(i)), n)).mod(n);
+ }
+
+ // make sure that g is not divisible by p_i or q_i
+ boolean divisible = false;
+ for (int i = 0; i < smallPrimes.size(); i++)
+ {
+ if (g.modPow(phi_n.divide((BigInteger)smallPrimes.elementAt(i)), n).equals(ONE))
+ {
+ if (debug)
+ {
+ System.out.println("g has order phi(n)/" + smallPrimes.elementAt(i) + "\n g: " + g);
+ }
+ divisible = true;
+ break;
+ }
+ }
+
+ if (divisible)
+ {
+ continue;
+ }
+
+ // make sure that g has order > phi_n/4
+
+ if (g.modPow(phi_n.divide(BigInteger.valueOf(4)), n).equals(ONE))
+ {
+ if (debug)
+ {
+ System.out.println("g has order phi(n)/4\n g:" + g);
+ }
+ continue;
+ }
+
+ if (g.modPow(phi_n.divide(p_), n).equals(ONE))
+ {
+ if (debug)
+ {
+ System.out.println("g has order phi(n)/p'\n g: " + g);
+ }
+ continue;
+ }
+ if (g.modPow(phi_n.divide(q_), n).equals(ONE))
+ {
+ if (debug)
+ {
+ System.out.println("g has order phi(n)/q'\n g: " + g);
+ }
+ continue;
+ }
+ if (g.modPow(phi_n.divide(a), n).equals(ONE))
+ {
+ if (debug)
+ {
+ System.out.println("g has order phi(n)/a\n g: " + g);
+ }
+ continue;
+ }
+ if (g.modPow(phi_n.divide(b), n).equals(ONE))
+ {
+ if (debug)
+ {
+ System.out.println("g has order phi(n)/b\n g: " + g);
+ }
+ continue;
+ }
+ break;
+ }
+ if (debug)
+ {
+ System.out.println("needed " + tries + " tries to generate g");
+ System.out.println();
+ System.out.println("found new NaccacheStern cipher variables:");
+ System.out.println("smallPrimes: " + smallPrimes);
+ System.out.println("sigma:...... " + sigma + " (" + sigma.bitLength() + " bits)");
+ System.out.println("a:.......... " + a);
+ System.out.println("b:.......... " + b);
+ System.out.println("p':......... " + p_);
+ System.out.println("q':......... " + q_);
+ System.out.println("p:.......... " + p);
+ System.out.println("q:.......... " + q);
+ System.out.println("n:.......... " + n);
+ System.out.println("phi(n):..... " + phi_n);
+ System.out.println("g:.......... " + g);
+ System.out.println();
+ }
+
+ return new AsymmetricCipherKeyPair(new NaccacheSternKeyParameters(false, g, n, sigma.bitLength()),
+ new NaccacheSternPrivateKeyParameters(g, n, sigma.bitLength(), smallPrimes, phi_n));
+ }
+
+ private static BigInteger generatePrime(
+ int bitLength,
+ int certainty,
+ SecureRandom rand)
+ {
+ BigInteger p_ = new BigInteger(bitLength, certainty, rand);
+ while (p_.bitLength() != bitLength)
+ {
+ p_ = new BigInteger(bitLength, certainty, rand);
+ }
+ return p_;
+ }
+
+ /**
+ * Generates a permuted ArrayList from the original one. The original List
+ * is not modified
+ *
+ * @param arr
+ * the ArrayList to be permuted
+ * @param rand
+ * the source of Randomness for permutation
+ * @return a new ArrayList with the permuted elements.
+ */
+ private static Vector permuteList(
+ Vector arr,
+ SecureRandom rand)
+ {
+ Vector retval = new Vector();
+ Vector tmp = new Vector();
+ for (int i = 0; i < arr.size(); i++)
+ {
+ tmp.addElement(arr.elementAt(i));
+ }
+ retval.addElement(tmp.elementAt(0));
+ tmp.removeElementAt(0);
+ while (tmp.size() != 0)
+ {
+ retval.insertElementAt(tmp.elementAt(0), getInt(rand, retval.size() + 1));
+ tmp.removeElementAt(0);
+ }
+ return retval;
+ }
+
+ private static int getInt(
+ SecureRandom rand,
+ int n)
+ {
+ if ((n & -n) == n)
+ {
+ return (int)((n * (long)(rand.nextInt() & 0x7fffffff)) >> 31);
+ }
+
+ int bits, val;
+ do
+ {
+ bits = rand.nextInt() & 0x7fffffff;
+ val = bits % n;
+ }
+ while (bits - val + (n-1) < 0);
+
+ return val;
+ }
+
+ /**
+ * Finds the first 'count' primes starting with 3
+ *
+ * @param count
+ * the number of primes to find
+ * @return a vector containing the found primes as Integer
+ */
+ private static Vector findFirstPrimes(
+ int count)
+ {
+ Vector primes = new Vector(count);
+
+ for (int i = 0; i != count; i++)
+ {
+ primes.addElement(BigInteger.valueOf(smallPrimes[i]));
+ }
+
+ return primes;
+ }
+
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/generators/OpenSSLPBEParametersGenerator.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/generators/OpenSSLPBEParametersGenerator.java
new file mode 100644
index 0000000..9d30f83
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/generators/OpenSSLPBEParametersGenerator.java
@@ -0,0 +1,131 @@
+package org.bc.crypto.generators;
+
+import org.bc.crypto.CipherParameters;
+import org.bc.crypto.Digest;
+import org.bc.crypto.PBEParametersGenerator;
+import org.bc.crypto.digests.MD5Digest;
+import org.bc.crypto.params.KeyParameter;
+import org.bc.crypto.params.ParametersWithIV;
+
+/**
+ * Generator for PBE derived keys and ivs as usd by OpenSSL.
+ * byte
.
+ * @exception java.io.IOException if an I/O error occurs.
+ */
+ public void write(
+ int b)
+ throws IOException
+ {
+ oneByte[0] = (byte)b;
+
+ if (bufferedBlockCipher != null)
+ {
+ int len = bufferedBlockCipher.processBytes(oneByte, 0, 1, buf, 0);
+
+ if (len != 0)
+ {
+ out.write(buf, 0, len);
+ }
+ }
+ else
+ {
+ out.write(streamCipher.returnByte((byte)b));
+ }
+ }
+
+ /**
+ * Writes b.length
bytes from the specified byte array
+ * to this output stream.
+ * write
method of
+ * CipherOutputStream
calls the write
+ * method of three arguments with the three arguments
+ * b
, 0
, and b.length
.
+ *
+ * @param b the data.
+ * @exception java.io.IOException if an I/O error occurs.
+ * @see #write(byte[], int, int)
+ */
+ public void write(
+ byte[] b)
+ throws IOException
+ {
+ write(b, 0, b.length);
+ }
+
+ /**
+ * Writes len
bytes from the specified byte array
+ * starting at offset off
to this output stream.
+ *
+ * @param b the data.
+ * @param off the start offset in the data.
+ * @param len the number of bytes to write.
+ * @exception java.io.IOException if an I/O error occurs.
+ */
+ public void write(
+ byte[] b,
+ int off,
+ int len)
+ throws IOException
+ {
+ if (bufferedBlockCipher != null)
+ {
+ byte[] buf = new byte[bufferedBlockCipher.getOutputSize(len)];
+
+ int outLen = bufferedBlockCipher.processBytes(b, off, len, buf, 0);
+
+ if (outLen != 0)
+ {
+ out.write(buf, 0, outLen);
+ }
+ }
+ else
+ {
+ byte[] buf = new byte[len];
+
+ streamCipher.processBytes(b, off, len, buf, 0);
+
+ out.write(buf, 0, len);
+ }
+ }
+
+ /**
+ * Flushes this output stream by forcing any buffered output bytes
+ * that have already been processed by the encapsulated cipher object
+ * to be written out.
+ *
+ * write
methods is less than
+ * the cipher's block size, no bytes will be written out.
+ *
+ * @exception java.io.IOException if an I/O error occurs.
+ */
+ public void flush()
+ throws IOException
+ {
+ super.flush();
+ }
+
+ /**
+ * Closes this output stream and releases any system resources
+ * associated with this stream.
+ * doFinal
method of the encapsulated
+ * cipher object, which causes any bytes buffered by the encapsulated
+ * cipher to be processed. The result is written out by calling the
+ * flush
method of this output stream.
+ * close
method of the underlying output
+ * stream.
+ *
+ * @exception java.io.IOException if an I/O error occurs.
+ */
+ public void close()
+ throws IOException
+ {
+ try
+ {
+ if (bufferedBlockCipher != null)
+ {
+ byte[] buf = new byte[bufferedBlockCipher.getOutputSize(0)];
+
+ int outLen = bufferedBlockCipher.doFinal(buf, 0);
+
+ if (outLen != 0)
+ {
+ out.write(buf, 0, outLen);
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ throw new IOException("Error closing stream: " + e.toString());
+ }
+
+ flush();
+
+ super.close();
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/io/DigestInputStream.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/io/DigestInputStream.java
new file mode 100644
index 0000000..8538bdf
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/io/DigestInputStream.java
@@ -0,0 +1,52 @@
+package org.bc.crypto.io;
+
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.bc.crypto.Digest;
+
+public class DigestInputStream
+ extends FilterInputStream
+{
+ protected Digest digest;
+
+ public DigestInputStream(
+ InputStream stream,
+ Digest digest)
+ {
+ super(stream);
+ this.digest = digest;
+ }
+
+ public int read()
+ throws IOException
+ {
+ int b = in.read();
+
+ if (b >= 0)
+ {
+ digest.update((byte)b);
+ }
+ return b;
+ }
+
+ public int read(
+ byte[] b,
+ int off,
+ int len)
+ throws IOException
+ {
+ int n = in.read(b, off, len);
+ if (n > 0)
+ {
+ digest.update(b, off, n);
+ }
+ return n;
+ }
+
+ public Digest getDigest()
+ {
+ return digest;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/io/DigestOutputStream.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/io/DigestOutputStream.java
new file mode 100644
index 0000000..b67b58b
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/io/DigestOutputStream.java
@@ -0,0 +1,42 @@
+package org.bc.crypto.io;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.bc.crypto.Digest;
+
+public class DigestOutputStream
+ extends OutputStream
+{
+ protected Digest digest;
+
+ public DigestOutputStream(
+ Digest Digest)
+ {
+ this.digest = Digest;
+ }
+
+ public void write(int b)
+ throws IOException
+ {
+ digest.update((byte)b);
+ }
+
+ public void write(
+ byte[] b,
+ int off,
+ int len)
+ throws IOException
+ {
+ digest.update(b, off, len);
+ }
+
+ public byte[] getDigest()
+ {
+ byte[] res = new byte[digest.getDigestSize()];
+
+ digest.doFinal(res, 0);
+
+ return res;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/io/MacInputStream.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/io/MacInputStream.java
new file mode 100644
index 0000000..cc3edaa
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/io/MacInputStream.java
@@ -0,0 +1,52 @@
+package org.bc.crypto.io;
+
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.bc.crypto.Mac;
+
+public class MacInputStream
+ extends FilterInputStream
+{
+ protected Mac mac;
+
+ public MacInputStream(
+ InputStream stream,
+ Mac mac)
+ {
+ super(stream);
+ this.mac = mac;
+ }
+
+ public int read()
+ throws IOException
+ {
+ int b = in.read();
+
+ if (b >= 0)
+ {
+ mac.update((byte)b);
+ }
+ return b;
+ }
+
+ public int read(
+ byte[] b,
+ int off,
+ int len)
+ throws IOException
+ {
+ int n = in.read(b, off, len);
+ if (n >= 0)
+ {
+ mac.update(b, off, n);
+ }
+ return n;
+ }
+
+ public Mac getMac()
+ {
+ return mac;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/io/MacOutputStream.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/io/MacOutputStream.java
new file mode 100644
index 0000000..1d26868
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/io/MacOutputStream.java
@@ -0,0 +1,42 @@
+package org.bc.crypto.io;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.bc.crypto.Mac;
+
+public class MacOutputStream
+ extends OutputStream
+{
+ protected Mac mac;
+
+ public MacOutputStream(
+ Mac mac)
+ {
+ this.mac = mac;
+ }
+
+ public void write(int b)
+ throws IOException
+ {
+ mac.update((byte)b);
+ }
+
+ public void write(
+ byte[] b,
+ int off,
+ int len)
+ throws IOException
+ {
+ mac.update(b, off, len);
+ }
+
+ public byte[] getMac()
+ {
+ byte[] res = new byte[mac.getMacSize()];
+
+ mac.doFinal(res, 0);
+
+ return res;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/io/SignerInputStream.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/io/SignerInputStream.java
new file mode 100644
index 0000000..ab37fed
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/io/SignerInputStream.java
@@ -0,0 +1,52 @@
+package org.bc.crypto.io;
+
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.bc.crypto.Signer;
+
+public class SignerInputStream
+ extends FilterInputStream
+{
+ protected Signer signer;
+
+ public SignerInputStream(
+ InputStream stream,
+ Signer signer)
+ {
+ super(stream);
+ this.signer = signer;
+ }
+
+ public int read()
+ throws IOException
+ {
+ int b = in.read();
+
+ if (b >= 0)
+ {
+ signer.update((byte)b);
+ }
+ return b;
+ }
+
+ public int read(
+ byte[] b,
+ int off,
+ int len)
+ throws IOException
+ {
+ int n = in.read(b, off, len);
+ if (n > 0)
+ {
+ signer.update(b, off, n);
+ }
+ return n;
+ }
+
+ public Signer getSigner()
+ {
+ return signer;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/io/SignerOutputStream.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/io/SignerOutputStream.java
new file mode 100644
index 0000000..5cbb934
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/io/SignerOutputStream.java
@@ -0,0 +1,38 @@
+package org.bc.crypto.io;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.bc.crypto.Signer;
+
+public class SignerOutputStream
+ extends OutputStream
+{
+ protected Signer signer;
+
+ public SignerOutputStream(
+ Signer Signer)
+ {
+ this.signer = Signer;
+ }
+
+ public void write(int b)
+ throws IOException
+ {
+ signer.update((byte)b);
+ }
+
+ public void write(
+ byte[] b,
+ int off,
+ int len)
+ throws IOException
+ {
+ signer.update(b, off, len);
+ }
+
+ public Signer getSigner()
+ {
+ return signer;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/macs/BlockCipherMac.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/macs/BlockCipherMac.java
new file mode 100644
index 0000000..2683e06
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/macs/BlockCipherMac.java
@@ -0,0 +1,174 @@
+package org.bc.crypto.macs;
+
+import org.bc.crypto.BlockCipher;
+import org.bc.crypto.CipherParameters;
+import org.bc.crypto.Mac;
+import org.bc.crypto.modes.CBCBlockCipher;
+
+public class BlockCipherMac
+ implements Mac
+{
+ private byte[] mac;
+
+ private byte[] buf;
+ private int bufOff;
+ private BlockCipher cipher;
+
+ private int macSize;
+
+ /**
+ * create a standard MAC based on a block cipher. This will produce an
+ * authentication code half the length of the block size of the cipher.
+ *
+ * @param cipher the cipher to be used as the basis of the MAC generation.
+ * @deprecated use CBCBlockCipherMac
+ */
+ public BlockCipherMac(
+ BlockCipher cipher)
+ {
+ this(cipher, (cipher.getBlockSize() * 8) / 2);
+ }
+
+ /**
+ * create a standard MAC based on a block cipher with the size of the
+ * MAC been given in bits.
+ *
If the implementation supports it, this will be an online operation and will not retain the associated data.
+ *
+ * @param in the byte to be processed.
+ */
+ public void processAADByte(byte in);
+
+ /**
+ * Add a sequence of bytes to the associated data check.
+ *
If the implementation supports it, this will be an online operation and will not retain the associated data.
+ *
+ * @param in the input byte array.
+ * @param inOff the offset into the in array where the data to be processed starts.
+ * @param len the number of bytes to be processed.
+ */
+ public void processAADBytes(byte[] in, int inOff, int len);
+
+ /**
+ * encrypt/decrypt a single byte.
+ *
+ * @param in the byte to be processed.
+ * @param out the output buffer the processed byte goes into.
+ * @param outOff the offset into the output byte array the processed data starts at.
+ * @return the number of bytes written to out.
+ * @exception DataLengthException if the output buffer is too small.
+ */
+ public int processByte(byte in, byte[] out, int outOff)
+ throws DataLengthException;
+
+ /**
+ * process a block of bytes from in putting the result into out.
+ *
+ * @param in the input byte array.
+ * @param inOff the offset into the in array where the data to be processed starts.
+ * @param len the number of bytes to be processed.
+ * @param out the output buffer the processed bytes go into.
+ * @param outOff the offset into the output byte array the processed data starts at.
+ * @return the number of bytes written to out.
+ * @exception DataLengthException if the output buffer is too small.
+ */
+ public int processBytes(byte[] in, int inOff, int len, byte[] out, int outOff)
+ throws DataLengthException;
+
+ /**
+ * Finish the operation either appending or verifying the MAC at the end of the data.
+ *
+ * @param out space for any resulting output data.
+ * @param outOff offset into out to start copying the data at.
+ * @return number of bytes written into out.
+ * @throws IllegalStateException if the cipher is in an inappropriate state.
+ * @throws org.bc.crypto.InvalidCipherTextException if the MAC fails to match.
+ */
+ public int doFinal(byte[] out, int outOff)
+ throws IllegalStateException, InvalidCipherTextException;
+
+ /**
+ * Return the value of the MAC associated with the last stream processed.
+ *
+ * @return MAC for plaintext data.
+ */
+ public byte[] getMac();
+
+ /**
+ * return the size of the output buffer required for a processBytes
+ * an input of len bytes.
+ *
+ * @param len the length of the input.
+ * @return the space required to accommodate a call to processBytes
+ * with len bytes of input.
+ */
+ public int getUpdateOutputSize(int len);
+
+ /**
+ * return the size of the output buffer required for a processBytes plus a
+ * doFinal with an input of len bytes.
+ *
+ * @param len the length of the input.
+ * @return the space required to accommodate a call to processBytes and doFinal
+ * with len bytes of input.
+ */
+ public int getOutputSize(int len);
+
+ /**
+ * Reset the cipher. After resetting the cipher is in the same state
+ * as it was after the last init (if there was one).
+ */
+ public void reset();
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/modes/CBCBlockCipher.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/modes/CBCBlockCipher.java
new file mode 100644
index 0000000..c55fe6a
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/modes/CBCBlockCipher.java
@@ -0,0 +1,253 @@
+package org.bc.crypto.modes;
+
+import org.bc.crypto.BlockCipher;
+import org.bc.crypto.CipherParameters;
+import org.bc.crypto.DataLengthException;
+import org.bc.crypto.params.ParametersWithIV;
+import org.bc.util.Arrays;
+
+/**
+ * implements Cipher-Block-Chaining (CBC) mode on top of a simple cipher.
+ */
+public class CBCBlockCipher
+ implements BlockCipher
+{
+ private byte[] IV;
+ private byte[] cbcV;
+ private byte[] cbcNextV;
+
+ private int blockSize;
+ private BlockCipher cipher = null;
+ private boolean encrypting;
+
+ /**
+ * Basic constructor.
+ *
+ * @param cipher the block cipher to be used as the basis of chaining.
+ */
+ public CBCBlockCipher(
+ BlockCipher cipher)
+ {
+ this.cipher = cipher;
+ this.blockSize = cipher.getBlockSize();
+
+ this.IV = new byte[blockSize];
+ this.cbcV = new byte[blockSize];
+ this.cbcNextV = new byte[blockSize];
+ }
+
+ /**
+ * return the underlying block cipher that we are wrapping.
+ *
+ * @return the underlying block cipher that we are wrapping.
+ */
+ public BlockCipher getUnderlyingCipher()
+ {
+ return cipher;
+ }
+
+ /**
+ * Initialise the cipher and, possibly, the initialisation vector (IV).
+ * If an IV isn't passed as part of the parameter, the IV will be all zeros.
+ *
+ * @param encrypting if true the cipher is initialised for
+ * encryption, if false for decryption.
+ * @param params the key and other data required by the cipher.
+ * @exception IllegalArgumentException if the params argument is
+ * inappropriate.
+ */
+ public void init(
+ boolean encrypting,
+ CipherParameters params)
+ throws IllegalArgumentException
+ {
+ boolean oldEncrypting = this.encrypting;
+
+ this.encrypting = encrypting;
+
+ if (params instanceof ParametersWithIV)
+ {
+ ParametersWithIV ivParam = (ParametersWithIV)params;
+ byte[] iv = ivParam.getIV();
+
+ if (iv.length != blockSize)
+ {
+ throw new IllegalArgumentException("initialisation vector must be the same length as block size");
+ }
+
+ System.arraycopy(iv, 0, IV, 0, iv.length);
+
+ reset();
+
+ // if null it's an IV changed only.
+ if (ivParam.getParameters() != null)
+ {
+ cipher.init(encrypting, ivParam.getParameters());
+ }
+ else if (oldEncrypting != encrypting)
+ {
+ throw new IllegalArgumentException("cannot change encrypting state without providing key.");
+ }
+ }
+ else
+ {
+ reset();
+
+ // if it's null, key is to be reused.
+ if (params != null)
+ {
+ cipher.init(encrypting, params);
+ }
+ else if (oldEncrypting != encrypting)
+ {
+ throw new IllegalArgumentException("cannot change encrypting state without providing key.");
+ }
+ }
+ }
+
+ /**
+ * return the algorithm name and mode.
+ *
+ * @return the name of the underlying algorithm followed by "/CBC".
+ */
+ public String getAlgorithmName()
+ {
+ return cipher.getAlgorithmName() + "/CBC";
+ }
+
+ /**
+ * return the block size of the underlying cipher.
+ *
+ * @return the block size of the underlying cipher.
+ */
+ public int getBlockSize()
+ {
+ return cipher.getBlockSize();
+ }
+
+ /**
+ * Process one block of input from the array in and write it to
+ * the out array.
+ *
+ * @param in the array containing the input data.
+ * @param inOff offset into the in array the data starts at.
+ * @param out the array the output data will be copied into.
+ * @param outOff the offset into the out array the output will start at.
+ * @exception DataLengthException if there isn't enough data in in, or
+ * space in out.
+ * @exception IllegalStateException if the cipher isn't initialised.
+ * @return the number of bytes processed and produced.
+ */
+ public int processBlock(
+ byte[] in,
+ int inOff,
+ byte[] out,
+ int outOff)
+ throws DataLengthException, IllegalStateException
+ {
+ return (encrypting) ? encryptBlock(in, inOff, out, outOff) : decryptBlock(in, inOff, out, outOff);
+ }
+
+ /**
+ * reset the chaining vector back to the IV and reset the underlying
+ * cipher.
+ */
+ public void reset()
+ {
+ System.arraycopy(IV, 0, cbcV, 0, IV.length);
+ Arrays.fill(cbcNextV, (byte)0);
+
+ cipher.reset();
+ }
+
+ /**
+ * Do the appropriate chaining step for CBC mode encryption.
+ *
+ * @param in the array containing the data to be encrypted.
+ * @param inOff offset into the in array the data starts at.
+ * @param out the array the encrypted data will be copied into.
+ * @param outOff the offset into the out array the output will start at.
+ * @exception DataLengthException if there isn't enough data in in, or
+ * space in out.
+ * @exception IllegalStateException if the cipher isn't initialised.
+ * @return the number of bytes processed and produced.
+ */
+ private int encryptBlock(
+ byte[] in,
+ int inOff,
+ byte[] out,
+ int outOff)
+ throws DataLengthException, IllegalStateException
+ {
+ if ((inOff + blockSize) > in.length)
+ {
+ throw new DataLengthException("input buffer too short");
+ }
+
+ /*
+ * XOR the cbcV and the input,
+ * then encrypt the cbcV
+ */
+ for (int i = 0; i < blockSize; i++)
+ {
+ cbcV[i] ^= in[inOff + i];
+ }
+
+ int length = cipher.processBlock(cbcV, 0, out, outOff);
+
+ /*
+ * copy ciphertext to cbcV
+ */
+ System.arraycopy(out, outOff, cbcV, 0, cbcV.length);
+
+ return length;
+ }
+
+ /**
+ * Do the appropriate chaining step for CBC mode decryption.
+ *
+ * @param in the array containing the data to be decrypted.
+ * @param inOff offset into the in array the data starts at.
+ * @param out the array the decrypted data will be copied into.
+ * @param outOff the offset into the out array the output will start at.
+ * @exception DataLengthException if there isn't enough data in in, or
+ * space in out.
+ * @exception IllegalStateException if the cipher isn't initialised.
+ * @return the number of bytes processed and produced.
+ */
+ private int decryptBlock(
+ byte[] in,
+ int inOff,
+ byte[] out,
+ int outOff)
+ throws DataLengthException, IllegalStateException
+ {
+ if ((inOff + blockSize) > in.length)
+ {
+ throw new DataLengthException("input buffer too short");
+ }
+
+ System.arraycopy(in, inOff, cbcNextV, 0, blockSize);
+
+ int length = cipher.processBlock(in, inOff, out, outOff);
+
+ /*
+ * XOR the cbcV and the output
+ */
+ for (int i = 0; i < blockSize; i++)
+ {
+ out[outOff + i] ^= cbcV[i];
+ }
+
+ /*
+ * swap the back up buffer into next position
+ */
+ byte[] tmp;
+
+ tmp = cbcV;
+ cbcV = cbcNextV;
+ cbcNextV = tmp;
+
+ return length;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/modes/CCMBlockCipher.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/modes/CCMBlockCipher.java
new file mode 100644
index 0000000..c9577d6
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/modes/CCMBlockCipher.java
@@ -0,0 +1,367 @@
+package org.bc.crypto.modes;
+
+import java.io.ByteArrayOutputStream;
+
+import org.bc.crypto.BlockCipher;
+import org.bc.crypto.CipherParameters;
+import org.bc.crypto.DataLengthException;
+import org.bc.crypto.InvalidCipherTextException;
+import org.bc.crypto.Mac;
+import org.bc.crypto.macs.CBCBlockCipherMac;
+import org.bc.crypto.params.AEADParameters;
+import org.bc.crypto.params.ParametersWithIV;
+import org.bc.util.Arrays;
+
+/**
+ * Implements the Counter with Cipher Block Chaining mode (CCM) detailed in
+ * NIST Special Publication 800-38C.
+ * APR2011_439
, this parameter set gives 128 bits of security but uses product-form polynomials and f=1+pF
.
+ */
+ public static final NTRUEncryptionKeyGenerationParameters APR2011_439_FAST = new NTRUEncryptionKeyGenerationParameters(439, 2048, 9, 8, 5, 130, 128, 9, 32, 9, true, new byte[]{0, 7, 101}, true, true, new SHA256Digest());
+
+ /**
+ * A parameter set that gives 256 bits of security and uses simple ternary polynomials.
+ */
+ public static final NTRUEncryptionKeyGenerationParameters APR2011_743 = new NTRUEncryptionKeyGenerationParameters(743, 2048, 248, 220, 256, 10, 27, 14, true, new byte[]{0, 7, 105}, false, false, new SHA512Digest());
+
+ /**
+ * Like APR2011_743
, this parameter set gives 256 bits of security but uses product-form polynomials and f=1+pF
.
+ */
+ public static final NTRUEncryptionKeyGenerationParameters APR2011_743_FAST = new NTRUEncryptionKeyGenerationParameters(743, 2048, 11, 11, 15, 220, 256, 10, 27, 14, true, new byte[]{0, 7, 105}, false, true, new SHA512Digest());
+
+ public int N, q, df, df1, df2, df3;
+ public int dr;
+ public int dr1;
+ public int dr2;
+ public int dr3;
+ public int dg;
+ int llen;
+ public int maxMsgLenBytes;
+ public int db;
+ public int bufferLenBits;
+ int bufferLenTrits;
+ public int dm0;
+ public int pkLen;
+ public int c;
+ public int minCallsR;
+ public int minCallsMask;
+ public boolean hashSeed;
+ public byte[] oid;
+ public boolean sparse;
+ public boolean fastFp;
+ public int polyType;
+ public Digest hashAlg;
+
+ /**
+ * Constructs a parameter set that uses ternary private keys (i.e. polyType=SIMPLE).
+ *
+ * @param N number of polynomial coefficients
+ * @param q modulus
+ * @param df number of ones in the private polynomial f
+ * @param dm0 minimum acceptable number of -1's, 0's, and 1's in the polynomial m'
in the last encryption step
+ * @param db number of random bits to prepend to the message
+ * @param c a parameter for the Index Generation Function ({@link org.bc.crypto.engines.IndexGenerator})
+ * @param minCallsR minimum number of hash calls for the IGF to make
+ * @param minCallsMask minimum number of calls to generate the masking polynomial
+ * @param hashSeed whether to hash the seed in the MGF first (true) or use the seed directly (false)
+ * @param oid three bytes that uniquely identify the parameter set
+ * @param sparse whether to treat ternary polynomials as sparsely populated ({@link org.bc.math.ntru.polynomial.SparseTernaryPolynomial} vs {@link org.bc.math.ntru.polynomial.DenseTernaryPolynomial})
+ * @param fastFp whether f=1+p*F
for a ternary F
(true) or f
is ternary (false)
+ * @param hashAlg a valid identifier for a java.security.MessageDigest
instance such as SHA-256
. The MessageDigest
must support the getDigestLength()
method.
+ */
+ public NTRUEncryptionKeyGenerationParameters(int N, int q, int df, int dm0, int db, int c, int minCallsR, int minCallsMask, boolean hashSeed, byte[] oid, boolean sparse, boolean fastFp, Digest hashAlg)
+ {
+ super(new SecureRandom(), db);
+ this.N = N;
+ this.q = q;
+ this.df = df;
+ this.db = db;
+ this.dm0 = dm0;
+ this.c = c;
+ this.minCallsR = minCallsR;
+ this.minCallsMask = minCallsMask;
+ this.hashSeed = hashSeed;
+ this.oid = oid;
+ this.sparse = sparse;
+ this.fastFp = fastFp;
+ this.polyType = NTRUParameters.TERNARY_POLYNOMIAL_TYPE_SIMPLE;
+ this.hashAlg = hashAlg;
+ init();
+ }
+
+ /**
+ * Constructs a parameter set that uses product-form private keys (i.e. polyType=PRODUCT).
+ *
+ * @param N number of polynomial coefficients
+ * @param q modulus
+ * @param df1 number of ones in the private polynomial f1
+ * @param df2 number of ones in the private polynomial f2
+ * @param df3 number of ones in the private polynomial f3
+ * @param dm0 minimum acceptable number of -1's, 0's, and 1's in the polynomial m'
in the last encryption step
+ * @param db number of random bits to prepend to the message
+ * @param c a parameter for the Index Generation Function ({@link org.bc.crypto.engines.IndexGenerator})
+ * @param minCallsR minimum number of hash calls for the IGF to make
+ * @param minCallsMask minimum number of calls to generate the masking polynomial
+ * @param hashSeed whether to hash the seed in the MGF first (true) or use the seed directly (false)
+ * @param oid three bytes that uniquely identify the parameter set
+ * @param sparse whether to treat ternary polynomials as sparsely populated ({@link org.bc.math.ntru.polynomial.SparseTernaryPolynomial} vs {@link org.bc.math.ntru.polynomial.DenseTernaryPolynomial})
+ * @param fastFp whether f=1+p*F
for a ternary F
(true) or f
is ternary (false)
+ * @param hashAlg a valid identifier for a java.security.MessageDigest
instance such as SHA-256
+ */
+ public NTRUEncryptionKeyGenerationParameters(int N, int q, int df1, int df2, int df3, int dm0, int db, int c, int minCallsR, int minCallsMask, boolean hashSeed, byte[] oid, boolean sparse, boolean fastFp, Digest hashAlg)
+ {
+ super(new SecureRandom(), db);
+
+ this.N = N;
+ this.q = q;
+ this.df1 = df1;
+ this.df2 = df2;
+ this.df3 = df3;
+ this.db = db;
+ this.dm0 = dm0;
+ this.c = c;
+ this.minCallsR = minCallsR;
+ this.minCallsMask = minCallsMask;
+ this.hashSeed = hashSeed;
+ this.oid = oid;
+ this.sparse = sparse;
+ this.fastFp = fastFp;
+ this.polyType = NTRUParameters.TERNARY_POLYNOMIAL_TYPE_PRODUCT;
+ this.hashAlg = hashAlg;
+ init();
+ }
+
+ private void init()
+ {
+ dr = df;
+ dr1 = df1;
+ dr2 = df2;
+ dr3 = df3;
+ dg = N / 3;
+ llen = 1; // ceil(log2(maxMsgLenBytes))
+ maxMsgLenBytes = N * 3 / 2 / 8 - llen - db / 8 - 1;
+ bufferLenBits = (N * 3 / 2 + 7) / 8 * 8 + 1;
+ bufferLenTrits = N - 1;
+ pkLen = db;
+ }
+
+ /**
+ * Reads a parameter set from an input stream.
+ *
+ * @param is an input stream
+ * @throws java.io.IOException
+ */
+ public NTRUEncryptionKeyGenerationParameters(InputStream is)
+ throws IOException
+ {
+ super(new SecureRandom(), -1);
+ DataInputStream dis = new DataInputStream(is);
+ N = dis.readInt();
+ q = dis.readInt();
+ df = dis.readInt();
+ df1 = dis.readInt();
+ df2 = dis.readInt();
+ df3 = dis.readInt();
+ db = dis.readInt();
+ dm0 = dis.readInt();
+ c = dis.readInt();
+ minCallsR = dis.readInt();
+ minCallsMask = dis.readInt();
+ hashSeed = dis.readBoolean();
+ oid = new byte[3];
+ dis.read(oid);
+ sparse = dis.readBoolean();
+ fastFp = dis.readBoolean();
+ polyType = dis.read();
+
+ String alg = dis.readUTF();
+
+ if ("SHA-512".equals(alg))
+ {
+ hashAlg = new SHA512Digest();
+ }
+ else if ("SHA-256".equals(alg))
+ {
+ hashAlg = new SHA256Digest();
+ }
+
+ init();
+ }
+
+ public NTRUEncryptionParameters getEncryptionParameters()
+ {
+ if (polyType == NTRUParameters.TERNARY_POLYNOMIAL_TYPE_SIMPLE)
+ {
+ return new NTRUEncryptionParameters(N, q, df, dm0, db, c, minCallsR, minCallsMask, hashSeed, oid, sparse, fastFp, hashAlg);
+ }
+ else
+ {
+ return new NTRUEncryptionParameters(N, q, df1, df2, df3, dm0, db, c, minCallsR, minCallsMask, hashSeed, oid, sparse, fastFp, hashAlg);
+ }
+ }
+
+ public NTRUEncryptionKeyGenerationParameters clone()
+ {
+ if (polyType == NTRUParameters.TERNARY_POLYNOMIAL_TYPE_SIMPLE)
+ {
+ return new NTRUEncryptionKeyGenerationParameters(N, q, df, dm0, db, c, minCallsR, minCallsMask, hashSeed, oid, sparse, fastFp, hashAlg);
+ }
+ else
+ {
+ return new NTRUEncryptionKeyGenerationParameters(N, q, df1, df2, df3, dm0, db, c, minCallsR, minCallsMask, hashSeed, oid, sparse, fastFp, hashAlg);
+ }
+ }
+
+ /**
+ * Returns the maximum length a plaintext message can be with this parameter set.
+ *
+ * @return the maximum length in bytes
+ */
+ public int getMaxMessageLength()
+ {
+ return maxMsgLenBytes;
+ }
+
+ /**
+ * Writes the parameter set to an output stream
+ *
+ * @param os an output stream
+ * @throws java.io.IOException
+ */
+ public void writeTo(OutputStream os)
+ throws IOException
+ {
+ DataOutputStream dos = new DataOutputStream(os);
+ dos.writeInt(N);
+ dos.writeInt(q);
+ dos.writeInt(df);
+ dos.writeInt(df1);
+ dos.writeInt(df2);
+ dos.writeInt(df3);
+ dos.writeInt(db);
+ dos.writeInt(dm0);
+ dos.writeInt(c);
+ dos.writeInt(minCallsR);
+ dos.writeInt(minCallsMask);
+ dos.writeBoolean(hashSeed);
+ dos.write(oid);
+ dos.writeBoolean(sparse);
+ dos.writeBoolean(fastFp);
+ dos.write(polyType);
+ dos.writeUTF(hashAlg.getAlgorithmName());
+ }
+
+
+ public int hashCode()
+ {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + N;
+ result = prime * result + bufferLenBits;
+ result = prime * result + bufferLenTrits;
+ result = prime * result + c;
+ result = prime * result + db;
+ result = prime * result + df;
+ result = prime * result + df1;
+ result = prime * result + df2;
+ result = prime * result + df3;
+ result = prime * result + dg;
+ result = prime * result + dm0;
+ result = prime * result + dr;
+ result = prime * result + dr1;
+ result = prime * result + dr2;
+ result = prime * result + dr3;
+ result = prime * result + (fastFp ? 1231 : 1237);
+ result = prime * result + ((hashAlg == null) ? 0 : hashAlg.getAlgorithmName().hashCode());
+ result = prime * result + (hashSeed ? 1231 : 1237);
+ result = prime * result + llen;
+ result = prime * result + maxMsgLenBytes;
+ result = prime * result + minCallsMask;
+ result = prime * result + minCallsR;
+ result = prime * result + Arrays.hashCode(oid);
+ result = prime * result + pkLen;
+ result = prime * result + polyType;
+ result = prime * result + q;
+ result = prime * result + (sparse ? 1231 : 1237);
+ return result;
+ }
+
+ public boolean equals(Object obj)
+ {
+ if (this == obj)
+ {
+ return true;
+ }
+ if (obj == null)
+ {
+ return false;
+ }
+ if (getClass() != obj.getClass())
+ {
+ return false;
+ }
+ NTRUEncryptionKeyGenerationParameters other = (NTRUEncryptionKeyGenerationParameters)obj;
+ if (N != other.N)
+ {
+ return false;
+ }
+ if (bufferLenBits != other.bufferLenBits)
+ {
+ return false;
+ }
+ if (bufferLenTrits != other.bufferLenTrits)
+ {
+ return false;
+ }
+ if (c != other.c)
+ {
+ return false;
+ }
+ if (db != other.db)
+ {
+ return false;
+ }
+ if (df != other.df)
+ {
+ return false;
+ }
+ if (df1 != other.df1)
+ {
+ return false;
+ }
+ if (df2 != other.df2)
+ {
+ return false;
+ }
+ if (df3 != other.df3)
+ {
+ return false;
+ }
+ if (dg != other.dg)
+ {
+ return false;
+ }
+ if (dm0 != other.dm0)
+ {
+ return false;
+ }
+ if (dr != other.dr)
+ {
+ return false;
+ }
+ if (dr1 != other.dr1)
+ {
+ return false;
+ }
+ if (dr2 != other.dr2)
+ {
+ return false;
+ }
+ if (dr3 != other.dr3)
+ {
+ return false;
+ }
+ if (fastFp != other.fastFp)
+ {
+ return false;
+ }
+ if (hashAlg == null)
+ {
+ if (other.hashAlg != null)
+ {
+ return false;
+ }
+ }
+ else if (!hashAlg.getAlgorithmName().equals(other.hashAlg.getAlgorithmName()))
+ {
+ return false;
+ }
+ if (hashSeed != other.hashSeed)
+ {
+ return false;
+ }
+ if (llen != other.llen)
+ {
+ return false;
+ }
+ if (maxMsgLenBytes != other.maxMsgLenBytes)
+ {
+ return false;
+ }
+ if (minCallsMask != other.minCallsMask)
+ {
+ return false;
+ }
+ if (minCallsR != other.minCallsR)
+ {
+ return false;
+ }
+ if (!Arrays.equals(oid, other.oid))
+ {
+ return false;
+ }
+ if (pkLen != other.pkLen)
+ {
+ return false;
+ }
+ if (polyType != other.polyType)
+ {
+ return false;
+ }
+ if (q != other.q)
+ {
+ return false;
+ }
+ if (sparse != other.sparse)
+ {
+ return false;
+ }
+ return true;
+ }
+
+ public String toString()
+ {
+ StringBuilder output = new StringBuilder("EncryptionParameters(N=" + N + " q=" + q);
+ if (polyType == NTRUParameters.TERNARY_POLYNOMIAL_TYPE_SIMPLE)
+ {
+ output.append(" polyType=SIMPLE df=" + df);
+ }
+ else
+ {
+ output.append(" polyType=PRODUCT df1=" + df1 + " df2=" + df2 + " df3=" + df3);
+ }
+ output.append(" dm0=" + dm0 + " db=" + db + " c=" + c + " minCallsR=" + minCallsR + " minCallsMask=" + minCallsMask +
+ " hashSeed=" + hashSeed + " hashAlg=" + hashAlg + " oid=" + Arrays.toString(oid) + " sparse=" + sparse + ")");
+ return output.toString();
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/NTRUEncryptionKeyParameters.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/NTRUEncryptionKeyParameters.java
new file mode 100644
index 0000000..0442784
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/NTRUEncryptionKeyParameters.java
@@ -0,0 +1,18 @@
+package org.bc.crypto.params;
+
+public class NTRUEncryptionKeyParameters
+ extends AsymmetricKeyParameter
+{
+ final protected NTRUEncryptionParameters params;
+
+ public NTRUEncryptionKeyParameters(boolean privateKey, NTRUEncryptionParameters params)
+ {
+ super(privateKey);
+ this.params = params;
+ }
+
+ public NTRUEncryptionParameters getParameters()
+ {
+ return params;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/NTRUEncryptionParameters.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/NTRUEncryptionParameters.java
new file mode 100644
index 0000000..dd7ff01
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/NTRUEncryptionParameters.java
@@ -0,0 +1,410 @@
+package org.bc.crypto.params;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Arrays;
+
+import org.bc.crypto.Digest;
+import org.bc.crypto.digests.SHA256Digest;
+import org.bc.crypto.digests.SHA512Digest;
+
+/**
+ * A set of parameters for NtruEncrypt. Several predefined parameter sets are available and new ones can be created as well.
+ */
+public class NTRUEncryptionParameters
+ implements Cloneable
+{
+
+ public int N, q, df, df1, df2, df3;
+ public int dr;
+ public int dr1;
+ public int dr2;
+ public int dr3;
+ public int dg;
+ int llen;
+ public int maxMsgLenBytes;
+ public int db;
+ public int bufferLenBits;
+ int bufferLenTrits;
+ public int dm0;
+ public int pkLen;
+ public int c;
+ public int minCallsR;
+ public int minCallsMask;
+ public boolean hashSeed;
+ public byte[] oid;
+ public boolean sparse;
+ public boolean fastFp;
+ public int polyType;
+ public Digest hashAlg;
+
+ /**
+ * Constructs a parameter set that uses ternary private keys (i.e. polyType=SIMPLE).
+ *
+ * @param N number of polynomial coefficients
+ * @param q modulus
+ * @param df number of ones in the private polynomial f
+ * @param dm0 minimum acceptable number of -1's, 0's, and 1's in the polynomial m'
in the last encryption step
+ * @param db number of random bits to prepend to the message
+ * @param c a parameter for the Index Generation Function ({@link org.bc.crypto.engines.IndexGenerator})
+ * @param minCallsR minimum number of hash calls for the IGF to make
+ * @param minCallsMask minimum number of calls to generate the masking polynomial
+ * @param hashSeed whether to hash the seed in the MGF first (true) or use the seed directly (false)
+ * @param oid three bytes that uniquely identify the parameter set
+ * @param sparse whether to treat ternary polynomials as sparsely populated ({@link org.bc.math.ntru.polynomial.SparseTernaryPolynomial} vs {@link org.bc.math.ntru.polynomial.DenseTernaryPolynomial})
+ * @param fastFp whether f=1+p*F
for a ternary F
(true) or f
is ternary (false)
+ * @param hashAlg a valid identifier for a java.security.MessageDigest
instance such as SHA-256
. The MessageDigest
must support the getDigestLength()
method.
+ */
+ public NTRUEncryptionParameters(int N, int q, int df, int dm0, int db, int c, int minCallsR, int minCallsMask, boolean hashSeed, byte[] oid, boolean sparse, boolean fastFp, Digest hashAlg)
+ {
+ this.N = N;
+ this.q = q;
+ this.df = df;
+ this.db = db;
+ this.dm0 = dm0;
+ this.c = c;
+ this.minCallsR = minCallsR;
+ this.minCallsMask = minCallsMask;
+ this.hashSeed = hashSeed;
+ this.oid = oid;
+ this.sparse = sparse;
+ this.fastFp = fastFp;
+ this.polyType = NTRUParameters.TERNARY_POLYNOMIAL_TYPE_SIMPLE;
+ this.hashAlg = hashAlg;
+ init();
+ }
+
+ /**
+ * Constructs a parameter set that uses product-form private keys (i.e. polyType=PRODUCT).
+ *
+ * @param N number of polynomial coefficients
+ * @param q modulus
+ * @param df1 number of ones in the private polynomial f1
+ * @param df2 number of ones in the private polynomial f2
+ * @param df3 number of ones in the private polynomial f3
+ * @param dm0 minimum acceptable number of -1's, 0's, and 1's in the polynomial m'
in the last encryption step
+ * @param db number of random bits to prepend to the message
+ * @param c a parameter for the Index Generation Function ({@link org.bc.crypto.engines.IndexGenerator})
+ * @param minCallsR minimum number of hash calls for the IGF to make
+ * @param minCallsMask minimum number of calls to generate the masking polynomial
+ * @param hashSeed whether to hash the seed in the MGF first (true) or use the seed directly (false)
+ * @param oid three bytes that uniquely identify the parameter set
+ * @param sparse whether to treat ternary polynomials as sparsely populated ({@link org.bc.math.ntru.polynomial.SparseTernaryPolynomial} vs {@link org.bc.math.ntru.polynomial.DenseTernaryPolynomial})
+ * @param fastFp whether f=1+p*F
for a ternary F
(true) or f
is ternary (false)
+ * @param hashAlg a valid identifier for a java.security.MessageDigest
instance such as SHA-256
+ */
+ public NTRUEncryptionParameters(int N, int q, int df1, int df2, int df3, int dm0, int db, int c, int minCallsR, int minCallsMask, boolean hashSeed, byte[] oid, boolean sparse, boolean fastFp, Digest hashAlg)
+ {
+ this.N = N;
+ this.q = q;
+ this.df1 = df1;
+ this.df2 = df2;
+ this.df3 = df3;
+ this.db = db;
+ this.dm0 = dm0;
+ this.c = c;
+ this.minCallsR = minCallsR;
+ this.minCallsMask = minCallsMask;
+ this.hashSeed = hashSeed;
+ this.oid = oid;
+ this.sparse = sparse;
+ this.fastFp = fastFp;
+ this.polyType = NTRUParameters.TERNARY_POLYNOMIAL_TYPE_PRODUCT;
+ this.hashAlg = hashAlg;
+ init();
+ }
+
+ private void init()
+ {
+ dr = df;
+ dr1 = df1;
+ dr2 = df2;
+ dr3 = df3;
+ dg = N / 3;
+ llen = 1; // ceil(log2(maxMsgLenBytes))
+ maxMsgLenBytes = N * 3 / 2 / 8 - llen - db / 8 - 1;
+ bufferLenBits = (N * 3 / 2 + 7) / 8 * 8 + 1;
+ bufferLenTrits = N - 1;
+ pkLen = db;
+ }
+
+ /**
+ * Reads a parameter set from an input stream.
+ *
+ * @param is an input stream
+ * @throws IOException
+ */
+ public NTRUEncryptionParameters(InputStream is)
+ throws IOException
+ {
+ DataInputStream dis = new DataInputStream(is);
+ N = dis.readInt();
+ q = dis.readInt();
+ df = dis.readInt();
+ df1 = dis.readInt();
+ df2 = dis.readInt();
+ df3 = dis.readInt();
+ db = dis.readInt();
+ dm0 = dis.readInt();
+ c = dis.readInt();
+ minCallsR = dis.readInt();
+ minCallsMask = dis.readInt();
+ hashSeed = dis.readBoolean();
+ oid = new byte[3];
+ dis.read(oid);
+ sparse = dis.readBoolean();
+ fastFp = dis.readBoolean();
+ polyType = dis.read();
+
+ String alg = dis.readUTF();
+
+ if ("SHA-512".equals(alg))
+ {
+ hashAlg = new SHA512Digest();
+ }
+ else if ("SHA-256".equals(alg))
+ {
+ hashAlg = new SHA256Digest();
+ }
+
+ init();
+ }
+
+ public NTRUEncryptionParameters clone()
+ {
+ if (polyType == NTRUParameters.TERNARY_POLYNOMIAL_TYPE_SIMPLE)
+ {
+ return new NTRUEncryptionParameters(N, q, df, dm0, db, c, minCallsR, minCallsMask, hashSeed, oid, sparse, fastFp, hashAlg);
+ }
+ else
+ {
+ return new NTRUEncryptionParameters(N, q, df1, df2, df3, dm0, db, c, minCallsR, minCallsMask, hashSeed, oid, sparse, fastFp, hashAlg);
+ }
+ }
+
+ /**
+ * Returns the maximum length a plaintext message can be with this parameter set.
+ *
+ * @return the maximum length in bytes
+ */
+ public int getMaxMessageLength()
+ {
+ return maxMsgLenBytes;
+ }
+
+ /**
+ * Writes the parameter set to an output stream
+ *
+ * @param os an output stream
+ * @throws IOException
+ */
+ public void writeTo(OutputStream os)
+ throws IOException
+ {
+ DataOutputStream dos = new DataOutputStream(os);
+ dos.writeInt(N);
+ dos.writeInt(q);
+ dos.writeInt(df);
+ dos.writeInt(df1);
+ dos.writeInt(df2);
+ dos.writeInt(df3);
+ dos.writeInt(db);
+ dos.writeInt(dm0);
+ dos.writeInt(c);
+ dos.writeInt(minCallsR);
+ dos.writeInt(minCallsMask);
+ dos.writeBoolean(hashSeed);
+ dos.write(oid);
+ dos.writeBoolean(sparse);
+ dos.writeBoolean(fastFp);
+ dos.write(polyType);
+ dos.writeUTF(hashAlg.getAlgorithmName());
+ }
+
+
+ public int hashCode()
+ {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + N;
+ result = prime * result + bufferLenBits;
+ result = prime * result + bufferLenTrits;
+ result = prime * result + c;
+ result = prime * result + db;
+ result = prime * result + df;
+ result = prime * result + df1;
+ result = prime * result + df2;
+ result = prime * result + df3;
+ result = prime * result + dg;
+ result = prime * result + dm0;
+ result = prime * result + dr;
+ result = prime * result + dr1;
+ result = prime * result + dr2;
+ result = prime * result + dr3;
+ result = prime * result + (fastFp ? 1231 : 1237);
+ result = prime * result + ((hashAlg == null) ? 0 : hashAlg.getAlgorithmName().hashCode());
+ result = prime * result + (hashSeed ? 1231 : 1237);
+ result = prime * result + llen;
+ result = prime * result + maxMsgLenBytes;
+ result = prime * result + minCallsMask;
+ result = prime * result + minCallsR;
+ result = prime * result + Arrays.hashCode(oid);
+ result = prime * result + pkLen;
+ result = prime * result + polyType;
+ result = prime * result + q;
+ result = prime * result + (sparse ? 1231 : 1237);
+ return result;
+ }
+
+ public boolean equals(Object obj)
+ {
+ if (this == obj)
+ {
+ return true;
+ }
+ if (obj == null)
+ {
+ return false;
+ }
+ if (getClass() != obj.getClass())
+ {
+ return false;
+ }
+ NTRUEncryptionParameters other = (NTRUEncryptionParameters)obj;
+ if (N != other.N)
+ {
+ return false;
+ }
+ if (bufferLenBits != other.bufferLenBits)
+ {
+ return false;
+ }
+ if (bufferLenTrits != other.bufferLenTrits)
+ {
+ return false;
+ }
+ if (c != other.c)
+ {
+ return false;
+ }
+ if (db != other.db)
+ {
+ return false;
+ }
+ if (df != other.df)
+ {
+ return false;
+ }
+ if (df1 != other.df1)
+ {
+ return false;
+ }
+ if (df2 != other.df2)
+ {
+ return false;
+ }
+ if (df3 != other.df3)
+ {
+ return false;
+ }
+ if (dg != other.dg)
+ {
+ return false;
+ }
+ if (dm0 != other.dm0)
+ {
+ return false;
+ }
+ if (dr != other.dr)
+ {
+ return false;
+ }
+ if (dr1 != other.dr1)
+ {
+ return false;
+ }
+ if (dr2 != other.dr2)
+ {
+ return false;
+ }
+ if (dr3 != other.dr3)
+ {
+ return false;
+ }
+ if (fastFp != other.fastFp)
+ {
+ return false;
+ }
+ if (hashAlg == null)
+ {
+ if (other.hashAlg != null)
+ {
+ return false;
+ }
+ }
+ else if (!hashAlg.getAlgorithmName().equals(other.hashAlg.getAlgorithmName()))
+ {
+ return false;
+ }
+ if (hashSeed != other.hashSeed)
+ {
+ return false;
+ }
+ if (llen != other.llen)
+ {
+ return false;
+ }
+ if (maxMsgLenBytes != other.maxMsgLenBytes)
+ {
+ return false;
+ }
+ if (minCallsMask != other.minCallsMask)
+ {
+ return false;
+ }
+ if (minCallsR != other.minCallsR)
+ {
+ return false;
+ }
+ if (!Arrays.equals(oid, other.oid))
+ {
+ return false;
+ }
+ if (pkLen != other.pkLen)
+ {
+ return false;
+ }
+ if (polyType != other.polyType)
+ {
+ return false;
+ }
+ if (q != other.q)
+ {
+ return false;
+ }
+ if (sparse != other.sparse)
+ {
+ return false;
+ }
+ return true;
+ }
+
+ public String toString()
+ {
+ StringBuilder output = new StringBuilder("EncryptionParameters(N=" + N + " q=" + q);
+ if (polyType == NTRUParameters.TERNARY_POLYNOMIAL_TYPE_SIMPLE)
+ {
+ output.append(" polyType=SIMPLE df=" + df);
+ }
+ else
+ {
+ output.append(" polyType=PRODUCT df1=" + df1 + " df2=" + df2 + " df3=" + df3);
+ }
+ output.append(" dm0=" + dm0 + " db=" + db + " c=" + c + " minCallsR=" + minCallsR + " minCallsMask=" + minCallsMask +
+ " hashSeed=" + hashSeed + " hashAlg=" + hashAlg + " oid=" + Arrays.toString(oid) + " sparse=" + sparse + ")");
+ return output.toString();
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/NTRUEncryptionPrivateKeyParameters.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/NTRUEncryptionPrivateKeyParameters.java
new file mode 100644
index 0000000..c302da3
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/NTRUEncryptionPrivateKeyParameters.java
@@ -0,0 +1,199 @@
+package org.bc.crypto.params;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.bc.math.ntru.polynomial.DenseTernaryPolynomial;
+import org.bc.math.ntru.polynomial.IntegerPolynomial;
+import org.bc.math.ntru.polynomial.Polynomial;
+import org.bc.math.ntru.polynomial.ProductFormPolynomial;
+import org.bc.math.ntru.polynomial.SparseTernaryPolynomial;
+
+/**
+ * A NtruEncrypt private key is essentially a polynomial named f
+ * which takes different forms depending on whether product-form polynomials are used,
+ * and on fastP
+ * The inverse of f
modulo p
is precomputed on initialization.
+ */
+public class NTRUEncryptionPrivateKeyParameters
+ extends NTRUEncryptionKeyParameters
+{
+ public Polynomial t;
+ public IntegerPolynomial fp;
+ public IntegerPolynomial h;
+
+ /**
+ * Constructs a new private key from a polynomial
+ *
+ * @param h the public polynomial for the key.
+ * @param t the polynomial which determines the key: if fastFp=true
, f=1+3t
; otherwise, f=t
+ * @param fp the inverse of f
+ * @param params the NtruEncrypt parameters to use
+ */
+ public NTRUEncryptionPrivateKeyParameters(IntegerPolynomial h, Polynomial t, IntegerPolynomial fp, NTRUEncryptionParameters params)
+ {
+ super(true, params);
+
+ this.h = h;
+ this.t = t;
+ this.fp = fp;
+ }
+
+ /**
+ * Converts a byte array to a polynomial f
and constructs a new private key
+ *
+ * @param b an encoded polynomial
+ * @param params the NtruEncrypt parameters to use
+ * @see #getEncoded()
+ */
+ public NTRUEncryptionPrivateKeyParameters(byte[] b, NTRUEncryptionParameters params)
+ throws IOException
+ {
+ this(new ByteArrayInputStream(b), params);
+ }
+
+ /**
+ * Reads a polynomial f
from an input stream and constructs a new private key
+ *
+ * @param is an input stream
+ * @param params the NtruEncrypt parameters to use
+ * @see #writeTo(OutputStream)
+ */
+ public NTRUEncryptionPrivateKeyParameters(InputStream is, NTRUEncryptionParameters params)
+ throws IOException
+ {
+ super(true, params);
+
+ if (params.polyType == NTRUParameters.TERNARY_POLYNOMIAL_TYPE_PRODUCT)
+ {
+ int N = params.N;
+ int df1 = params.df1;
+ int df2 = params.df2;
+ int df3Ones = params.df3;
+ int df3NegOnes = params.fastFp ? params.df3 : params.df3 - 1;
+ h = IntegerPolynomial.fromBinary(is, params.N, params.q);
+ t = ProductFormPolynomial.fromBinary(is, N, df1, df2, df3Ones, df3NegOnes);
+ }
+ else
+ {
+ h = IntegerPolynomial.fromBinary(is, params.N, params.q);
+ IntegerPolynomial fInt = IntegerPolynomial.fromBinary3Tight(is, params.N);
+ t = params.sparse ? new SparseTernaryPolynomial(fInt) : new DenseTernaryPolynomial(fInt);
+ }
+
+ init();
+ }
+
+ /**
+ * Initializes fp
from t.
+ */
+ private void init()
+ {
+ if (params.fastFp)
+ {
+ fp = new IntegerPolynomial(params.N);
+ fp.coeffs[0] = 1;
+ }
+ else
+ {
+ fp = t.toIntegerPolynomial().invertF3();
+ }
+ }
+
+ /**
+ * Converts the key to a byte array
+ *
+ * @return the encoded key
+ * @see #NTRUEncryptionPrivateKeyParameters(byte[], NTRUEncryptionParameters)
+ */
+ public byte[] getEncoded()
+ {
+ byte[] hBytes = h.toBinary(params.q);
+ byte[] tBytes;
+
+ if (t instanceof ProductFormPolynomial)
+ {
+ tBytes = ((ProductFormPolynomial)t).toBinary();
+ }
+ else
+ {
+ tBytes = t.toIntegerPolynomial().toBinary3Tight();
+ }
+
+ byte[] res = new byte[hBytes.length + tBytes.length];
+
+ System.arraycopy(hBytes, 0, res, 0, hBytes.length);
+ System.arraycopy(tBytes, 0, res, hBytes.length, tBytes.length);
+
+ return res;
+ }
+
+ /**
+ * Writes the key to an output stream
+ *
+ * @param os an output stream
+ * @throws IOException
+ * @see #NTRUEncryptionPrivateKeyParameters(InputStream, NTRUEncryptionParameters)
+ */
+ public void writeTo(OutputStream os)
+ throws IOException
+ {
+ os.write(getEncoded());
+ }
+
+ public int hashCode()
+ {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((params == null) ? 0 : params.hashCode());
+ result = prime * result + ((t == null) ? 0 : t.hashCode());
+ result = prime * result + ((h == null) ? 0 : h.hashCode());
+ return result;
+ }
+
+ public boolean equals(Object obj)
+ {
+ if (this == obj)
+ {
+ return true;
+ }
+ if (obj == null)
+ {
+ return false;
+ }
+ if (!(obj instanceof NTRUEncryptionPrivateKeyParameters))
+ {
+ return false;
+ }
+ NTRUEncryptionPrivateKeyParameters other = (NTRUEncryptionPrivateKeyParameters)obj;
+ if (params == null)
+ {
+ if (other.params != null)
+ {
+ return false;
+ }
+ }
+ else if (!params.equals(other.params))
+ {
+ return false;
+ }
+ if (t == null)
+ {
+ if (other.t != null)
+ {
+ return false;
+ }
+ }
+ else if (!t.equals(other.t))
+ {
+ return false;
+ }
+ if (!h.equals(other.h))
+ {
+ return false;
+ }
+ return true;
+ }
+}
\ No newline at end of file
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/NTRUEncryptionPublicKeyParameters.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/NTRUEncryptionPublicKeyParameters.java
new file mode 100644
index 0000000..4546888
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/NTRUEncryptionPublicKeyParameters.java
@@ -0,0 +1,131 @@
+package org.bc.crypto.params;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.bc.math.ntru.polynomial.IntegerPolynomial;
+
+/**
+ * A NtruEncrypt public key is essentially a polynomial named h
.
+ */
+public class NTRUEncryptionPublicKeyParameters
+ extends NTRUEncryptionKeyParameters
+{
+ public IntegerPolynomial h;
+
+ /**
+ * Constructs a new public key from a polynomial
+ *
+ * @param h the polynomial h
which determines the key
+ * @param params the NtruEncrypt parameters to use
+ */
+ public NTRUEncryptionPublicKeyParameters(IntegerPolynomial h, NTRUEncryptionParameters params)
+ {
+ super(false, params);
+
+ this.h = h;
+ }
+
+ /**
+ * Converts a byte array to a polynomial h
and constructs a new public key
+ *
+ * @param b an encoded polynomial
+ * @param params the NtruEncrypt parameters to use
+ * @see #getEncoded()
+ */
+ public NTRUEncryptionPublicKeyParameters(byte[] b, NTRUEncryptionParameters params)
+ {
+ super(false, params);
+
+ h = IntegerPolynomial.fromBinary(b, params.N, params.q);
+ }
+
+ /**
+ * Reads a polynomial h
from an input stream and constructs a new public key
+ *
+ * @param is an input stream
+ * @param params the NtruEncrypt parameters to use
+ * @see #writeTo(OutputStream)
+ */
+ public NTRUEncryptionPublicKeyParameters(InputStream is, NTRUEncryptionParameters params)
+ throws IOException
+ {
+ super(false, params);
+
+ h = IntegerPolynomial.fromBinary(is, params.N, params.q);
+ }
+
+ /**
+ * Converts the key to a byte array
+ *
+ * @return the encoded key
+ * @see #NTRUEncryptionPublicKeyParameters(byte[], NTRUEncryptionParameters)
+ */
+ public byte[] getEncoded()
+ {
+ return h.toBinary(params.q);
+ }
+
+ /**
+ * Writes the key to an output stream
+ *
+ * @param os an output stream
+ * @throws IOException
+ * @see #NTRUEncryptionPublicKeyParameters(InputStream, NTRUEncryptionParameters)
+ */
+ public void writeTo(OutputStream os)
+ throws IOException
+ {
+ os.write(getEncoded());
+ }
+
+ public int hashCode()
+ {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((h == null) ? 0 : h.hashCode());
+ result = prime * result + ((params == null) ? 0 : params.hashCode());
+ return result;
+ }
+
+ public boolean equals(Object obj)
+ {
+ if (this == obj)
+ {
+ return true;
+ }
+ if (obj == null)
+ {
+ return false;
+ }
+ if (!(obj instanceof NTRUEncryptionPublicKeyParameters))
+ {
+ return false;
+ }
+ NTRUEncryptionPublicKeyParameters other = (NTRUEncryptionPublicKeyParameters)obj;
+ if (h == null)
+ {
+ if (other.h != null)
+ {
+ return false;
+ }
+ }
+ else if (!h.equals(other.h))
+ {
+ return false;
+ }
+ if (params == null)
+ {
+ if (other.params != null)
+ {
+ return false;
+ }
+ }
+ else if (!params.equals(other.params))
+ {
+ return false;
+ }
+ return true;
+ }
+}
\ No newline at end of file
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/NTRUParameters.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/NTRUParameters.java
new file mode 100644
index 0000000..6b66c2c
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/NTRUParameters.java
@@ -0,0 +1,7 @@
+package org.bc.crypto.params;
+
+public class NTRUParameters
+{
+ public static final int TERNARY_POLYNOMIAL_TYPE_SIMPLE = 0;
+ public static final int TERNARY_POLYNOMIAL_TYPE_PRODUCT = 1;
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/NTRUSigningKeyGenerationParameters.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/NTRUSigningKeyGenerationParameters.java
new file mode 100644
index 0000000..a8ec5e6
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/NTRUSigningKeyGenerationParameters.java
@@ -0,0 +1,407 @@
+package org.bc.crypto.params;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.security.SecureRandom;
+import java.text.DecimalFormat;
+
+import org.bc.crypto.Digest;
+import org.bc.crypto.KeyGenerationParameters;
+import org.bc.crypto.digests.SHA256Digest;
+import org.bc.crypto.digests.SHA512Digest;
+
+/**
+ * A set of parameters for NtruSign. Several predefined parameter sets are available and new ones can be created as well.
+ */
+public class NTRUSigningKeyGenerationParameters
+ extends KeyGenerationParameters
+ implements Cloneable
+{
+ public static final int BASIS_TYPE_STANDARD = 0;
+ public static final int BASIS_TYPE_TRANSPOSE = 1;
+
+ public static final int KEY_GEN_ALG_RESULTANT = 0;
+ public static final int KEY_GEN_ALG_FLOAT = 1;
+
+ /**
+ * Gives 128 bits of security
+ */
+ public static final NTRUSigningKeyGenerationParameters APR2011_439 = new NTRUSigningKeyGenerationParameters(439, 2048, 146, 1, BASIS_TYPE_TRANSPOSE, 0.165, 400, 280, false, true, KEY_GEN_ALG_RESULTANT, new SHA256Digest());
+
+ /**
+ * Like APR2011_439
, this parameter set gives 128 bits of security but uses product-form polynomials
+ */
+ public static final NTRUSigningKeyGenerationParameters APR2011_439_PROD = new NTRUSigningKeyGenerationParameters(439, 2048, 9, 8, 5, 1, BASIS_TYPE_TRANSPOSE, 0.165, 400, 280, false, true, KEY_GEN_ALG_RESULTANT, new SHA256Digest());
+
+ /**
+ * Gives 256 bits of security
+ */
+ public static final NTRUSigningKeyGenerationParameters APR2011_743 = new NTRUSigningKeyGenerationParameters(743, 2048, 248, 1, BASIS_TYPE_TRANSPOSE, 0.127, 405, 360, true, false, KEY_GEN_ALG_RESULTANT, new SHA512Digest());
+
+ /**
+ * Like APR2011_439
, this parameter set gives 256 bits of security but uses product-form polynomials
+ */
+ public static final NTRUSigningKeyGenerationParameters APR2011_743_PROD = new NTRUSigningKeyGenerationParameters(743, 2048, 11, 11, 15, 1, BASIS_TYPE_TRANSPOSE, 0.127, 405, 360, true, false, KEY_GEN_ALG_RESULTANT, new SHA512Digest());
+
+ /**
+ * Generates key pairs quickly. Use for testing only.
+ */
+ public static final NTRUSigningKeyGenerationParameters TEST157 = new NTRUSigningKeyGenerationParameters(157, 256, 29, 1, BASIS_TYPE_TRANSPOSE, 0.38, 200, 80, false, false, KEY_GEN_ALG_RESULTANT, new SHA256Digest());
+ /**
+ * Generates key pairs quickly. Use for testing only.
+ */
+ public static final NTRUSigningKeyGenerationParameters TEST157_PROD = new NTRUSigningKeyGenerationParameters(157, 256, 5, 5, 8, 1, BASIS_TYPE_TRANSPOSE, 0.38, 200, 80, false, false, KEY_GEN_ALG_RESULTANT, new SHA256Digest());
+
+
+ public int N;
+ public int q;
+ public int d, d1, d2, d3, B;
+ double beta;
+ public double betaSq;
+ double normBound;
+ public double normBoundSq;
+ public int signFailTolerance = 100;
+ double keyNormBound;
+ public double keyNormBoundSq;
+ public boolean primeCheck; // true if N and 2N+1 are prime
+ public int basisType;
+ int bitsF = 6; // max #bits needed to encode one coefficient of the polynomial F
+ public boolean sparse; // whether to treat ternary polynomials as sparsely populated
+ public int keyGenAlg;
+ public Digest hashAlg;
+ public int polyType;
+
+ /**
+ * Constructs a parameter set that uses ternary private keys (i.e. polyType=SIMPLE).
+ *
+ * @param N number of polynomial coefficients
+ * @param q modulus
+ * @param d number of -1's in the private polynomials f
and g
+ * @param B number of perturbations
+ * @param basisType whether to use the standard or transpose lattice
+ * @param beta balancing factor for the transpose lattice
+ * @param normBound maximum norm for valid signatures
+ * @param keyNormBound maximum norm for the ploynomials F
and G
+ * @param primeCheck whether 2N+1
is prime
+ * @param sparse whether to treat ternary polynomials as sparsely populated ({@link org.bc.math.ntru.polynomial.SparseTernaryPolynomial} vs {@link org.bc.math.ntru.polynomial.DenseTernaryPolynomial})
+ * @param keyGenAlg RESULTANT
produces better bases, FLOAT
is slightly faster. RESULTANT
follows the EESS standard while FLOAT
is described in Hoffstein et al: An Introduction to Mathematical Cryptography.
+ * @param hashAlg a valid identifier for a java.security.MessageDigest
instance such as SHA-256
. The MessageDigest
must support the getDigestLength()
method.
+ */
+ public NTRUSigningKeyGenerationParameters(int N, int q, int d, int B, int basisType, double beta, double normBound, double keyNormBound, boolean primeCheck, boolean sparse, int keyGenAlg, Digest hashAlg)
+ {
+ super(new SecureRandom(), N);
+ this.N = N;
+ this.q = q;
+ this.d = d;
+ this.B = B;
+ this.basisType = basisType;
+ this.beta = beta;
+ this.normBound = normBound;
+ this.keyNormBound = keyNormBound;
+ this.primeCheck = primeCheck;
+ this.sparse = sparse;
+ this.keyGenAlg = keyGenAlg;
+ this.hashAlg = hashAlg;
+ polyType = NTRUParameters.TERNARY_POLYNOMIAL_TYPE_SIMPLE;
+ init();
+ }
+
+ /**
+ * Constructs a parameter set that uses product-form private keys (i.e. polyType=PRODUCT).
+ *
+ * @param N number of polynomial coefficients
+ * @param q modulus
+ * @param d1 number of -1's in the private polynomials f
and g
+ * @param d2 number of -1's in the private polynomials f
and g
+ * @param d3 number of -1's in the private polynomials f
and g
+ * @param B number of perturbations
+ * @param basisType whether to use the standard or transpose lattice
+ * @param beta balancing factor for the transpose lattice
+ * @param normBound maximum norm for valid signatures
+ * @param keyNormBound maximum norm for the ploynomials F
and G
+ * @param primeCheck whether 2N+1
is prime
+ * @param sparse whether to treat ternary polynomials as sparsely populated ({@link org.bc.math.ntru.polynomial.SparseTernaryPolynomial} vs {@link org.bc.math.ntru.polynomial.DenseTernaryPolynomial})
+ * @param keyGenAlg RESULTANT
produces better bases, FLOAT
is slightly faster. RESULTANT
follows the EESS standard while FLOAT
is described in Hoffstein et al: An Introduction to Mathematical Cryptography.
+ * @param hashAlg a valid identifier for a java.security.MessageDigest
instance such as SHA-256
. The MessageDigest
must support the getDigestLength()
method.
+ */
+ public NTRUSigningKeyGenerationParameters(int N, int q, int d1, int d2, int d3, int B, int basisType, double beta, double normBound, double keyNormBound, boolean primeCheck, boolean sparse, int keyGenAlg, Digest hashAlg)
+ {
+ super(new SecureRandom(), N);
+ this.N = N;
+ this.q = q;
+ this.d1 = d1;
+ this.d2 = d2;
+ this.d3 = d3;
+ this.B = B;
+ this.basisType = basisType;
+ this.beta = beta;
+ this.normBound = normBound;
+ this.keyNormBound = keyNormBound;
+ this.primeCheck = primeCheck;
+ this.sparse = sparse;
+ this.keyGenAlg = keyGenAlg;
+ this.hashAlg = hashAlg;
+ polyType = NTRUParameters.TERNARY_POLYNOMIAL_TYPE_PRODUCT;
+ init();
+ }
+
+ private void init()
+ {
+ betaSq = beta * beta;
+ normBoundSq = normBound * normBound;
+ keyNormBoundSq = keyNormBound * keyNormBound;
+ }
+
+ /**
+ * Reads a parameter set from an input stream.
+ *
+ * @param is an input stream
+ * @throws java.io.IOException
+ */
+ public NTRUSigningKeyGenerationParameters(InputStream is)
+ throws IOException
+ {
+ super(new SecureRandom(), 0); // TODO:
+ DataInputStream dis = new DataInputStream(is);
+ N = dis.readInt();
+ q = dis.readInt();
+ d = dis.readInt();
+ d1 = dis.readInt();
+ d2 = dis.readInt();
+ d3 = dis.readInt();
+ B = dis.readInt();
+ basisType = dis.readInt();
+ beta = dis.readDouble();
+ normBound = dis.readDouble();
+ keyNormBound = dis.readDouble();
+ signFailTolerance = dis.readInt();
+ primeCheck = dis.readBoolean();
+ sparse = dis.readBoolean();
+ bitsF = dis.readInt();
+ keyGenAlg = dis.read();
+ String alg = dis.readUTF();
+ if ("SHA-512".equals(alg))
+ {
+ hashAlg = new SHA512Digest();
+ }
+ else if ("SHA-256".equals(alg))
+ {
+ hashAlg = new SHA256Digest();
+ }
+ polyType = dis.read();
+ init();
+ }
+
+ /**
+ * Writes the parameter set to an output stream
+ *
+ * @param os an output stream
+ * @throws java.io.IOException
+ */
+ public void writeTo(OutputStream os)
+ throws IOException
+ {
+ DataOutputStream dos = new DataOutputStream(os);
+ dos.writeInt(N);
+ dos.writeInt(q);
+ dos.writeInt(d);
+ dos.writeInt(d1);
+ dos.writeInt(d2);
+ dos.writeInt(d3);
+ dos.writeInt(B);
+ dos.writeInt(basisType);
+ dos.writeDouble(beta);
+ dos.writeDouble(normBound);
+ dos.writeDouble(keyNormBound);
+ dos.writeInt(signFailTolerance);
+ dos.writeBoolean(primeCheck);
+ dos.writeBoolean(sparse);
+ dos.writeInt(bitsF);
+ dos.write(keyGenAlg);
+ dos.writeUTF(hashAlg.getAlgorithmName());
+ dos.write(polyType);
+ }
+
+ public NTRUSigningParameters getSigningParameters()
+ {
+ return new NTRUSigningParameters(N, q, d, B, beta, normBound, hashAlg);
+ }
+
+ public NTRUSigningKeyGenerationParameters clone()
+ {
+ if (polyType == NTRUParameters.TERNARY_POLYNOMIAL_TYPE_SIMPLE)
+ {
+ return new NTRUSigningKeyGenerationParameters(N, q, d, B, basisType, beta, normBound, keyNormBound, primeCheck, sparse, keyGenAlg, hashAlg);
+ }
+ else
+ {
+ return new NTRUSigningKeyGenerationParameters(N, q, d1, d2, d3, B, basisType, beta, normBound, keyNormBound, primeCheck, sparse, keyGenAlg, hashAlg);
+ }
+ }
+
+ public int hashCode()
+ {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + B;
+ result = prime * result + N;
+ result = prime * result + basisType;
+ long temp;
+ temp = Double.doubleToLongBits(beta);
+ result = prime * result + (int)(temp ^ (temp >>> 32));
+ temp = Double.doubleToLongBits(betaSq);
+ result = prime * result + (int)(temp ^ (temp >>> 32));
+ result = prime * result + bitsF;
+ result = prime * result + d;
+ result = prime * result + d1;
+ result = prime * result + d2;
+ result = prime * result + d3;
+ result = prime * result + ((hashAlg == null) ? 0 : hashAlg.getAlgorithmName().hashCode());
+ result = prime * result + keyGenAlg;
+ temp = Double.doubleToLongBits(keyNormBound);
+ result = prime * result + (int)(temp ^ (temp >>> 32));
+ temp = Double.doubleToLongBits(keyNormBoundSq);
+ result = prime * result + (int)(temp ^ (temp >>> 32));
+ temp = Double.doubleToLongBits(normBound);
+ result = prime * result + (int)(temp ^ (temp >>> 32));
+ temp = Double.doubleToLongBits(normBoundSq);
+ result = prime * result + (int)(temp ^ (temp >>> 32));
+ result = prime * result + polyType;
+ result = prime * result + (primeCheck ? 1231 : 1237);
+ result = prime * result + q;
+ result = prime * result + signFailTolerance;
+ result = prime * result + (sparse ? 1231 : 1237);
+ return result;
+ }
+
+ public boolean equals(Object obj)
+ {
+ if (this == obj)
+ {
+ return true;
+ }
+ if (obj == null)
+ {
+ return false;
+ }
+ if (!(obj instanceof NTRUSigningKeyGenerationParameters))
+ {
+ return false;
+ }
+ NTRUSigningKeyGenerationParameters other = (NTRUSigningKeyGenerationParameters)obj;
+ if (B != other.B)
+ {
+ return false;
+ }
+ if (N != other.N)
+ {
+ return false;
+ }
+ if (basisType != other.basisType)
+ {
+ return false;
+ }
+ if (Double.doubleToLongBits(beta) != Double.doubleToLongBits(other.beta))
+ {
+ return false;
+ }
+ if (Double.doubleToLongBits(betaSq) != Double.doubleToLongBits(other.betaSq))
+ {
+ return false;
+ }
+ if (bitsF != other.bitsF)
+ {
+ return false;
+ }
+ if (d != other.d)
+ {
+ return false;
+ }
+ if (d1 != other.d1)
+ {
+ return false;
+ }
+ if (d2 != other.d2)
+ {
+ return false;
+ }
+ if (d3 != other.d3)
+ {
+ return false;
+ }
+ if (hashAlg == null)
+ {
+ if (other.hashAlg != null)
+ {
+ return false;
+ }
+ }
+ else if (!hashAlg.getAlgorithmName().equals(other.hashAlg.getAlgorithmName()))
+ {
+ return false;
+ }
+ if (keyGenAlg != other.keyGenAlg)
+ {
+ return false;
+ }
+ if (Double.doubleToLongBits(keyNormBound) != Double.doubleToLongBits(other.keyNormBound))
+ {
+ return false;
+ }
+ if (Double.doubleToLongBits(keyNormBoundSq) != Double.doubleToLongBits(other.keyNormBoundSq))
+ {
+ return false;
+ }
+ if (Double.doubleToLongBits(normBound) != Double.doubleToLongBits(other.normBound))
+ {
+ return false;
+ }
+ if (Double.doubleToLongBits(normBoundSq) != Double.doubleToLongBits(other.normBoundSq))
+ {
+ return false;
+ }
+ if (polyType != other.polyType)
+ {
+ return false;
+ }
+ if (primeCheck != other.primeCheck)
+ {
+ return false;
+ }
+ if (q != other.q)
+ {
+ return false;
+ }
+ if (signFailTolerance != other.signFailTolerance)
+ {
+ return false;
+ }
+ if (sparse != other.sparse)
+ {
+ return false;
+ }
+ return true;
+ }
+
+ public String toString()
+ {
+ DecimalFormat format = new DecimalFormat("0.00");
+
+ StringBuilder output = new StringBuilder("SignatureParameters(N=" + N + " q=" + q);
+ if (polyType == NTRUParameters.TERNARY_POLYNOMIAL_TYPE_SIMPLE)
+ {
+ output.append(" polyType=SIMPLE d=" + d);
+ }
+ else
+ {
+ output.append(" polyType=PRODUCT d1=" + d1 + " d2=" + d2 + " d3=" + d3);
+ }
+ output.append(" B=" + B + " basisType=" + basisType + " beta=" + format.format(beta) +
+ " normBound=" + format.format(normBound) + " keyNormBound=" + format.format(keyNormBound) +
+ " prime=" + primeCheck + " sparse=" + sparse + " keyGenAlg=" + keyGenAlg + " hashAlg=" + hashAlg + ")");
+ return output.toString();
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/NTRUSigningParameters.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/NTRUSigningParameters.java
new file mode 100644
index 0000000..bf696c5
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/NTRUSigningParameters.java
@@ -0,0 +1,269 @@
+package org.bc.crypto.params;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.text.DecimalFormat;
+
+import org.bc.crypto.Digest;
+import org.bc.crypto.digests.SHA256Digest;
+import org.bc.crypto.digests.SHA512Digest;
+
+/**
+ * A set of parameters for NtruSign. Several predefined parameter sets are available and new ones can be created as well.
+ */
+public class NTRUSigningParameters
+ implements Cloneable
+{
+ public int N;
+ public int q;
+ public int d, d1, d2, d3, B;
+ double beta;
+ public double betaSq;
+ double normBound;
+ public double normBoundSq;
+ public int signFailTolerance = 100;
+ int bitsF = 6; // max #bits needed to encode one coefficient of the polynomial F
+ public Digest hashAlg;
+
+ /**
+ * Constructs a parameter set that uses ternary private keys (i.e. polyType=SIMPLE).
+ *
+ * @param N number of polynomial coefficients
+ * @param q modulus
+ * @param d number of -1's in the private polynomials f
and g
+ * @param B number of perturbations
+ * @param beta balancing factor for the transpose lattice
+ * @param normBound maximum norm for valid signatures
+ * @param hashAlg a valid identifier for a java.security.MessageDigest
instance such as SHA-256
. The MessageDigest
must support the getDigestLength()
method.
+ */
+ public NTRUSigningParameters(int N, int q, int d, int B, double beta, double normBound, Digest hashAlg)
+ {
+ this.N = N;
+ this.q = q;
+ this.d = d;
+ this.B = B;
+ this.beta = beta;
+ this.normBound = normBound;
+ this.hashAlg = hashAlg;
+ init();
+ }
+
+ /**
+ * Constructs a parameter set that uses product-form private keys (i.e. polyType=PRODUCT).
+ *
+ * @param N number of polynomial coefficients
+ * @param q modulus
+ * @param d1 number of -1's in the private polynomials f
and g
+ * @param d2 number of -1's in the private polynomials f
and g
+ * @param d3 number of -1's in the private polynomials f
and g
+ * @param B number of perturbations
+ * @param beta balancing factor for the transpose lattice
+ * @param normBound maximum norm for valid signatures
+ * @param keyNormBound maximum norm for the ploynomials F
and G
+ * @param hashAlg a valid identifier for a java.security.MessageDigest
instance such as SHA-256
. The MessageDigest
must support the getDigestLength()
method.
+ */
+ public NTRUSigningParameters(int N, int q, int d1, int d2, int d3, int B, double beta, double normBound, double keyNormBound, Digest hashAlg)
+ {
+ this.N = N;
+ this.q = q;
+ this.d1 = d1;
+ this.d2 = d2;
+ this.d3 = d3;
+ this.B = B;
+ this.beta = beta;
+ this.normBound = normBound;
+ this.hashAlg = hashAlg;
+ init();
+ }
+
+ private void init()
+ {
+ betaSq = beta * beta;
+ normBoundSq = normBound * normBound;
+ }
+
+ /**
+ * Reads a parameter set from an input stream.
+ *
+ * @param is an input stream
+ * @throws IOException
+ */
+ public NTRUSigningParameters(InputStream is)
+ throws IOException
+ {
+ DataInputStream dis = new DataInputStream(is);
+ N = dis.readInt();
+ q = dis.readInt();
+ d = dis.readInt();
+ d1 = dis.readInt();
+ d2 = dis.readInt();
+ d3 = dis.readInt();
+ B = dis.readInt();
+ beta = dis.readDouble();
+ normBound = dis.readDouble();
+ signFailTolerance = dis.readInt();
+ bitsF = dis.readInt();
+ String alg = dis.readUTF();
+ if ("SHA-512".equals(alg))
+ {
+ hashAlg = new SHA512Digest();
+ }
+ else if ("SHA-256".equals(alg))
+ {
+ hashAlg = new SHA256Digest();
+ }
+ init();
+ }
+
+ /**
+ * Writes the parameter set to an output stream
+ *
+ * @param os an output stream
+ * @throws IOException
+ */
+ public void writeTo(OutputStream os)
+ throws IOException
+ {
+ DataOutputStream dos = new DataOutputStream(os);
+ dos.writeInt(N);
+ dos.writeInt(q);
+ dos.writeInt(d);
+ dos.writeInt(d1);
+ dos.writeInt(d2);
+ dos.writeInt(d3);
+ dos.writeInt(B);
+ dos.writeDouble(beta);
+ dos.writeDouble(normBound);
+ dos.writeInt(signFailTolerance);
+ dos.writeInt(bitsF);
+ dos.writeUTF(hashAlg.getAlgorithmName());
+ }
+
+ public NTRUSigningParameters clone()
+ {
+ return new NTRUSigningParameters(N, q, d, B, beta, normBound, hashAlg);
+ }
+
+ public int hashCode()
+ {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + B;
+ result = prime * result + N;
+ long temp;
+ temp = Double.doubleToLongBits(beta);
+ result = prime * result + (int)(temp ^ (temp >>> 32));
+ temp = Double.doubleToLongBits(betaSq);
+ result = prime * result + (int)(temp ^ (temp >>> 32));
+ result = prime * result + bitsF;
+ result = prime * result + d;
+ result = prime * result + d1;
+ result = prime * result + d2;
+ result = prime * result + d3;
+ result = prime * result + ((hashAlg == null) ? 0 : hashAlg.getAlgorithmName().hashCode());
+ temp = Double.doubleToLongBits(normBound);
+ result = prime * result + (int)(temp ^ (temp >>> 32));
+ temp = Double.doubleToLongBits(normBoundSq);
+ result = prime * result + (int)(temp ^ (temp >>> 32));
+ result = prime * result + q;
+ result = prime * result + signFailTolerance;
+ return result;
+ }
+
+ public boolean equals(Object obj)
+ {
+ if (this == obj)
+ {
+ return true;
+ }
+ if (obj == null)
+ {
+ return false;
+ }
+ if (!(obj instanceof NTRUSigningParameters))
+ {
+ return false;
+ }
+ NTRUSigningParameters other = (NTRUSigningParameters)obj;
+ if (B != other.B)
+ {
+ return false;
+ }
+ if (N != other.N)
+ {
+ return false;
+ }
+ if (Double.doubleToLongBits(beta) != Double.doubleToLongBits(other.beta))
+ {
+ return false;
+ }
+ if (Double.doubleToLongBits(betaSq) != Double.doubleToLongBits(other.betaSq))
+ {
+ return false;
+ }
+ if (bitsF != other.bitsF)
+ {
+ return false;
+ }
+ if (d != other.d)
+ {
+ return false;
+ }
+ if (d1 != other.d1)
+ {
+ return false;
+ }
+ if (d2 != other.d2)
+ {
+ return false;
+ }
+ if (d3 != other.d3)
+ {
+ return false;
+ }
+ if (hashAlg == null)
+ {
+ if (other.hashAlg != null)
+ {
+ return false;
+ }
+ }
+ else if (!hashAlg.getAlgorithmName().equals(other.hashAlg.getAlgorithmName()))
+ {
+ return false;
+ }
+ if (Double.doubleToLongBits(normBound) != Double.doubleToLongBits(other.normBound))
+ {
+ return false;
+ }
+ if (Double.doubleToLongBits(normBoundSq) != Double.doubleToLongBits(other.normBoundSq))
+ {
+ return false;
+ }
+ if (q != other.q)
+ {
+ return false;
+ }
+ if (signFailTolerance != other.signFailTolerance)
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ public String toString()
+ {
+ DecimalFormat format = new DecimalFormat("0.00");
+
+ StringBuilder output = new StringBuilder("SignatureParameters(N=" + N + " q=" + q);
+
+ output.append(" B=" + B + " beta=" + format.format(beta) +
+ " normBound=" + format.format(normBound) +
+ " hashAlg=" + hashAlg + ")");
+ return output.toString();
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/NTRUSigningPrivateKeyParameters.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/NTRUSigningPrivateKeyParameters.java
new file mode 100644
index 0000000..e60706c
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/NTRUSigningPrivateKeyParameters.java
@@ -0,0 +1,384 @@
+package org.bc.crypto.params;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.bc.math.ntru.polynomial.DenseTernaryPolynomial;
+import org.bc.math.ntru.polynomial.IntegerPolynomial;
+import org.bc.math.ntru.polynomial.Polynomial;
+import org.bc.math.ntru.polynomial.ProductFormPolynomial;
+import org.bc.math.ntru.polynomial.SparseTernaryPolynomial;
+
+/**
+ * A NtruSign private key comprises one or more {@link NTRUSigningPrivateKeyParameters.Basis} of three polynomials each,
+ * except the zeroth basis for which h
is undefined.
+ */
+public class NTRUSigningPrivateKeyParameters
+ extends AsymmetricKeyParameter
+{
+ private Listi
-th basis
+ *
+ * @param i the index
+ * @return the basis at index i
+ */
+ public Basis getBasis(int i)
+ {
+ return bases.get(i);
+ }
+
+ public NTRUSigningPublicKeyParameters getPublicKey()
+ {
+ return publicKey;
+ }
+
+ /**
+ * Converts the key to a byte array
+ *
+ * @return the encoded key
+ */
+ public byte[] getEncoded()
+ throws IOException
+ {
+ ByteArrayOutputStream os = new ByteArrayOutputStream();
+ for (int i = 0; i < bases.size(); i++)
+ {
+ // all bases except for the first one contain a public key
+ bases.get(i).encode(os, i != 0);
+ }
+
+ os.write(publicKey.getEncoded());
+
+ return os.toByteArray();
+ }
+
+ /**
+ * Writes the key to an output stream
+ *
+ * @param os an output stream
+ * @throws IOException
+ */
+ public void writeTo(OutputStream os)
+ throws IOException
+ {
+ os.write(getEncoded());
+ }
+
+ @Override
+ public int hashCode()
+ {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((bases == null) ? 0 : bases.hashCode());
+ for (Basis basis : bases)
+ {
+ result += basis.hashCode();
+ }
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (this == obj)
+ {
+ return true;
+ }
+ if (obj == null)
+ {
+ return false;
+ }
+ if (getClass() != obj.getClass())
+ {
+ return false;
+ }
+ NTRUSigningPrivateKeyParameters other = (NTRUSigningPrivateKeyParameters)obj;
+ if (bases == null)
+ {
+ if (other.bases != null)
+ {
+ return false;
+ }
+ }
+ if (bases.size() != other.bases.size())
+ {
+ return false;
+ }
+ for (int i = 0; i < bases.size(); i++)
+ {
+ Basis basis1 = bases.get(i);
+ Basis basis2 = other.bases.get(i);
+ if (!basis1.f.equals(basis2.f))
+ {
+ return false;
+ }
+ if (!basis1.fPrime.equals(basis2.fPrime))
+ {
+ return false;
+ }
+ if (i != 0 && !basis1.h.equals(basis2.h)) // don't compare h for the 0th basis
+ {
+ return false;
+ }
+ if (!basis1.params.equals(basis2.params))
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * A NtruSign basis. Contains three polynomials f, f', h
.
+ */
+ public static class Basis
+ {
+ public Polynomial f;
+ public Polynomial fPrime;
+ public IntegerPolynomial h;
+ NTRUSigningKeyGenerationParameters params;
+
+ /**
+ * Constructs a new basis from polynomials f, f', h
.
+ *
+ * @param f
+ * @param fPrime
+ * @param h
+ * @param params NtruSign parameters
+ */
+ protected Basis(Polynomial f, Polynomial fPrime, IntegerPolynomial h, NTRUSigningKeyGenerationParameters params)
+ {
+ this.f = f;
+ this.fPrime = fPrime;
+ this.h = h;
+ this.params = params;
+ }
+
+ /**
+ * Reads a basis from an input stream and constructs a new basis.
+ *
+ * @param is an input stream
+ * @param params NtruSign parameters
+ * @param include_h whether to read the polynomial h
(true
) or only f
and f'
(false
)
+ */
+ Basis(InputStream is, NTRUSigningKeyGenerationParameters params, boolean include_h)
+ throws IOException
+ {
+ int N = params.N;
+ int q = params.q;
+ int d1 = params.d1;
+ int d2 = params.d2;
+ int d3 = params.d3;
+ boolean sparse = params.sparse;
+ this.params = params;
+
+ if (params.polyType == NTRUParameters.TERNARY_POLYNOMIAL_TYPE_PRODUCT)
+ {
+ f = ProductFormPolynomial.fromBinary(is, N, d1, d2, d3 + 1, d3);
+ }
+ else
+ {
+ IntegerPolynomial fInt = IntegerPolynomial.fromBinary3Tight(is, N);
+ f = sparse ? new SparseTernaryPolynomial(fInt) : new DenseTernaryPolynomial(fInt);
+ }
+
+ if (params.basisType == NTRUSigningKeyGenerationParameters.BASIS_TYPE_STANDARD)
+ {
+ IntegerPolynomial fPrimeInt = IntegerPolynomial.fromBinary(is, N, q);
+ for (int i = 0; i < fPrimeInt.coeffs.length; i++)
+ {
+ fPrimeInt.coeffs[i] -= q / 2;
+ }
+ fPrime = fPrimeInt;
+ }
+ else if (params.polyType == NTRUParameters.TERNARY_POLYNOMIAL_TYPE_PRODUCT)
+ {
+ fPrime = ProductFormPolynomial.fromBinary(is, N, d1, d2, d3 + 1, d3);
+ }
+ else
+ {
+ fPrime = IntegerPolynomial.fromBinary3Tight(is, N);
+ }
+
+ if (include_h)
+ {
+ h = IntegerPolynomial.fromBinary(is, N, q);
+ }
+ }
+
+ /**
+ * Writes the basis to an output stream
+ *
+ * @param os an output stream
+ * @param include_h whether to write the polynomial h
(true
) or only f
and f'
(false
)
+ * @throws IOException
+ */
+ void encode(OutputStream os, boolean include_h)
+ throws IOException
+ {
+ int q = params.q;
+
+ os.write(getEncoded(f));
+ if (params.basisType == NTRUSigningKeyGenerationParameters.BASIS_TYPE_STANDARD)
+ {
+ IntegerPolynomial fPrimeInt = fPrime.toIntegerPolynomial();
+ for (int i = 0; i < fPrimeInt.coeffs.length; i++)
+ {
+ fPrimeInt.coeffs[i] += q / 2;
+ }
+ os.write(fPrimeInt.toBinary(q));
+ }
+ else
+ {
+ os.write(getEncoded(fPrime));
+ }
+ if (include_h)
+ {
+ os.write(h.toBinary(q));
+ }
+ }
+
+ private byte[] getEncoded(Polynomial p)
+ {
+ if (p instanceof ProductFormPolynomial)
+ {
+ return ((ProductFormPolynomial)p).toBinary();
+ }
+ else
+ {
+ return p.toIntegerPolynomial().toBinary3Tight();
+ }
+ }
+
+ @Override
+ public int hashCode()
+ {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((f == null) ? 0 : f.hashCode());
+ result = prime * result + ((fPrime == null) ? 0 : fPrime.hashCode());
+ result = prime * result + ((h == null) ? 0 : h.hashCode());
+ result = prime * result + ((params == null) ? 0 : params.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (this == obj)
+ {
+ return true;
+ }
+ if (obj == null)
+ {
+ return false;
+ }
+ if (!(obj instanceof Basis))
+ {
+ return false;
+ }
+ Basis other = (Basis)obj;
+ if (f == null)
+ {
+ if (other.f != null)
+ {
+ return false;
+ }
+ }
+ else if (!f.equals(other.f))
+ {
+ return false;
+ }
+ if (fPrime == null)
+ {
+ if (other.fPrime != null)
+ {
+ return false;
+ }
+ }
+ else if (!fPrime.equals(other.fPrime))
+ {
+ return false;
+ }
+ if (h == null)
+ {
+ if (other.h != null)
+ {
+ return false;
+ }
+ }
+ else if (!h.equals(other.h))
+ {
+ return false;
+ }
+ if (params == null)
+ {
+ if (other.params != null)
+ {
+ return false;
+ }
+ }
+ else if (!params.equals(other.params))
+ {
+ return false;
+ }
+ return true;
+ }
+ }
+}
\ No newline at end of file
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/NTRUSigningPublicKeyParameters.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/NTRUSigningPublicKeyParameters.java
new file mode 100644
index 0000000..bc34217
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/NTRUSigningPublicKeyParameters.java
@@ -0,0 +1,100 @@
+package org.bc.crypto.params;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.bc.math.ntru.polynomial.IntegerPolynomial;
+
+/**
+ * A NtruSign public key is essentially a polynomial named h
.
+ */
+public class NTRUSigningPublicKeyParameters
+ extends AsymmetricKeyParameter
+{
+ private NTRUSigningParameters params;
+ public IntegerPolynomial h;
+
+ /**
+ * Constructs a new public key from a polynomial
+ * @param h the polynomial h
which determines the key
+ * @param params the NtruSign parameters to use
+ */
+ public NTRUSigningPublicKeyParameters(IntegerPolynomial h, NTRUSigningParameters params) {
+ super(false);
+ this.h = h;
+ this.params = params;
+ }
+
+ /**
+ * Converts a byte array to a polynomial h
and constructs a new public key
+ * @param b an encoded polynomial
+ * @param params the NtruSign parameters to use
+ */
+ public NTRUSigningPublicKeyParameters(byte[] b, NTRUSigningParameters params) {
+ super(false);
+ h = IntegerPolynomial.fromBinary(b, params.N, params.q);
+ this.params = params;
+ }
+
+ /**
+ * Reads a polynomial h
from an input stream and constructs a new public key
+ * @param is an input stream
+ * @param params the NtruSign parameters to use
+ */
+ public NTRUSigningPublicKeyParameters(InputStream is, NTRUSigningParameters params) throws IOException {
+ super(false);
+ h = IntegerPolynomial.fromBinary(is, params.N, params.q);
+ this.params = params;
+ }
+
+
+
+ /**
+ * Converts the key to a byte array
+ * @return the encoded key
+ */
+ public byte[] getEncoded() {
+ return h.toBinary(params.q);
+ }
+
+ /**
+ * Writes the key to an output stream
+ * @param os an output stream
+ * @throws IOException
+ */
+ public void writeTo(OutputStream os) throws IOException {
+ os.write(getEncoded());
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((h == null) ? 0 : h.hashCode());
+ result = prime * result + ((params == null) ? 0 : params.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ NTRUSigningPublicKeyParameters other = (NTRUSigningPublicKeyParameters) obj;
+ if (h == null) {
+ if (other.h != null)
+ return false;
+ } else if (!h.equals(other.h))
+ return false;
+ if (params == null) {
+ if (other.params != null)
+ return false;
+ } else if (!params.equals(other.params))
+ return false;
+ return true;
+ }
+}
\ No newline at end of file
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/NaccacheSternKeyGenerationParameters.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/NaccacheSternKeyGenerationParameters.java
new file mode 100644
index 0000000..3e304ad
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/NaccacheSternKeyGenerationParameters.java
@@ -0,0 +1,97 @@
+package org.bc.crypto.params;
+
+import java.security.SecureRandom;
+
+import org.bc.crypto.KeyGenerationParameters;
+
+/**
+ * Parameters for NaccacheStern public private key generation. For details on
+ * this cipher, please see
+ *
+ * http://www.gemplus.com/smart/rd/publications/pdf/NS98pkcs.pdf
+ */
+public class NaccacheSternKeyGenerationParameters extends KeyGenerationParameters
+{
+
+ // private BigInteger publicExponent;
+ private int certainty;
+
+ private int cntSmallPrimes;
+
+ private boolean debug = false;
+
+ /**
+ * Parameters for generating a NaccacheStern KeyPair.
+ *
+ * @param random
+ * The source of randomness
+ * @param strength
+ * The desired strength of the Key in Bits
+ * @param certainty
+ * the probability that the generated primes are not really prime
+ * as integer: 2^(-certainty) is then the probability
+ * @param cntSmallPrimes
+ * How many small key factors are desired
+ */
+ public NaccacheSternKeyGenerationParameters(SecureRandom random, int strength, int certainty, int cntSmallPrimes)
+ {
+ this(random, strength, certainty, cntSmallPrimes, false);
+ }
+
+ /**
+ * Parameters for a NaccacheStern KeyPair.
+ *
+ * @param random
+ * The source of randomness
+ * @param strength
+ * The desired strength of the Key in Bits
+ * @param certainty
+ * the probability that the generated primes are not really prime
+ * as integer: 2^(-certainty) is then the probability
+ * @param cntSmallPrimes
+ * How many small key factors are desired
+ * @param debug
+ * Turn debugging on or off (reveals secret information, use with
+ * caution)
+ */
+ public NaccacheSternKeyGenerationParameters(SecureRandom random,
+ int strength, int certainty, int cntSmallPrimes, boolean debug)
+ {
+ super(random, strength);
+
+ this.certainty = certainty;
+ if (cntSmallPrimes % 2 == 1)
+ {
+ throw new IllegalArgumentException("cntSmallPrimes must be a multiple of 2");
+ }
+ if (cntSmallPrimes < 30)
+ {
+ throw new IllegalArgumentException("cntSmallPrimes must be >= 30 for security reasons");
+ }
+ this.cntSmallPrimes = cntSmallPrimes;
+
+ this.debug = debug;
+ }
+
+ /**
+ * @return Returns the certainty.
+ */
+ public int getCertainty()
+ {
+ return certainty;
+ }
+
+ /**
+ * @return Returns the cntSmallPrimes.
+ */
+ public int getCntSmallPrimes()
+ {
+ return cntSmallPrimes;
+ }
+
+ public boolean isDebug()
+ {
+ return debug;
+ }
+
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/NaccacheSternKeyParameters.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/NaccacheSternKeyParameters.java
new file mode 100644
index 0000000..d073ed1
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/NaccacheSternKeyParameters.java
@@ -0,0 +1,53 @@
+package org.bc.crypto.params;
+
+import java.math.BigInteger;
+
+/**
+ * Public key parameters for NaccacheStern cipher. For details on this cipher,
+ * please see
+ *
+ * http://www.gemplus.com/smart/rd/publications/pdf/NS98pkcs.pdf
+ */
+public class NaccacheSternKeyParameters extends AsymmetricKeyParameter
+{
+
+ private BigInteger g, n;
+
+ int lowerSigmaBound;
+
+ /**
+ * @param privateKey
+ */
+ public NaccacheSternKeyParameters(boolean privateKey, BigInteger g, BigInteger n, int lowerSigmaBound)
+ {
+ super(privateKey);
+ this.g = g;
+ this.n = n;
+ this.lowerSigmaBound = lowerSigmaBound;
+ }
+
+ /**
+ * @return Returns the g.
+ */
+ public BigInteger getG()
+ {
+ return g;
+ }
+
+ /**
+ * @return Returns the lowerSigmaBound.
+ */
+ public int getLowerSigmaBound()
+ {
+ return lowerSigmaBound;
+ }
+
+ /**
+ * @return Returns the n.
+ */
+ public BigInteger getModulus()
+ {
+ return n;
+ }
+
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/NaccacheSternPrivateKeyParameters.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/NaccacheSternPrivateKeyParameters.java
new file mode 100644
index 0000000..3556346
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/NaccacheSternPrivateKeyParameters.java
@@ -0,0 +1,50 @@
+package org.bc.crypto.params;
+
+import java.math.BigInteger;
+import java.util.Vector;
+
+/**
+ * Private key parameters for NaccacheStern cipher. For details on this cipher,
+ * please see
+ *
+ * http://www.gemplus.com/smart/rd/publications/pdf/NS98pkcs.pdf
+ */
+public class NaccacheSternPrivateKeyParameters extends NaccacheSternKeyParameters
+{
+ private BigInteger phi_n;
+ private Vector smallPrimes;
+
+ /**
+ * Constructs a NaccacheSternPrivateKey
+ *
+ * @param g
+ * the public enryption parameter g
+ * @param n
+ * the public modulus n = p*q
+ * @param lowerSigmaBound
+ * the public lower sigma bound up to which data can be encrypted
+ * @param smallPrimes
+ * the small primes, of which sigma is constructed in the right
+ * order
+ * @param phi_n
+ * the private modulus phi(n) = (p-1)(q-1)
+ */
+ public NaccacheSternPrivateKeyParameters(BigInteger g, BigInteger n,
+ int lowerSigmaBound, Vector smallPrimes,
+ BigInteger phi_n)
+ {
+ super(true, g, n, lowerSigmaBound);
+ this.smallPrimes = smallPrimes;
+ this.phi_n = phi_n;
+ }
+
+ public BigInteger getPhi_n()
+ {
+ return phi_n;
+ }
+
+ public Vector getSmallPrimes()
+ {
+ return smallPrimes;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/ParametersWithIV.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/ParametersWithIV.java
new file mode 100644
index 0000000..7cc01c1
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/ParametersWithIV.java
@@ -0,0 +1,39 @@
+package org.bc.crypto.params;
+
+import org.bc.crypto.CipherParameters;
+
+public class ParametersWithIV
+ implements CipherParameters
+{
+ private byte[] iv;
+ private CipherParameters parameters;
+
+ public ParametersWithIV(
+ CipherParameters parameters,
+ byte[] iv)
+ {
+ this(parameters, iv, 0, iv.length);
+ }
+
+ public ParametersWithIV(
+ CipherParameters parameters,
+ byte[] iv,
+ int ivOff,
+ int ivLen)
+ {
+ this.iv = new byte[ivLen];
+ this.parameters = parameters;
+
+ System.arraycopy(iv, ivOff, this.iv, 0, ivLen);
+ }
+
+ public byte[] getIV()
+ {
+ return iv;
+ }
+
+ public CipherParameters getParameters()
+ {
+ return parameters;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/ParametersWithRandom.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/ParametersWithRandom.java
new file mode 100644
index 0000000..c916601
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/ParametersWithRandom.java
@@ -0,0 +1,36 @@
+package org.bc.crypto.params;
+
+import org.bc.crypto.CipherParameters;
+
+import java.security.SecureRandom;
+
+public class ParametersWithRandom
+ implements CipherParameters
+{
+ private SecureRandom random;
+ private CipherParameters parameters;
+
+ public ParametersWithRandom(
+ CipherParameters parameters,
+ SecureRandom random)
+ {
+ this.random = random;
+ this.parameters = parameters;
+ }
+
+ public ParametersWithRandom(
+ CipherParameters parameters)
+ {
+ this(parameters, new SecureRandom());
+ }
+
+ public SecureRandom getRandom()
+ {
+ return random;
+ }
+
+ public CipherParameters getParameters()
+ {
+ return parameters;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/ParametersWithSBox.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/ParametersWithSBox.java
new file mode 100644
index 0000000..cb5b205
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/ParametersWithSBox.java
@@ -0,0 +1,28 @@
+package org.bc.crypto.params;
+
+import org.bc.crypto.CipherParameters;
+
+public class ParametersWithSBox
+ implements CipherParameters
+{
+ private CipherParameters parameters;
+ private byte[] sBox;
+
+ public ParametersWithSBox(
+ CipherParameters parameters,
+ byte[] sBox)
+ {
+ this.parameters = parameters;
+ this.sBox = sBox;
+ }
+
+ public byte[] getSBox()
+ {
+ return sBox;
+ }
+
+ public CipherParameters getParameters()
+ {
+ return parameters;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/ParametersWithSalt.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/ParametersWithSalt.java
new file mode 100644
index 0000000..72383c4
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/ParametersWithSalt.java
@@ -0,0 +1,42 @@
+package org.bc.crypto.params;
+
+import org.bc.crypto.CipherParameters;
+
+/**
+ * Cipher parameters with a fixed salt value associated with them.
+ */
+public class ParametersWithSalt
+ implements CipherParameters
+{
+ private byte[] salt;
+ private CipherParameters parameters;
+
+ public ParametersWithSalt(
+ CipherParameters parameters,
+ byte[] salt)
+ {
+ this(parameters, salt, 0, salt.length);
+ }
+
+ public ParametersWithSalt(
+ CipherParameters parameters,
+ byte[] salt,
+ int saltOff,
+ int saltLen)
+ {
+ this.salt = new byte[saltLen];
+ this.parameters = parameters;
+
+ System.arraycopy(salt, saltOff, this.salt, 0, saltLen);
+ }
+
+ public byte[] getSalt()
+ {
+ return salt;
+ }
+
+ public CipherParameters getParameters()
+ {
+ return parameters;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/RC2Parameters.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/RC2Parameters.java
new file mode 100644
index 0000000..3cd203e
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/RC2Parameters.java
@@ -0,0 +1,36 @@
+package org.bc.crypto.params;
+
+import org.bc.crypto.CipherParameters;
+
+public class RC2Parameters
+ implements CipherParameters
+{
+ private byte[] key;
+ private int bits;
+
+ public RC2Parameters(
+ byte[] key)
+ {
+ this(key, (key.length > 128) ? 1024 : (key.length * 8));
+ }
+
+ public RC2Parameters(
+ byte[] key,
+ int bits)
+ {
+ this.key = new byte[key.length];
+ this.bits = bits;
+
+ System.arraycopy(key, 0, this.key, 0, key.length);
+ }
+
+ public byte[] getKey()
+ {
+ return key;
+ }
+
+ public int getEffectiveKeyBits()
+ {
+ return bits;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/RC5Parameters.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/RC5Parameters.java
new file mode 100644
index 0000000..108124a
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/RC5Parameters.java
@@ -0,0 +1,35 @@
+package org.bc.crypto.params;
+
+import org.bc.crypto.CipherParameters;
+
+public class RC5Parameters
+ implements CipherParameters
+{
+ private byte[] key;
+ private int rounds;
+
+ public RC5Parameters(
+ byte[] key,
+ int rounds)
+ {
+ if (key.length > 255)
+ {
+ throw new IllegalArgumentException("RC5 key length can be no greater than 255");
+ }
+
+ this.key = new byte[key.length];
+ this.rounds = rounds;
+
+ System.arraycopy(key, 0, this.key, 0, key.length);
+ }
+
+ public byte[] getKey()
+ {
+ return key;
+ }
+
+ public int getRounds()
+ {
+ return rounds;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/RSABlindingParameters.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/RSABlindingParameters.java
new file mode 100644
index 0000000..5f9dd44
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/RSABlindingParameters.java
@@ -0,0 +1,35 @@
+package org.bc.crypto.params;
+
+import org.bc.crypto.CipherParameters;
+
+import java.math.BigInteger;
+
+public class RSABlindingParameters
+ implements CipherParameters
+{
+ private RSAKeyParameters publicKey;
+ private BigInteger blindingFactor;
+
+ public RSABlindingParameters(
+ RSAKeyParameters publicKey,
+ BigInteger blindingFactor)
+ {
+ if (publicKey instanceof RSAPrivateCrtKeyParameters)
+ {
+ throw new IllegalArgumentException("RSA parameters should be for a public key");
+ }
+
+ this.publicKey = publicKey;
+ this.blindingFactor = blindingFactor;
+ }
+
+ public RSAKeyParameters getPublicKey()
+ {
+ return publicKey;
+ }
+
+ public BigInteger getBlindingFactor()
+ {
+ return blindingFactor;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/RSAKeyGenerationParameters.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/RSAKeyGenerationParameters.java
new file mode 100644
index 0000000..f58156c
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/RSAKeyGenerationParameters.java
@@ -0,0 +1,48 @@
+package org.bc.crypto.params;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
+import org.bc.crypto.KeyGenerationParameters;
+
+public class RSAKeyGenerationParameters
+ extends KeyGenerationParameters
+{
+ private BigInteger publicExponent;
+ private int certainty;
+
+ public RSAKeyGenerationParameters(
+ BigInteger publicExponent,
+ SecureRandom random,
+ int strength,
+ int certainty)
+ {
+ super(random, strength);
+
+ if (strength < 12)
+ {
+ throw new IllegalArgumentException("key strength too small");
+ }
+
+ //
+ // public exponent cannot be even
+ //
+ if (!publicExponent.testBit(0))
+ {
+ throw new IllegalArgumentException("public exponent cannot be even");
+ }
+
+ this.publicExponent = publicExponent;
+ this.certainty = certainty;
+ }
+
+ public BigInteger getPublicExponent()
+ {
+ return publicExponent;
+ }
+
+ public int getCertainty()
+ {
+ return certainty;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/RSAKeyParameters.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/RSAKeyParameters.java
new file mode 100644
index 0000000..79f6de6
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/RSAKeyParameters.java
@@ -0,0 +1,31 @@
+package org.bc.crypto.params;
+
+import java.math.BigInteger;
+
+public class RSAKeyParameters
+ extends AsymmetricKeyParameter
+{
+ private BigInteger modulus;
+ private BigInteger exponent;
+
+ public RSAKeyParameters(
+ boolean isPrivate,
+ BigInteger modulus,
+ BigInteger exponent)
+ {
+ super(isPrivate);
+
+ this.modulus = modulus;
+ this.exponent = exponent;
+ }
+
+ public BigInteger getModulus()
+ {
+ return modulus;
+ }
+
+ public BigInteger getExponent()
+ {
+ return exponent;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/RSAPrivateCrtKeyParameters.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/RSAPrivateCrtKeyParameters.java
new file mode 100644
index 0000000..fad5860
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/params/RSAPrivateCrtKeyParameters.java
@@ -0,0 +1,67 @@
+package org.bc.crypto.params;
+
+import java.math.BigInteger;
+
+public class RSAPrivateCrtKeyParameters
+ extends RSAKeyParameters
+{
+ private BigInteger e;
+ private BigInteger p;
+ private BigInteger q;
+ private BigInteger dP;
+ private BigInteger dQ;
+ private BigInteger qInv;
+
+ /**
+ *
+ */
+ public RSAPrivateCrtKeyParameters(
+ BigInteger modulus,
+ BigInteger publicExponent,
+ BigInteger privateExponent,
+ BigInteger p,
+ BigInteger q,
+ BigInteger dP,
+ BigInteger dQ,
+ BigInteger qInv)
+ {
+ super(true, modulus, privateExponent);
+
+ this.e = publicExponent;
+ this.p = p;
+ this.q = q;
+ this.dP = dP;
+ this.dQ = dQ;
+ this.qInv = qInv;
+ }
+
+ public BigInteger getPublicExponent()
+ {
+ return e;
+ }
+
+ public BigInteger getP()
+ {
+ return p;
+ }
+
+ public BigInteger getQ()
+ {
+ return q;
+ }
+
+ public BigInteger getDP()
+ {
+ return dP;
+ }
+
+ public BigInteger getDQ()
+ {
+ return dQ;
+ }
+
+ public BigInteger getQInv()
+ {
+ return qInv;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/parsers/DHIESPublicKeyParser.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/parsers/DHIESPublicKeyParser.java
new file mode 100644
index 0000000..b476179
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/parsers/DHIESPublicKeyParser.java
@@ -0,0 +1,31 @@
+package org.bc.crypto.parsers;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.math.BigInteger;
+
+import org.bc.crypto.KeyParser;
+import org.bc.crypto.params.AsymmetricKeyParameter;
+import org.bc.crypto.params.DHParameters;
+import org.bc.crypto.params.DHPublicKeyParameters;
+
+public class DHIESPublicKeyParser
+ implements KeyParser
+{
+ private DHParameters dhParams;
+
+ public DHIESPublicKeyParser(DHParameters dhParams)
+ {
+ this.dhParams = dhParams;
+ }
+
+ public AsymmetricKeyParameter readKey(InputStream stream)
+ throws IOException
+ {
+ byte[] V = new byte[(dhParams.getP().bitLength() + 7) / 8];
+
+ stream.read(V, 0, V.length);
+
+ return new DHPublicKeyParameters(new BigInteger(1, V), dhParams);
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/parsers/ECIESPublicKeyParser.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/parsers/ECIESPublicKeyParser.java
new file mode 100644
index 0000000..6154ced
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/parsers/ECIESPublicKeyParser.java
@@ -0,0 +1,53 @@
+package org.bc.crypto.parsers;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.bc.crypto.KeyParser;
+import org.bc.crypto.params.AsymmetricKeyParameter;
+import org.bc.crypto.params.ECDomainParameters;
+import org.bc.crypto.params.ECPublicKeyParameters;
+
+public class ECIESPublicKeyParser
+ implements KeyParser
+{
+ private ECDomainParameters ecParams;
+
+ public ECIESPublicKeyParser(ECDomainParameters ecParams)
+ {
+ this.ecParams = ecParams;
+ }
+
+ public AsymmetricKeyParameter readKey(InputStream stream)
+ throws IOException
+ {
+ byte[] V;
+ int first = stream.read();
+
+ // Decode the public ephemeral key
+ switch (first)
+ {
+ case 0x00: // infinity
+ throw new IOException("Sender's public key invalid.");
+
+ case 0x02: // compressed
+ case 0x03: // Byte length calculated as in ECPoint.getEncoded();
+ V = new byte[1 + (ecParams.getCurve().getFieldSize()+7)/8];
+ break;
+
+ case 0x04: // uncompressed or
+ case 0x06: // hybrid
+ case 0x07: // Byte length calculated as in ECPoint.getEncoded();
+ V = new byte[1 + 2*((ecParams.getCurve().getFieldSize()+7)/8)];
+ break;
+
+ default:
+ throw new IOException("Sender's public key has invalid point encoding 0x" + Integer.toString(first, 16));
+ }
+
+ V[0] = (byte)first;
+ stream.read(V, 1, V.length - 1);
+
+ return new ECPublicKeyParameters(ecParams.getCurve().decodePoint(V), ecParams);
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/prng/DigestRandomGenerator.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/prng/DigestRandomGenerator.java
new file mode 100644
index 0000000..c04ccfa
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/prng/DigestRandomGenerator.java
@@ -0,0 +1,123 @@
+package org.bc.crypto.prng;
+
+import org.bc.crypto.Digest;
+
+/**
+ * Random generation based on the digest with counter. Calling addSeedMaterial will
+ * always increase the entropy of the hash.
+ *
+ * // First 1850 fractional digit of Pi number.
+ * byte[] key = new BigInteger("14159265358979323846...5068006422512520511").toByteArray();
+ * s = 0;
+ * P = new byte[256];
+ * for (int i = 0; i < 256; i++) {
+ * P[i] = (byte) i;
+ * }
+ * for (int m = 0; m < 768; m++) {
+ * s = P[(s + P[m & 0xff] + key[m % key.length]) & 0xff];
+ * byte temp = P[m & 0xff];
+ * P[m & 0xff] = P[s & 0xff];
+ * P[s & 0xff] = temp;
+ * }
+ */
+ private byte[] P =
+ {
+ (byte) 0xbb, (byte) 0x2c, (byte) 0x62, (byte) 0x7f,
+ (byte) 0xb5, (byte) 0xaa, (byte) 0xd4, (byte) 0x0d, (byte) 0x81,
+ (byte) 0xfe, (byte) 0xb2, (byte) 0x82, (byte) 0xcb, (byte) 0xa0,
+ (byte) 0xa1, (byte) 0x08, (byte) 0x18, (byte) 0x71, (byte) 0x56,
+ (byte) 0xe8, (byte) 0x49, (byte) 0x02, (byte) 0x10, (byte) 0xc4,
+ (byte) 0xde, (byte) 0x35, (byte) 0xa5, (byte) 0xec, (byte) 0x80,
+ (byte) 0x12, (byte) 0xb8, (byte) 0x69, (byte) 0xda, (byte) 0x2f,
+ (byte) 0x75, (byte) 0xcc, (byte) 0xa2, (byte) 0x09, (byte) 0x36,
+ (byte) 0x03, (byte) 0x61, (byte) 0x2d, (byte) 0xfd, (byte) 0xe0,
+ (byte) 0xdd, (byte) 0x05, (byte) 0x43, (byte) 0x90, (byte) 0xad,
+ (byte) 0xc8, (byte) 0xe1, (byte) 0xaf, (byte) 0x57, (byte) 0x9b,
+ (byte) 0x4c, (byte) 0xd8, (byte) 0x51, (byte) 0xae, (byte) 0x50,
+ (byte) 0x85, (byte) 0x3c, (byte) 0x0a, (byte) 0xe4, (byte) 0xf3,
+ (byte) 0x9c, (byte) 0x26, (byte) 0x23, (byte) 0x53, (byte) 0xc9,
+ (byte) 0x83, (byte) 0x97, (byte) 0x46, (byte) 0xb1, (byte) 0x99,
+ (byte) 0x64, (byte) 0x31, (byte) 0x77, (byte) 0xd5, (byte) 0x1d,
+ (byte) 0xd6, (byte) 0x78, (byte) 0xbd, (byte) 0x5e, (byte) 0xb0,
+ (byte) 0x8a, (byte) 0x22, (byte) 0x38, (byte) 0xf8, (byte) 0x68,
+ (byte) 0x2b, (byte) 0x2a, (byte) 0xc5, (byte) 0xd3, (byte) 0xf7,
+ (byte) 0xbc, (byte) 0x6f, (byte) 0xdf, (byte) 0x04, (byte) 0xe5,
+ (byte) 0x95, (byte) 0x3e, (byte) 0x25, (byte) 0x86, (byte) 0xa6,
+ (byte) 0x0b, (byte) 0x8f, (byte) 0xf1, (byte) 0x24, (byte) 0x0e,
+ (byte) 0xd7, (byte) 0x40, (byte) 0xb3, (byte) 0xcf, (byte) 0x7e,
+ (byte) 0x06, (byte) 0x15, (byte) 0x9a, (byte) 0x4d, (byte) 0x1c,
+ (byte) 0xa3, (byte) 0xdb, (byte) 0x32, (byte) 0x92, (byte) 0x58,
+ (byte) 0x11, (byte) 0x27, (byte) 0xf4, (byte) 0x59, (byte) 0xd0,
+ (byte) 0x4e, (byte) 0x6a, (byte) 0x17, (byte) 0x5b, (byte) 0xac,
+ (byte) 0xff, (byte) 0x07, (byte) 0xc0, (byte) 0x65, (byte) 0x79,
+ (byte) 0xfc, (byte) 0xc7, (byte) 0xcd, (byte) 0x76, (byte) 0x42,
+ (byte) 0x5d, (byte) 0xe7, (byte) 0x3a, (byte) 0x34, (byte) 0x7a,
+ (byte) 0x30, (byte) 0x28, (byte) 0x0f, (byte) 0x73, (byte) 0x01,
+ (byte) 0xf9, (byte) 0xd1, (byte) 0xd2, (byte) 0x19, (byte) 0xe9,
+ (byte) 0x91, (byte) 0xb9, (byte) 0x5a, (byte) 0xed, (byte) 0x41,
+ (byte) 0x6d, (byte) 0xb4, (byte) 0xc3, (byte) 0x9e, (byte) 0xbf,
+ (byte) 0x63, (byte) 0xfa, (byte) 0x1f, (byte) 0x33, (byte) 0x60,
+ (byte) 0x47, (byte) 0x89, (byte) 0xf0, (byte) 0x96, (byte) 0x1a,
+ (byte) 0x5f, (byte) 0x93, (byte) 0x3d, (byte) 0x37, (byte) 0x4b,
+ (byte) 0xd9, (byte) 0xa8, (byte) 0xc1, (byte) 0x1b, (byte) 0xf6,
+ (byte) 0x39, (byte) 0x8b, (byte) 0xb7, (byte) 0x0c, (byte) 0x20,
+ (byte) 0xce, (byte) 0x88, (byte) 0x6e, (byte) 0xb6, (byte) 0x74,
+ (byte) 0x8e, (byte) 0x8d, (byte) 0x16, (byte) 0x29, (byte) 0xf2,
+ (byte) 0x87, (byte) 0xf5, (byte) 0xeb, (byte) 0x70, (byte) 0xe3,
+ (byte) 0xfb, (byte) 0x55, (byte) 0x9f, (byte) 0xc6, (byte) 0x44,
+ (byte) 0x4a, (byte) 0x45, (byte) 0x7d, (byte) 0xe2, (byte) 0x6b,
+ (byte) 0x5c, (byte) 0x6c, (byte) 0x66, (byte) 0xa9, (byte) 0x8c,
+ (byte) 0xee, (byte) 0x84, (byte) 0x13, (byte) 0xa7, (byte) 0x1e,
+ (byte) 0x9d, (byte) 0xdc, (byte) 0x67, (byte) 0x48, (byte) 0xba,
+ (byte) 0x2e, (byte) 0xe6, (byte) 0xa4, (byte) 0xab, (byte) 0x7c,
+ (byte) 0x94, (byte) 0x00, (byte) 0x21, (byte) 0xef, (byte) 0xea,
+ (byte) 0xbe, (byte) 0xca, (byte) 0x72, (byte) 0x4f, (byte) 0x52,
+ (byte) 0x98, (byte) 0x3f, (byte) 0xc2, (byte) 0x14, (byte) 0x7b,
+ (byte) 0x3b, (byte) 0x54 };
+
+ /**
+ * Value generated in the same way as {@link VMPCRandomGenerator#P};
+ */
+ private byte s = (byte) 0xbe;
+
+ public VMPCRandomGenerator()
+ {
+ }
+
+ public void addSeedMaterial(byte[] seed)
+ {
+ for (int m = 0; m < seed.length; m++)
+ {
+ s = P[(s + P[n & 0xff] + seed[m]) & 0xff];
+ byte temp = P[n & 0xff];
+ P[n & 0xff] = P[s & 0xff];
+ P[s & 0xff] = temp;
+ n = (byte) ((n + 1) & 0xff);
+ }
+ }
+
+ public void addSeedMaterial(long seed)
+ {
+ byte[] s = new byte[4];
+ s[3] = (byte) (seed & 0x000000ff);
+ s[2] = (byte) ((seed & 0x0000ff00) >> 8);
+ s[1] = (byte) ((seed & 0x00ff0000) >> 16);
+ s[0] = (byte) ((seed & 0xff000000) >> 24);
+ addSeedMaterial(s);
+ }
+
+ public void nextBytes(byte[] bytes)
+ {
+ nextBytes(bytes, 0, bytes.length);
+ }
+
+ public void nextBytes(byte[] bytes, int start, int len)
+ {
+ synchronized (P)
+ {
+ int end = start + len;
+ for (int i = start; i != end; i++)
+ {
+ s = P[(s + P[n & 0xff]) & 0xff];
+ bytes[i] = P[(P[(P[s & 0xff]) & 0xff] + 1) & 0xff];
+ byte temp = P[n & 0xff];
+ P[n & 0xff] = P[s & 0xff];
+ P[s & 0xff] = temp;
+ n = (byte) ((n + 1) & 0xff);
+ }
+ }
+ }
+
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/signers/DSADigestSigner.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/signers/DSADigestSigner.java
new file mode 100644
index 0000000..34fc43d
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/signers/DSADigestSigner.java
@@ -0,0 +1,163 @@
+package org.bc.crypto.signers;
+
+import java.io.IOException;
+import java.math.BigInteger;
+
+import org.bc.asn1.ASN1EncodableVector;
+import org.bc.asn1.ASN1Encoding;
+import org.bc.asn1.ASN1Primitive;
+import org.bc.asn1.ASN1Sequence;
+import org.bc.asn1.DERInteger;
+import org.bc.asn1.DERSequence;
+import org.bc.crypto.CipherParameters;
+import org.bc.crypto.DSA;
+import org.bc.crypto.Digest;
+import org.bc.crypto.Signer;
+import org.bc.crypto.params.AsymmetricKeyParameter;
+import org.bc.crypto.params.ParametersWithRandom;
+
+public class DSADigestSigner
+ implements Signer
+{
+ private final Digest digest;
+ private final DSA dsaSigner;
+ private boolean forSigning;
+
+ public DSADigestSigner(
+ DSA signer,
+ Digest digest)
+ {
+ this.digest = digest;
+ this.dsaSigner = signer;
+ }
+
+ public void init(
+ boolean forSigning,
+ CipherParameters parameters)
+ {
+ this.forSigning = forSigning;
+
+ AsymmetricKeyParameter k;
+
+ if (parameters instanceof ParametersWithRandom)
+ {
+ k = (AsymmetricKeyParameter)((ParametersWithRandom)parameters).getParameters();
+ }
+ else
+ {
+ k = (AsymmetricKeyParameter)parameters;
+ }
+
+ if (forSigning && !k.isPrivate())
+ {
+ throw new IllegalArgumentException("Signing Requires Private Key.");
+ }
+
+ if (!forSigning && k.isPrivate())
+ {
+ throw new IllegalArgumentException("Verification Requires Public Key.");
+ }
+
+ reset();
+
+ dsaSigner.init(forSigning, parameters);
+ }
+
+ /**
+ * update the internal digest with the byte b
+ */
+ public void update(
+ byte input)
+ {
+ digest.update(input);
+ }
+
+ /**
+ * update the internal digest with the byte array in
+ */
+ public void update(
+ byte[] input,
+ int inOff,
+ int length)
+ {
+ digest.update(input, inOff, length);
+ }
+
+ /**
+ * Generate a signature for the message we've been loaded with using
+ * the key we were initialised with.
+ */
+ public byte[] generateSignature()
+ {
+ if (!forSigning)
+ {
+ throw new IllegalStateException("DSADigestSigner not initialised for signature generation.");
+ }
+
+ byte[] hash = new byte[digest.getDigestSize()];
+ digest.doFinal(hash, 0);
+
+ BigInteger[] sig = dsaSigner.generateSignature(hash);
+
+ try
+ {
+ return derEncode(sig[0], sig[1]);
+ }
+ catch (IOException e)
+ {
+ throw new IllegalStateException("unable to encode signature");
+ }
+ }
+
+ public boolean verifySignature(
+ byte[] signature)
+ {
+ if (forSigning)
+ {
+ throw new IllegalStateException("DSADigestSigner not initialised for verification");
+ }
+
+ byte[] hash = new byte[digest.getDigestSize()];
+ digest.doFinal(hash, 0);
+
+ try
+ {
+ BigInteger[] sig = derDecode(signature);
+ return dsaSigner.verifySignature(hash, sig[0], sig[1]);
+ }
+ catch (IOException e)
+ {
+ return false;
+ }
+ }
+
+ public void reset()
+ {
+ digest.reset();
+ }
+
+ private byte[] derEncode(
+ BigInteger r,
+ BigInteger s)
+ throws IOException
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+ v.add(new DERInteger(r));
+ v.add(new DERInteger(s));
+
+ return new DERSequence(v).getEncoded(ASN1Encoding.DER);
+ }
+
+ private BigInteger[] derDecode(
+ byte[] encoding)
+ throws IOException
+ {
+ ASN1Sequence s = (ASN1Sequence)ASN1Primitive.fromByteArray(encoding);
+
+ return new BigInteger[]
+ {
+ ((DERInteger)s.getObjectAt(0)).getValue(),
+ ((DERInteger)s.getObjectAt(1)).getValue()
+ };
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/signers/DSASigner.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/signers/DSASigner.java
new file mode 100644
index 0000000..c23093b
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/signers/DSASigner.java
@@ -0,0 +1,138 @@
+package org.bc.crypto.signers;
+
+import org.bc.crypto.CipherParameters;
+import org.bc.crypto.DSA;
+import org.bc.crypto.params.DSAKeyParameters;
+import org.bc.crypto.params.DSAParameters;
+import org.bc.crypto.params.DSAPrivateKeyParameters;
+import org.bc.crypto.params.DSAPublicKeyParameters;
+import org.bc.crypto.params.ParametersWithRandom;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
+/**
+ * The Digital Signature Algorithm - as described in "Handbook of Applied
+ * Cryptography", pages 452 - 453.
+ */
+public class DSASigner
+ implements DSA
+{
+ DSAKeyParameters key;
+
+ SecureRandom random;
+
+ public void init(
+ boolean forSigning,
+ CipherParameters param)
+ {
+ if (forSigning)
+ {
+ if (param instanceof ParametersWithRandom)
+ {
+ ParametersWithRandom rParam = (ParametersWithRandom)param;
+
+ this.random = rParam.getRandom();
+ this.key = (DSAPrivateKeyParameters)rParam.getParameters();
+ }
+ else
+ {
+ this.random = new SecureRandom();
+ this.key = (DSAPrivateKeyParameters)param;
+ }
+ }
+ else
+ {
+ this.key = (DSAPublicKeyParameters)param;
+ }
+ }
+
+ /**
+ * generate a signature for the given message using the key we were
+ * initialised with. For conventional DSA the message should be a SHA-1
+ * hash of the message of interest.
+ *
+ * @param message the message that will be verified later.
+ */
+ public BigInteger[] generateSignature(
+ byte[] message)
+ {
+ DSAParameters params = key.getParameters();
+ BigInteger m = calculateE(params.getQ(), message);
+ BigInteger k;
+ int qBitLength = params.getQ().bitLength();
+
+ do
+ {
+ k = new BigInteger(qBitLength, random);
+ }
+ while (k.compareTo(params.getQ()) >= 0);
+
+ BigInteger r = params.getG().modPow(k, params.getP()).mod(params.getQ());
+
+ k = k.modInverse(params.getQ()).multiply(
+ m.add(((DSAPrivateKeyParameters)key).getX().multiply(r)));
+
+ BigInteger s = k.mod(params.getQ());
+
+ BigInteger[] res = new BigInteger[2];
+
+ res[0] = r;
+ res[1] = s;
+
+ return res;
+ }
+
+ /**
+ * return true if the value r and s represent a DSA signature for
+ * the passed in message for standard DSA the message should be a
+ * SHA-1 hash of the real message to be verified.
+ */
+ public boolean verifySignature(
+ byte[] message,
+ BigInteger r,
+ BigInteger s)
+ {
+ DSAParameters params = key.getParameters();
+ BigInteger m = calculateE(params.getQ(), message);
+ BigInteger zero = BigInteger.valueOf(0);
+
+ if (zero.compareTo(r) >= 0 || params.getQ().compareTo(r) <= 0)
+ {
+ return false;
+ }
+
+ if (zero.compareTo(s) >= 0 || params.getQ().compareTo(s) <= 0)
+ {
+ return false;
+ }
+
+ BigInteger w = s.modInverse(params.getQ());
+
+ BigInteger u1 = m.multiply(w).mod(params.getQ());
+ BigInteger u2 = r.multiply(w).mod(params.getQ());
+
+ u1 = params.getG().modPow(u1, params.getP());
+ u2 = ((DSAPublicKeyParameters)key).getY().modPow(u2, params.getP());
+
+ BigInteger v = u1.multiply(u2).mod(params.getP()).mod(params.getQ());
+
+ return v.equals(r);
+ }
+
+ private BigInteger calculateE(BigInteger n, byte[] message)
+ {
+ if (n.bitLength() >= message.length * 8)
+ {
+ return new BigInteger(1, message);
+ }
+ else
+ {
+ byte[] trunc = new byte[n.bitLength() / 8];
+
+ System.arraycopy(message, 0, trunc, 0, trunc.length);
+
+ return new BigInteger(1, trunc);
+ }
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/signers/DSTU4145Signer.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/signers/DSTU4145Signer.java
new file mode 100644
index 0000000..b709779
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/signers/DSTU4145Signer.java
@@ -0,0 +1,156 @@
+package org.bc.crypto.signers;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
+import org.bc.crypto.CipherParameters;
+import org.bc.crypto.DSA;
+import org.bc.crypto.params.ECKeyParameters;
+import org.bc.crypto.params.ECPrivateKeyParameters;
+import org.bc.crypto.params.ECPublicKeyParameters;
+import org.bc.crypto.params.ParametersWithRandom;
+import org.bc.math.ec.ECAlgorithms;
+import org.bc.math.ec.ECCurve;
+import org.bc.math.ec.ECFieldElement;
+import org.bc.math.ec.ECPoint;
+import org.bc.util.Arrays;
+
+/**
+ * DSTU 4145-2002
+ * initSign
was not called
+ */
+ public byte[] generateSignature()
+ {
+ if (hashAlg == null || signingKeyPair == null)
+ {
+ throw new IllegalStateException("Call initSign first!");
+ }
+
+ byte[] msgHash = new byte[hashAlg.getDigestSize()];
+
+ hashAlg.doFinal(msgHash, 0);
+ return signHash(msgHash, signingKeyPair);
+ }
+
+ private byte[] signHash(byte[] msgHash, NTRUSigningPrivateKeyParameters kp)
+ {
+ int r = 0;
+ IntegerPolynomial s;
+ IntegerPolynomial i;
+
+ NTRUSigningPublicKeyParameters kPub = kp.getPublicKey();
+ do
+ {
+ r++;
+ if (r > params.signFailTolerance)
+ {
+ throw new IllegalStateException("Signing failed: too many retries (max=" + params.signFailTolerance + ")");
+ }
+ i = createMsgRep(msgHash, r);
+ s = sign(i, kp);
+ }
+ while (!verify(i, s, kPub.h));
+
+ byte[] rawSig = s.toBinary(params.q);
+ ByteBuffer sbuf = ByteBuffer.allocate(rawSig.length + 4);
+ sbuf.put(rawSig);
+ sbuf.putInt(r);
+ return sbuf.array();
+ }
+
+ private IntegerPolynomial sign(IntegerPolynomial i, NTRUSigningPrivateKeyParameters kp)
+ {
+ int N = params.N;
+ int q = params.q;
+ int perturbationBases = params.B;
+
+ NTRUSigningPrivateKeyParameters kPriv = kp;
+ NTRUSigningPublicKeyParameters kPub = kp.getPublicKey();
+
+ IntegerPolynomial s = new IntegerPolynomial(N);
+ int iLoop = perturbationBases;
+ while (iLoop >= 1)
+ {
+ Polynomial f = kPriv.getBasis(iLoop).f;
+ Polynomial fPrime = kPriv.getBasis(iLoop).fPrime;
+
+ IntegerPolynomial y = f.mult(i);
+ y.div(q);
+ y = fPrime.mult(y);
+
+ IntegerPolynomial x = fPrime.mult(i);
+ x.div(q);
+ x = f.mult(x);
+
+ IntegerPolynomial si = y;
+ si.sub(x);
+ s.add(si);
+
+ IntegerPolynomial hi = (IntegerPolynomial)kPriv.getBasis(iLoop).h.clone();
+ if (iLoop > 1)
+ {
+ hi.sub(kPriv.getBasis(iLoop - 1).h);
+ }
+ else
+ {
+ hi.sub(kPub.h);
+ }
+ i = si.mult(hi, q);
+
+ iLoop--;
+ }
+
+ Polynomial f = kPriv.getBasis(0).f;
+ Polynomial fPrime = kPriv.getBasis(0).fPrime;
+
+ IntegerPolynomial y = f.mult(i);
+ y.div(q);
+ y = fPrime.mult(y);
+
+ IntegerPolynomial x = fPrime.mult(i);
+ x.div(q);
+ x = f.mult(x);
+
+ y.sub(x);
+ s.add(y);
+ s.modPositive(q);
+ return s;
+ }
+
+ /**
+ * Verifies a signature for any data previously added via {@link #update(byte[], int, int)}.
+ *
+ * @param sig a signature
+ * @return whether the signature is valid
+ * @throws IllegalStateException if initVerify
was not called
+ */
+ public boolean verifySignature(byte[] sig)
+ {
+ if (hashAlg == null || verificationKey == null)
+ {
+ throw new IllegalStateException("Call initVerify first!");
+ }
+
+ byte[] msgHash = new byte[hashAlg.getDigestSize()];
+
+ hashAlg.doFinal(msgHash, 0);
+
+ return verifyHash(msgHash, sig, verificationKey);
+ }
+
+ private boolean verifyHash(byte[] msgHash, byte[] sig, NTRUSigningPublicKeyParameters pub)
+ {
+ ByteBuffer sbuf = ByteBuffer.wrap(sig);
+ byte[] rawSig = new byte[sig.length - 4];
+ sbuf.get(rawSig);
+ IntegerPolynomial s = IntegerPolynomial.fromBinary(rawSig, params.N, params.q);
+ int r = sbuf.getInt();
+ return verify(createMsgRep(msgHash, r), s, pub.h);
+ }
+
+ private boolean verify(IntegerPolynomial i, IntegerPolynomial s, IntegerPolynomial h)
+ {
+ int q = params.q;
+ double normBoundSq = params.normBoundSq;
+ double betaSq = params.betaSq;
+
+ IntegerPolynomial t = h.mult(s, q);
+ t.sub(i);
+ long centeredNormSq = (long)(s.centeredNormSq(q) + betaSq * t.centeredNormSq(q));
+ return centeredNormSq <= normBoundSq;
+ }
+
+ protected IntegerPolynomial createMsgRep(byte[] msgHash, int r)
+ {
+ int N = params.N;
+ int q = params.q;
+
+ int c = 31 - Integer.numberOfLeadingZeros(q);
+ int B = (c + 7) / 8;
+ IntegerPolynomial i = new IntegerPolynomial(N);
+
+ ByteBuffer cbuf = ByteBuffer.allocate(msgHash.length + 4);
+ cbuf.put(msgHash);
+ cbuf.putInt(r);
+ NTRUSignerPrng prng = new NTRUSignerPrng(cbuf.array(), params.hashAlg);
+
+ for (int t = 0; t < N; t++)
+ {
+ byte[] o = prng.nextBytes(B);
+ int hi = o[o.length - 1];
+ hi >>= 8 * B - c;
+ hi <<= 8 * B - c;
+ o[o.length - 1] = (byte)hi;
+
+ ByteBuffer obuf = ByteBuffer.allocate(4);
+ obuf.put(o);
+ obuf.rewind();
+ // reverse byte order so it matches the endianness of java ints
+ i.coeffs[t] = Integer.reverseBytes(obuf.getInt());
+ }
+ return i;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/signers/NTRUSignerPrng.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/signers/NTRUSignerPrng.java
new file mode 100644
index 0000000..97f6d68
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/signers/NTRUSignerPrng.java
@@ -0,0 +1,54 @@
+package org.bc.crypto.signers;
+
+import java.nio.ByteBuffer;
+
+import org.bc.crypto.Digest;
+
+/**
+ * An implementation of the deterministic pseudo-random generator in EESS section 3.7.3.1
+ */
+public class NTRUSignerPrng {
+ private int counter;
+ private byte[] seed;
+ private Digest hashAlg;
+
+ /**
+ * Constructs a new PRNG and seeds it with a byte array.
+ * @param seed a seed
+ * @param hashAlg the hash algorithm to use
+ */
+ NTRUSignerPrng(byte[] seed, Digest hashAlg) {
+ counter = 0;
+ this.seed = seed;
+ this.hashAlg = hashAlg;
+ }
+
+ /**
+ * Returns n
random bytes
+ * @param n number of bytes to return
+ * @return the next n
random bytes
+ */
+ byte[] nextBytes(int n) {
+ ByteBuffer buf = ByteBuffer.allocate(n);
+
+ while (buf.hasRemaining()) {
+ ByteBuffer cbuf = ByteBuffer.allocate(seed.length + 4);
+ cbuf.put(seed);
+ cbuf.putInt(counter);
+ byte[] array = cbuf.array();
+ byte[] hash = new byte[hashAlg.getDigestSize()];
+
+ hashAlg.update(array, 0, array.length);
+
+ hashAlg.doFinal(hash, 0);
+
+ if (buf.remaining() < hash.length)
+ buf.put(hash, 0, buf.remaining());
+ else
+ buf.put(hash);
+ counter++;
+ }
+
+ return buf.array();
+ }
+}
\ No newline at end of file
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/signers/PSSSigner.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/signers/PSSSigner.java
new file mode 100644
index 0000000..1ef82b4
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/signers/PSSSigner.java
@@ -0,0 +1,348 @@
+package org.bc.crypto.signers;
+
+import java.security.SecureRandom;
+
+import org.bc.crypto.AsymmetricBlockCipher;
+import org.bc.crypto.CipherParameters;
+import org.bc.crypto.CryptoException;
+import org.bc.crypto.DataLengthException;
+import org.bc.crypto.Digest;
+import org.bc.crypto.Signer;
+import org.bc.crypto.params.ParametersWithRandom;
+import org.bc.crypto.params.RSABlindingParameters;
+import org.bc.crypto.params.RSAKeyParameters;
+
+/**
+ * RSA-PSS as described in PKCS# 1 v 2.1.
+ *
+ * DO NOT USE THIS FILE UNLESS YOU KNOW EXACTLY WHAT YOU ARE DOING.
+ *
+ *
+ * @deprecated Perform certificate verification in TlsAuthentication implementation
+ */
+public class AlwaysValidVerifyer implements CertificateVerifyer
+{
+ /**
+ * Return true.
+ *
+ * @see org.bc.crypto.tls.CertificateVerifyer#isValid(org.bc.asn1.x509.Certificate[])
+ */
+ public boolean isValid(org.bc.asn1.x509.Certificate[] certs)
+ {
+ return true;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/ByteQueue.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/ByteQueue.java
new file mode 100644
index 0000000..8081aa2
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/ByteQueue.java
@@ -0,0 +1,123 @@
+package org.bc.crypto.tls;
+
+/**
+ * A queue for bytes. This file could be more optimized.
+ */
+public class ByteQueue
+{
+ /**
+ * @return The smallest number which can be written as 2^x which is bigger than i.
+ */
+ public static final int nextTwoPow(int i)
+ {
+ /*
+ * This code is based of a lot of code I found on the Internet which mostly
+ * referenced a book called "Hacking delight".
+ */
+ i |= (i >> 1);
+ i |= (i >> 2);
+ i |= (i >> 4);
+ i |= (i >> 8);
+ i |= (i >> 16);
+ return i + 1;
+ }
+
+ /**
+ * The initial size for our buffer.
+ */
+ private static final int INITBUFSIZE = 1024;
+
+ /**
+ * The buffer where we store our data.
+ */
+ private byte[] databuf = new byte[ByteQueue.INITBUFSIZE];
+
+ /**
+ * How many bytes at the beginning of the buffer are skipped.
+ */
+ private int skipped = 0;
+
+ /**
+ * How many bytes in the buffer are valid data.
+ */
+ private int available = 0;
+
+ /**
+ * Read data from the buffer.
+ *
+ * @param buf The buffer where the read data will be copied to.
+ * @param offset How many bytes to skip at the beginning of buf.
+ * @param len How many bytes to read at all.
+ * @param skip How many bytes from our data to skip.
+ */
+ public void read(byte[] buf, int offset, int len, int skip)
+ {
+ if ((available - skip) < len)
+ {
+ throw new TlsRuntimeException("Not enough data to read");
+ }
+ if ((buf.length - offset) < len)
+ {
+ throw new TlsRuntimeException("Buffer size of " + buf.length
+ + " is too small for a read of " + len + " bytes");
+ }
+ System.arraycopy(databuf, skipped + skip, buf, offset, len);
+ return;
+ }
+
+ /**
+ * Add some data to our buffer.
+ *
+ * @param data A byte-array to read data from.
+ * @param offset How many bytes to skip at the beginning of the array.
+ * @param len How many bytes to read from the array.
+ */
+ public void addData(byte[] data, int offset, int len)
+ {
+ if ((skipped + available + len) > databuf.length)
+ {
+ byte[] tmp = new byte[ByteQueue.nextTwoPow(data.length)];
+ System.arraycopy(databuf, skipped, tmp, 0, available);
+ skipped = 0;
+ databuf = tmp;
+ }
+ System.arraycopy(data, offset, databuf, skipped + available, len);
+ available += len;
+ }
+
+ /**
+ * Remove some bytes from our data from the beginning.
+ *
+ * @param i How many bytes to remove.
+ */
+ public void removeData(int i)
+ {
+ if (i > available)
+ {
+ throw new TlsRuntimeException("Cannot remove " + i + " bytes, only got " + available);
+ }
+
+ /*
+ * Skip the data.
+ */
+ available -= i;
+ skipped += i;
+
+ /*
+ * If more than half of our data is skipped, we will move the data in the buffer.
+ */
+ if (skipped > (databuf.length / 2))
+ {
+ System.arraycopy(databuf, skipped, databuf, 0, available);
+ skipped = 0;
+ }
+ }
+
+ /**
+ * @return The number of bytes which are available in this buffer.
+ */
+ public int size()
+ {
+ return available;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/Certificate.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/Certificate.java
new file mode 100644
index 0000000..2eab412
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/Certificate.java
@@ -0,0 +1,120 @@
+package org.bc.crypto.tls;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Vector;
+
+import org.bc.asn1.ASN1Encoding;
+import org.bc.asn1.ASN1InputStream;
+import org.bc.asn1.ASN1Primitive;
+
+/**
+ * A representation for a certificate chain as used by a tls server.
+ */
+public class Certificate
+{
+ public static final Certificate EMPTY_CHAIN = new Certificate(new org.bc.asn1.x509.Certificate[0]);
+
+ /**
+ * The certificates.
+ */
+ protected org.bc.asn1.x509.Certificate[] certs;
+
+ /**
+ * Parse the ServerCertificate message.
+ *
+ * @param is The stream where to parse from.
+ * @return A Certificate object with the certs, the server has sended.
+ * @throws IOException If something goes wrong during parsing.
+ */
+ protected static Certificate parse(InputStream is) throws IOException
+ {
+ org.bc.asn1.x509.Certificate[] certs;
+ int left = TlsUtils.readUint24(is);
+ if (left == 0)
+ {
+ return EMPTY_CHAIN;
+ }
+ Vector tmp = new Vector();
+ while (left > 0)
+ {
+ int size = TlsUtils.readUint24(is);
+ left -= 3 + size;
+ byte[] buf = new byte[size];
+ TlsUtils.readFully(buf, is);
+ ByteArrayInputStream bis = new ByteArrayInputStream(buf);
+ ASN1InputStream ais = new ASN1InputStream(bis);
+ ASN1Primitive o = ais.readObject();
+ tmp.addElement(org.bc.asn1.x509.Certificate.getInstance(o));
+ if (bis.available() > 0)
+ {
+ throw new IllegalArgumentException(
+ "Sorry, there is garbage data left after the certificate");
+ }
+ }
+ certs = new org.bc.asn1.x509.Certificate[tmp.size()];
+ for (int i = 0; i < tmp.size(); i++)
+ {
+ certs[i] = (org.bc.asn1.x509.Certificate)tmp.elementAt(i);
+ }
+ return new Certificate(certs);
+ }
+
+ /**
+ * Encodes version of the ClientCertificate message
+ *
+ * @param os stream to write the message to
+ * @throws IOException If something goes wrong
+ */
+ protected void encode(OutputStream os) throws IOException
+ {
+ Vector encCerts = new Vector();
+ int totalSize = 0;
+ for (int i = 0; i < this.certs.length; ++i)
+ {
+ byte[] encCert = certs[i].getEncoded(ASN1Encoding.DER);
+ encCerts.addElement(encCert);
+ totalSize += encCert.length + 3;
+ }
+
+ TlsUtils.writeUint24(totalSize, os);
+
+ for (int i = 0; i < encCerts.size(); ++i)
+ {
+ byte[] encCert = (byte[])encCerts.elementAt(i);
+ TlsUtils.writeOpaque24(encCert, os);
+ }
+ }
+
+ /**
+ * Private constructor from a cert array.
+ *
+ * @param certs The certs the chain should contain.
+ */
+ public Certificate(org.bc.asn1.x509.Certificate[] certs)
+ {
+ if (certs == null)
+ {
+ throw new IllegalArgumentException("'certs' cannot be null");
+ }
+
+ this.certs = certs;
+ }
+
+ /**
+ * @return An array which contains the certs, this chain contains.
+ */
+ public org.bc.asn1.x509.Certificate[] getCerts()
+ {
+ org.bc.asn1.x509.Certificate[] result = new org.bc.asn1.x509.Certificate[certs.length];
+ System.arraycopy(certs, 0, result, 0, certs.length);
+ return result;
+ }
+
+ public boolean isEmpty()
+ {
+ return certs.length == 0;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/CertificateRequest.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/CertificateRequest.java
new file mode 100644
index 0000000..1a32a51
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/CertificateRequest.java
@@ -0,0 +1,28 @@
+package org.bc.crypto.tls;
+
+import java.util.Vector;
+
+public class CertificateRequest
+{
+ private short[] certificateTypes;
+ private Vector certificateAuthorities;
+
+ public CertificateRequest(short[] certificateTypes, Vector certificateAuthorities)
+ {
+ this.certificateTypes = certificateTypes;
+ this.certificateAuthorities = certificateAuthorities;
+ }
+
+ public short[] getCertificateTypes()
+ {
+ return certificateTypes;
+ }
+
+ /**
+ * @return Vector of X500Name
+ */
+ public Vector getCertificateAuthorities()
+ {
+ return certificateAuthorities;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/CertificateVerifyer.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/CertificateVerifyer.java
new file mode 100644
index 0000000..0d62c35
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/CertificateVerifyer.java
@@ -0,0 +1,16 @@
+package org.bc.crypto.tls;
+
+/**
+ * This should be implemented by any class which can find out, if a given certificate
+ * chain is being accepted by an client.
+ *
+ * @deprecated Perform certificate verification in TlsAuthentication implementation
+ */
+public interface CertificateVerifyer
+{
+ /**
+ * @param certs The certs, which are part of the chain.
+ * @return True, if the chain is accepted, false otherwise.
+ */
+ public boolean isValid(org.bc.asn1.x509.Certificate[] certs);
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/CipherSuite.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/CipherSuite.java
new file mode 100644
index 0000000..69164c6
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/CipherSuite.java
@@ -0,0 +1,135 @@
+package org.bc.crypto.tls;
+
+/**
+ * RFC 2246 A.5
+ */
+public class CipherSuite
+{
+ public static final int TLS_NULL_WITH_NULL_NULL = 0x0000;
+ public static final int TLS_RSA_WITH_NULL_MD5 = 0x0001;
+ public static final int TLS_RSA_WITH_NULL_SHA = 0x0002;
+ public static final int TLS_RSA_EXPORT_WITH_RC4_40_MD5 = 0x0003;
+ public static final int TLS_RSA_WITH_RC4_128_MD5 = 0x0004;
+ public static final int TLS_RSA_WITH_RC4_128_SHA = 0x0005;
+ public static final int TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5 = 0x0006;
+ public static final int TLS_RSA_WITH_IDEA_CBC_SHA = 0x0007;
+ public static final int TLS_RSA_EXPORT_WITH_DES40_CBC_SHA = 0x0008;
+ public static final int TLS_RSA_WITH_DES_CBC_SHA = 0x0009;
+ public static final int TLS_RSA_WITH_3DES_EDE_CBC_SHA = 0x000A;
+ public static final int TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA = 0x000B;
+ public static final int TLS_DH_DSS_WITH_DES_CBC_SHA = 0x000C;
+ public static final int TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA = 0x000D;
+ public static final int TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA = 0x000E;
+ public static final int TLS_DH_RSA_WITH_DES_CBC_SHA = 0x000F;
+ public static final int TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA = 0x0010;
+ public static final int TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA = 0x0011;
+ public static final int TLS_DHE_DSS_WITH_DES_CBC_SHA = 0x0012;
+ public static final int TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA = 0x0013;
+ public static final int TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA = 0x0014;
+ public static final int TLS_DHE_RSA_WITH_DES_CBC_SHA = 0x0015;
+ public static final int TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA = 0x0016;
+ public static final int TLS_DH_anon_EXPORT_WITH_RC4_40_MD5 = 0x0017;
+ public static final int TLS_DH_anon_WITH_RC4_128_MD5 = 0x0018;
+ public static final int TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA = 0x0019;
+ public static final int TLS_DH_anon_WITH_DES_CBC_SHA = 0x001A;
+ public static final int TLS_DH_anon_WITH_3DES_EDE_CBC_SHA = 0x001B;
+
+ /*
+ * RFC 3268
+ */
+ public static final int TLS_RSA_WITH_AES_128_CBC_SHA = 0x002F;
+ public static final int TLS_DH_DSS_WITH_AES_128_CBC_SHA = 0x0030;
+ public static final int TLS_DH_RSA_WITH_AES_128_CBC_SHA = 0x0031;
+ public static final int TLS_DHE_DSS_WITH_AES_128_CBC_SHA = 0x0032;
+ public static final int TLS_DHE_RSA_WITH_AES_128_CBC_SHA = 0x0033;
+ public static final int TLS_DH_anon_WITH_AES_128_CBC_SHA = 0x0034;
+ public static final int TLS_RSA_WITH_AES_256_CBC_SHA = 0x0035;
+ public static final int TLS_DH_DSS_WITH_AES_256_CBC_SHA = 0x0036;
+ public static final int TLS_DH_RSA_WITH_AES_256_CBC_SHA = 0x0037;
+ public static final int TLS_DHE_DSS_WITH_AES_256_CBC_SHA = 0x0038;
+ public static final int TLS_DHE_RSA_WITH_AES_256_CBC_SHA = 0x0039;
+ public static final int TLS_DH_anon_WITH_AES_256_CBC_SHA = 0x003A;
+
+ /*
+ * RFC 4279
+ */
+ public static final int TLS_PSK_WITH_RC4_128_SHA = 0x008A;
+ public static final int TLS_PSK_WITH_3DES_EDE_CBC_SHA = 0x008B;
+ public static final int TLS_PSK_WITH_AES_128_CBC_SHA = 0x008C;
+ public static final int TLS_PSK_WITH_AES_256_CBC_SHA = 0x008D;
+ public static final int TLS_DHE_PSK_WITH_RC4_128_SHA = 0x008E;
+ public static final int TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA = 0x008F;
+ public static final int TLS_DHE_PSK_WITH_AES_128_CBC_SHA = 0x0090;
+ public static final int TLS_DHE_PSK_WITH_AES_256_CBC_SHA = 0x0091;
+ public static final int TLS_RSA_PSK_WITH_RC4_128_SHA = 0x0092;
+ public static final int TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA = 0x0093;
+ public static final int TLS_RSA_PSK_WITH_AES_128_CBC_SHA = 0x0094;
+ public static final int TLS_RSA_PSK_WITH_AES_256_CBC_SHA = 0x0095;
+
+ /*
+ * RFC 4492
+ */
+ public static final int TLS_ECDH_ECDSA_WITH_NULL_SHA = 0xC001;
+ public static final int TLS_ECDH_ECDSA_WITH_RC4_128_SHA = 0xC002;
+ public static final int TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA = 0xC003;
+ public static final int TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA = 0xC004;
+ public static final int TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA = 0xC005;
+ public static final int TLS_ECDHE_ECDSA_WITH_NULL_SHA = 0xC006;
+ public static final int TLS_ECDHE_ECDSA_WITH_RC4_128_SHA = 0xC007;
+ public static final int TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA = 0xC008;
+ public static final int TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA = 0xC009;
+ public static final int TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA = 0xC00A;
+ public static final int TLS_ECDH_RSA_WITH_NULL_SHA = 0xC00B;
+ public static final int TLS_ECDH_RSA_WITH_RC4_128_SHA = 0xC00C;
+ public static final int TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA = 0xC00D;
+ public static final int TLS_ECDH_RSA_WITH_AES_128_CBC_SHA = 0xC00E;
+ public static final int TLS_ECDH_RSA_WITH_AES_256_CBC_SHA = 0xC00F;
+ public static final int TLS_ECDHE_RSA_WITH_NULL_SHA = 0xC010;
+ public static final int TLS_ECDHE_RSA_WITH_RC4_128_SHA = 0xC011;
+ public static final int TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA = 0xC012;
+ public static final int TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA = 0xC013;
+ public static final int TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA = 0xC014;
+ public static final int TLS_ECDH_anon_WITH_NULL_SHA = 0xC015;
+ public static final int TLS_ECDH_anon_WITH_RC4_128_SHA = 0xC016;
+ public static final int TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA = 0xC017;
+ public static final int TLS_ECDH_anon_WITH_AES_128_CBC_SHA = 0xC018;
+ public static final int TLS_ECDH_anon_WITH_AES_256_CBC_SHA = 0xC019;
+
+ /*
+ * RFC 5054
+ */
+ public static final int TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA = 0xC01A;
+ public static final int TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA = 0xC01B;
+ public static final int TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA = 0xC01C;
+ public static final int TLS_SRP_SHA_WITH_AES_128_CBC_SHA = 0xC01D;
+ public static final int TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA = 0xC01E;
+ public static final int TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA = 0xC01F;
+ public static final int TLS_SRP_SHA_WITH_AES_256_CBC_SHA = 0xC020;
+ public static final int TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA = 0xC021;
+ public static final int TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA = 0xC022;
+
+ /*
+ * RFC 5289
+ */
+ public static final int TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 = 0xC023;
+ public static final int TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 = 0xC024;
+ public static final int TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 = 0xC025;
+ public static final int TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 = 0xC026;
+ public static final int TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 = 0xC027;
+ public static final int TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 = 0xC028;
+ public static final int TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 = 0xC029;
+ public static final int TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 = 0xC02A;
+ public static final int TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 = 0xC02B;
+ public static final int TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 = 0xC02C;
+ public static final int TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 = 0xC02D;
+ public static final int TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 = 0xC02E;
+ public static final int TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 = 0xC02F;
+ public static final int TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 = 0xC030;
+ public static final int TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 = 0xC031;
+ public static final int TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 = 0xC032;
+
+ /*
+ * RFC 5746
+ */
+ public static final int TLS_EMPTY_RENEGOTIATION_INFO_SCSV = 0x00FF;
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/ClientCertificateType.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/ClientCertificateType.java
new file mode 100644
index 0000000..920ad76
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/ClientCertificateType.java
@@ -0,0 +1,19 @@
+package org.bc.crypto.tls;
+
+/**
+ * RFC 2246 7.4.4
+ */
+public class ClientCertificateType
+{
+ public static final short rsa_sign = 1;
+ public static final short dss_sign = 2;
+ public static final short rsa_fixed_dh = 3;
+ public static final short dss_fixed_dh = 4;
+
+ /*
+ * RFC 4492 5.5
+ */
+ public static final short ecdsa_sign = 64;
+ public static final short rsa_fixed_ecdh = 65;
+ public static final short ecdsa_fixed_ecdh = 66;
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/CombinedHash.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/CombinedHash.java
new file mode 100644
index 0000000..70af45b
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/CombinedHash.java
@@ -0,0 +1,114 @@
+package org.bc.crypto.tls;
+
+import org.bc.crypto.Digest;
+import org.bc.crypto.digests.MD5Digest;
+import org.bc.crypto.digests.SHA1Digest;
+
+/**
+ * A combined hash, which implements md5(m) || sha1(m).
+ */
+class CombinedHash implements Digest
+{
+ protected TlsClientContext context;
+ protected MD5Digest md5;
+ protected SHA1Digest sha1;
+
+ CombinedHash()
+ {
+ this.md5 = new MD5Digest();
+ this.sha1 = new SHA1Digest();
+ }
+
+ CombinedHash(TlsClientContext context)
+ {
+ this.context = context;
+ this.md5 = new MD5Digest();
+ this.sha1 = new SHA1Digest();
+ }
+
+ CombinedHash(CombinedHash t)
+ {
+ this.context = t.context;
+ this.md5 = new MD5Digest(t.md5);
+ this.sha1 = new SHA1Digest(t.sha1);
+ }
+
+ /**
+ * @see org.bc.crypto.Digest#getAlgorithmName()
+ */
+ public String getAlgorithmName()
+ {
+ return md5.getAlgorithmName() + " and " + sha1.getAlgorithmName();
+ }
+
+ /**
+ * @see org.bc.crypto.Digest#getDigestSize()
+ */
+ public int getDigestSize()
+ {
+ return 16 + 20;
+ }
+
+ /**
+ * @see org.bc.crypto.Digest#update(byte)
+ */
+ public void update(byte in)
+ {
+ md5.update(in);
+ sha1.update(in);
+ }
+
+ /**
+ * @see org.bc.crypto.Digest#update(byte[],int,int)
+ */
+ public void update(byte[] in, int inOff, int len)
+ {
+ md5.update(in, inOff, len);
+ sha1.update(in, inOff, len);
+ }
+
+ /**
+ * @see org.bc.crypto.Digest#doFinal(byte[],int)
+ */
+ public int doFinal(byte[] out, int outOff)
+ {
+ if (context != null)
+ {
+ boolean isTls = context.getServerVersion().getFullVersion() >= ProtocolVersion.TLSv10.getFullVersion();
+
+ if (!isTls)
+ {
+ ssl3Complete(md5, SSL3Mac.MD5_IPAD, SSL3Mac.MD5_OPAD);
+ ssl3Complete(sha1, SSL3Mac.SHA1_IPAD, SSL3Mac.SHA1_OPAD);
+ }
+ }
+
+ int i1 = md5.doFinal(out, outOff);
+ int i2 = sha1.doFinal(out, outOff + 16);
+ return i1 + i2;
+ }
+
+ /**
+ * @see org.bc.crypto.Digest#reset()
+ */
+ public void reset()
+ {
+ md5.reset();
+ sha1.reset();
+ }
+
+ protected void ssl3Complete(Digest d, byte[] ipad, byte[] opad)
+ {
+ byte[] secret = context.getSecurityParameters().masterSecret;
+
+ d.update(secret, 0, secret.length);
+ d.update(ipad, 0, ipad.length);
+
+ byte[] tmp = new byte[d.getDigestSize()];
+ d.doFinal(tmp, 0);
+
+ d.update(secret, 0, secret.length);
+ d.update(opad, 0, opad.length);
+ d.update(tmp, 0, tmp.length);
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/CompressionMethod.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/CompressionMethod.java
new file mode 100644
index 0000000..13e4853
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/CompressionMethod.java
@@ -0,0 +1,19 @@
+package org.bc.crypto.tls;
+
+/**
+ * RFC 2246 6.1
+ */
+public class CompressionMethod
+{
+ public static final short NULL = 0;
+
+ /*
+ * RFC 3749 2
+ */
+ public static final short DEFLATE = 1;
+
+ /*
+ * Values from 224 decimal (0xE0) through 255 decimal (0xFF)
+ * inclusive are reserved for private use.
+ */
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/ContentType.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/ContentType.java
new file mode 100644
index 0000000..e4c13b0
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/ContentType.java
@@ -0,0 +1,12 @@
+package org.bc.crypto.tls;
+
+/**
+ * RFC 2246 6.2.1
+ */
+public class ContentType
+{
+ public static final short change_cipher_spec = 20;
+ public static final short alert = 21;
+ public static final short handshake = 22;
+ public static final short application_data = 23;
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/DefaultTlsAgreementCredentials.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/DefaultTlsAgreementCredentials.java
new file mode 100644
index 0000000..5b126d7
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/DefaultTlsAgreementCredentials.java
@@ -0,0 +1,68 @@
+package org.bc.crypto.tls;
+
+import java.math.BigInteger;
+
+import org.bc.crypto.BasicAgreement;
+import org.bc.crypto.agreement.DHBasicAgreement;
+import org.bc.crypto.agreement.ECDHBasicAgreement;
+import org.bc.crypto.params.AsymmetricKeyParameter;
+import org.bc.crypto.params.DHPrivateKeyParameters;
+import org.bc.crypto.params.ECPrivateKeyParameters;
+import org.bc.util.BigIntegers;
+
+public class DefaultTlsAgreementCredentials implements TlsAgreementCredentials
+{
+ protected Certificate clientCert;
+ protected AsymmetricKeyParameter clientPrivateKey;
+
+ protected BasicAgreement basicAgreement;
+
+ public DefaultTlsAgreementCredentials(Certificate clientCertificate, AsymmetricKeyParameter clientPrivateKey)
+ {
+ if (clientCertificate == null)
+ {
+ throw new IllegalArgumentException("'clientCertificate' cannot be null");
+ }
+ if (clientCertificate.certs.length == 0)
+ {
+ throw new IllegalArgumentException("'clientCertificate' cannot be empty");
+ }
+ if (clientPrivateKey == null)
+ {
+ throw new IllegalArgumentException("'clientPrivateKey' cannot be null");
+ }
+ if (!clientPrivateKey.isPrivate())
+ {
+ throw new IllegalArgumentException("'clientPrivateKey' must be private");
+ }
+
+ if (clientPrivateKey instanceof DHPrivateKeyParameters)
+ {
+ basicAgreement = new DHBasicAgreement();
+ }
+ else if (clientPrivateKey instanceof ECPrivateKeyParameters)
+ {
+ basicAgreement = new ECDHBasicAgreement();
+ }
+ else
+ {
+ throw new IllegalArgumentException("'clientPrivateKey' type not supported: "
+ + clientPrivateKey.getClass().getName());
+ }
+
+ this.clientCert = clientCertificate;
+ this.clientPrivateKey = clientPrivateKey;
+ }
+
+ public Certificate getCertificate()
+ {
+ return clientCert;
+ }
+
+ public byte[] generateAgreement(AsymmetricKeyParameter serverPublicKey)
+ {
+ basicAgreement.init(clientPrivateKey);
+ BigInteger agreementValue = basicAgreement.calculateAgreement(serverPublicKey);
+ return BigIntegers.asUnsignedByteArray(agreementValue);
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/DefaultTlsCipherFactory.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/DefaultTlsCipherFactory.java
new file mode 100644
index 0000000..d933e70
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/DefaultTlsCipherFactory.java
@@ -0,0 +1,85 @@
+package org.bc.crypto.tls;
+
+import java.io.IOException;
+
+import org.bc.crypto.BlockCipher;
+import org.bc.crypto.Digest;
+import org.bc.crypto.StreamCipher;
+import org.bc.crypto.digests.MD5Digest;
+import org.bc.crypto.digests.SHA1Digest;
+import org.bc.crypto.digests.SHA256Digest;
+import org.bc.crypto.digests.SHA384Digest;
+import org.bc.crypto.engines.AESFastEngine;
+import org.bc.crypto.engines.DESedeEngine;
+import org.bc.crypto.engines.RC4Engine;
+import org.bc.crypto.modes.CBCBlockCipher;
+
+public class DefaultTlsCipherFactory implements TlsCipherFactory
+{
+ public TlsCipher createCipher(TlsClientContext context, int encryptionAlgorithm, int digestAlgorithm) throws IOException
+ {
+ switch (encryptionAlgorithm)
+ {
+ case EncryptionAlgorithm._3DES_EDE_CBC:
+ return createDESedeCipher(context, 24, digestAlgorithm);
+ case EncryptionAlgorithm.AES_128_CBC:
+ return createAESCipher(context, 16, digestAlgorithm);
+ case EncryptionAlgorithm.AES_256_CBC:
+ return createAESCipher(context, 32, digestAlgorithm);
+ case EncryptionAlgorithm.RC4_128:
+ return createRC4Cipher(context, 16, digestAlgorithm);
+ default:
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+ }
+
+ protected TlsCipher createAESCipher(TlsClientContext context, int cipherKeySize, int digestAlgorithm) throws IOException
+ {
+ return new TlsBlockCipher(context, createAESBlockCipher(),
+ createAESBlockCipher(), createDigest(digestAlgorithm), createDigest(digestAlgorithm), cipherKeySize);
+ }
+
+ protected TlsCipher createRC4Cipher(TlsClientContext context, int cipherKeySize, int digestAlgorithm) throws IOException
+ {
+ return new TlsStreamCipher(context, createRC4StreamCipher(), createRC4StreamCipher(),
+ createDigest(digestAlgorithm), createDigest(digestAlgorithm), cipherKeySize);
+ }
+
+ protected TlsCipher createDESedeCipher(TlsClientContext context, int cipherKeySize, int digestAlgorithm) throws IOException
+ {
+ return new TlsBlockCipher(context, createDESedeBlockCipher(),
+ createDESedeBlockCipher(), createDigest(digestAlgorithm), createDigest(digestAlgorithm), cipherKeySize);
+ }
+
+ protected StreamCipher createRC4StreamCipher()
+ {
+ return new RC4Engine();
+ }
+
+ protected BlockCipher createAESBlockCipher()
+ {
+ return new CBCBlockCipher(new AESFastEngine());
+ }
+
+ protected BlockCipher createDESedeBlockCipher()
+ {
+ return new CBCBlockCipher(new DESedeEngine());
+ }
+
+ protected Digest createDigest(int digestAlgorithm) throws IOException
+ {
+ switch (digestAlgorithm)
+ {
+ case DigestAlgorithm.MD5:
+ return new MD5Digest();
+ case DigestAlgorithm.SHA:
+ return new SHA1Digest();
+ case DigestAlgorithm.SHA256:
+ return new SHA256Digest();
+ case DigestAlgorithm.SHA384:
+ return new SHA384Digest();
+ default:
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/DefaultTlsClient.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/DefaultTlsClient.java
new file mode 100644
index 0000000..f53cfe1
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/DefaultTlsClient.java
@@ -0,0 +1,264 @@
+package org.bc.crypto.tls;
+
+import java.io.IOException;
+import java.util.Hashtable;
+
+public abstract class DefaultTlsClient implements TlsClient
+{
+ protected TlsCipherFactory cipherFactory;
+
+ protected TlsClientContext context;
+
+ protected int selectedCipherSuite;
+ protected int selectedCompressionMethod;
+
+ public DefaultTlsClient()
+ {
+ this(new DefaultTlsCipherFactory());
+ }
+
+ public DefaultTlsClient(TlsCipherFactory cipherFactory)
+ {
+ this.cipherFactory = cipherFactory;
+ }
+
+ public void init(TlsClientContext context)
+ {
+ this.context = context;
+ }
+
+ public ProtocolVersion getClientVersion()
+ {
+ return ProtocolVersion.TLSv10;
+ }
+
+ public int[] getCipherSuites()
+ {
+ return new int[] {
+ CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA,
+ CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA,
+ CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
+ CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA,
+ CipherSuite.TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA,
+ CipherSuite.TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA,
+ CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA,
+ CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA,
+ CipherSuite.TLS_RSA_WITH_3DES_EDE_CBC_SHA,
+ CipherSuite.TLS_RSA_WITH_RC4_128_SHA,
+ };
+ }
+
+ public Hashtable getClientExtensions()
+ {
+ return null;
+ }
+
+ public short[] getCompressionMethods()
+ {
+ return new short[] { CompressionMethod.NULL };
+ }
+
+ public void notifyServerVersion(ProtocolVersion serverVersion) throws IOException
+ {
+ if (!ProtocolVersion.TLSv10.equals(serverVersion))
+ {
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ }
+ }
+
+ public void notifySessionID(byte[] sessionID)
+ {
+ // Currently ignored
+ }
+
+ public void notifySelectedCipherSuite(int selectedCipherSuite)
+ {
+ this.selectedCipherSuite = selectedCipherSuite;
+ }
+
+ public void notifySelectedCompressionMethod(short selectedCompressionMethod)
+ {
+ this.selectedCompressionMethod = selectedCompressionMethod;
+ }
+
+ public void notifySecureRenegotiation(boolean secureRenegotiation) throws IOException
+ {
+ if (!secureRenegotiation)
+ {
+ /*
+ * RFC 5746 3.4. If the extension is not present, the server does not support
+ * secure renegotiation; set secure_renegotiation flag to FALSE. In this case,
+ * some clients may want to terminate the handshake instead of continuing; see
+ * Section 4.1 for discussion.
+ */
+// throw new TlsFatalAlert(AlertDescription.handshake_failure);
+ }
+ }
+
+ public void processServerExtensions(Hashtable serverExtensions)
+ {
+ }
+
+ public TlsKeyExchange getKeyExchange() throws IOException
+ {
+ switch (selectedCipherSuite)
+ {
+ case CipherSuite.TLS_RSA_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_RSA_WITH_RC4_128_SHA:
+ return createRSAKeyExchange();
+
+ case CipherSuite.TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_DH_DSS_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_DH_DSS_WITH_AES_256_CBC_SHA:
+ return createDHKeyExchange(KeyExchangeAlgorithm.DH_DSS);
+
+ case CipherSuite.TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_DH_RSA_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_DH_RSA_WITH_AES_256_CBC_SHA:
+ return createDHKeyExchange(KeyExchangeAlgorithm.DH_RSA);
+
+ case CipherSuite.TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA:
+ return createDHEKeyExchange(KeyExchangeAlgorithm.DHE_DSS);
+
+ case CipherSuite.TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA:
+ return createDHEKeyExchange(KeyExchangeAlgorithm.DHE_RSA);
+
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_RC4_128_SHA:
+ return createECDHKeyExchange(KeyExchangeAlgorithm.ECDH_ECDSA);
+
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA:
+ return createECDHEKeyExchange(KeyExchangeAlgorithm.ECDHE_ECDSA);
+
+ case CipherSuite.TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_ECDH_RSA_WITH_RC4_128_SHA:
+ return createECDHKeyExchange(KeyExchangeAlgorithm.ECDH_RSA);
+
+ case CipherSuite.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_RC4_128_SHA:
+ return createECDHEKeyExchange(KeyExchangeAlgorithm.ECDHE_RSA);
+
+ default:
+ /*
+ * Note: internal error here; the TlsProtocolHandler verifies that the
+ * server-selected cipher suite was in the list of client-offered cipher
+ * suites, so if we now can't produce an implementation, we shouldn't have
+ * offered it!
+ */
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+ }
+
+ public TlsCompression getCompression() throws IOException
+ {
+ switch (selectedCompressionMethod)
+ {
+ case CompressionMethod.NULL:
+ return new TlsNullCompression();
+
+ default:
+ /*
+ * Note: internal error here; the TlsProtocolHandler verifies that the
+ * server-selected compression method was in the list of client-offered compression
+ * methods, so if we now can't produce an implementation, we shouldn't have
+ * offered it!
+ */
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+ }
+
+ public TlsCipher getCipher() throws IOException
+ {
+ switch (selectedCipherSuite)
+ {
+ case CipherSuite.TLS_RSA_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA:
+ return cipherFactory.createCipher(context, EncryptionAlgorithm._3DES_EDE_CBC, DigestAlgorithm.SHA);
+
+ case CipherSuite.TLS_RSA_WITH_RC4_128_SHA:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_RC4_128_SHA:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA:
+ case CipherSuite.TLS_ECDH_RSA_WITH_RC4_128_SHA:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_RC4_128_SHA:
+ return cipherFactory.createCipher(context, EncryptionAlgorithm.RC4_128, DigestAlgorithm.SHA);
+
+ case CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_DH_DSS_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_DH_RSA_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA:
+ return cipherFactory.createCipher(context, EncryptionAlgorithm.AES_128_CBC, DigestAlgorithm.SHA);
+
+ case CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_DH_DSS_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_DH_RSA_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:
+ return cipherFactory.createCipher(context, EncryptionAlgorithm.AES_256_CBC, DigestAlgorithm.SHA);
+
+ default:
+ /*
+ * Note: internal error here; the TlsProtocolHandler verifies that the
+ * server-selected cipher suite was in the list of client-offered cipher
+ * suites, so if we now can't produce an implementation, we shouldn't have
+ * offered it!
+ */
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+ }
+
+ protected TlsKeyExchange createDHKeyExchange(int keyExchange)
+ {
+ return new TlsDHKeyExchange(context, keyExchange);
+ }
+
+ protected TlsKeyExchange createDHEKeyExchange(int keyExchange)
+ {
+ return new TlsDHEKeyExchange(context, keyExchange);
+ }
+
+ protected TlsKeyExchange createECDHKeyExchange(int keyExchange)
+ {
+ return new TlsECDHKeyExchange(context, keyExchange);
+ }
+
+ protected TlsKeyExchange createECDHEKeyExchange(int keyExchange)
+ {
+ return new TlsECDHEKeyExchange(context, keyExchange);
+ }
+
+ protected TlsKeyExchange createRSAKeyExchange()
+ {
+ return new TlsRSAKeyExchange(context);
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/DefaultTlsSignerCredentials.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/DefaultTlsSignerCredentials.java
new file mode 100644
index 0000000..eb1ab8b
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/DefaultTlsSignerCredentials.java
@@ -0,0 +1,79 @@
+package org.bc.crypto.tls;
+
+import java.io.IOException;
+
+import org.bc.crypto.CryptoException;
+import org.bc.crypto.params.AsymmetricKeyParameter;
+import org.bc.crypto.params.DSAPrivateKeyParameters;
+import org.bc.crypto.params.ECPrivateKeyParameters;
+import org.bc.crypto.params.RSAKeyParameters;
+
+public class DefaultTlsSignerCredentials implements TlsSignerCredentials
+{
+ protected TlsClientContext context;
+ protected Certificate clientCert;
+ protected AsymmetricKeyParameter clientPrivateKey;
+
+ protected TlsSigner clientSigner;
+
+ public DefaultTlsSignerCredentials(TlsClientContext context, Certificate clientCertificate,
+ AsymmetricKeyParameter clientPrivateKey)
+ {
+ if (clientCertificate == null)
+ {
+ throw new IllegalArgumentException("'clientCertificate' cannot be null");
+ }
+ if (clientCertificate.certs.length == 0)
+ {
+ throw new IllegalArgumentException("'clientCertificate' cannot be empty");
+ }
+ if (clientPrivateKey == null)
+ {
+ throw new IllegalArgumentException("'clientPrivateKey' cannot be null");
+ }
+ if (!clientPrivateKey.isPrivate())
+ {
+ throw new IllegalArgumentException("'clientPrivateKey' must be private");
+ }
+
+ if (clientPrivateKey instanceof RSAKeyParameters)
+ {
+ clientSigner = new TlsRSASigner();
+ }
+ else if (clientPrivateKey instanceof DSAPrivateKeyParameters)
+ {
+ clientSigner = new TlsDSSSigner();
+ }
+ else if (clientPrivateKey instanceof ECPrivateKeyParameters)
+ {
+ clientSigner = new TlsECDSASigner();
+ }
+ else
+ {
+ throw new IllegalArgumentException("'clientPrivateKey' type not supported: "
+ + clientPrivateKey.getClass().getName());
+ }
+
+ this.context = context;
+ this.clientCert = clientCertificate;
+ this.clientPrivateKey = clientPrivateKey;
+ }
+
+ public Certificate getCertificate()
+ {
+ return clientCert;
+ }
+
+ public byte[] generateCertificateSignature(byte[] md5andsha1) throws IOException
+ {
+ try
+ {
+ return clientSigner.calculateRawSignature(context.getSecureRandom(), clientPrivateKey,
+ md5andsha1);
+ }
+ catch (CryptoException e)
+ {
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/DigestAlgorithm.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/DigestAlgorithm.java
new file mode 100644
index 0000000..52617ae
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/DigestAlgorithm.java
@@ -0,0 +1,18 @@
+package org.bc.crypto.tls;
+
+public class DigestAlgorithm
+{
+ /*
+ * Note that the values here are implementation-specific and arbitrary.
+ * It is recommended not to depend on the particular values (e.g. serialization).
+ */
+ public static final int NULL = 0;
+ public static final int MD5 = 1;
+ public static final int SHA = 2;
+
+ /*
+ * RFC 5289
+ */
+ public static final int SHA256 = 3;
+ public static final int SHA384 = 4;
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/ECCurveType.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/ECCurveType.java
new file mode 100644
index 0000000..8d291cc
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/ECCurveType.java
@@ -0,0 +1,28 @@
+package org.bc.crypto.tls;
+
+/**
+ * RFC 4492 5.4
+ */
+public class ECCurveType
+{
+ /**
+ * Indicates the elliptic curve domain parameters are conveyed verbosely, and the
+ * underlying finite field is a prime field.
+ */
+ public static final short explicit_prime = 1;
+
+ /**
+ * Indicates the elliptic curve domain parameters are conveyed verbosely, and the
+ * underlying finite field is a characteristic-2 field.
+ */
+ public static final short explicit_char2 = 2;
+
+ /**
+ * Indicates that a named curve is used. This option SHOULD be used when applicable.
+ */
+ public static final short named_curve = 3;
+
+ /*
+ * Values 248 through 255 are reserved for private use.
+ */
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/ECPointFormat.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/ECPointFormat.java
new file mode 100644
index 0000000..5890367
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/ECPointFormat.java
@@ -0,0 +1,15 @@
+package org.bc.crypto.tls;
+
+/**
+ * RFC 4492 5.1.2
+ */
+public class ECPointFormat
+{
+ public static final short uncompressed = 0;
+ public static final short ansiX962_compressed_prime = 1;
+ public static final short ansiX962_compressed_char2 = 2;
+
+ /*
+ * reserved (248..255)
+ */
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/EncryptionAlgorithm.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/EncryptionAlgorithm.java
new file mode 100644
index 0000000..4656d19
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/EncryptionAlgorithm.java
@@ -0,0 +1,29 @@
+package org.bc.crypto.tls;
+
+public class EncryptionAlgorithm
+{
+ /*
+ * Note that the values here are implementation-specific and arbitrary.
+ * It is recommended not to depend on the particular values (e.g. serialization).
+ */
+ public static final int NULL = 0;
+ public static final int RC4_40 = 1;
+ public static final int RC4_128 = 2;
+ public static final int RC2_CBC_40 = 3;
+ public static final int IDEA_CBC = 4;
+ public static final int DES40_CBC = 5;
+ public static final int DES_CBC = 6;
+ public static final int _3DES_EDE_CBC = 7;
+
+ /*
+ * RFC 3268
+ */
+ public static final int AES_128_CBC = 8;
+ public static final int AES_256_CBC = 9;
+
+ /*
+ * RFC 5289
+ */
+ public static final int AES_128_GCM = 10;
+ public static final int AES_256_GCM = 11;
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/ExtensionType.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/ExtensionType.java
new file mode 100644
index 0000000..e781483
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/ExtensionType.java
@@ -0,0 +1,30 @@
+package org.bc.crypto.tls;
+
+/**
+ * RFC 4366 2.3
+ */
+public class ExtensionType
+{
+ public static final int server_name = 0;
+ public static final int max_fragment_length = 1;
+ public static final int client_certificate_url = 2;
+ public static final int trusted_ca_keys = 3;
+ public static final int truncated_hmac = 4;
+ public static final int status_request = 5;
+
+ /*
+ * RFC 4492
+ */
+ public static final int elliptic_curves = 10;
+ public static final int ec_point_formats = 11;
+
+ /*
+ * RFC 5054 2.8.1
+ */
+ public static final int srp = 12;
+
+ /*
+ * RFC 5746 6
+ */
+ public static final int renegotiation_info = 0xff01;
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/HandshakeType.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/HandshakeType.java
new file mode 100644
index 0000000..ab06fca
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/HandshakeType.java
@@ -0,0 +1,18 @@
+package org.bc.crypto.tls;
+
+/**
+ * RFC 2246 7.4
+ */
+public class HandshakeType
+{
+ public static final short hello_request = 0;
+ public static final short client_hello = 1;
+ public static final short server_hello = 2;
+ public static final short certificate = 11;
+ public static final short server_key_exchange = 12;
+ public static final short certificate_request = 13;
+ public static final short server_hello_done = 14;
+ public static final short certificate_verify = 15;
+ public static final short client_key_exchange = 16;
+ public static final short finished = 20;
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/KeyExchangeAlgorithm.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/KeyExchangeAlgorithm.java
new file mode 100644
index 0000000..2936e1f
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/KeyExchangeAlgorithm.java
@@ -0,0 +1,33 @@
+package org.bc.crypto.tls;
+
+public class KeyExchangeAlgorithm
+{
+ /*
+ * Note that the values here are implementation-specific and arbitrary.
+ * It is recommended not to depend on the particular values (e.g. serialization).
+ */
+ public static final int NULL = 0;
+ public static final int RSA = 1;
+ public static final int RSA_EXPORT = 2;
+ public static final int DHE_DSS = 3;
+ public static final int DHE_DSS_EXPORT = 4;
+ public static final int DHE_RSA = 5;
+ public static final int DHE_RSA_EXPORT = 6;
+ public static final int DH_DSS = 7;
+ public static final int DH_DSS_EXPORT = 8;
+ public static final int DH_RSA = 9;
+ public static final int DH_RSA_EXPORT = 10;
+ public static final int DH_anon = 11;
+ public static final int DH_anon_EXPORT = 12;
+ public static final int PSK = 13;
+ public static final int DHE_PSK = 14;
+ public static final int RSA_PSK = 15;
+ public static final int ECDH_ECDSA = 16;
+ public static final int ECDHE_ECDSA = 17;
+ public static final int ECDH_RSA = 18;
+ public static final int ECDHE_RSA = 19;
+ public static final int ECDH_anon = 20;
+ public static final int SRP = 21;
+ public static final int SRP_DSS = 22;
+ public static final int SRP_RSA = 23;
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/LegacyTlsAuthentication.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/LegacyTlsAuthentication.java
new file mode 100644
index 0000000..b4e24fa
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/LegacyTlsAuthentication.java
@@ -0,0 +1,32 @@
+package org.bc.crypto.tls;
+
+import java.io.IOException;
+
+/**
+ * A temporary class to wrap old CertificateVerifyer stuff for new TlsAuthentication
+ *
+ * @deprecated
+ */
+public class LegacyTlsAuthentication implements TlsAuthentication
+{
+ protected CertificateVerifyer verifyer;
+
+ public LegacyTlsAuthentication(CertificateVerifyer verifyer)
+ {
+ this.verifyer = verifyer;
+ }
+
+ public void notifyServerCertificate(Certificate serverCertificate) throws IOException
+ {
+ if (!this.verifyer.isValid(serverCertificate.getCerts()))
+ {
+ throw new TlsFatalAlert(AlertDescription.user_canceled);
+ }
+ }
+
+ public TlsCredentials getClientCredentials(CertificateRequest certificateRequest)
+ throws IOException
+ {
+ return null;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/LegacyTlsClient.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/LegacyTlsClient.java
new file mode 100644
index 0000000..4d290a0
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/LegacyTlsClient.java
@@ -0,0 +1,29 @@
+package org.bc.crypto.tls;
+
+import java.io.IOException;
+
+/**
+ * A temporary class to use LegacyTlsAuthentication
+ *
+ * @deprecated
+ */
+public class LegacyTlsClient extends DefaultTlsClient
+{
+ /** @deprecated */
+ protected CertificateVerifyer verifyer;
+
+ /**
+ * @deprecated
+ */
+ public LegacyTlsClient(CertificateVerifyer verifyer)
+ {
+ super();
+
+ this.verifyer = verifyer;
+ }
+
+ public TlsAuthentication getAuthentication() throws IOException
+ {
+ return new LegacyTlsAuthentication(verifyer);
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/NamedCurve.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/NamedCurve.java
new file mode 100644
index 0000000..f124de2
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/NamedCurve.java
@@ -0,0 +1,100 @@
+package org.bc.crypto.tls;
+
+import org.bc.asn1.sec.SECNamedCurves;
+import org.bc.asn1.x9.X9ECParameters;
+import org.bc.crypto.params.ECDomainParameters;
+
+/**
+ * RFC 4492 5.1.1
+ *
+ * The named curves defined here are those specified in SEC 2 [13]. Note that many of
+ * these curves are also recommended in ANSI X9.62 [7] and FIPS 186-2 [11]. Values 0xFE00
+ * through 0xFEFF are reserved for private use. Values 0xFF01 and 0xFF02 indicate that the
+ * client supports arbitrary prime and characteristic-2 curves, respectively (the curve
+ * parameters must be encoded explicitly in ECParameters).
+ */
+public class NamedCurve
+{
+ public static final int sect163k1 = 1;
+ public static final int sect163r1 = 2;
+ public static final int sect163r2 = 3;
+ public static final int sect193r1 = 4;
+ public static final int sect193r2 = 5;
+ public static final int sect233k1 = 6;
+ public static final int sect233r1 = 7;
+ public static final int sect239k1 = 8;
+ public static final int sect283k1 = 9;
+ public static final int sect283r1 = 10;
+ public static final int sect409k1 = 11;
+ public static final int sect409r1 = 12;
+ public static final int sect571k1 = 13;
+ public static final int sect571r1 = 14;
+ public static final int secp160k1 = 15;
+ public static final int secp160r1 = 16;
+ public static final int secp160r2 = 17;
+ public static final int secp192k1 = 18;
+ public static final int secp192r1 = 19;
+ public static final int secp224k1 = 20;
+ public static final int secp224r1 = 21;
+ public static final int secp256k1 = 22;
+ public static final int secp256r1 = 23;
+ public static final int secp384r1 = 24;
+ public static final int secp521r1 = 25;
+
+ /*
+ * reserved (0xFE00..0xFEFF)
+ */
+
+ public static final int arbitrary_explicit_prime_curves = 0xFF01;
+ public static final int arbitrary_explicit_char2_curves = 0xFF02;
+
+ private static final String[] curveNames = new String[] {
+ "sect163k1",
+ "sect163r1",
+ "sect163r2",
+ "sect193r1",
+ "sect193r2",
+ "sect233k1",
+ "sect233r1",
+ "sect239k1",
+ "sect283k1",
+ "sect283r1",
+ "sect409k1",
+ "sect409r1",
+ "sect571k1",
+ "sect571r1",
+ "secp160k1",
+ "secp160r1",
+ "secp160r2",
+ "secp192k1",
+ "secp192r1",
+ "secp224k1",
+ "secp224r1",
+ "secp256k1",
+ "secp256r1",
+ "secp384r1",
+ "secp521r1", };
+
+ static ECDomainParameters getECParameters(int namedCurve)
+ {
+ int index = namedCurve - 1;
+ if (index < 0 || index >= curveNames.length)
+ {
+ return null;
+ }
+
+ String curveName = curveNames[index];
+
+ // Lazily created the first time a particular curve is accessed
+ X9ECParameters ecP = SECNamedCurves.getByName(curveName);
+
+ if (ecP == null)
+ {
+ return null;
+ }
+
+ // It's a bit inefficient to do this conversion every time
+ return new ECDomainParameters(ecP.getCurve(), ecP.getG(), ecP.getN(), ecP.getH(),
+ ecP.getSeed());
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/PSKTlsClient.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/PSKTlsClient.java
new file mode 100644
index 0000000..a3e5dcb
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/PSKTlsClient.java
@@ -0,0 +1,200 @@
+package org.bc.crypto.tls;
+
+import java.io.IOException;
+import java.util.Hashtable;
+
+public abstract class PSKTlsClient implements TlsClient
+{
+ protected TlsCipherFactory cipherFactory;
+ protected TlsPSKIdentity pskIdentity;
+
+ protected TlsClientContext context;
+
+ protected int selectedCompressionMethod;
+ protected int selectedCipherSuite;
+
+ public PSKTlsClient(TlsPSKIdentity pskIdentity)
+ {
+ this(new DefaultTlsCipherFactory(), pskIdentity);
+ }
+
+ public PSKTlsClient(TlsCipherFactory cipherFactory, TlsPSKIdentity pskIdentity)
+ {
+ this.cipherFactory = cipherFactory;
+ this.pskIdentity = pskIdentity;
+ }
+
+ public ProtocolVersion getClientVersion()
+ {
+ return ProtocolVersion.TLSv10;
+ }
+
+ public void init(TlsClientContext context)
+ {
+ this.context = context;
+ }
+
+ public int[] getCipherSuites()
+ {
+ return new int[] {
+ CipherSuite.TLS_DHE_PSK_WITH_AES_256_CBC_SHA,
+ CipherSuite.TLS_DHE_PSK_WITH_AES_128_CBC_SHA,
+ CipherSuite.TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA,
+ CipherSuite.TLS_DHE_PSK_WITH_RC4_128_SHA,
+ CipherSuite.TLS_RSA_PSK_WITH_AES_256_CBC_SHA,
+ CipherSuite.TLS_RSA_PSK_WITH_AES_128_CBC_SHA,
+ CipherSuite.TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA,
+ CipherSuite.TLS_RSA_PSK_WITH_RC4_128_SHA,
+ CipherSuite.TLS_PSK_WITH_AES_256_CBC_SHA,
+ CipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA,
+ CipherSuite.TLS_PSK_WITH_3DES_EDE_CBC_SHA,
+ CipherSuite.TLS_PSK_WITH_RC4_128_SHA,
+ };
+ }
+
+ public Hashtable getClientExtensions() throws IOException
+ {
+ return null;
+ }
+
+ public short[] getCompressionMethods()
+ {
+ return new short[] { CompressionMethod.NULL };
+ }
+
+ public void notifyServerVersion(ProtocolVersion serverVersion) throws IOException
+ {
+ if (!ProtocolVersion.TLSv10.equals(serverVersion))
+ {
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ }
+ }
+
+ public void notifySessionID(byte[] sessionID)
+ {
+ // Currently ignored
+ }
+
+ public void notifySelectedCipherSuite(int selectedCipherSuite)
+ {
+ this.selectedCipherSuite = selectedCipherSuite;
+ }
+
+ public void notifySelectedCompressionMethod(short selectedCompressionMethod)
+ {
+ this.selectedCompressionMethod = selectedCompressionMethod;
+ }
+
+ public void notifySecureRenegotiation(boolean secureRenegotiation) throws IOException
+ {
+ if (!secureRenegotiation)
+ {
+ /*
+ * RFC 5746 3.4. If the extension is not present, the server does not support
+ * secure renegotiation; set secure_renegotiation flag to FALSE. In this case,
+ * some clients may want to terminate the handshake instead of continuing; see
+ * Section 4.1 for discussion.
+ */
+// throw new TlsFatalAlert(AlertDescription.handshake_failure);
+ }
+ }
+
+ public void processServerExtensions(Hashtable serverExtensions)
+ {
+ }
+
+ public TlsKeyExchange getKeyExchange() throws IOException
+ {
+ switch (selectedCipherSuite)
+ {
+ case CipherSuite.TLS_PSK_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_PSK_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_PSK_WITH_RC4_128_SHA:
+ return createPSKKeyExchange(KeyExchangeAlgorithm.PSK);
+
+ case CipherSuite.TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_RSA_PSK_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_RSA_PSK_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_RSA_PSK_WITH_RC4_128_SHA:
+ return createPSKKeyExchange(KeyExchangeAlgorithm.RSA_PSK);
+
+ case CipherSuite.TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_DHE_PSK_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_DHE_PSK_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_DHE_PSK_WITH_RC4_128_SHA:
+ return createPSKKeyExchange(KeyExchangeAlgorithm.DHE_PSK);
+
+ default:
+ /*
+ * Note: internal error here; the TlsProtocolHandler verifies that the
+ * server-selected cipher suite was in the list of client-offered cipher
+ * suites, so if we now can't produce an implementation, we shouldn't have
+ * offered it!
+ */
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+ }
+
+ public TlsCompression getCompression() throws IOException
+ {
+ switch (selectedCompressionMethod)
+ {
+ case CompressionMethod.NULL:
+ return new TlsNullCompression();
+
+ default:
+ /*
+ * Note: internal error here; the TlsProtocolHandler verifies that the
+ * server-selected compression method was in the list of client-offered compression
+ * methods, so if we now can't produce an implementation, we shouldn't have
+ * offered it!
+ */
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+ }
+
+ public TlsCipher getCipher() throws IOException
+ {
+ switch (selectedCipherSuite)
+ {
+ case CipherSuite.TLS_PSK_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA:
+ return cipherFactory.createCipher(context, EncryptionAlgorithm._3DES_EDE_CBC,
+ DigestAlgorithm.SHA);
+
+ case CipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_RSA_PSK_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_DHE_PSK_WITH_AES_128_CBC_SHA:
+ return cipherFactory.createCipher(context, EncryptionAlgorithm.AES_128_CBC,
+ DigestAlgorithm.SHA);
+
+ case CipherSuite.TLS_PSK_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_RSA_PSK_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_DHE_PSK_WITH_AES_256_CBC_SHA:
+ return cipherFactory.createCipher(context, EncryptionAlgorithm.AES_256_CBC,
+ DigestAlgorithm.SHA);
+
+ case CipherSuite.TLS_PSK_WITH_RC4_128_SHA:
+ case CipherSuite.TLS_RSA_PSK_WITH_RC4_128_SHA:
+ case CipherSuite.TLS_DHE_PSK_WITH_RC4_128_SHA:
+ return cipherFactory.createCipher(context, EncryptionAlgorithm.RC4_128,
+ DigestAlgorithm.SHA);
+
+ default:
+ /*
+ * Note: internal error here; the TlsProtocolHandler verifies that the
+ * server-selected cipher suite was in the list of client-offered cipher
+ * suites, so if we now can't produce an implementation, we shouldn't have
+ * offered it!
+ */
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+ }
+
+ protected TlsKeyExchange createPSKKeyExchange(int keyExchange)
+ {
+ return new TlsPSKKeyExchange(context, keyExchange, pskIdentity);
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/ProtocolVersion.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/ProtocolVersion.java
new file mode 100644
index 0000000..cba84ca
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/ProtocolVersion.java
@@ -0,0 +1,64 @@
+package org.bc.crypto.tls;
+
+import java.io.IOException;
+
+public class ProtocolVersion
+{
+ public static final ProtocolVersion SSLv3 = new ProtocolVersion(0x0300);
+ public static final ProtocolVersion TLSv10 = new ProtocolVersion(0x0301);
+ public static final ProtocolVersion TLSv11 = new ProtocolVersion(0x0302);
+ public static final ProtocolVersion TLSv12 = new ProtocolVersion(0x0303);
+
+ private int version;
+
+ private ProtocolVersion(int v)
+ {
+ version = v & 0xffff;
+ }
+
+ public int getFullVersion()
+ {
+ return version;
+ }
+
+ public int getMajorVersion()
+ {
+ return version >> 8;
+ }
+
+ public int getMinorVersion()
+ {
+ return version & 0xff;
+ }
+
+ public boolean equals(Object obj)
+ {
+ return this == obj;
+ }
+
+ public int hashCode()
+ {
+ return version;
+ }
+
+ public static ProtocolVersion get(int major, int minor) throws IOException
+ {
+ switch (major)
+ {
+ case 3:
+ switch (minor)
+ {
+ case 0:
+ return SSLv3;
+ case 1:
+ return TLSv10;
+ case 2:
+ return TLSv11;
+ case 3:
+ return TLSv12;
+ }
+ }
+
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/RecordStream.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/RecordStream.java
new file mode 100644
index 0000000..7e975bd
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/RecordStream.java
@@ -0,0 +1,191 @@
+package org.bc.crypto.tls;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.bc.crypto.Digest;
+
+/**
+ * An implementation of the TLS 1.0 record layer, allowing downgrade to SSLv3.
+ */
+class RecordStream
+{
+ private TlsProtocolHandler handler;
+ private InputStream is;
+ private OutputStream os;
+ private TlsCompression readCompression = null;
+ private TlsCompression writeCompression = null;
+ private TlsCipher readCipher = null;
+ private TlsCipher writeCipher = null;
+ private ByteArrayOutputStream buffer = new ByteArrayOutputStream();
+
+ private TlsClientContext context = null;
+ private CombinedHash hash = null;
+
+ RecordStream(TlsProtocolHandler handler, InputStream is, OutputStream os)
+ {
+ this.handler = handler;
+ this.is = is;
+ this.os = os;
+ this.readCompression = new TlsNullCompression();
+ this.writeCompression = this.readCompression;
+ this.readCipher = new TlsNullCipher();
+ this.writeCipher = this.readCipher;
+ }
+
+ void init(TlsClientContext context)
+ {
+ this.context = context;
+ this.hash = new CombinedHash(context);
+ }
+
+ void clientCipherSpecDecided(TlsCompression tlsCompression, TlsCipher tlsCipher)
+ {
+ this.writeCompression = tlsCompression;
+ this.writeCipher = tlsCipher;
+ }
+
+ void serverClientSpecReceived()
+ {
+ this.readCompression = this.writeCompression;
+ this.readCipher = this.writeCipher;
+ }
+
+ public void readData() throws IOException
+ {
+ short type = TlsUtils.readUint8(is);
+
+ // TODO In light of versioning and SSLv3, what should we expect here?
+ ProtocolVersion expectedVersion = ProtocolVersion.TLSv10; //context.getServerVersion();
+ if (!expectedVersion.equals(TlsUtils.readVersion(is)))
+ {
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ }
+
+ int size = TlsUtils.readUint16(is);
+ byte[] buf = decodeAndVerify(type, is, size);
+ handler.processData(type, buf, 0, buf.length);
+ }
+
+ protected byte[] decodeAndVerify(short type, InputStream is, int len) throws IOException
+ {
+ byte[] buf = new byte[len];
+ TlsUtils.readFully(buf, is);
+ byte[] decoded = readCipher.decodeCiphertext(type, buf, 0, buf.length);
+
+ OutputStream cOut = readCompression.decompress(buffer);
+
+ if (cOut == buffer)
+ {
+ return decoded;
+ }
+
+ cOut.write(decoded, 0, decoded.length);
+ cOut.flush();
+ return getBufferContents();
+ }
+
+ protected void writeMessage(short type, byte[] message, int offset, int len) throws IOException
+ {
+ if (type == ContentType.handshake)
+ {
+ updateHandshakeData(message, offset, len);
+ }
+
+ OutputStream cOut = writeCompression.compress(buffer);
+
+ byte[] ciphertext;
+ if (cOut == buffer)
+ {
+ ciphertext = writeCipher.encodePlaintext(type, message, offset, len);
+ }
+ else
+ {
+ cOut.write(message, offset, len);
+ cOut.flush();
+ byte[] compressed = getBufferContents();
+ ciphertext = writeCipher.encodePlaintext(type, compressed, 0, compressed.length);
+ }
+
+ byte[] writeMessage = new byte[ciphertext.length + 5];
+ TlsUtils.writeUint8(type, writeMessage, 0);
+ // TODO In light of versioning, what should we send here?
+// TlsUtils.writeVersion(context.getServerVersion(), writeMessage, 1);
+ TlsUtils.writeVersion(ProtocolVersion.TLSv10, writeMessage, 1);
+ TlsUtils.writeUint16(ciphertext.length, writeMessage, 3);
+ System.arraycopy(ciphertext, 0, writeMessage, 5, ciphertext.length);
+ os.write(writeMessage);
+ os.flush();
+ }
+
+ void updateHandshakeData(byte[] message, int offset, int len)
+ {
+ hash.update(message, offset, len);
+ }
+
+ /**
+ * 'sender' only relevant to SSLv3
+ */
+ byte[] getCurrentHash(byte[] sender)
+ {
+ Digest d = new CombinedHash(hash);
+
+ boolean isTls = context.getServerVersion().getFullVersion() >= ProtocolVersion.TLSv10.getFullVersion();
+
+ if (!isTls)
+ {
+ if (sender != null)
+ {
+ d.update(sender, 0, sender.length);
+ }
+ }
+
+ return doFinal(d);
+ }
+
+ protected void close() throws IOException
+ {
+ IOException e = null;
+ try
+ {
+ is.close();
+ }
+ catch (IOException ex)
+ {
+ e = ex;
+ }
+ try
+ {
+ os.close();
+ }
+ catch (IOException ex)
+ {
+ e = ex;
+ }
+ if (e != null)
+ {
+ throw e;
+ }
+ }
+
+ protected void flush() throws IOException
+ {
+ os.flush();
+ }
+
+ private byte[] getBufferContents()
+ {
+ byte[] contents = buffer.toByteArray();
+ buffer.reset();
+ return contents;
+ }
+
+ private static byte[] doFinal(Digest d)
+ {
+ byte[] bs = new byte[d.getDigestSize()];
+ d.doFinal(bs, 0);
+ return bs;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/SRPTlsClient.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/SRPTlsClient.java
new file mode 100644
index 0000000..08a4199
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/SRPTlsClient.java
@@ -0,0 +1,203 @@
+package org.bc.crypto.tls;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.Hashtable;
+
+import org.bc.util.Arrays;
+import org.bc.util.Integers;
+
+public abstract class SRPTlsClient
+ implements TlsClient
+{
+ public static final Integer EXT_SRP = Integers.valueOf(ExtensionType.srp);
+
+ protected TlsCipherFactory cipherFactory;
+ protected byte[] identity;
+ protected byte[] password;
+
+ protected TlsClientContext context;
+
+ protected int selectedCompressionMethod;
+ protected int selectedCipherSuite;
+
+ public SRPTlsClient(byte[] identity, byte[] password)
+ {
+ this(new DefaultTlsCipherFactory(), identity, password);
+ }
+
+ public SRPTlsClient(TlsCipherFactory cipherFactory, byte[] identity, byte[] password)
+ {
+ this.cipherFactory = cipherFactory;
+ this.identity = Arrays.clone(identity);
+ this.password = Arrays.clone(password);
+ }
+
+ public void init(TlsClientContext context)
+ {
+ this.context = context;
+ }
+
+ public ProtocolVersion getClientVersion()
+ {
+ return ProtocolVersion.TLSv10;
+ }
+
+ public int[] getCipherSuites()
+ {
+ return new int[] {
+ CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA,
+ CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA,
+ CipherSuite.TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA,
+ CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA,
+ CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA,
+ CipherSuite.TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA,
+ CipherSuite.TLS_SRP_SHA_WITH_AES_256_CBC_SHA,
+ CipherSuite.TLS_SRP_SHA_WITH_AES_128_CBC_SHA,
+ CipherSuite.TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA, };
+ }
+
+ public Hashtable getClientExtensions() throws IOException
+ {
+ Hashtable clientExtensions = new Hashtable();
+
+ ByteArrayOutputStream srpData = new ByteArrayOutputStream();
+ TlsUtils.writeOpaque8(this.identity, srpData);
+ clientExtensions.put(EXT_SRP, srpData.toByteArray());
+
+ return clientExtensions;
+ }
+
+ public short[] getCompressionMethods()
+ {
+ return new short[] { CompressionMethod.NULL };
+ }
+
+ public void notifyServerVersion(ProtocolVersion serverVersion) throws IOException
+ {
+ if (!ProtocolVersion.TLSv10.equals(serverVersion))
+ {
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ }
+ }
+
+ public void notifySessionID(byte[] sessionID)
+ {
+ // Currently ignored
+ }
+
+ public void notifySelectedCipherSuite(int selectedCipherSuite)
+ {
+ this.selectedCipherSuite = selectedCipherSuite;
+ }
+
+ public void notifySelectedCompressionMethod(short selectedCompressionMethod)
+ {
+ this.selectedCompressionMethod = selectedCompressionMethod;
+ }
+
+ public void notifySecureRenegotiation(boolean secureRenegotiation) throws IOException
+ {
+ if (!secureRenegotiation)
+ {
+ /*
+ * RFC 5746 3.4. If the extension is not present, the server does not support
+ * secure renegotiation; set secure_renegotiation flag to FALSE. In this case,
+ * some clients may want to terminate the handshake instead of continuing; see
+ * Section 4.1 for discussion.
+ */
+// throw new TlsFatalAlert(AlertDescription.handshake_failure);
+ }
+ }
+
+ public void processServerExtensions(Hashtable serverExtensions)
+ {
+ // There is no server response for the SRP extension
+ }
+
+ public TlsKeyExchange getKeyExchange() throws IOException
+ {
+ switch (selectedCipherSuite)
+ {
+ case CipherSuite.TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_SRP_SHA_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_SRP_SHA_WITH_AES_256_CBC_SHA:
+ return createSRPKeyExchange(KeyExchangeAlgorithm.SRP);
+
+ case CipherSuite.TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA:
+ return createSRPKeyExchange(KeyExchangeAlgorithm.SRP_RSA);
+
+ case CipherSuite.TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA:
+ return createSRPKeyExchange(KeyExchangeAlgorithm.SRP_DSS);
+
+ default:
+ /*
+ * Note: internal error here; the TlsProtocolHandler verifies that the
+ * server-selected cipher suite was in the list of client-offered cipher
+ * suites, so if we now can't produce an implementation, we shouldn't have
+ * offered it!
+ */
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+ }
+
+ public TlsCompression getCompression() throws IOException
+ {
+ switch (selectedCompressionMethod)
+ {
+ case CompressionMethod.NULL:
+ return new TlsNullCompression();
+
+ default:
+ /*
+ * Note: internal error here; the TlsProtocolHandler verifies that the
+ * server-selected compression method was in the list of client-offered compression
+ * methods, so if we now can't produce an implementation, we shouldn't have
+ * offered it!
+ */
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+ }
+
+ public TlsCipher getCipher() throws IOException
+ {
+ switch (selectedCipherSuite)
+ {
+ case CipherSuite.TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA:
+ return cipherFactory.createCipher(context, EncryptionAlgorithm._3DES_EDE_CBC,
+ DigestAlgorithm.SHA);
+
+ case CipherSuite.TLS_SRP_SHA_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA:
+ return cipherFactory.createCipher(context, EncryptionAlgorithm.AES_128_CBC,
+ DigestAlgorithm.SHA);
+
+ case CipherSuite.TLS_SRP_SHA_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA:
+ return cipherFactory.createCipher(context, EncryptionAlgorithm.AES_256_CBC,
+ DigestAlgorithm.SHA);
+
+ default:
+ /*
+ * Note: internal error here; the TlsProtocolHandler verifies that the
+ * server-selected cipher suite was in the list of client-offered cipher
+ * suites, so if we now can't produce an implementation, we shouldn't have
+ * offered it!
+ */
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+ }
+
+ protected TlsKeyExchange createSRPKeyExchange(int keyExchange)
+ {
+ return new TlsSRPKeyExchange(context, keyExchange, identity, password);
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/SSL3Mac.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/SSL3Mac.java
new file mode 100644
index 0000000..bd3de6c
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/SSL3Mac.java
@@ -0,0 +1,117 @@
+package org.bc.crypto.tls;
+
+import org.bc.crypto.CipherParameters;
+import org.bc.crypto.Digest;
+import org.bc.crypto.Mac;
+import org.bc.crypto.params.KeyParameter;
+import org.bc.util.Arrays;
+
+/**
+ * HMAC implementation based on original internet draft for HMAC (RFC 2104)
+ *
+ * The difference is that padding is concatentated versus XORed with the key
+ *
+ * H(K + opad, H(K + ipad, text))
+ */
+public class SSL3Mac implements Mac
+{
+ private final static byte IPAD = (byte)0x36;
+ private final static byte OPAD = (byte)0x5C;
+
+ static final byte[] MD5_IPAD = genPad(IPAD, 48);
+ static final byte[] MD5_OPAD = genPad(OPAD, 48);
+ static final byte[] SHA1_IPAD = genPad(IPAD, 40);
+ static final byte[] SHA1_OPAD = genPad(OPAD, 40);
+
+ private Digest digest;
+
+ private byte[] secret;
+ private byte[] ipad, opad;
+
+ /**
+ * Base constructor for one of the standard digest algorithms that the byteLength of
+ * the algorithm is know for. Behaviour is undefined for digests other than MD5 or SHA1.
+ *
+ * @param digest the digest.
+ */
+ public SSL3Mac(Digest digest)
+ {
+ this.digest = digest;
+
+ if (digest.getDigestSize() == 20)
+ {
+ this.ipad = SHA1_IPAD;
+ this.opad = SHA1_OPAD;
+ }
+ else
+ {
+ this.ipad = MD5_IPAD;
+ this.opad = MD5_OPAD;
+ }
+ }
+
+ public String getAlgorithmName()
+ {
+ return digest.getAlgorithmName() + "/SSL3MAC";
+ }
+
+ public Digest getUnderlyingDigest()
+ {
+ return digest;
+ }
+
+ public void init(CipherParameters params)
+ {
+ secret = Arrays.clone(((KeyParameter)params).getKey());
+
+ reset();
+ }
+
+ public int getMacSize()
+ {
+ return digest.getDigestSize();
+ }
+
+ public void update(byte in)
+ {
+ digest.update(in);
+ }
+
+ public void update(byte[] in, int inOff, int len)
+ {
+ digest.update(in, inOff, len);
+ }
+
+ public int doFinal(byte[] out, int outOff)
+ {
+ byte[] tmp = new byte[digest.getDigestSize()];
+ digest.doFinal(tmp, 0);
+
+ digest.update(secret, 0, secret.length);
+ digest.update(opad, 0, opad.length);
+ digest.update(tmp, 0, tmp.length);
+
+ int len = digest.doFinal(out, outOff);
+
+ reset();
+
+ return len;
+ }
+
+ /**
+ * Reset the mac generator.
+ */
+ public void reset()
+ {
+ digest.reset();
+ digest.update(secret, 0, secret.length);
+ digest.update(ipad, 0, ipad.length);
+ }
+
+ private static byte[] genPad(byte b, int count)
+ {
+ byte[] padding = new byte[count];
+ Arrays.fill(padding, b);
+ return padding;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/SecurityParameters.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/SecurityParameters.java
new file mode 100644
index 0000000..64525f8
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/SecurityParameters.java
@@ -0,0 +1,23 @@
+package org.bc.crypto.tls;
+
+public class SecurityParameters
+{
+ byte[] clientRandom = null;
+ byte[] serverRandom = null;
+ byte[] masterSecret = null;
+
+ public byte[] getClientRandom()
+ {
+ return clientRandom;
+ }
+
+ public byte[] getServerRandom()
+ {
+ return serverRandom;
+ }
+
+ public byte[] getMasterSecret()
+ {
+ return masterSecret;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsAgreementCredentials.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsAgreementCredentials.java
new file mode 100644
index 0000000..dbfa3e7
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsAgreementCredentials.java
@@ -0,0 +1,10 @@
+package org.bc.crypto.tls;
+
+import java.io.IOException;
+
+import org.bc.crypto.params.AsymmetricKeyParameter;
+
+public interface TlsAgreementCredentials extends TlsCredentials
+{
+ byte[] generateAgreement(AsymmetricKeyParameter serverPublicKey) throws IOException;
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsAuthentication.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsAuthentication.java
new file mode 100644
index 0000000..36e1e84
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsAuthentication.java
@@ -0,0 +1,24 @@
+package org.bc.crypto.tls;
+
+import java.io.IOException;
+
+public interface TlsAuthentication
+{
+ /**
+ * Called by the protocol handler to report the server certificate
+ * Note: this method is responsible for certificate verification and validation
+ *
+ * @param serverCertificate the server certificate received
+ * @throws IOException
+ */
+ void notifyServerCertificate(Certificate serverCertificate) throws IOException;
+
+ /**
+ * Return client credentials in response to server's certificate request
+ *
+ * @param certificateRequest details of the certificate request
+ * @return a TlsCredentials object or null for no client authentication
+ * @throws IOException
+ */
+ TlsCredentials getClientCredentials(CertificateRequest certificateRequest) throws IOException;
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsBlockCipher.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsBlockCipher.java
new file mode 100644
index 0000000..2db7d58
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsBlockCipher.java
@@ -0,0 +1,229 @@
+package org.bc.crypto.tls;
+
+import java.io.IOException;
+import java.security.SecureRandom;
+
+import org.bc.crypto.BlockCipher;
+import org.bc.crypto.Digest;
+import org.bc.crypto.params.KeyParameter;
+import org.bc.crypto.params.ParametersWithIV;
+import org.bc.util.Arrays;
+
+/**
+ * A generic TLS 1.0 / SSLv3 block cipher.
+ * This can be used for AES or 3DES for example.
+ */
+public class TlsBlockCipher implements TlsCipher
+{
+ protected TlsClientContext context;
+ protected byte[] randomData;
+
+ protected BlockCipher encryptCipher;
+ protected BlockCipher decryptCipher;
+
+ protected TlsMac writeMac;
+ protected TlsMac readMac;
+
+ public TlsMac getWriteMac()
+ {
+ return writeMac;
+ }
+
+ public TlsMac getReadMac()
+ {
+ return readMac;
+ }
+
+ public TlsBlockCipher(TlsClientContext context, BlockCipher encryptCipher,
+ BlockCipher decryptCipher, Digest writeDigest, Digest readDigest, int cipherKeySize)
+ {
+ this.context = context;
+
+ this.randomData = new byte[256];
+ context.getSecureRandom().nextBytes(randomData);
+
+ this.encryptCipher = encryptCipher;
+ this.decryptCipher = decryptCipher;
+
+ int key_block_size = (2 * cipherKeySize) + writeDigest.getDigestSize()
+ + readDigest.getDigestSize() + encryptCipher.getBlockSize()
+ + decryptCipher.getBlockSize();
+
+ byte[] key_block = TlsUtils.calculateKeyBlock(context, key_block_size);
+
+ int offset = 0;
+
+ // Init MACs
+ writeMac = new TlsMac(context, writeDigest, key_block, offset, writeDigest.getDigestSize());
+ offset += writeDigest.getDigestSize();
+ readMac = new TlsMac(context, readDigest, key_block, offset, readDigest.getDigestSize());
+ offset += readDigest.getDigestSize();
+
+ // Init Ciphers
+ this.initCipher(true, encryptCipher, key_block, cipherKeySize, offset, offset
+ + (cipherKeySize * 2));
+ offset += cipherKeySize;
+ this.initCipher(false, decryptCipher, key_block, cipherKeySize, offset, offset
+ + cipherKeySize + encryptCipher.getBlockSize());
+ }
+
+ protected void initCipher(boolean forEncryption, BlockCipher cipher, byte[] key_block,
+ int key_size, int key_offset, int iv_offset)
+ {
+ KeyParameter key_parameter = new KeyParameter(key_block, key_offset, key_size);
+ ParametersWithIV parameters_with_iv = new ParametersWithIV(key_parameter, key_block,
+ iv_offset, cipher.getBlockSize());
+ cipher.init(forEncryption, parameters_with_iv);
+ }
+
+ public byte[] encodePlaintext(short type, byte[] plaintext, int offset, int len)
+ {
+ int blocksize = encryptCipher.getBlockSize();
+ int padding_length = blocksize - 1 - ((len + writeMac.getSize()) % blocksize);
+
+ boolean isTls = context.getServerVersion().getFullVersion() >= ProtocolVersion.TLSv10.getFullVersion();
+
+ if (isTls)
+ {
+ // Add a random number of extra blocks worth of padding
+ int maxExtraPadBlocks = (255 - padding_length) / blocksize;
+ int actualExtraPadBlocks = chooseExtraPadBlocks(context.getSecureRandom(), maxExtraPadBlocks);
+ padding_length += actualExtraPadBlocks * blocksize;
+ }
+
+ int totalsize = len + writeMac.getSize() + padding_length + 1;
+ byte[] outbuf = new byte[totalsize];
+ System.arraycopy(plaintext, offset, outbuf, 0, len);
+ byte[] mac = writeMac.calculateMac(type, plaintext, offset, len);
+ System.arraycopy(mac, 0, outbuf, len, mac.length);
+ int paddoffset = len + mac.length;
+ for (int i = 0; i <= padding_length; i++)
+ {
+ outbuf[i + paddoffset] = (byte)padding_length;
+ }
+ for (int i = 0; i < totalsize; i += blocksize)
+ {
+ encryptCipher.processBlock(outbuf, i, outbuf, i);
+ }
+ return outbuf;
+ }
+
+ public byte[] decodeCiphertext(short type, byte[] ciphertext, int offset, int len)
+ throws IOException
+ {
+ int blockSize = decryptCipher.getBlockSize();
+ int macSize = readMac.getSize();
+
+ /*
+ * TODO[TLS 1.1] Explicit IV implies minLen = blockSize + max(blockSize, macSize + 1),
+ * and will need further changes to offset and plen variables below.
+ */
+
+ int minLen = Math.max(blockSize, macSize + 1);
+ if (len < minLen)
+ {
+ throw new TlsFatalAlert(AlertDescription.decode_error);
+ }
+
+ if (len % blockSize != 0)
+ {
+ throw new TlsFatalAlert(AlertDescription.decryption_failed);
+ }
+
+ for (int i = 0; i < len; i += blockSize)
+ {
+ decryptCipher.processBlock(ciphertext, offset + i, ciphertext, offset + i);
+ }
+
+ int plen = len;
+
+ // If there's anything wrong with the padding, this will return zero
+ int totalPad = checkPaddingConstantTime(ciphertext, offset, plen, blockSize, macSize);
+
+ int macInputLen = plen - totalPad - macSize;
+
+ byte[] decryptedMac = Arrays.copyOfRange(ciphertext, offset + macInputLen, offset + macInputLen + macSize);
+ byte[] calculatedMac = readMac.calculateMacConstantTime(type, ciphertext, offset, macInputLen, plen - macSize, randomData);
+
+ boolean badMac = !Arrays.constantTimeAreEqual(calculatedMac, decryptedMac);
+
+ if (badMac || totalPad == 0)
+ {
+ throw new TlsFatalAlert(AlertDescription.bad_record_mac);
+ }
+
+ return Arrays.copyOfRange(ciphertext, offset, offset + macInputLen);
+ }
+
+ protected int checkPaddingConstantTime(byte[] buf, int off, int len, int blockSize, int macSize)
+ {
+ int end = off + len;
+ byte lastByte = buf[end - 1];
+ int padlen = lastByte & 0xff;
+ int totalPad = padlen + 1;
+
+ int dummyIndex = 0;
+ byte padDiff = 0;
+
+ boolean isTls = context.getServerVersion().getFullVersion() >= ProtocolVersion.TLSv10.getFullVersion();
+
+ if ((!isTls && totalPad > blockSize) || (macSize + totalPad > len))
+ {
+ totalPad = 0;
+ }
+ else
+ {
+ int padPos = end - totalPad;
+ do
+ {
+ padDiff |= (buf[padPos++] ^ lastByte);
+ }
+ while (padPos < end);
+
+ dummyIndex = totalPad;
+
+ if (padDiff != 0)
+ {
+ totalPad = 0;
+ }
+ }
+
+ // Run some extra dummy checks so the number of checks is always constant
+ {
+ byte[] dummyPad = randomData;
+ while (dummyIndex < 256)
+ {
+ padDiff |= (dummyPad[dummyIndex++] ^ lastByte);
+ }
+ // Ensure the above loop is not eliminated
+ dummyPad[0] ^= padDiff;
+ }
+
+ return totalPad;
+ }
+
+ protected int chooseExtraPadBlocks(SecureRandom r, int max)
+ {
+// return r.nextInt(max + 1);
+
+ int x = r.nextInt();
+ int n = lowestBitSet(x);
+ return Math.min(n, max);
+ }
+
+ protected int lowestBitSet(int x)
+ {
+ if (x == 0)
+ {
+ return 32;
+ }
+
+ int n = 0;
+ while ((x & 1) == 0)
+ {
+ ++n;
+ x >>= 1;
+ }
+ return n;
+ }
+}
\ No newline at end of file
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsCipher.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsCipher.java
new file mode 100644
index 0000000..bcff141
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsCipher.java
@@ -0,0 +1,10 @@
+package org.bc.crypto.tls;
+
+import java.io.IOException;
+
+public interface TlsCipher
+{
+ byte[] encodePlaintext(short type, byte[] plaintext, int offset, int len) throws IOException;
+
+ byte[] decodeCiphertext(short type, byte[] ciphertext, int offset, int len) throws IOException;
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsCipherFactory.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsCipherFactory.java
new file mode 100644
index 0000000..43abef9
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsCipherFactory.java
@@ -0,0 +1,11 @@
+package org.bc.crypto.tls;
+
+import java.io.IOException;
+
+public interface TlsCipherFactory
+{
+ /**
+ * See enumeration classes EncryptionAlgorithm and DigestAlgorithm for appropriate argument values
+ */
+ TlsCipher createCipher(TlsClientContext context, int encryptionAlgorithm, int digestAlgorithm) throws IOException;
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsClient.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsClient.java
new file mode 100644
index 0000000..c67ff99
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsClient.java
@@ -0,0 +1,39 @@
+package org.bc.crypto.tls;
+
+import java.io.IOException;
+import java.util.Hashtable;
+
+public interface TlsClient
+{
+ void init(TlsClientContext context);
+
+ ProtocolVersion getClientVersion();
+
+ int[] getCipherSuites();
+
+ short[] getCompressionMethods();
+
+ // Hashtable is (Integer -> byte[])
+ Hashtable getClientExtensions() throws IOException;
+
+ void notifyServerVersion(ProtocolVersion selectedVersion) throws IOException;
+
+ void notifySessionID(byte[] sessionID);
+
+ void notifySelectedCipherSuite(int selectedCipherSuite);
+
+ void notifySelectedCompressionMethod(short selectedCompressionMethod);
+
+ void notifySecureRenegotiation(boolean secureNegotiation) throws IOException;
+
+ // Hashtable is (Integer -> byte[])
+ void processServerExtensions(Hashtable serverExtensions);
+
+ TlsKeyExchange getKeyExchange() throws IOException;
+
+ TlsAuthentication getAuthentication() throws IOException;
+
+ TlsCompression getCompression() throws IOException;
+
+ TlsCipher getCipher() throws IOException;
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsClientContext.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsClientContext.java
new file mode 100644
index 0000000..57d9277
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsClientContext.java
@@ -0,0 +1,18 @@
+package org.bc.crypto.tls;
+
+import java.security.SecureRandom;
+
+public interface TlsClientContext
+{
+ SecureRandom getSecureRandom();
+
+ SecurityParameters getSecurityParameters();
+
+ ProtocolVersion getClientVersion();
+
+ ProtocolVersion getServerVersion();
+
+ Object getUserObject();
+
+ void setUserObject(Object userObject);
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsClientContextImpl.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsClientContextImpl.java
new file mode 100644
index 0000000..7f165d9
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsClientContextImpl.java
@@ -0,0 +1,59 @@
+package org.bc.crypto.tls;
+
+import java.security.SecureRandom;
+
+class TlsClientContextImpl implements TlsClientContext
+{
+ private SecureRandom secureRandom;
+ private SecurityParameters securityParameters;
+
+ private ProtocolVersion clientVersion = null;
+ private ProtocolVersion serverVersion = null;
+ private Object userObject = null;
+
+ TlsClientContextImpl(SecureRandom secureRandom, SecurityParameters securityParameters)
+ {
+ this.secureRandom = secureRandom;
+ this.securityParameters = securityParameters;
+ }
+
+ public SecureRandom getSecureRandom()
+ {
+ return secureRandom;
+ }
+
+ public SecurityParameters getSecurityParameters()
+ {
+ return securityParameters;
+ }
+
+ public ProtocolVersion getClientVersion()
+ {
+ return clientVersion;
+ }
+
+ public void setClientVersion(ProtocolVersion clientVersion)
+ {
+ this.clientVersion = clientVersion;
+ }
+
+ public ProtocolVersion getServerVersion()
+ {
+ return serverVersion;
+ }
+
+ public void setServerVersion(ProtocolVersion serverVersion)
+ {
+ this.serverVersion = serverVersion;
+ }
+
+ public Object getUserObject()
+ {
+ return userObject;
+ }
+
+ public void setUserObject(Object userObject)
+ {
+ this.userObject = userObject;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsCompression.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsCompression.java
new file mode 100644
index 0000000..836adc4
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsCompression.java
@@ -0,0 +1,10 @@
+package org.bc.crypto.tls;
+
+import java.io.OutputStream;
+
+public interface TlsCompression
+{
+ OutputStream compress(OutputStream output);
+
+ OutputStream decompress(OutputStream output);
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsCredentials.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsCredentials.java
new file mode 100644
index 0000000..d7d678d
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsCredentials.java
@@ -0,0 +1,6 @@
+package org.bc.crypto.tls;
+
+public interface TlsCredentials
+{
+ Certificate getCertificate();
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsDHEKeyExchange.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsDHEKeyExchange.java
new file mode 100644
index 0000000..2b43268
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsDHEKeyExchange.java
@@ -0,0 +1,57 @@
+package org.bc.crypto.tls;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.math.BigInteger;
+
+import org.bc.crypto.Signer;
+import org.bc.crypto.io.SignerInputStream;
+import org.bc.crypto.params.DHParameters;
+import org.bc.crypto.params.DHPublicKeyParameters;
+
+class TlsDHEKeyExchange extends TlsDHKeyExchange
+{
+ TlsDHEKeyExchange(TlsClientContext context, int keyExchange)
+ {
+ super(context, keyExchange);
+ }
+
+ public void skipServerKeyExchange() throws IOException
+ {
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+
+ public void processServerKeyExchange(InputStream is)
+ throws IOException
+ {
+ SecurityParameters securityParameters = context.getSecurityParameters();
+
+ Signer signer = initSigner(tlsSigner, securityParameters);
+ InputStream sigIn = new SignerInputStream(is, signer);
+
+ byte[] pBytes = TlsUtils.readOpaque16(sigIn);
+ byte[] gBytes = TlsUtils.readOpaque16(sigIn);
+ byte[] YsBytes = TlsUtils.readOpaque16(sigIn);
+
+ byte[] sigByte = TlsUtils.readOpaque16(is);
+ if (!signer.verifySignature(sigByte))
+ {
+ throw new TlsFatalAlert(AlertDescription.bad_certificate);
+ }
+
+ BigInteger p = new BigInteger(1, pBytes);
+ BigInteger g = new BigInteger(1, gBytes);
+ BigInteger Ys = new BigInteger(1, YsBytes);
+
+ this.dhAgreeServerPublicKey = validateDHPublicKey(new DHPublicKeyParameters(Ys,
+ new DHParameters(p, g)));
+ }
+
+ protected Signer initSigner(TlsSigner tlsSigner, SecurityParameters securityParameters)
+ {
+ Signer signer = tlsSigner.createVerifyer(this.serverPublicKey);
+ signer.update(securityParameters.clientRandom, 0, securityParameters.clientRandom.length);
+ signer.update(securityParameters.serverRandom, 0, securityParameters.serverRandom.length);
+ return signer;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsDHKeyExchange.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsDHKeyExchange.java
new file mode 100644
index 0000000..3b488f0
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsDHKeyExchange.java
@@ -0,0 +1,210 @@
+package org.bc.crypto.tls;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.math.BigInteger;
+
+import org.bc.asn1.x509.KeyUsage;
+import org.bc.asn1.x509.SubjectPublicKeyInfo;
+import org.bc.crypto.AsymmetricCipherKeyPair;
+import org.bc.crypto.params.AsymmetricKeyParameter;
+import org.bc.crypto.params.DHParameters;
+import org.bc.crypto.params.DHPrivateKeyParameters;
+import org.bc.crypto.params.DHPublicKeyParameters;
+import org.bc.crypto.util.PublicKeyFactory;
+
+/**
+ * TLS 1.0 DH key exchange.
+ */
+class TlsDHKeyExchange implements TlsKeyExchange
+{
+ protected static final BigInteger ONE = BigInteger.valueOf(1);
+ protected static final BigInteger TWO = BigInteger.valueOf(2);
+
+ protected TlsClientContext context;
+ protected int keyExchange;
+ protected TlsSigner tlsSigner;
+
+ protected AsymmetricKeyParameter serverPublicKey = null;
+ protected DHPublicKeyParameters dhAgreeServerPublicKey = null;
+ protected TlsAgreementCredentials agreementCredentials;
+ protected DHPrivateKeyParameters dhAgreeClientPrivateKey = null;
+
+ TlsDHKeyExchange(TlsClientContext context, int keyExchange)
+ {
+ switch (keyExchange)
+ {
+ case KeyExchangeAlgorithm.DH_RSA:
+ case KeyExchangeAlgorithm.DH_DSS:
+ this.tlsSigner = null;
+ break;
+ case KeyExchangeAlgorithm.DHE_RSA:
+ this.tlsSigner = new TlsRSASigner();
+ break;
+ case KeyExchangeAlgorithm.DHE_DSS:
+ this.tlsSigner = new TlsDSSSigner();
+ break;
+ default:
+ throw new IllegalArgumentException("unsupported key exchange algorithm");
+ }
+
+ this.context = context;
+ this.keyExchange = keyExchange;
+ }
+
+ public void skipServerCertificate() throws IOException
+ {
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+
+ public void processServerCertificate(Certificate serverCertificate) throws IOException
+ {
+ org.bc.asn1.x509.Certificate x509Cert = serverCertificate.certs[0];
+ SubjectPublicKeyInfo keyInfo = x509Cert.getSubjectPublicKeyInfo();
+
+ try
+ {
+ this.serverPublicKey = PublicKeyFactory.createKey(keyInfo);
+ }
+ catch (RuntimeException e)
+ {
+ throw new TlsFatalAlert(AlertDescription.unsupported_certificate);
+ }
+
+ if (tlsSigner == null)
+ {
+ try
+ {
+ this.dhAgreeServerPublicKey = validateDHPublicKey((DHPublicKeyParameters)this.serverPublicKey);
+ }
+ catch (ClassCastException e)
+ {
+ throw new TlsFatalAlert(AlertDescription.certificate_unknown);
+ }
+
+ TlsUtils.validateKeyUsage(x509Cert, KeyUsage.keyAgreement);
+ }
+ else
+ {
+ if (!tlsSigner.isValidPublicKey(this.serverPublicKey))
+ {
+ throw new TlsFatalAlert(AlertDescription.certificate_unknown);
+ }
+
+ TlsUtils.validateKeyUsage(x509Cert, KeyUsage.digitalSignature);
+ }
+
+ // TODO
+ /*
+ * Perform various checks per RFC2246 7.4.2: "Unless otherwise specified, the
+ * signing algorithm for the certificate must be the same as the algorithm for the
+ * certificate key."
+ */
+ }
+
+ public void skipServerKeyExchange() throws IOException
+ {
+ // OK
+ }
+
+ public void processServerKeyExchange(InputStream is)
+ throws IOException
+ {
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+
+ public void validateCertificateRequest(CertificateRequest certificateRequest)
+ throws IOException
+ {
+ short[] types = certificateRequest.getCertificateTypes();
+ for (int i = 0; i < types.length; ++i)
+ {
+ switch (types[i])
+ {
+ case ClientCertificateType.rsa_sign:
+ case ClientCertificateType.dss_sign:
+ case ClientCertificateType.rsa_fixed_dh:
+ case ClientCertificateType.dss_fixed_dh:
+ case ClientCertificateType.ecdsa_sign:
+ break;
+ default:
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ }
+ }
+ }
+
+ public void skipClientCredentials() throws IOException
+ {
+ this.agreementCredentials = null;
+ }
+
+ public void processClientCredentials(TlsCredentials clientCredentials) throws IOException
+ {
+ if (clientCredentials instanceof TlsAgreementCredentials)
+ {
+ // TODO Validate client cert has matching parameters (see 'areCompatibleParameters')?
+
+ this.agreementCredentials = (TlsAgreementCredentials)clientCredentials;
+ }
+ else if (clientCredentials instanceof TlsSignerCredentials)
+ {
+ // OK
+ }
+ else
+ {
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+ }
+
+ public void generateClientKeyExchange(OutputStream os) throws IOException
+ {
+ /*
+ * RFC 2246 7.4.7.2 If the client certificate already contains a suitable
+ * Diffie-Hellman key, then Yc is implicit and does not need to be sent again. In
+ * this case, the Client Key Exchange message will be sent, but will be empty.
+ */
+ if (agreementCredentials == null)
+ {
+ generateEphemeralClientKeyExchange(dhAgreeServerPublicKey.getParameters(), os);
+ }
+ }
+
+ public byte[] generatePremasterSecret() throws IOException
+ {
+ if (agreementCredentials != null)
+ {
+ return agreementCredentials.generateAgreement(dhAgreeServerPublicKey);
+ }
+
+ return calculateDHBasicAgreement(dhAgreeServerPublicKey, dhAgreeClientPrivateKey);
+ }
+
+ protected boolean areCompatibleParameters(DHParameters a, DHParameters b)
+ {
+ return a.getP().equals(b.getP()) && a.getG().equals(b.getG());
+ }
+
+ protected byte[] calculateDHBasicAgreement(DHPublicKeyParameters publicKey,
+ DHPrivateKeyParameters privateKey)
+ {
+ return TlsDHUtils.calculateDHBasicAgreement(publicKey, privateKey);
+ }
+
+ protected AsymmetricCipherKeyPair generateDHKeyPair(DHParameters dhParams)
+ {
+ return TlsDHUtils.generateDHKeyPair(context.getSecureRandom(), dhParams);
+ }
+
+ protected void generateEphemeralClientKeyExchange(DHParameters dhParams, OutputStream os)
+ throws IOException
+ {
+ this.dhAgreeClientPrivateKey = TlsDHUtils.generateEphemeralClientKeyExchange(context.getSecureRandom(), dhParams, os);
+ }
+
+ protected DHPublicKeyParameters validateDHPublicKey(DHPublicKeyParameters key)
+ throws IOException
+ {
+ return TlsDHUtils.validateDHPublicKey(key);
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsDHUtils.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsDHUtils.java
new file mode 100644
index 0000000..fffa3e5
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsDHUtils.java
@@ -0,0 +1,76 @@
+package org.bc.crypto.tls;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
+import org.bc.crypto.AsymmetricCipherKeyPair;
+import org.bc.crypto.agreement.DHBasicAgreement;
+import org.bc.crypto.generators.DHBasicKeyPairGenerator;
+import org.bc.crypto.params.DHKeyGenerationParameters;
+import org.bc.crypto.params.DHParameters;
+import org.bc.crypto.params.DHPrivateKeyParameters;
+import org.bc.crypto.params.DHPublicKeyParameters;
+import org.bc.util.BigIntegers;
+
+public class TlsDHUtils
+{
+ static final BigInteger ONE = BigInteger.valueOf(1);
+ static final BigInteger TWO = BigInteger.valueOf(2);
+
+ public static byte[] calculateDHBasicAgreement(DHPublicKeyParameters publicKey,
+ DHPrivateKeyParameters privateKey)
+ {
+ DHBasicAgreement dhAgree = new DHBasicAgreement();
+ dhAgree.init(privateKey);
+ BigInteger agreement = dhAgree.calculateAgreement(publicKey);
+ return BigIntegers.asUnsignedByteArray(agreement);
+ }
+
+ public static AsymmetricCipherKeyPair generateDHKeyPair(SecureRandom random, DHParameters dhParams)
+ {
+ DHBasicKeyPairGenerator dhGen = new DHBasicKeyPairGenerator();
+ dhGen.init(new DHKeyGenerationParameters(random, dhParams));
+ return dhGen.generateKeyPair();
+ }
+
+ public static DHPrivateKeyParameters generateEphemeralClientKeyExchange(SecureRandom random, DHParameters dhParams, OutputStream os)
+ throws IOException
+ {
+ AsymmetricCipherKeyPair dhAgreeClientKeyPair = generateDHKeyPair(random, dhParams);
+ DHPrivateKeyParameters dhAgreeClientPrivateKey = (DHPrivateKeyParameters)dhAgreeClientKeyPair.getPrivate();
+
+ BigInteger Yc = ((DHPublicKeyParameters)dhAgreeClientKeyPair.getPublic()).getY();
+ byte[] keData = BigIntegers.asUnsignedByteArray(Yc);
+ TlsUtils.writeOpaque16(keData, os);
+
+ return dhAgreeClientPrivateKey;
+ }
+
+ public static DHPublicKeyParameters validateDHPublicKey(DHPublicKeyParameters key)
+ throws IOException
+ {
+ BigInteger Y = key.getY();
+ DHParameters params = key.getParameters();
+ BigInteger p = params.getP();
+ BigInteger g = params.getG();
+
+ if (!p.isProbablePrime(2))
+ {
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ }
+ if (g.compareTo(TWO) < 0 || g.compareTo(p.subtract(TWO)) > 0)
+ {
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ }
+ if (Y.compareTo(TWO) < 0 || Y.compareTo(p.subtract(ONE)) > 0)
+ {
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ }
+
+ // TODO See RFC 2631 for more discussion of Diffie-Hellman validation
+
+ return key;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsDSASigner.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsDSASigner.java
new file mode 100644
index 0000000..19e9621
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsDSASigner.java
@@ -0,0 +1,34 @@
+package org.bc.crypto.tls;
+
+import java.security.SecureRandom;
+
+import org.bc.crypto.CryptoException;
+import org.bc.crypto.DSA;
+import org.bc.crypto.Signer;
+import org.bc.crypto.digests.NullDigest;
+import org.bc.crypto.digests.SHA1Digest;
+import org.bc.crypto.params.AsymmetricKeyParameter;
+import org.bc.crypto.params.ParametersWithRandom;
+import org.bc.crypto.signers.DSADigestSigner;
+
+abstract class TlsDSASigner implements TlsSigner
+{
+ public byte[] calculateRawSignature(SecureRandom secureRandom, AsymmetricKeyParameter privateKey, byte[] md5andsha1)
+ throws CryptoException
+ {
+ // Note: Only use the SHA1 part of the hash
+ Signer signer = new DSADigestSigner(createDSAImpl(), new NullDigest());
+ signer.init(true, new ParametersWithRandom(privateKey, secureRandom));
+ signer.update(md5andsha1, 16, 20);
+ return signer.generateSignature();
+ }
+
+ public Signer createVerifyer(AsymmetricKeyParameter publicKey)
+ {
+ Signer verifyer = new DSADigestSigner(createDSAImpl(), new SHA1Digest());
+ verifyer.init(false, publicKey);
+ return verifyer;
+ }
+
+ protected abstract DSA createDSAImpl();
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsDSSSigner.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsDSSSigner.java
new file mode 100644
index 0000000..dfc7354
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsDSSSigner.java
@@ -0,0 +1,19 @@
+package org.bc.crypto.tls;
+
+import org.bc.crypto.DSA;
+import org.bc.crypto.params.AsymmetricKeyParameter;
+import org.bc.crypto.params.DSAPublicKeyParameters;
+import org.bc.crypto.signers.DSASigner;
+
+class TlsDSSSigner extends TlsDSASigner
+{
+ public boolean isValidPublicKey(AsymmetricKeyParameter publicKey)
+ {
+ return publicKey instanceof DSAPublicKeyParameters;
+ }
+
+ protected DSA createDSAImpl()
+ {
+ return new DSASigner();
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsECDHEKeyExchange.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsECDHEKeyExchange.java
new file mode 100644
index 0000000..ab7104a
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsECDHEKeyExchange.java
@@ -0,0 +1,112 @@
+package org.bc.crypto.tls;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.bc.crypto.Signer;
+import org.bc.crypto.io.SignerInputStream;
+import org.bc.crypto.params.ECDomainParameters;
+import org.bc.crypto.params.ECPublicKeyParameters;
+import org.bc.math.ec.ECPoint;
+
+/**
+ * ECDHE key exchange (see RFC 4492)
+ */
+class TlsECDHEKeyExchange extends TlsECDHKeyExchange
+{
+ TlsECDHEKeyExchange(TlsClientContext context, int keyExchange)
+ {
+ super(context, keyExchange);
+ }
+
+ public void skipServerKeyExchange() throws IOException
+ {
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+
+ public void processServerKeyExchange(InputStream is)
+ throws IOException
+ {
+ SecurityParameters securityParameters = context.getSecurityParameters();
+
+ Signer signer = initSigner(tlsSigner, securityParameters);
+ InputStream sigIn = new SignerInputStream(is, signer);
+
+ short curveType = TlsUtils.readUint8(sigIn);
+ ECDomainParameters curve_params;
+
+ // Currently, we only support named curves
+ if (curveType == ECCurveType.named_curve)
+ {
+ int namedCurve = TlsUtils.readUint16(sigIn);
+
+ // TODO Check namedCurve is one we offered?
+
+ curve_params = NamedCurve.getECParameters(namedCurve);
+ }
+ else
+ {
+ // TODO Add support for explicit curve parameters (read from sigIn)
+
+ throw new TlsFatalAlert(AlertDescription.handshake_failure);
+ }
+
+ byte[] publicBytes = TlsUtils.readOpaque8(sigIn);
+
+ byte[] sigByte = TlsUtils.readOpaque16(is);
+ if (!signer.verifySignature(sigByte))
+ {
+ throw new TlsFatalAlert(AlertDescription.bad_certificate);
+ }
+
+ // TODO Check curve_params not null
+
+ ECPoint Q = curve_params.getCurve().decodePoint(publicBytes);
+
+ this.ecAgreeServerPublicKey = validateECPublicKey(new ECPublicKeyParameters(Q, curve_params));
+ }
+
+ public void validateCertificateRequest(CertificateRequest certificateRequest)
+ throws IOException
+ {
+ /*
+ * RFC 4492 3. [...] The ECDSA_fixed_ECDH and RSA_fixed_ECDH mechanisms are usable
+ * with ECDH_ECDSA and ECDH_RSA. Their use with ECDHE_ECDSA and ECDHE_RSA is
+ * prohibited because the use of a long-term ECDH client key would jeopardize the
+ * forward secrecy property of these algorithms.
+ */
+ short[] types = certificateRequest.getCertificateTypes();
+ for (int i = 0; i < types.length; ++i)
+ {
+ switch (types[i])
+ {
+ case ClientCertificateType.rsa_sign:
+ case ClientCertificateType.dss_sign:
+ case ClientCertificateType.ecdsa_sign:
+ break;
+ default:
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ }
+ }
+ }
+
+ public void processClientCredentials(TlsCredentials clientCredentials) throws IOException
+ {
+ if (clientCredentials instanceof TlsSignerCredentials)
+ {
+ // OK
+ }
+ else
+ {
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+ }
+
+ protected Signer initSigner(TlsSigner tlsSigner, SecurityParameters securityParameters)
+ {
+ Signer signer = tlsSigner.createVerifyer(this.serverPublicKey);
+ signer.update(securityParameters.clientRandom, 0, securityParameters.clientRandom.length);
+ signer.update(securityParameters.serverRandom, 0, securityParameters.serverRandom.length);
+ return signer;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsECDHKeyExchange.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsECDHKeyExchange.java
new file mode 100644
index 0000000..b9bbaed
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsECDHKeyExchange.java
@@ -0,0 +1,239 @@
+package org.bc.crypto.tls;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.math.BigInteger;
+
+import org.bc.asn1.x509.KeyUsage;
+import org.bc.asn1.x509.SubjectPublicKeyInfo;
+import org.bc.crypto.AsymmetricCipherKeyPair;
+import org.bc.crypto.agreement.ECDHBasicAgreement;
+import org.bc.crypto.generators.ECKeyPairGenerator;
+import org.bc.crypto.params.AsymmetricKeyParameter;
+import org.bc.crypto.params.ECDomainParameters;
+import org.bc.crypto.params.ECKeyGenerationParameters;
+import org.bc.crypto.params.ECPrivateKeyParameters;
+import org.bc.crypto.params.ECPublicKeyParameters;
+import org.bc.crypto.util.PublicKeyFactory;
+import org.bc.util.BigIntegers;
+
+/**
+ * ECDH key exchange (see RFC 4492)
+ */
+class TlsECDHKeyExchange implements TlsKeyExchange
+{
+ protected TlsClientContext context;
+ protected int keyExchange;
+ protected TlsSigner tlsSigner;
+
+ protected AsymmetricKeyParameter serverPublicKey;
+ protected ECPublicKeyParameters ecAgreeServerPublicKey;
+ protected TlsAgreementCredentials agreementCredentials;
+ protected ECPrivateKeyParameters ecAgreeClientPrivateKey = null;
+
+ TlsECDHKeyExchange(TlsClientContext context, int keyExchange)
+ {
+ switch (keyExchange)
+ {
+ case KeyExchangeAlgorithm.ECDHE_RSA:
+ this.tlsSigner = new TlsRSASigner();
+ break;
+ case KeyExchangeAlgorithm.ECDHE_ECDSA:
+ this.tlsSigner = new TlsECDSASigner();
+ break;
+ case KeyExchangeAlgorithm.ECDH_RSA:
+ case KeyExchangeAlgorithm.ECDH_ECDSA:
+ this.tlsSigner = null;
+ break;
+ default:
+ throw new IllegalArgumentException("unsupported key exchange algorithm");
+ }
+
+ this.context = context;
+ this.keyExchange = keyExchange;
+ }
+
+ public void skipServerCertificate() throws IOException
+ {
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+
+ public void processServerCertificate(Certificate serverCertificate) throws IOException
+ {
+ org.bc.asn1.x509.Certificate x509Cert = serverCertificate.certs[0];
+ SubjectPublicKeyInfo keyInfo = x509Cert.getSubjectPublicKeyInfo();
+
+ try
+ {
+ this.serverPublicKey = PublicKeyFactory.createKey(keyInfo);
+ }
+ catch (RuntimeException e)
+ {
+ throw new TlsFatalAlert(AlertDescription.unsupported_certificate);
+ }
+
+ if (tlsSigner == null)
+ {
+ try
+ {
+ this.ecAgreeServerPublicKey = validateECPublicKey((ECPublicKeyParameters)this.serverPublicKey);
+ }
+ catch (ClassCastException e)
+ {
+ throw new TlsFatalAlert(AlertDescription.certificate_unknown);
+ }
+
+ TlsUtils.validateKeyUsage(x509Cert, KeyUsage.keyAgreement);
+ }
+ else
+ {
+ if (!tlsSigner.isValidPublicKey(this.serverPublicKey))
+ {
+ throw new TlsFatalAlert(AlertDescription.certificate_unknown);
+ }
+
+ TlsUtils.validateKeyUsage(x509Cert, KeyUsage.digitalSignature);
+ }
+
+ // TODO
+ /*
+ * Perform various checks per RFC2246 7.4.2: "Unless otherwise specified, the
+ * signing algorithm for the certificate must be the same as the algorithm for the
+ * certificate key."
+ */
+ }
+
+ public void skipServerKeyExchange() throws IOException
+ {
+ // do nothing
+ }
+
+ public void processServerKeyExchange(InputStream is)
+ throws IOException
+ {
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+
+ public void validateCertificateRequest(CertificateRequest certificateRequest)
+ throws IOException
+ {
+ /*
+ * RFC 4492 3. [...] The ECDSA_fixed_ECDH and RSA_fixed_ECDH mechanisms are usable
+ * with ECDH_ECDSA and ECDH_RSA. Their use with ECDHE_ECDSA and ECDHE_RSA is
+ * prohibited because the use of a long-term ECDH client key would jeopardize the
+ * forward secrecy property of these algorithms.
+ */
+ short[] types = certificateRequest.getCertificateTypes();
+ for (int i = 0; i < types.length; ++i)
+ {
+ switch (types[i])
+ {
+ case ClientCertificateType.rsa_sign:
+ case ClientCertificateType.dss_sign:
+ case ClientCertificateType.ecdsa_sign:
+ case ClientCertificateType.rsa_fixed_ecdh:
+ case ClientCertificateType.ecdsa_fixed_ecdh:
+ break;
+ default:
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ }
+ }
+ }
+
+ public void skipClientCredentials() throws IOException
+ {
+ this.agreementCredentials = null;
+ }
+
+ public void processClientCredentials(TlsCredentials clientCredentials) throws IOException
+ {
+ if (clientCredentials instanceof TlsAgreementCredentials)
+ {
+ // TODO Validate client cert has matching parameters (see 'areOnSameCurve')?
+
+ this.agreementCredentials = (TlsAgreementCredentials)clientCredentials;
+ }
+ else if (clientCredentials instanceof TlsSignerCredentials)
+ {
+ // OK
+ }
+ else
+ {
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+ }
+
+ public void generateClientKeyExchange(OutputStream os) throws IOException
+ {
+ if (agreementCredentials == null)
+ {
+ generateEphemeralClientKeyExchange(ecAgreeServerPublicKey.getParameters(), os);
+ }
+ }
+
+ public byte[] generatePremasterSecret() throws IOException
+ {
+ if (agreementCredentials != null)
+ {
+ return agreementCredentials.generateAgreement(ecAgreeServerPublicKey);
+ }
+
+ return calculateECDHBasicAgreement(ecAgreeServerPublicKey, ecAgreeClientPrivateKey);
+ }
+
+ protected boolean areOnSameCurve(ECDomainParameters a, ECDomainParameters b)
+ {
+ // TODO Move to ECDomainParameters.equals() or other utility method?
+ return a.getCurve().equals(b.getCurve()) && a.getG().equals(b.getG())
+ && a.getN().equals(b.getN()) && a.getH().equals(b.getH());
+ }
+
+ protected byte[] externalizeKey(ECPublicKeyParameters keyParameters) throws IOException
+ {
+ // TODO Add support for compressed encoding and SPF extension
+
+ /*
+ * RFC 4492 5.7. ...an elliptic curve point in uncompressed or compressed format.
+ * Here, the format MUST conform to what the server has requested through a
+ * Supported Point Formats Extension if this extension was used, and MUST be
+ * uncompressed if this extension was not used.
+ */
+ return keyParameters.getQ().getEncoded();
+ }
+
+ protected AsymmetricCipherKeyPair generateECKeyPair(ECDomainParameters ecParams)
+ {
+ ECKeyPairGenerator keyPairGenerator = new ECKeyPairGenerator();
+ ECKeyGenerationParameters keyGenerationParameters = new ECKeyGenerationParameters(ecParams,
+ context.getSecureRandom());
+ keyPairGenerator.init(keyGenerationParameters);
+ return keyPairGenerator.generateKeyPair();
+ }
+
+ protected void generateEphemeralClientKeyExchange(ECDomainParameters ecParams, OutputStream os)
+ throws IOException
+ {
+ AsymmetricCipherKeyPair ecAgreeClientKeyPair = generateECKeyPair(ecParams);
+ this.ecAgreeClientPrivateKey = (ECPrivateKeyParameters)ecAgreeClientKeyPair.getPrivate();
+
+ byte[] keData = externalizeKey((ECPublicKeyParameters)ecAgreeClientKeyPair.getPublic());
+ TlsUtils.writeOpaque8(keData, os);
+ }
+
+ protected byte[] calculateECDHBasicAgreement(ECPublicKeyParameters publicKey,
+ ECPrivateKeyParameters privateKey)
+ {
+ ECDHBasicAgreement basicAgreement = new ECDHBasicAgreement();
+ basicAgreement.init(privateKey);
+ BigInteger agreement = basicAgreement.calculateAgreement(publicKey);
+ return BigIntegers.asUnsignedByteArray(agreement);
+ }
+
+ protected ECPublicKeyParameters validateECPublicKey(ECPublicKeyParameters key)
+ throws IOException
+ {
+ // TODO Check RFC 4492 for validation
+ return key;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsECDSASigner.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsECDSASigner.java
new file mode 100644
index 0000000..b6a8d27
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsECDSASigner.java
@@ -0,0 +1,19 @@
+package org.bc.crypto.tls;
+
+import org.bc.crypto.DSA;
+import org.bc.crypto.params.AsymmetricKeyParameter;
+import org.bc.crypto.params.ECPublicKeyParameters;
+import org.bc.crypto.signers.ECDSASigner;
+
+class TlsECDSASigner extends TlsDSASigner
+{
+ public boolean isValidPublicKey(AsymmetricKeyParameter publicKey)
+ {
+ return publicKey instanceof ECPublicKeyParameters;
+ }
+
+ protected DSA createDSAImpl()
+ {
+ return new ECDSASigner();
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsFatalAlert.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsFatalAlert.java
new file mode 100644
index 0000000..8e4f149
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsFatalAlert.java
@@ -0,0 +1,20 @@
+package org.bc.crypto.tls;
+
+import java.io.IOException;
+
+public class TlsFatalAlert extends IOException
+{
+ private static final long serialVersionUID = 3584313123679111168L;
+
+ private short alertDescription;
+
+ public TlsFatalAlert(short alertDescription)
+ {
+ this.alertDescription = alertDescription;
+ }
+
+ public short getAlertDescription()
+ {
+ return alertDescription;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsInputStream.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsInputStream.java
new file mode 100644
index 0000000..9ef50fb
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsInputStream.java
@@ -0,0 +1,37 @@
+package org.bc.crypto.tls;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * An InputStream for an TLS 1.0 connection.
+ */
+class TlsInputStream extends InputStream
+{
+ private byte[] buf = new byte[1];
+ private TlsProtocolHandler handler = null;
+
+ TlsInputStream(TlsProtocolHandler handler)
+ {
+ this.handler = handler;
+ }
+
+ public int read(byte[] buf, int offset, int len) throws IOException
+ {
+ return this.handler.readApplicationData(buf, offset, len);
+ }
+
+ public int read() throws IOException
+ {
+ if (this.read(buf) < 0)
+ {
+ return -1;
+ }
+ return buf[0] & 0xff;
+ }
+
+ public void close() throws IOException
+ {
+ handler.close();
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsKeyExchange.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsKeyExchange.java
new file mode 100644
index 0000000..a6b7655
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsKeyExchange.java
@@ -0,0 +1,30 @@
+package org.bc.crypto.tls;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * A generic interface for key exchange implementations in TLS 1.0.
+ */
+public interface TlsKeyExchange
+{
+ void skipServerCertificate() throws IOException;
+
+ void processServerCertificate(Certificate serverCertificate) throws IOException;
+
+ void skipServerKeyExchange() throws IOException;
+
+ void processServerKeyExchange(InputStream is)
+ throws IOException;
+
+ void validateCertificateRequest(CertificateRequest certificateRequest) throws IOException;
+
+ void skipClientCredentials() throws IOException;
+
+ void processClientCredentials(TlsCredentials clientCredentials) throws IOException;
+
+ void generateClientKeyExchange(OutputStream os) throws IOException;
+
+ byte[] generatePremasterSecret() throws IOException;
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsMac.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsMac.java
new file mode 100644
index 0000000..cfe1ccc
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsMac.java
@@ -0,0 +1,163 @@
+package org.bc.crypto.tls;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+import org.bc.crypto.Digest;
+import org.bc.crypto.Mac;
+import org.bc.crypto.macs.HMac;
+import org.bc.crypto.params.KeyParameter;
+import org.bc.util.Arrays;
+
+/**
+ * A generic TLS MAC implementation, which can be used with any kind of Digest to act as
+ * an HMAC.
+ */
+public class TlsMac
+{
+ protected TlsClientContext context;
+ protected long seqNo;
+ protected byte[] secret;
+ protected Mac mac;
+
+ /**
+ * Generate a new instance of an TlsMac.
+ *
+ * @param context the TLS client context
+ * @param digest The digest to use.
+ * @param key_block A byte-array where the key for this mac is located.
+ * @param offset The number of bytes to skip, before the key starts in the buffer.
+ * @param len The length of the key.
+ */
+ public TlsMac(TlsClientContext context, Digest digest, byte[] key_block, int offset, int len)
+ {
+ this.context = context;
+ this.seqNo = 0;
+
+ KeyParameter param = new KeyParameter(key_block, offset, len);
+
+ this.secret = Arrays.clone(param.getKey());
+
+ boolean isTls = context.getServerVersion().getFullVersion() >= ProtocolVersion.TLSv10.getFullVersion();
+
+ if (isTls)
+ {
+ this.mac = new HMac(digest);
+ }
+ else
+ {
+ this.mac = new SSL3Mac(digest);
+ }
+
+ this.mac.init(param);
+ }
+
+ /**
+ * @return the MAC write secret
+ */
+ public byte[] getMACSecret()
+ {
+ return this.secret;
+ }
+
+ /**
+ * @return the current write sequence number
+ */
+ public long getSequenceNumber()
+ {
+ return this.seqNo;
+ }
+
+ /**
+ * Increment the current write sequence number
+ */
+ public void incSequenceNumber()
+ {
+ this.seqNo++;
+ }
+
+ /**
+ * @return The Keysize of the mac.
+ */
+ public int getSize()
+ {
+ return mac.getMacSize();
+ }
+
+ /**
+ * Calculate the mac for some given data.
+ *
+ * TlsMac will keep track of the sequence number internally.
+ *
+ * @param type The message type of the message.
+ * @param message A byte-buffer containing the message.
+ * @param offset The number of bytes to skip, before the message starts.
+ * @param len The length of the message.
+ * @return A new byte-buffer containing the mac value.
+ */
+ public byte[] calculateMac(short type, byte[] message, int offset, int len)
+ {
+ ProtocolVersion serverVersion = context.getServerVersion();
+ boolean isTls = serverVersion.getFullVersion() >= ProtocolVersion.TLSv10.getFullVersion();
+
+ ByteArrayOutputStream bosMac = new ByteArrayOutputStream(isTls ? 13 : 11);
+ try
+ {
+ TlsUtils.writeUint64(seqNo++, bosMac);
+ TlsUtils.writeUint8(type, bosMac);
+
+ if (isTls)
+ {
+ TlsUtils.writeVersion(serverVersion, bosMac);
+ }
+
+ TlsUtils.writeUint16(len, bosMac);
+ }
+ catch (IOException e)
+ {
+ // This should never happen
+ throw new IllegalStateException("Internal error during mac calculation");
+ }
+
+ byte[] macHeader = bosMac.toByteArray();
+ mac.update(macHeader, 0, macHeader.length);
+ mac.update(message, offset, len);
+
+ byte[] result = new byte[mac.getMacSize()];
+ mac.doFinal(result, 0);
+ return result;
+ }
+
+ public byte[] calculateMacConstantTime(short type, byte[] message, int offset, int len, int fullLength, byte[] dummyData)
+ {
+ // Actual MAC only calculated on 'len' bytes
+ byte[] result = calculateMac(type, message, offset, len);
+
+ ProtocolVersion serverVersion = context.getServerVersion();
+ boolean isTls = serverVersion.getFullVersion() >= ProtocolVersion.TLSv10.getFullVersion();
+
+ // ...but ensure a constant number of complete digest blocks are processed (per 'fullLength')
+ if (isTls)
+ {
+ // TODO Currently all TLS digests use a block size of 64, a suffix (length field) of 8, and padding (1+)
+ int db = 64, ds = 8;
+
+ int L1 = 13 + fullLength;
+ int L2 = 13 + len;
+
+ // How many extra full blocks do we need to calculate?
+ int extra = ((L1 + ds) / db) - ((L2 + ds) / db);
+
+ while (--extra >= 0)
+ {
+ mac.update(dummyData, 0, db);
+ }
+
+ // One more byte in case the implementation is "lazy" about processing blocks
+ mac.update(dummyData[0]);
+ mac.reset();
+ }
+
+ return result;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsNullCipher.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsNullCipher.java
new file mode 100644
index 0000000..dd3b4ca
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsNullCipher.java
@@ -0,0 +1,24 @@
+package org.bc.crypto.tls;
+
+/**
+ * A NULL CipherSuite in java, this should only be used during handshake.
+ */
+public class TlsNullCipher implements TlsCipher
+{
+ public byte[] encodePlaintext(short type, byte[] plaintext, int offset, int len)
+ {
+ return copyData(plaintext, offset, len);
+ }
+
+ public byte[] decodeCiphertext(short type, byte[] ciphertext, int offset, int len)
+ {
+ return copyData(ciphertext, offset, len);
+ }
+
+ protected byte[] copyData(byte[] text, int offset, int len)
+ {
+ byte[] result = new byte[len];
+ System.arraycopy(text, offset, result, 0, len);
+ return result;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsNullCompression.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsNullCompression.java
new file mode 100644
index 0000000..d971a6d
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsNullCompression.java
@@ -0,0 +1,16 @@
+package org.bc.crypto.tls;
+
+import java.io.OutputStream;
+
+public class TlsNullCompression implements TlsCompression
+{
+ public OutputStream compress(OutputStream output)
+ {
+ return output;
+ }
+
+ public OutputStream decompress(OutputStream output)
+ {
+ return output;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsOutputStream.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsOutputStream.java
new file mode 100644
index 0000000..2bda1ad
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsOutputStream.java
@@ -0,0 +1,39 @@
+package org.bc.crypto.tls;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * An OutputStream for an TLS connection.
+ */
+class TlsOutputStream extends OutputStream
+{
+ private byte[] buf = new byte[1];
+ private TlsProtocolHandler handler;
+
+ TlsOutputStream(TlsProtocolHandler handler)
+ {
+ this.handler = handler;
+ }
+
+ public void write(byte buf[], int offset, int len) throws IOException
+ {
+ this.handler.writeData(buf, offset, len);
+ }
+
+ public void write(int arg0) throws IOException
+ {
+ buf[0] = (byte)arg0;
+ this.write(buf, 0, 1);
+ }
+
+ public void close() throws IOException
+ {
+ handler.close();
+ }
+
+ public void flush() throws IOException
+ {
+ handler.flush();
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsPSKIdentity.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsPSKIdentity.java
new file mode 100644
index 0000000..8f6b1bd
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsPSKIdentity.java
@@ -0,0 +1,12 @@
+package org.bc.crypto.tls;
+
+public interface TlsPSKIdentity
+{
+ void skipIdentityHint();
+
+ void notifyIdentityHint(byte[] psk_identity_hint);
+
+ byte[] getPSKIdentity();
+
+ byte[] getPSK();
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsPSKKeyExchange.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsPSKKeyExchange.java
new file mode 100644
index 0000000..74ec68c
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsPSKKeyExchange.java
@@ -0,0 +1,210 @@
+package org.bc.crypto.tls;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.math.BigInteger;
+
+import org.bc.asn1.x509.KeyUsage;
+import org.bc.asn1.x509.SubjectPublicKeyInfo;
+import org.bc.crypto.params.AsymmetricKeyParameter;
+import org.bc.crypto.params.DHParameters;
+import org.bc.crypto.params.DHPrivateKeyParameters;
+import org.bc.crypto.params.DHPublicKeyParameters;
+import org.bc.crypto.params.RSAKeyParameters;
+import org.bc.crypto.util.PublicKeyFactory;
+
+class TlsPSKKeyExchange implements TlsKeyExchange
+{
+ protected TlsClientContext context;
+ protected int keyExchange;
+ protected TlsPSKIdentity pskIdentity;
+
+ protected byte[] psk_identity_hint = null;
+
+ protected DHPublicKeyParameters dhAgreeServerPublicKey = null;
+ protected DHPrivateKeyParameters dhAgreeClientPrivateKey = null;
+
+ protected AsymmetricKeyParameter serverPublicKey = null;
+ protected RSAKeyParameters rsaServerPublicKey = null;
+ protected byte[] premasterSecret;
+
+ TlsPSKKeyExchange(TlsClientContext context, int keyExchange, TlsPSKIdentity pskIdentity)
+ {
+ switch (keyExchange)
+ {
+ case KeyExchangeAlgorithm.PSK:
+ case KeyExchangeAlgorithm.RSA_PSK:
+ case KeyExchangeAlgorithm.DHE_PSK:
+ break;
+ default:
+ throw new IllegalArgumentException("unsupported key exchange algorithm");
+ }
+
+ this.context = context;
+ this.keyExchange = keyExchange;
+ this.pskIdentity = pskIdentity;
+ }
+
+ public void skipServerCertificate() throws IOException
+ {
+ if (keyExchange == KeyExchangeAlgorithm.RSA_PSK)
+ {
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+ }
+
+ public void processServerCertificate(Certificate serverCertificate) throws IOException
+ {
+ if (keyExchange != KeyExchangeAlgorithm.RSA_PSK)
+ {
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+
+ org.bc.asn1.x509.Certificate x509Cert = serverCertificate.certs[0];
+ SubjectPublicKeyInfo keyInfo = x509Cert.getSubjectPublicKeyInfo();
+
+ try
+ {
+ this.serverPublicKey = PublicKeyFactory.createKey(keyInfo);
+ }
+ catch (RuntimeException e)
+ {
+ throw new TlsFatalAlert(AlertDescription.unsupported_certificate);
+ }
+
+ // Sanity check the PublicKeyFactory
+ if (this.serverPublicKey.isPrivate())
+ {
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+
+ this.rsaServerPublicKey = validateRSAPublicKey((RSAKeyParameters) this.serverPublicKey);
+
+ TlsUtils.validateKeyUsage(x509Cert, KeyUsage.keyEncipherment);
+
+ // TODO
+ /*
+ * Perform various checks per RFC2246 7.4.2: "Unless otherwise
+ * specified, the signing algorithm for the certificate must be the same
+ * as the algorithm for the certificate key."
+ */
+ }
+
+ public void skipServerKeyExchange() throws IOException
+ {
+ if (keyExchange == KeyExchangeAlgorithm.DHE_PSK)
+ {
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+
+ this.psk_identity_hint = new byte[0];
+ }
+
+ public void processServerKeyExchange(InputStream is) throws IOException
+ {
+ this.psk_identity_hint = TlsUtils.readOpaque16(is);
+
+ if (this.keyExchange == KeyExchangeAlgorithm.DHE_PSK)
+ {
+ byte[] pBytes = TlsUtils.readOpaque16(is);
+ byte[] gBytes = TlsUtils.readOpaque16(is);
+ byte[] YsBytes = TlsUtils.readOpaque16(is);
+
+ BigInteger p = new BigInteger(1, pBytes);
+ BigInteger g = new BigInteger(1, gBytes);
+ BigInteger Ys = new BigInteger(1, YsBytes);
+
+ this.dhAgreeServerPublicKey = TlsDHUtils.validateDHPublicKey(new DHPublicKeyParameters(Ys,
+ new DHParameters(p, g)));
+ }
+ else if (this.psk_identity_hint.length == 0)
+ {
+ // TODO Should we enforce that this message should have been skipped if hint is empty?
+// throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+ }
+
+ public void validateCertificateRequest(CertificateRequest certificateRequest)
+ throws IOException
+ {
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+
+ public void skipClientCredentials() throws IOException
+ {
+ // OK
+ }
+
+ public void processClientCredentials(TlsCredentials clientCredentials) throws IOException
+ {
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+
+ public void generateClientKeyExchange(OutputStream os) throws IOException
+ {
+ if (psk_identity_hint == null || psk_identity_hint.length == 0)
+ {
+ pskIdentity.skipIdentityHint();
+ }
+ else
+ {
+ pskIdentity.notifyIdentityHint(psk_identity_hint);
+ }
+
+ byte[] psk_identity = pskIdentity.getPSKIdentity();
+
+ TlsUtils.writeOpaque16(psk_identity, os);
+
+ if (this.keyExchange == KeyExchangeAlgorithm.RSA_PSK)
+ {
+ this.premasterSecret = TlsRSAUtils.generateEncryptedPreMasterSecret(context,
+ this.rsaServerPublicKey, os);
+ }
+ else if (this.keyExchange == KeyExchangeAlgorithm.DHE_PSK)
+ {
+ this.dhAgreeClientPrivateKey = TlsDHUtils.generateEphemeralClientKeyExchange(
+ context.getSecureRandom(), dhAgreeServerPublicKey.getParameters(), os);
+ }
+ }
+
+ public byte[] generatePremasterSecret() throws IOException
+ {
+ byte[] psk = pskIdentity.getPSK();
+ byte[] other_secret = generateOtherSecret(psk.length);
+
+ ByteArrayOutputStream buf = new ByteArrayOutputStream(4 + other_secret.length + psk.length);
+ TlsUtils.writeOpaque16(other_secret, buf);
+ TlsUtils.writeOpaque16(psk, buf);
+ return buf.toByteArray();
+ }
+
+ protected byte[] generateOtherSecret(int pskLength)
+ {
+ if (this.keyExchange == KeyExchangeAlgorithm.DHE_PSK)
+ {
+ return TlsDHUtils.calculateDHBasicAgreement(dhAgreeServerPublicKey, dhAgreeClientPrivateKey);
+ }
+
+ if (this.keyExchange == KeyExchangeAlgorithm.RSA_PSK)
+ {
+ return this.premasterSecret;
+ }
+
+ return new byte[pskLength];
+ }
+
+ protected RSAKeyParameters validateRSAPublicKey(RSAKeyParameters key) throws IOException
+ {
+ // TODO What is the minimum bit length required?
+ // key.getModulus().bitLength();
+
+ if (!key.getExponent().isProbablePrime(2))
+ {
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ }
+
+ return key;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsProtocolHandler.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsProtocolHandler.java
new file mode 100644
index 0000000..b06fa5c
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsProtocolHandler.java
@@ -0,0 +1,1260 @@
+package org.bc.crypto.tls;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.security.SecureRandom;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
+
+import org.bc.asn1.ASN1Primitive;
+import org.bc.asn1.x500.X500Name;
+import org.bc.crypto.prng.ThreadedSeedGenerator;
+import org.bc.util.Arrays;
+import org.bc.util.Integers;
+
+/**
+ * An implementation of all high level protocols in TLS 1.0.
+ */
+public class TlsProtocolHandler
+{
+ private static final Integer EXT_RenegotiationInfo = Integers.valueOf(ExtensionType.renegotiation_info);
+
+ /*
+ * Our Connection states
+ */
+ private static final short CS_CLIENT_HELLO_SEND = 1;
+ private static final short CS_SERVER_HELLO_RECEIVED = 2;
+ private static final short CS_SERVER_CERTIFICATE_RECEIVED = 3;
+ private static final short CS_SERVER_KEY_EXCHANGE_RECEIVED = 4;
+ private static final short CS_CERTIFICATE_REQUEST_RECEIVED = 5;
+ private static final short CS_SERVER_HELLO_DONE_RECEIVED = 6;
+ private static final short CS_CLIENT_KEY_EXCHANGE_SEND = 7;
+ private static final short CS_CERTIFICATE_VERIFY_SEND = 8;
+ private static final short CS_CLIENT_CHANGE_CIPHER_SPEC_SEND = 9;
+ private static final short CS_CLIENT_FINISHED_SEND = 10;
+ private static final short CS_SERVER_CHANGE_CIPHER_SPEC_RECEIVED = 11;
+ private static final short CS_DONE = 12;
+
+ private static final byte[] emptybuf = new byte[0];
+
+ private static final String TLS_ERROR_MESSAGE = "Internal TLS error, this could be an attack";
+
+ /*
+ * Queues for data from some protocols.
+ */
+ private ByteQueue applicationDataQueue = new ByteQueue();
+ private ByteQueue changeCipherSpecQueue = new ByteQueue();
+ private ByteQueue alertQueue = new ByteQueue();
+ private ByteQueue handshakeQueue = new ByteQueue();
+
+ /*
+ * The Record Stream we use
+ */
+ private RecordStream rs;
+ private SecureRandom random;
+
+ private TlsInputStream tlsInputStream = null;
+ private TlsOutputStream tlsOutputStream = null;
+
+ private boolean closed = false;
+ private boolean failedWithError = false;
+ private boolean appDataReady = false;
+ private Hashtable clientExtensions;
+
+ private SecurityParameters securityParameters = null;
+
+ private TlsClientContextImpl tlsClientContext = null;
+ private TlsClient tlsClient = null;
+ private int[] offeredCipherSuites = null;
+ private short[] offeredCompressionMethods = null;
+ private TlsKeyExchange keyExchange = null;
+ private TlsAuthentication authentication = null;
+ private CertificateRequest certificateRequest = null;
+
+ private short connection_state = 0;
+
+ private static SecureRandom createSecureRandom()
+ {
+ /*
+ * We use our threaded seed generator to generate a good random seed. If the user
+ * has a better random seed, he should use the constructor with a SecureRandom.
+ */
+ ThreadedSeedGenerator tsg = new ThreadedSeedGenerator();
+ SecureRandom random = new SecureRandom();
+
+ /*
+ * Hopefully, 20 bytes in fast mode are good enough.
+ */
+ random.setSeed(tsg.generateSeed(20, true));
+
+ return random;
+ }
+
+ public TlsProtocolHandler(InputStream is, OutputStream os)
+ {
+ this(is, os, createSecureRandom());
+ }
+
+ public TlsProtocolHandler(InputStream is, OutputStream os, SecureRandom sr)
+ {
+ this.rs = new RecordStream(this, is, os);
+ this.random = sr;
+ }
+
+ protected void processData(short protocol, byte[] buf, int offset, int len) throws IOException
+ {
+ /*
+ * Have a look at the protocol type, and add it to the correct queue.
+ */
+ switch (protocol)
+ {
+ case ContentType.change_cipher_spec:
+ changeCipherSpecQueue.addData(buf, offset, len);
+ processChangeCipherSpec();
+ break;
+ case ContentType.alert:
+ alertQueue.addData(buf, offset, len);
+ processAlert();
+ break;
+ case ContentType.handshake:
+ handshakeQueue.addData(buf, offset, len);
+ processHandshake();
+ break;
+ case ContentType.application_data:
+ if (!appDataReady)
+ {
+ this.failWithError(AlertLevel.fatal, AlertDescription.unexpected_message);
+ }
+ applicationDataQueue.addData(buf, offset, len);
+ processApplicationData();
+ break;
+ default:
+ /*
+ * Uh, we don't know this protocol.
+ *
+ * RFC2246 defines on page 13, that we should ignore this.
+ */
+ }
+ }
+
+ private void processHandshake() throws IOException
+ {
+ boolean read;
+ do
+ {
+ read = false;
+ /*
+ * We need the first 4 bytes, they contain type and length of the message.
+ */
+ if (handshakeQueue.size() >= 4)
+ {
+ byte[] beginning = new byte[4];
+ handshakeQueue.read(beginning, 0, 4, 0);
+ ByteArrayInputStream bis = new ByteArrayInputStream(beginning);
+ short type = TlsUtils.readUint8(bis);
+ int len = TlsUtils.readUint24(bis);
+
+ /*
+ * Check if we have enough bytes in the buffer to read the full message.
+ */
+ if (handshakeQueue.size() >= (len + 4))
+ {
+ /*
+ * Read the message.
+ */
+ byte[] buf = new byte[len];
+ handshakeQueue.read(buf, 0, len, 4);
+ handshakeQueue.removeData(len + 4);
+
+ /*
+ * RFC 2246 7.4.9. The value handshake_messages includes all handshake
+ * messages starting at client hello up to, but not including, this
+ * finished message. [..] Note: [Also,] Hello Request messages are
+ * omitted from handshake hashes.
+ */
+ switch (type)
+ {
+ case HandshakeType.hello_request:
+ case HandshakeType.finished:
+ break;
+ default:
+ rs.updateHandshakeData(beginning, 0, 4);
+ rs.updateHandshakeData(buf, 0, len);
+ break;
+ }
+
+ /*
+ * Now, parse the message.
+ */
+ processHandshakeMessage(type, buf);
+ read = true;
+ }
+ }
+ }
+ while (read);
+ }
+
+ private void processHandshakeMessage(short type, byte[] buf) throws IOException
+ {
+ ByteArrayInputStream is = new ByteArrayInputStream(buf);
+
+ switch (type)
+ {
+ case HandshakeType.certificate:
+ {
+ switch (connection_state)
+ {
+ case CS_SERVER_HELLO_RECEIVED:
+ {
+ // Parse the Certificate message and send to cipher suite
+
+ Certificate serverCertificate = Certificate.parse(is);
+
+ assertEmpty(is);
+
+ this.keyExchange.processServerCertificate(serverCertificate);
+
+ this.authentication = tlsClient.getAuthentication();
+ this.authentication.notifyServerCertificate(serverCertificate);
+
+ break;
+ }
+ default:
+ this.failWithError(AlertLevel.fatal, AlertDescription.unexpected_message);
+ }
+
+ connection_state = CS_SERVER_CERTIFICATE_RECEIVED;
+ break;
+ }
+ case HandshakeType.finished:
+ switch (connection_state)
+ {
+ case CS_SERVER_CHANGE_CIPHER_SPEC_RECEIVED:
+ /*
+ * Read the checksum from the finished message, it has always 12
+ * bytes for TLS 1.0 and 36 for SSLv3.
+ */
+ boolean isTls = tlsClientContext.getServerVersion().getFullVersion() >= ProtocolVersion.TLSv10.getFullVersion();
+
+ int checksumLength = isTls ? 12 : 36;
+ byte[] serverVerifyData = new byte[checksumLength];
+ TlsUtils.readFully(serverVerifyData, is);
+
+ assertEmpty(is);
+
+ /*
+ * Calculate our own checksum.
+ */
+ byte[] expectedServerVerifyData = TlsUtils.calculateVerifyData(tlsClientContext,
+ "server finished", rs.getCurrentHash(TlsUtils.SSL_SERVER));
+
+ /*
+ * Compare both checksums.
+ */
+ if (!Arrays.constantTimeAreEqual(expectedServerVerifyData, serverVerifyData))
+ {
+ /*
+ * Wrong checksum in the finished message.
+ */
+ this.failWithError(AlertLevel.fatal, AlertDescription.handshake_failure);
+ }
+
+ connection_state = CS_DONE;
+
+ /*
+ * We are now ready to receive application data.
+ */
+ this.appDataReady = true;
+ break;
+ default:
+ this.failWithError(AlertLevel.fatal, AlertDescription.unexpected_message);
+ }
+ break;
+ case HandshakeType.server_hello:
+ switch (connection_state)
+ {
+ case CS_CLIENT_HELLO_SEND:
+ /*
+ * Read the server hello message
+ */
+ ProtocolVersion server_version = TlsUtils.readVersion(is);
+ ProtocolVersion client_version = this.tlsClientContext.getClientVersion();
+ if (server_version.getFullVersion() > client_version.getFullVersion())
+ {
+ this.failWithError(AlertLevel.fatal, AlertDescription.illegal_parameter);
+ }
+
+ this.tlsClientContext.setServerVersion(server_version);
+ this.tlsClient.notifyServerVersion(server_version);
+
+ /*
+ * Read the server random
+ */
+ securityParameters.serverRandom = new byte[32];
+ TlsUtils.readFully(securityParameters.serverRandom, is);
+
+ byte[] sessionID = TlsUtils.readOpaque8(is);
+ if (sessionID.length > 32)
+ {
+ this.failWithError(AlertLevel.fatal, AlertDescription.illegal_parameter);
+ }
+
+ this.tlsClient.notifySessionID(sessionID);
+
+ /*
+ * Find out which CipherSuite the server has chosen and check that
+ * it was one of the offered ones.
+ */
+ int selectedCipherSuite = TlsUtils.readUint16(is);
+ if (!arrayContains(offeredCipherSuites, selectedCipherSuite)
+ || selectedCipherSuite == CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV)
+ {
+ this.failWithError(AlertLevel.fatal, AlertDescription.illegal_parameter);
+ }
+
+ this.tlsClient.notifySelectedCipherSuite(selectedCipherSuite);
+
+ /*
+ * Find out which CompressionMethod the server has chosen and check that
+ * it was one of the offered ones.
+ */
+ short selectedCompressionMethod = TlsUtils.readUint8(is);
+ if (!arrayContains(offeredCompressionMethods, selectedCompressionMethod))
+ {
+ this.failWithError(AlertLevel.fatal, AlertDescription.illegal_parameter);
+ }
+
+ this.tlsClient.notifySelectedCompressionMethod(selectedCompressionMethod);
+
+ /*
+ * RFC3546 2.2 The extended server hello message format MAY be
+ * sent in place of the server hello message when the client has
+ * requested extended functionality via the extended client hello
+ * message specified in Section 2.1. ... Note that the extended
+ * server hello message is only sent in response to an extended
+ * client hello message. This prevents the possibility that the
+ * extended server hello message could "break" existing TLS 1.0
+ * clients.
+ */
+
+ /*
+ * TODO RFC 3546 2.3 If [...] the older session is resumed, then
+ * the server MUST ignore extensions appearing in the client
+ * hello, and send a server hello containing no extensions.
+ */
+
+ // Integer -> byte[]
+ Hashtable serverExtensions = new Hashtable();
+
+ if (is.available() > 0)
+ {
+ // Process extensions from extended server hello
+ byte[] extBytes = TlsUtils.readOpaque16(is);
+
+ ByteArrayInputStream ext = new ByteArrayInputStream(extBytes);
+ while (ext.available() > 0)
+ {
+ Integer extType = Integers.valueOf(TlsUtils.readUint16(ext));
+ byte[] extValue = TlsUtils.readOpaque16(ext);
+
+ /*
+ * RFC 5746 Note that sending a "renegotiation_info"
+ * extension in response to a ClientHello containing only
+ * the SCSV is an explicit exception to the prohibition in
+ * RFC 5246, Section 7.4.1.4, on the server sending
+ * unsolicited extensions and is only allowed because the
+ * client is signaling its willingness to receive the
+ * extension via the TLS_EMPTY_RENEGOTIATION_INFO_SCSV
+ * SCSV. TLS implementations MUST continue to comply with
+ * Section 7.4.1.4 for all other extensions.
+ */
+
+ if (!extType.equals(EXT_RenegotiationInfo)
+ && clientExtensions.get(extType) == null)
+ {
+ /*
+ * RFC 3546 2.3 Note that for all extension types
+ * (including those defined in future), the extension
+ * type MUST NOT appear in the extended server hello
+ * unless the same extension type appeared in the
+ * corresponding client hello. Thus clients MUST abort
+ * the handshake if they receive an extension type in
+ * the extended server hello that they did not request
+ * in the associated (extended) client hello.
+ */
+ this.failWithError(AlertLevel.fatal,
+ AlertDescription.unsupported_extension);
+ }
+
+ if (serverExtensions.containsKey(extType))
+ {
+ /*
+ * RFC 3546 2.3 Also note that when multiple
+ * extensions of different types are present in the
+ * extended client hello or the extended server hello,
+ * the extensions may appear in any order. There MUST
+ * NOT be more than one extension of the same type.
+ */
+ this.failWithError(AlertLevel.fatal,
+ AlertDescription.illegal_parameter);
+ }
+
+ serverExtensions.put(extType, extValue);
+ }
+ }
+
+ assertEmpty(is);
+
+ /*
+ * RFC 5746 3.4. When a ServerHello is received, the client MUST
+ * check if it includes the "renegotiation_info" extension:
+ */
+ {
+ boolean secure_negotiation = serverExtensions.containsKey(EXT_RenegotiationInfo);
+
+ /*
+ * If the extension is present, set the secure_renegotiation
+ * flag to TRUE. The client MUST then verify that the length
+ * of the "renegotiated_connection" field is zero, and if it
+ * is not, MUST abort the handshake (by sending a fatal
+ * handshake_failure alert).
+ */
+ if (secure_negotiation)
+ {
+ byte[] renegExtValue = (byte[])serverExtensions.get(EXT_RenegotiationInfo);
+
+ if (!Arrays.constantTimeAreEqual(renegExtValue,
+ createRenegotiationInfo(emptybuf)))
+ {
+ this.failWithError(AlertLevel.fatal,
+ AlertDescription.handshake_failure);
+ }
+ }
+
+ tlsClient.notifySecureRenegotiation(secure_negotiation);
+ }
+
+ if (clientExtensions != null)
+ {
+ tlsClient.processServerExtensions(serverExtensions);
+ }
+
+ this.keyExchange = tlsClient.getKeyExchange();
+
+ connection_state = CS_SERVER_HELLO_RECEIVED;
+ break;
+ default:
+ this.failWithError(AlertLevel.fatal, AlertDescription.unexpected_message);
+ }
+ break;
+ case HandshakeType.server_hello_done:
+ switch (connection_state)
+ {
+ case CS_SERVER_HELLO_RECEIVED:
+
+ // There was no server certificate message; check it's OK
+ this.keyExchange.skipServerCertificate();
+ this.authentication = null;
+
+ // NB: Fall through to next case label
+
+ case CS_SERVER_CERTIFICATE_RECEIVED:
+
+ // There was no server key exchange message; check it's OK
+ this.keyExchange.skipServerKeyExchange();
+
+ // NB: Fall through to next case label
+
+ case CS_SERVER_KEY_EXCHANGE_RECEIVED:
+ case CS_CERTIFICATE_REQUEST_RECEIVED:
+
+ assertEmpty(is);
+
+ connection_state = CS_SERVER_HELLO_DONE_RECEIVED;
+
+ TlsCredentials clientCreds = null;
+ if (certificateRequest == null)
+ {
+ this.keyExchange.skipClientCredentials();
+ }
+ else
+ {
+ clientCreds = this.authentication.getClientCredentials(certificateRequest);
+
+ if (clientCreds == null)
+ {
+ this.keyExchange.skipClientCredentials();
+
+ boolean isTls = tlsClientContext.getServerVersion().getFullVersion() >= ProtocolVersion.TLSv10.getFullVersion();
+
+ if (isTls)
+ {
+ sendClientCertificate(Certificate.EMPTY_CHAIN);
+ }
+ else
+ {
+ sendAlert(AlertLevel.warning, AlertDescription.no_certificate);
+ }
+ }
+ else
+ {
+ this.keyExchange.processClientCredentials(clientCreds);
+
+ sendClientCertificate(clientCreds.getCertificate());
+ }
+ }
+
+ /*
+ * Send the client key exchange message, depending on the key
+ * exchange we are using in our CipherSuite.
+ */
+ sendClientKeyExchange();
+
+ connection_state = CS_CLIENT_KEY_EXCHANGE_SEND;
+
+ /*
+ * Calculate the master_secret
+ */
+ byte[] pms = this.keyExchange.generatePremasterSecret();
+
+ securityParameters.masterSecret = TlsUtils.calculateMasterSecret(
+ this.tlsClientContext, pms);
+
+ // TODO Is there a way to ensure the data is really overwritten?
+ /*
+ * RFC 2246 8.1. The pre_master_secret should be deleted from
+ * memory once the master_secret has been computed.
+ */
+ Arrays.fill(pms, (byte)0);
+
+ if (clientCreds != null && clientCreds instanceof TlsSignerCredentials)
+ {
+ TlsSignerCredentials signerCreds = (TlsSignerCredentials)clientCreds;
+ byte[] md5andsha1 = rs.getCurrentHash(null);
+ byte[] clientCertificateSignature = signerCreds.generateCertificateSignature(
+ md5andsha1);
+ sendCertificateVerify(clientCertificateSignature);
+
+ connection_state = CS_CERTIFICATE_VERIFY_SEND;
+ }
+
+ /*
+ * Now, we send change cipher state
+ */
+ byte[] cmessage = new byte[1];
+ cmessage[0] = 1;
+ rs.writeMessage(ContentType.change_cipher_spec, cmessage, 0,
+ cmessage.length);
+
+ connection_state = CS_CLIENT_CHANGE_CIPHER_SPEC_SEND;
+
+ /*
+ * Initialize our cipher suite
+ */
+ rs.clientCipherSpecDecided(tlsClient.getCompression(), tlsClient.getCipher());
+
+ /*
+ * Send our finished message.
+ */
+ byte[] clientVerifyData = TlsUtils.calculateVerifyData(tlsClientContext,
+ "client finished", rs.getCurrentHash(TlsUtils.SSL_CLIENT));
+
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ TlsUtils.writeUint8(HandshakeType.finished, bos);
+ TlsUtils.writeOpaque24(clientVerifyData, bos);
+ byte[] message = bos.toByteArray();
+
+ rs.writeMessage(ContentType.handshake, message, 0, message.length);
+
+ this.connection_state = CS_CLIENT_FINISHED_SEND;
+ break;
+ default:
+ this.failWithError(AlertLevel.fatal, AlertDescription.handshake_failure);
+ }
+ break;
+ case HandshakeType.server_key_exchange:
+ {
+ switch (connection_state)
+ {
+ case CS_SERVER_HELLO_RECEIVED:
+
+ // There was no server certificate message; check it's OK
+ this.keyExchange.skipServerCertificate();
+ this.authentication = null;
+
+ // NB: Fall through to next case label
+
+ case CS_SERVER_CERTIFICATE_RECEIVED:
+
+ this.keyExchange.processServerKeyExchange(is);
+
+ assertEmpty(is);
+ break;
+
+ default:
+ this.failWithError(AlertLevel.fatal, AlertDescription.unexpected_message);
+ }
+
+ this.connection_state = CS_SERVER_KEY_EXCHANGE_RECEIVED;
+ break;
+ }
+ case HandshakeType.certificate_request:
+ {
+ switch (connection_state)
+ {
+ case CS_SERVER_CERTIFICATE_RECEIVED:
+
+ // There was no server key exchange message; check it's OK
+ this.keyExchange.skipServerKeyExchange();
+
+ // NB: Fall through to next case label
+
+ case CS_SERVER_KEY_EXCHANGE_RECEIVED:
+ {
+ if (this.authentication == null)
+ {
+ /*
+ * RFC 2246 7.4.4. It is a fatal handshake_failure alert
+ * for an anonymous server to request client identification.
+ */
+ this.failWithError(AlertLevel.fatal, AlertDescription.handshake_failure);
+ }
+
+ int numTypes = TlsUtils.readUint8(is);
+ short[] certificateTypes = new short[numTypes];
+ for (int i = 0; i < numTypes; ++i)
+ {
+ certificateTypes[i] = TlsUtils.readUint8(is);
+ }
+
+ byte[] authorities = TlsUtils.readOpaque16(is);
+
+ assertEmpty(is);
+
+ Vector authorityDNs = new Vector();
+
+ ByteArrayInputStream bis = new ByteArrayInputStream(authorities);
+ while (bis.available() > 0)
+ {
+ byte[] dnBytes = TlsUtils.readOpaque16(bis);
+ authorityDNs.addElement(X500Name.getInstance(ASN1Primitive.fromByteArray(dnBytes)));
+ }
+
+ this.certificateRequest = new CertificateRequest(certificateTypes,
+ authorityDNs);
+ this.keyExchange.validateCertificateRequest(this.certificateRequest);
+
+ break;
+ }
+ default:
+ this.failWithError(AlertLevel.fatal, AlertDescription.unexpected_message);
+ }
+
+ this.connection_state = CS_CERTIFICATE_REQUEST_RECEIVED;
+ break;
+ }
+ case HandshakeType.hello_request:
+ /*
+ * RFC 2246 7.4.1.1 Hello request This message will be ignored by the
+ * client if the client is currently negotiating a session. This message
+ * may be ignored by the client if it does not wish to renegotiate a
+ * session, or the client may, if it wishes, respond with a
+ * no_renegotiation alert.
+ */
+ if (connection_state == CS_DONE)
+ {
+ // Renegotiation not supported yet
+ sendAlert(AlertLevel.warning, AlertDescription.no_renegotiation);
+ }
+ break;
+ case HandshakeType.client_key_exchange:
+ case HandshakeType.certificate_verify:
+ case HandshakeType.client_hello:
+ default:
+ // We do not support this!
+ this.failWithError(AlertLevel.fatal, AlertDescription.unexpected_message);
+ break;
+ }
+ }
+
+ private void processApplicationData()
+ {
+ /*
+ * There is nothing we need to do here.
+ *
+ * This function could be used for callbacks when application data arrives in the
+ * future.
+ */
+ }
+
+ private void processAlert() throws IOException
+ {
+ while (alertQueue.size() >= 2)
+ {
+ /*
+ * An alert is always 2 bytes. Read the alert.
+ */
+ byte[] tmp = new byte[2];
+ alertQueue.read(tmp, 0, 2, 0);
+ alertQueue.removeData(2);
+ short level = tmp[0];
+ short description = tmp[1];
+ if (level == AlertLevel.fatal)
+ {
+ /*
+ * This is a fatal error.
+ */
+ this.failedWithError = true;
+ this.closed = true;
+ /*
+ * Now try to close the stream, ignore errors.
+ */
+ try
+ {
+ rs.close();
+ }
+ catch (Exception e)
+ {
+
+ }
+ throw new IOException(TLS_ERROR_MESSAGE);
+ }
+ else
+ {
+ /*
+ * This is just a warning.
+ */
+ if (description == AlertDescription.close_notify)
+ {
+ /*
+ * Close notify
+ */
+ this.failWithError(AlertLevel.warning, AlertDescription.close_notify);
+ }
+ /*
+ * If it is just a warning, we continue.
+ */
+ }
+ }
+ }
+
+ /**
+ * This method is called, when a change cipher spec message is received.
+ *
+ * @throws IOException If the message has an invalid content or the handshake is not
+ * in the correct state.
+ */
+ private void processChangeCipherSpec() throws IOException
+ {
+ while (changeCipherSpecQueue.size() > 0)
+ {
+ /*
+ * A change cipher spec message is only one byte with the value 1.
+ */
+ byte[] b = new byte[1];
+ changeCipherSpecQueue.read(b, 0, 1, 0);
+ changeCipherSpecQueue.removeData(1);
+ if (b[0] != 1)
+ {
+ /*
+ * This should never happen.
+ */
+ this.failWithError(AlertLevel.fatal, AlertDescription.unexpected_message);
+ }
+
+ /*
+ * Check if we are in the correct connection state.
+ */
+ if (this.connection_state != CS_CLIENT_FINISHED_SEND)
+ {
+ this.failWithError(AlertLevel.fatal, AlertDescription.handshake_failure);
+ }
+
+ rs.serverClientSpecReceived();
+
+ this.connection_state = CS_SERVER_CHANGE_CIPHER_SPEC_RECEIVED;
+ }
+ }
+
+ private void sendClientCertificate(Certificate clientCert) throws IOException
+ {
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ TlsUtils.writeUint8(HandshakeType.certificate, bos);
+
+ // Reserve space for length
+ TlsUtils.writeUint24(0, bos);
+
+ clientCert.encode(bos);
+ byte[] message = bos.toByteArray();
+
+ // Patch actual length back in
+ TlsUtils.writeUint24(message.length - 4, message, 1);
+
+ rs.writeMessage(ContentType.handshake, message, 0, message.length);
+ }
+
+ private void sendClientKeyExchange() throws IOException
+ {
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+
+ TlsUtils.writeUint8(HandshakeType.client_key_exchange, bos);
+
+ // Reserve space for length
+ TlsUtils.writeUint24(0, bos);
+
+ this.keyExchange.generateClientKeyExchange(bos);
+ byte[] message = bos.toByteArray();
+
+ // Patch actual length back in
+ TlsUtils.writeUint24(message.length - 4, message, 1);
+
+ rs.writeMessage(ContentType.handshake, message, 0, message.length);
+ }
+
+ private void sendCertificateVerify(byte[] data) throws IOException
+ {
+ /*
+ * Send signature of handshake messages so far to prove we are the owner of the
+ * cert See RFC 2246 sections 4.7, 7.4.3 and 7.4.8
+ */
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ TlsUtils.writeUint8(HandshakeType.certificate_verify, bos);
+ TlsUtils.writeUint24(data.length + 2, bos);
+ TlsUtils.writeOpaque16(data, bos);
+ byte[] message = bos.toByteArray();
+
+ rs.writeMessage(ContentType.handshake, message, 0, message.length);
+ }
+
+ /**
+ * Connects to the remote system.
+ *
+ * @param verifyer Will be used when a certificate is received to verify that this
+ * certificate is accepted by the client.
+ * @throws IOException If handshake was not successful.
+ *
+ * @deprecated use version taking TlsClient
+ */
+ public void connect(CertificateVerifyer verifyer) throws IOException
+ {
+ this.connect(new LegacyTlsClient(verifyer));
+ }
+
+ /**
+ * Connects to the remote system using client authentication
+ *
+ * @param tlsClient
+ * @throws IOException If handshake was not successful.
+ */
+ public void connect(TlsClient tlsClient) throws IOException
+ {
+ if (tlsClient == null)
+ {
+ throw new IllegalArgumentException("'tlsClient' cannot be null");
+ }
+ if (this.tlsClient != null)
+ {
+ throw new IllegalStateException("connect can only be called once");
+ }
+
+ /*
+ * Send Client hello
+ *
+ * First, generate some random data.
+ */
+ this.securityParameters = new SecurityParameters();
+ this.securityParameters.clientRandom = new byte[32];
+ random.nextBytes(securityParameters.clientRandom);
+ TlsUtils.writeGMTUnixTime(securityParameters.clientRandom, 0);
+
+ this.tlsClientContext = new TlsClientContextImpl(random, securityParameters);
+
+ this.rs.init(tlsClientContext);
+
+ this.tlsClient = tlsClient;
+ this.tlsClient.init(tlsClientContext);
+
+ ByteArrayOutputStream os = new ByteArrayOutputStream();
+
+ ProtocolVersion client_version = this.tlsClient.getClientVersion();
+ this.tlsClientContext.setClientVersion(client_version);
+ // TODO For SSLv3 support, server version needs to be set to ProtocolVersion.SSLv3
+ this.tlsClientContext.setServerVersion(client_version);
+ TlsUtils.writeVersion(client_version, os);
+
+ os.write(securityParameters.clientRandom);
+
+ /*
+ * Length of Session id
+ */
+ TlsUtils.writeUint8((short)0, os);
+
+ /*
+ * Cipher suites
+ */
+ this.offeredCipherSuites = this.tlsClient.getCipherSuites();
+
+ // Integer -> byte[]
+ this.clientExtensions = this.tlsClient.getClientExtensions();
+
+ // Cipher Suites (and SCSV)
+ {
+ /*
+ * RFC 5746 3.4. The client MUST include either an empty "renegotiation_info"
+ * extension, or the TLS_EMPTY_RENEGOTIATION_INFO_SCSV signaling cipher suite
+ * value in the ClientHello. Including both is NOT RECOMMENDED.
+ */
+ boolean noRenegExt = clientExtensions == null
+ || clientExtensions.get(EXT_RenegotiationInfo) == null;
+
+ int count = offeredCipherSuites.length;
+ if (noRenegExt)
+ {
+ // Note: 1 extra slot for TLS_EMPTY_RENEGOTIATION_INFO_SCSV
+ ++count;
+ }
+
+ TlsUtils.writeUint16(2 * count, os);
+ TlsUtils.writeUint16Array(offeredCipherSuites, os);
+
+ if (noRenegExt)
+ {
+ TlsUtils.writeUint16(CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV, os);
+ }
+ }
+
+ // Compression methods
+ this.offeredCompressionMethods = this.tlsClient.getCompressionMethods();
+
+ TlsUtils.writeUint8((short)offeredCompressionMethods.length, os);
+ TlsUtils.writeUint8Array(offeredCompressionMethods, os);
+
+ // Extensions
+ if (clientExtensions != null)
+ {
+ ByteArrayOutputStream ext = new ByteArrayOutputStream();
+
+ Enumeration keys = clientExtensions.keys();
+ while (keys.hasMoreElements())
+ {
+ Integer extType = (Integer)keys.nextElement();
+ writeExtension(ext, extType, (byte[])clientExtensions.get(extType));
+ }
+
+ TlsUtils.writeOpaque16(ext.toByteArray(), os);
+ }
+
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ TlsUtils.writeUint8(HandshakeType.client_hello, bos);
+ TlsUtils.writeUint24(os.size(), bos);
+ bos.write(os.toByteArray());
+ byte[] message = bos.toByteArray();
+
+ safeWriteMessage(ContentType.handshake, message, 0, message.length);
+
+ connection_state = CS_CLIENT_HELLO_SEND;
+
+ /*
+ * We will now read data, until we have completed the handshake.
+ */
+ while (connection_state != CS_DONE)
+ {
+ safeReadData();
+ }
+
+ this.tlsInputStream = new TlsInputStream(this);
+ this.tlsOutputStream = new TlsOutputStream(this);
+ }
+
+ /**
+ * Read data from the network. The method will return immediately, if there is still
+ * some data left in the buffer, or block until some application data has been read
+ * from the network.
+ *
+ * @param buf The buffer where the data will be copied to.
+ * @param offset The position where the data will be placed in the buffer.
+ * @param len The maximum number of bytes to read.
+ * @return The number of bytes read.
+ * @throws IOException If something goes wrong during reading data.
+ */
+ protected int readApplicationData(byte[] buf, int offset, int len) throws IOException
+ {
+ while (applicationDataQueue.size() == 0)
+ {
+ /*
+ * We need to read some data.
+ */
+ if (this.closed)
+ {
+ if (this.failedWithError)
+ {
+ /*
+ * Something went terribly wrong, we should throw an IOException
+ */
+ throw new IOException(TLS_ERROR_MESSAGE);
+ }
+
+ /*
+ * Connection has been closed, there is no more data to read.
+ */
+ return -1;
+ }
+
+ safeReadData();
+ }
+ len = Math.min(len, applicationDataQueue.size());
+ applicationDataQueue.read(buf, offset, len, 0);
+ applicationDataQueue.removeData(len);
+ return len;
+ }
+
+ private void safeReadData() throws IOException
+ {
+ try
+ {
+ rs.readData();
+ }
+ catch (TlsFatalAlert e)
+ {
+ if (!this.closed)
+ {
+ this.failWithError(AlertLevel.fatal, e.getAlertDescription());
+ }
+ throw e;
+ }
+ catch (IOException e)
+ {
+ if (!this.closed)
+ {
+ this.failWithError(AlertLevel.fatal, AlertDescription.internal_error);
+ }
+ throw e;
+ }
+ catch (RuntimeException e)
+ {
+ if (!this.closed)
+ {
+ this.failWithError(AlertLevel.fatal, AlertDescription.internal_error);
+ }
+ throw e;
+ }
+ }
+
+ private void safeWriteMessage(short type, byte[] buf, int offset, int len) throws IOException
+ {
+ try
+ {
+ rs.writeMessage(type, buf, offset, len);
+ }
+ catch (TlsFatalAlert e)
+ {
+ if (!this.closed)
+ {
+ this.failWithError(AlertLevel.fatal, e.getAlertDescription());
+ }
+ throw e;
+ }
+ catch (IOException e)
+ {
+ if (!closed)
+ {
+ this.failWithError(AlertLevel.fatal, AlertDescription.internal_error);
+ }
+ throw e;
+ }
+ catch (RuntimeException e)
+ {
+ if (!closed)
+ {
+ this.failWithError(AlertLevel.fatal, AlertDescription.internal_error);
+ }
+ throw e;
+ }
+ }
+
+ /**
+ * Send some application data to the remote system.
+ *
+ * The method will handle fragmentation internally.
+ *
+ * @param buf The buffer with the data.
+ * @param offset The position in the buffer where the data is placed.
+ * @param len The length of the data.
+ * @throws IOException If something goes wrong during sending.
+ */
+ protected void writeData(byte[] buf, int offset, int len) throws IOException
+ {
+ if (this.closed)
+ {
+ if (this.failedWithError)
+ {
+ throw new IOException(TLS_ERROR_MESSAGE);
+ }
+
+ throw new IOException("Sorry, connection has been closed, you cannot write more data");
+ }
+
+ /*
+ * Protect against known IV attack!
+ *
+ * DO NOT REMOVE THIS LINE, EXCEPT YOU KNOW EXACTLY WHAT YOU ARE DOING HERE.
+ */
+ safeWriteMessage(ContentType.application_data, emptybuf, 0, 0);
+
+ do
+ {
+ /*
+ * We are only allowed to write fragments up to 2^14 bytes.
+ */
+ int toWrite = Math.min(len, 1 << 14);
+
+ safeWriteMessage(ContentType.application_data, buf, offset, toWrite);
+
+ offset += toWrite;
+ len -= toWrite;
+ }
+ while (len > 0);
+
+ }
+
+ /**
+ * @return An OutputStream which can be used to send data.
+ */
+ public OutputStream getOutputStream()
+ {
+ return this.tlsOutputStream;
+ }
+
+ /**
+ * @return An InputStream which can be used to read data.
+ */
+ public InputStream getInputStream()
+ {
+ return this.tlsInputStream;
+ }
+
+ /**
+ * Terminate this connection with an alert.
+ *
+ * Can be used for normal closure too.
+ *
+ * @param alertLevel The level of the alert, an be AlertLevel.fatal or AL_warning.
+ * @param alertDescription The exact alert message.
+ * @throws IOException If alert was fatal.
+ */
+ private void failWithError(short alertLevel, short alertDescription) throws IOException
+ {
+ /*
+ * Check if the connection is still open.
+ */
+ if (!closed)
+ {
+ /*
+ * Prepare the message
+ */
+ this.closed = true;
+
+ if (alertLevel == AlertLevel.fatal)
+ {
+ /*
+ * This is a fatal message.
+ */
+ this.failedWithError = true;
+ }
+ sendAlert(alertLevel, alertDescription);
+ rs.close();
+ if (alertLevel == AlertLevel.fatal)
+ {
+ throw new IOException(TLS_ERROR_MESSAGE);
+ }
+ }
+ else
+ {
+ throw new IOException(TLS_ERROR_MESSAGE);
+ }
+ }
+
+ private void sendAlert(short alertLevel, short alertDescription) throws IOException
+ {
+ byte[] error = new byte[2];
+ error[0] = (byte)alertLevel;
+ error[1] = (byte)alertDescription;
+
+ rs.writeMessage(ContentType.alert, error, 0, 2);
+ }
+
+ /**
+ * Closes this connection.
+ *
+ * @throws IOException If something goes wrong during closing.
+ */
+ public void close() throws IOException
+ {
+ if (!closed)
+ {
+ this.failWithError(AlertLevel.warning, AlertDescription.close_notify);
+ }
+ }
+
+ /**
+ * Make sure the InputStream is now empty. Fail otherwise.
+ *
+ * @param is The InputStream to check.
+ * @throws IOException If is is not empty.
+ */
+ protected void assertEmpty(ByteArrayInputStream is) throws IOException
+ {
+ if (is.available() > 0)
+ {
+ throw new TlsFatalAlert(AlertDescription.decode_error);
+ }
+ }
+
+ protected void flush() throws IOException
+ {
+ rs.flush();
+ }
+
+ private static boolean arrayContains(short[] a, short n)
+ {
+ for (int i = 0; i < a.length; ++i)
+ {
+ if (a[i] == n)
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private static boolean arrayContains(int[] a, int n)
+ {
+ for (int i = 0; i < a.length; ++i)
+ {
+ if (a[i] == n)
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private static byte[] createRenegotiationInfo(byte[] renegotiated_connection)
+ throws IOException
+ {
+ ByteArrayOutputStream buf = new ByteArrayOutputStream();
+ TlsUtils.writeOpaque8(renegotiated_connection, buf);
+ return buf.toByteArray();
+ }
+
+ private static void writeExtension(OutputStream output, Integer extType, byte[] extValue)
+ throws IOException
+ {
+ TlsUtils.writeUint16(extType.intValue(), output);
+ TlsUtils.writeOpaque16(extValue, output);
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsRSAKeyExchange.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsRSAKeyExchange.java
new file mode 100644
index 0000000..db06628
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsRSAKeyExchange.java
@@ -0,0 +1,165 @@
+package org.bc.crypto.tls;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.bc.asn1.x509.KeyUsage;
+import org.bc.asn1.x509.SubjectPublicKeyInfo;
+import org.bc.crypto.params.AsymmetricKeyParameter;
+import org.bc.crypto.params.RSAKeyParameters;
+import org.bc.crypto.util.PublicKeyFactory;
+
+/**
+ * TLS 1.0 and SSLv3 RSA key exchange.
+ */
+class TlsRSAKeyExchange implements TlsKeyExchange
+{
+ protected TlsClientContext context;
+
+ protected AsymmetricKeyParameter serverPublicKey = null;
+
+ protected RSAKeyParameters rsaServerPublicKey = null;
+
+ protected byte[] premasterSecret;
+
+ TlsRSAKeyExchange(TlsClientContext context)
+ {
+ this.context = context;
+ }
+
+ public void skipServerCertificate() throws IOException
+ {
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+
+ public void processServerCertificate(Certificate serverCertificate) throws IOException
+ {
+ org.bc.asn1.x509.Certificate x509Cert = serverCertificate.certs[0];
+ SubjectPublicKeyInfo keyInfo = x509Cert.getSubjectPublicKeyInfo();
+
+ try
+ {
+ this.serverPublicKey = PublicKeyFactory.createKey(keyInfo);
+ }
+ catch (RuntimeException e)
+ {
+ throw new TlsFatalAlert(AlertDescription.unsupported_certificate);
+ }
+
+ // Sanity check the PublicKeyFactory
+ if (this.serverPublicKey.isPrivate())
+ {
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+
+ this.rsaServerPublicKey = validateRSAPublicKey((RSAKeyParameters)this.serverPublicKey);
+
+ TlsUtils.validateKeyUsage(x509Cert, KeyUsage.keyEncipherment);
+
+ // TODO
+ /*
+ * Perform various checks per RFC2246 7.4.2: "Unless otherwise specified, the
+ * signing algorithm for the certificate must be the same as the algorithm for the
+ * certificate key."
+ */
+ }
+
+ public void skipServerKeyExchange() throws IOException
+ {
+ // OK
+ }
+
+ public void processServerKeyExchange(InputStream is)
+ throws IOException
+ {
+ // TODO
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+
+ public void validateCertificateRequest(CertificateRequest certificateRequest)
+ throws IOException
+ {
+ short[] types = certificateRequest.getCertificateTypes();
+ for (int i = 0; i < types.length; ++i)
+ {
+ switch (types[i])
+ {
+ case ClientCertificateType.rsa_sign:
+ case ClientCertificateType.dss_sign:
+ case ClientCertificateType.ecdsa_sign:
+ break;
+ default:
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ }
+ }
+ }
+
+ public void skipClientCredentials() throws IOException
+ {
+ // OK
+ }
+
+ public void processClientCredentials(TlsCredentials clientCredentials) throws IOException
+ {
+ if (!(clientCredentials instanceof TlsSignerCredentials))
+ {
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+ }
+
+ public void generateClientKeyExchange(OutputStream os) throws IOException
+ {
+ this.premasterSecret = TlsRSAUtils.generateEncryptedPreMasterSecret(context,
+ this.rsaServerPublicKey, os);
+ }
+
+ public byte[] generatePremasterSecret() throws IOException
+ {
+ byte[] tmp = this.premasterSecret;
+ this.premasterSecret = null;
+ return tmp;
+ }
+
+ // Would be needed to process RSA_EXPORT server key exchange
+// protected void processRSAServerKeyExchange(InputStream is, Signer signer) throws IOException
+// {
+// InputStream sigIn = is;
+// if (signer != null)
+// {
+// sigIn = new SignerInputStream(is, signer);
+// }
+//
+// byte[] modulusBytes = TlsUtils.readOpaque16(sigIn);
+// byte[] exponentBytes = TlsUtils.readOpaque16(sigIn);
+//
+// if (signer != null)
+// {
+// byte[] sigByte = TlsUtils.readOpaque16(is);
+//
+// if (!signer.verifySignature(sigByte))
+// {
+// handler.failWithError(AlertLevel.fatal, AlertDescription.bad_certificate);
+// }
+// }
+//
+// BigInteger modulus = new BigInteger(1, modulusBytes);
+// BigInteger exponent = new BigInteger(1, exponentBytes);
+//
+// this.rsaServerPublicKey = validateRSAPublicKey(new RSAKeyParameters(false, modulus,
+// exponent));
+// }
+
+ protected RSAKeyParameters validateRSAPublicKey(RSAKeyParameters key) throws IOException
+ {
+ // TODO What is the minimum bit length required?
+// key.getModulus().bitLength();
+
+ if (!key.getExponent().isProbablePrime(2))
+ {
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ }
+
+ return key;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsRSASigner.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsRSASigner.java
new file mode 100644
index 0000000..05ac66d
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsRSASigner.java
@@ -0,0 +1,37 @@
+package org.bc.crypto.tls;
+
+import java.security.SecureRandom;
+
+import org.bc.crypto.CryptoException;
+import org.bc.crypto.Signer;
+import org.bc.crypto.digests.NullDigest;
+import org.bc.crypto.encodings.PKCS1Encoding;
+import org.bc.crypto.engines.RSABlindedEngine;
+import org.bc.crypto.params.AsymmetricKeyParameter;
+import org.bc.crypto.params.ParametersWithRandom;
+import org.bc.crypto.params.RSAKeyParameters;
+import org.bc.crypto.signers.GenericSigner;
+
+class TlsRSASigner implements TlsSigner
+{
+ public byte[] calculateRawSignature(SecureRandom random, AsymmetricKeyParameter privateKey, byte[] md5andsha1)
+ throws CryptoException
+ {
+ Signer sig = new GenericSigner(new PKCS1Encoding(new RSABlindedEngine()), new NullDigest());
+ sig.init(true, new ParametersWithRandom(privateKey, random));
+ sig.update(md5andsha1, 0, md5andsha1.length);
+ return sig.generateSignature();
+ }
+
+ public Signer createVerifyer(AsymmetricKeyParameter publicKey)
+ {
+ Signer s = new GenericSigner(new PKCS1Encoding(new RSABlindedEngine()), new CombinedHash());
+ s.init(false, publicKey);
+ return s;
+ }
+
+ public boolean isValidPublicKey(AsymmetricKeyParameter publicKey)
+ {
+ return publicKey instanceof RSAKeyParameters && !publicKey.isPrivate();
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsRSAUtils.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsRSAUtils.java
new file mode 100644
index 0000000..f9a475b
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsRSAUtils.java
@@ -0,0 +1,51 @@
+package org.bc.crypto.tls;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.bc.crypto.InvalidCipherTextException;
+import org.bc.crypto.encodings.PKCS1Encoding;
+import org.bc.crypto.engines.RSABlindedEngine;
+import org.bc.crypto.params.ParametersWithRandom;
+import org.bc.crypto.params.RSAKeyParameters;
+
+public class TlsRSAUtils
+{
+ public static byte[] generateEncryptedPreMasterSecret(TlsClientContext context,
+ RSAKeyParameters rsaServerPublicKey, OutputStream os) throws IOException
+ {
+ /*
+ * Choose a PremasterSecret and send it encrypted to the server
+ */
+ byte[] premasterSecret = new byte[48];
+ context.getSecureRandom().nextBytes(premasterSecret);
+ TlsUtils.writeVersion(context.getClientVersion(), premasterSecret, 0);
+
+ PKCS1Encoding encoding = new PKCS1Encoding(new RSABlindedEngine());
+ encoding.init(true, new ParametersWithRandom(rsaServerPublicKey, context.getSecureRandom()));
+
+ try
+ {
+ boolean isTls = context.getServerVersion().getFullVersion() >= ProtocolVersion.TLSv10.getFullVersion();
+ byte[] keData = encoding.processBlock(premasterSecret, 0, premasterSecret.length);
+
+ if (isTls)
+ {
+ TlsUtils.writeOpaque16(keData, os);
+ }
+ else
+ {
+ os.write(keData);
+ }
+ }
+ catch (InvalidCipherTextException e)
+ {
+ /*
+ * This should never happen, only during decryption.
+ */
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+
+ return premasterSecret;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsRuntimeException.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsRuntimeException.java
new file mode 100644
index 0000000..1b5a21b
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsRuntimeException.java
@@ -0,0 +1,25 @@
+package org.bc.crypto.tls;
+
+public class TlsRuntimeException extends RuntimeException
+{
+ private static final long serialVersionUID = 1928023487348344086L;
+
+ Throwable e;
+
+ public TlsRuntimeException(String message, Throwable e)
+ {
+ super(message);
+
+ this.e = e;
+ }
+
+ public TlsRuntimeException(String message)
+ {
+ super(message);
+ }
+
+ public Throwable getCause()
+ {
+ return e;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsSRPKeyExchange.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsSRPKeyExchange.java
new file mode 100644
index 0000000..46ad74c
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsSRPKeyExchange.java
@@ -0,0 +1,202 @@
+package org.bc.crypto.tls;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.math.BigInteger;
+
+import org.bc.asn1.x509.KeyUsage;
+import org.bc.asn1.x509.SubjectPublicKeyInfo;
+import org.bc.crypto.CryptoException;
+import org.bc.crypto.Signer;
+import org.bc.crypto.agreement.srp.SRP6Client;
+import org.bc.crypto.agreement.srp.SRP6Util;
+import org.bc.crypto.digests.SHA1Digest;
+import org.bc.crypto.io.SignerInputStream;
+import org.bc.crypto.params.AsymmetricKeyParameter;
+import org.bc.crypto.util.PublicKeyFactory;
+import org.bc.util.BigIntegers;
+
+/**
+ * TLS 1.1 SRP key exchange.
+ */
+class TlsSRPKeyExchange implements TlsKeyExchange
+{
+ protected TlsClientContext context;
+ protected int keyExchange;
+ protected TlsSigner tlsSigner;
+ protected byte[] identity;
+ protected byte[] password;
+
+ protected AsymmetricKeyParameter serverPublicKey = null;
+
+ protected byte[] s = null;
+ protected BigInteger B = null;
+ protected SRP6Client srpClient = new SRP6Client();
+
+ TlsSRPKeyExchange(TlsClientContext context, int keyExchange, byte[] identity, byte[] password)
+ {
+ switch (keyExchange)
+ {
+ case KeyExchangeAlgorithm.SRP:
+ this.tlsSigner = null;
+ break;
+ case KeyExchangeAlgorithm.SRP_RSA:
+ this.tlsSigner = new TlsRSASigner();
+ break;
+ case KeyExchangeAlgorithm.SRP_DSS:
+ this.tlsSigner = new TlsDSSSigner();
+ break;
+ default:
+ throw new IllegalArgumentException("unsupported key exchange algorithm");
+ }
+
+ this.context = context;
+ this.keyExchange = keyExchange;
+ this.identity = identity;
+ this.password = password;
+ }
+
+ public void skipServerCertificate() throws IOException
+ {
+ if (tlsSigner != null)
+ {
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+ }
+
+ public void processServerCertificate(Certificate serverCertificate) throws IOException
+ {
+ if (tlsSigner == null)
+ {
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+
+ org.bc.asn1.x509.Certificate x509Cert = serverCertificate.certs[0];
+ SubjectPublicKeyInfo keyInfo = x509Cert.getSubjectPublicKeyInfo();
+
+ try
+ {
+ this.serverPublicKey = PublicKeyFactory.createKey(keyInfo);
+ }
+ catch (RuntimeException e)
+ {
+ throw new TlsFatalAlert(AlertDescription.unsupported_certificate);
+ }
+
+ if (!tlsSigner.isValidPublicKey(this.serverPublicKey))
+ {
+ throw new TlsFatalAlert(AlertDescription.certificate_unknown);
+ }
+
+ TlsUtils.validateKeyUsage(x509Cert, KeyUsage.digitalSignature);
+
+ // TODO
+ /*
+ * Perform various checks per RFC2246 7.4.2: "Unless otherwise specified, the
+ * signing algorithm for the certificate must be the same as the algorithm for the
+ * certificate key."
+ */
+ }
+
+ public void skipServerKeyExchange() throws IOException
+ {
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+
+ public void processServerKeyExchange(InputStream is) throws IOException
+ {
+ SecurityParameters securityParameters = context.getSecurityParameters();
+
+ InputStream sigIn = is;
+ Signer signer = null;
+
+ if (tlsSigner != null)
+ {
+ signer = initSigner(tlsSigner, securityParameters);
+ sigIn = new SignerInputStream(is, signer);
+ }
+
+ byte[] NBytes = TlsUtils.readOpaque16(sigIn);
+ byte[] gBytes = TlsUtils.readOpaque16(sigIn);
+ byte[] sBytes = TlsUtils.readOpaque8(sigIn);
+ byte[] BBytes = TlsUtils.readOpaque16(sigIn);
+
+ if (signer != null)
+ {
+ byte[] sigByte = TlsUtils.readOpaque16(is);
+
+ if (!signer.verifySignature(sigByte))
+ {
+ throw new TlsFatalAlert(AlertDescription.bad_certificate);
+ }
+ }
+
+ BigInteger N = new BigInteger(1, NBytes);
+ BigInteger g = new BigInteger(1, gBytes);
+
+ // TODO Validate group parameters (see RFC 5054)
+// handler.failWithError(AlertLevel.fatal, AlertDescription.insufficient_security);
+
+ this.s = sBytes;
+
+ /*
+ * RFC 5054 2.5.3: The client MUST abort the handshake with an "illegal_parameter"
+ * alert if B % N = 0.
+ */
+ try
+ {
+ this.B = SRP6Util.validatePublicValue(N, new BigInteger(1, BBytes));
+ }
+ catch (CryptoException e)
+ {
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ }
+
+ this.srpClient.init(N, g, new SHA1Digest(), context.getSecureRandom());
+ }
+
+ public void validateCertificateRequest(CertificateRequest certificateRequest)
+ throws IOException
+ {
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+
+ public void skipClientCredentials() throws IOException
+ {
+ // OK
+ }
+
+ public void processClientCredentials(TlsCredentials clientCredentials) throws IOException
+ {
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+
+ public void generateClientKeyExchange(OutputStream os) throws IOException
+ {
+ byte[] keData = BigIntegers.asUnsignedByteArray(srpClient.generateClientCredentials(s,
+ this.identity, this.password));
+ TlsUtils.writeOpaque16(keData, os);
+ }
+
+ public byte[] generatePremasterSecret() throws IOException
+ {
+ try
+ {
+ // TODO Check if this needs to be a fixed size
+ return BigIntegers.asUnsignedByteArray(srpClient.calculateSecret(B));
+ }
+ catch (CryptoException e)
+ {
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ }
+ }
+
+ protected Signer initSigner(TlsSigner tlsSigner, SecurityParameters securityParameters)
+ {
+ Signer signer = tlsSigner.createVerifyer(this.serverPublicKey);
+ signer.update(securityParameters.clientRandom, 0, securityParameters.clientRandom.length);
+ signer.update(securityParameters.serverRandom, 0, securityParameters.serverRandom.length);
+ return signer;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsSigner.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsSigner.java
new file mode 100644
index 0000000..1b3dc47
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsSigner.java
@@ -0,0 +1,17 @@
+package org.bc.crypto.tls;
+
+import java.security.SecureRandom;
+
+import org.bc.crypto.CryptoException;
+import org.bc.crypto.Signer;
+import org.bc.crypto.params.AsymmetricKeyParameter;
+
+interface TlsSigner
+{
+ byte[] calculateRawSignature(SecureRandom random, AsymmetricKeyParameter privateKey, byte[] md5andsha1)
+ throws CryptoException;
+
+ Signer createVerifyer(AsymmetricKeyParameter publicKey);
+
+ boolean isValidPublicKey(AsymmetricKeyParameter publicKey);
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsSignerCredentials.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsSignerCredentials.java
new file mode 100644
index 0000000..1ba7a95
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsSignerCredentials.java
@@ -0,0 +1,8 @@
+package org.bc.crypto.tls;
+
+import java.io.IOException;
+
+public interface TlsSignerCredentials extends TlsCredentials
+{
+ byte[] generateCertificateSignature(byte[] md5andsha1) throws IOException;
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsStreamCipher.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsStreamCipher.java
new file mode 100644
index 0000000..4fe5a54
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsStreamCipher.java
@@ -0,0 +1,98 @@
+package org.bc.crypto.tls;
+
+import java.io.IOException;
+
+import org.bc.crypto.Digest;
+import org.bc.crypto.StreamCipher;
+import org.bc.crypto.params.KeyParameter;
+import org.bc.util.Arrays;
+
+public class TlsStreamCipher implements TlsCipher
+{
+ protected TlsClientContext context;
+
+ protected StreamCipher encryptCipher;
+ protected StreamCipher decryptCipher;
+
+ protected TlsMac writeMac;
+ protected TlsMac readMac;
+
+ public TlsStreamCipher(TlsClientContext context, StreamCipher encryptCipher,
+ StreamCipher decryptCipher, Digest writeDigest, Digest readDigest, int cipherKeySize)
+ throws IOException
+ {
+ this.context = context;
+ this.encryptCipher = encryptCipher;
+ this.decryptCipher = decryptCipher;
+
+ int prfSize = (2 * cipherKeySize) + writeDigest.getDigestSize()
+ + readDigest.getDigestSize();
+
+ SecurityParameters securityParameters = context.getSecurityParameters();
+
+ byte[] keyBlock = TlsUtils.PRF(securityParameters.masterSecret, "key expansion",
+ TlsUtils.concat(securityParameters.serverRandom, securityParameters.clientRandom),
+ prfSize);
+
+ int offset = 0;
+
+ // Init MACs
+ writeMac = new TlsMac(context, writeDigest, keyBlock, offset, writeDigest.getDigestSize());
+ offset += writeDigest.getDigestSize();
+ readMac = new TlsMac(context, readDigest, keyBlock, offset, readDigest.getDigestSize());
+ offset += readDigest.getDigestSize();
+
+ // Build keys
+ KeyParameter encryptKey = new KeyParameter(keyBlock, offset, cipherKeySize);
+ offset += cipherKeySize;
+ KeyParameter decryptKey = new KeyParameter(keyBlock, offset, cipherKeySize);
+ offset += cipherKeySize;
+
+ if (offset != prfSize)
+ {
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+
+ encryptCipher.init(true, encryptKey);
+ decryptCipher.init(true, decryptKey);
+ }
+
+ public byte[] encodePlaintext(short type, byte[] plaintext, int offset, int len)
+ {
+ byte[] mac = writeMac.calculateMac(type, plaintext, offset, len);
+
+ byte[] outbuf = new byte[len + mac.length];
+
+ encryptCipher.processBytes(plaintext, offset, len, outbuf, 0);
+ encryptCipher.processBytes(mac, 0, mac.length, outbuf, len);
+
+ return outbuf;
+ }
+
+ public byte[] decodeCiphertext(short type, byte[] ciphertext, int offset, int len)
+ throws IOException
+ {
+ byte[] deciphered = new byte[len];
+ decryptCipher.processBytes(ciphertext, offset, len, deciphered, 0);
+
+ int plaintextSize = deciphered.length - readMac.getSize();
+ byte[] plainText = copyData(deciphered, 0, plaintextSize);
+
+ byte[] receivedMac = copyData(deciphered, plaintextSize, readMac.getSize());
+ byte[] computedMac = readMac.calculateMac(type, plainText, 0, plainText.length);
+
+ if (!Arrays.constantTimeAreEqual(receivedMac, computedMac))
+ {
+ throw new TlsFatalAlert(AlertDescription.bad_record_mac);
+ }
+
+ return plainText;
+ }
+
+ protected byte[] copyData(byte[] text, int offset, int len)
+ {
+ byte[] result = new byte[len];
+ System.arraycopy(text, offset, result, 0, len);
+ return result;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsUtils.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsUtils.java
new file mode 100644
index 0000000..ee54de3
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/tls/TlsUtils.java
@@ -0,0 +1,437 @@
+package org.bc.crypto.tls;
+
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.bc.asn1.x509.Extension;
+import org.bc.asn1.x509.Extensions;
+import org.bc.asn1.x509.KeyUsage;
+import org.bc.asn1.x509.X509Extension;
+import org.bc.crypto.Digest;
+import org.bc.crypto.digests.MD5Digest;
+import org.bc.crypto.digests.SHA1Digest;
+import org.bc.crypto.macs.HMac;
+import org.bc.crypto.params.KeyParameter;
+import org.bc.util.Arrays;
+import org.bc.util.Strings;
+import org.bc.util.io.Streams;
+
+/**
+ * Some helper fuctions for MicroTLS.
+ */
+public class TlsUtils
+{
+ protected static void writeUint8(short i, OutputStream os) throws IOException
+ {
+ os.write(i);
+ }
+
+ protected static void writeUint8(short i, byte[] buf, int offset)
+ {
+ buf[offset] = (byte)i;
+ }
+
+ protected static void writeUint16(int i, OutputStream os) throws IOException
+ {
+ os.write(i >> 8);
+ os.write(i);
+ }
+
+ protected static void writeUint16(int i, byte[] buf, int offset)
+ {
+ buf[offset] = (byte)(i >> 8);
+ buf[offset + 1] = (byte)i;
+ }
+
+ protected static void writeUint24(int i, OutputStream os) throws IOException
+ {
+ os.write(i >> 16);
+ os.write(i >> 8);
+ os.write(i);
+ }
+
+ protected static void writeUint24(int i, byte[] buf, int offset)
+ {
+ buf[offset] = (byte)(i >> 16);
+ buf[offset + 1] = (byte)(i >> 8);
+ buf[offset + 2] = (byte)(i);
+ }
+
+ protected static void writeUint32(long i, OutputStream os) throws IOException
+ {
+ os.write((int)(i >> 24));
+ os.write((int)(i >> 16));
+ os.write((int)(i >> 8));
+ os.write((int)(i));
+ }
+
+ protected static void writeUint32(long i, byte[] buf, int offset)
+ {
+ buf[offset] = (byte)(i >> 24);
+ buf[offset + 1] = (byte)(i >> 16);
+ buf[offset + 2] = (byte)(i >> 8);
+ buf[offset + 3] = (byte)(i);
+ }
+
+ protected static void writeUint64(long i, OutputStream os) throws IOException
+ {
+ os.write((int)(i >> 56));
+ os.write((int)(i >> 48));
+ os.write((int)(i >> 40));
+ os.write((int)(i >> 32));
+ os.write((int)(i >> 24));
+ os.write((int)(i >> 16));
+ os.write((int)(i >> 8));
+ os.write((int)(i));
+ }
+
+
+ protected static void writeUint64(long i, byte[] buf, int offset)
+ {
+ buf[offset] = (byte)(i >> 56);
+ buf[offset + 1] = (byte)(i >> 48);
+ buf[offset + 2] = (byte)(i >> 40);
+ buf[offset + 3] = (byte)(i >> 32);
+ buf[offset + 4] = (byte)(i >> 24);
+ buf[offset + 5] = (byte)(i >> 16);
+ buf[offset + 6] = (byte)(i >> 8);
+ buf[offset + 7] = (byte)(i);
+ }
+
+ protected static void writeOpaque8(byte[] buf, OutputStream os) throws IOException
+ {
+ writeUint8((short)buf.length, os);
+ os.write(buf);
+ }
+
+ protected static void writeOpaque16(byte[] buf, OutputStream os) throws IOException
+ {
+ writeUint16(buf.length, os);
+ os.write(buf);
+ }
+
+ protected static void writeOpaque24(byte[] buf, OutputStream os) throws IOException
+ {
+ writeUint24(buf.length, os);
+ os.write(buf);
+ }
+
+ protected static void writeUint8Array(short[] uints, OutputStream os) throws IOException
+ {
+ for (int i = 0; i < uints.length; ++i)
+ {
+ writeUint8(uints[i], os);
+ }
+ }
+
+ protected static void writeUint16Array(int[] uints, OutputStream os) throws IOException
+ {
+ for (int i = 0; i < uints.length; ++i)
+ {
+ writeUint16(uints[i], os);
+ }
+ }
+
+ protected static short readUint8(InputStream is) throws IOException
+ {
+ int i = is.read();
+ if (i == -1)
+ {
+ throw new EOFException();
+ }
+ return (short)i;
+ }
+
+ protected static int readUint16(InputStream is) throws IOException
+ {
+ int i1 = is.read();
+ int i2 = is.read();
+ if ((i1 | i2) < 0)
+ {
+ throw new EOFException();
+ }
+ return i1 << 8 | i2;
+ }
+
+ protected static int readUint24(InputStream is) throws IOException
+ {
+ int i1 = is.read();
+ int i2 = is.read();
+ int i3 = is.read();
+ if ((i1 | i2 | i3) < 0)
+ {
+ throw new EOFException();
+ }
+ return (i1 << 16) | (i2 << 8) | i3;
+ }
+
+ protected static long readUint32(InputStream is) throws IOException
+ {
+ int i1 = is.read();
+ int i2 = is.read();
+ int i3 = is.read();
+ int i4 = is.read();
+ if ((i1 | i2 | i3 | i4) < 0)
+ {
+ throw new EOFException();
+ }
+ return (((long)i1) << 24) | (((long)i2) << 16) | (((long)i3) << 8) | ((long)i4);
+ }
+
+ protected static void readFully(byte[] buf, InputStream is) throws IOException
+ {
+ if (Streams.readFully(is, buf) != buf.length)
+ {
+ throw new EOFException();
+ }
+ }
+
+ protected static byte[] readOpaque8(InputStream is) throws IOException
+ {
+ short length = readUint8(is);
+ byte[] value = new byte[length];
+ readFully(value, is);
+ return value;
+ }
+
+ protected static byte[] readOpaque16(InputStream is) throws IOException
+ {
+ int length = readUint16(is);
+ byte[] value = new byte[length];
+ readFully(value, is);
+ return value;
+ }
+
+ static ProtocolVersion readVersion(byte[] buf) throws IOException
+ {
+ return ProtocolVersion.get(buf[0], buf[1]);
+ }
+
+ static ProtocolVersion readVersion(InputStream is) throws IOException
+ {
+ int i1 = is.read();
+ int i2 = is.read();
+ return ProtocolVersion.get(i1, i2);
+ }
+
+ protected static void writeGMTUnixTime(byte[] buf, int offset)
+ {
+ int t = (int)(System.currentTimeMillis() / 1000L);
+ buf[offset] = (byte)(t >> 24);
+ buf[offset + 1] = (byte)(t >> 16);
+ buf[offset + 2] = (byte)(t >> 8);
+ buf[offset + 3] = (byte)t;
+ }
+
+ static void writeVersion(ProtocolVersion version, OutputStream os) throws IOException
+ {
+ os.write(version.getMajorVersion());
+ os.write(version.getMinorVersion());
+ }
+
+ static void writeVersion(ProtocolVersion version, byte[] buf, int offset) throws IOException
+ {
+ buf[offset] = (byte)version.getMajorVersion();
+ buf[offset + 1] = (byte)version.getMinorVersion();
+ }
+
+ private static void hmac_hash(Digest digest, byte[] secret, byte[] seed, byte[] out)
+ {
+ HMac mac = new HMac(digest);
+ KeyParameter param = new KeyParameter(secret);
+ byte[] a = seed;
+ int size = digest.getDigestSize();
+ int iterations = (out.length + size - 1) / size;
+ byte[] buf = new byte[mac.getMacSize()];
+ byte[] buf2 = new byte[mac.getMacSize()];
+ for (int i = 0; i < iterations; i++)
+ {
+ mac.init(param);
+ mac.update(a, 0, a.length);
+ mac.doFinal(buf, 0);
+ a = buf;
+ mac.init(param);
+ mac.update(a, 0, a.length);
+ mac.update(seed, 0, seed.length);
+ mac.doFinal(buf2, 0);
+ System.arraycopy(buf2, 0, out, (size * i), Math.min(size, out.length - (size * i)));
+ }
+ }
+
+ protected static byte[] PRF(byte[] secret, String asciiLabel, byte[] seed, int size)
+ {
+ byte[] label = Strings.toByteArray(asciiLabel);
+
+ int s_half = (secret.length + 1) / 2;
+ byte[] s1 = new byte[s_half];
+ byte[] s2 = new byte[s_half];
+ System.arraycopy(secret, 0, s1, 0, s_half);
+ System.arraycopy(secret, secret.length - s_half, s2, 0, s_half);
+
+ byte[] ls = concat(label, seed);
+
+ byte[] buf = new byte[size];
+ byte[] prf = new byte[size];
+ hmac_hash(new MD5Digest(), s1, ls, prf);
+ hmac_hash(new SHA1Digest(), s2, ls, buf);
+ for (int i = 0; i < size; i++)
+ {
+ buf[i] ^= prf[i];
+ }
+ return buf;
+ }
+
+ static byte[] PRF_1_2(Digest digest, byte[] secret, String asciiLabel, byte[] seed, int size)
+ {
+ byte[] label = Strings.toByteArray(asciiLabel);
+ byte[] labelSeed = concat(label, seed);
+
+ byte[] buf = new byte[size];
+ hmac_hash(digest, secret, labelSeed, buf);
+ return buf;
+ }
+
+ static byte[] concat(byte[] a, byte[] b)
+ {
+ byte[] c = new byte[a.length + b.length];
+ System.arraycopy(a, 0, c, 0, a.length);
+ System.arraycopy(b, 0, c, a.length, b.length);
+ return c;
+ }
+
+ static void validateKeyUsage(org.bc.asn1.x509.Certificate c, int keyUsageBits) throws IOException
+ {
+ Extensions exts = c.getTBSCertificate().getExtensions();
+ if (exts != null)
+ {
+ Extension ext = exts.getExtension(X509Extension.keyUsage);
+ if (ext != null)
+ {
+ KeyUsage ku = KeyUsage.getInstance(ext);
+ int bits = ku.getBytes()[0] & 0xff;
+ if ((bits & keyUsageBits) != keyUsageBits)
+ {
+ throw new TlsFatalAlert(AlertDescription.certificate_unknown);
+ }
+ }
+ }
+ }
+
+ static byte[] calculateKeyBlock(TlsClientContext context, int size)
+ {
+ ProtocolVersion pv = context.getServerVersion();
+ SecurityParameters sp = context.getSecurityParameters();
+ byte[] random = concat(sp.serverRandom, sp.clientRandom);
+
+ boolean isTls = pv.getFullVersion() >= ProtocolVersion.TLSv10.getFullVersion();
+
+ if (isTls)
+ {
+ return PRF(sp.masterSecret, "key expansion", random, size);
+ }
+
+ Digest md5 = new MD5Digest();
+ Digest sha1 = new SHA1Digest();
+ int md5Size = md5.getDigestSize();
+ byte[] shatmp = new byte[sha1.getDigestSize()];
+ byte[] tmp = new byte[size + md5Size];
+
+ int i = 0, pos = 0;
+ while (pos < size)
+ {
+ byte[] ssl3Const = SSL3_CONST[i];
+
+ sha1.update(ssl3Const, 0, ssl3Const.length);
+ sha1.update(sp.masterSecret, 0, sp.masterSecret.length);
+ sha1.update(random, 0, random.length);
+ sha1.doFinal(shatmp, 0);
+
+ md5.update(sp.masterSecret, 0, sp.masterSecret.length);
+ md5.update(shatmp, 0, shatmp.length);
+ md5.doFinal(tmp, pos);
+
+ pos += md5Size;
+ ++i;
+ }
+
+ byte rval[] = new byte[size];
+ System.arraycopy(tmp, 0, rval, 0, size);
+ return rval;
+ }
+
+ static byte[] calculateMasterSecret(TlsClientContext context, byte[] pms)
+ {
+ ProtocolVersion pv = context.getServerVersion();
+ SecurityParameters sp = context.getSecurityParameters();
+ byte[] random = concat(sp.clientRandom, sp.serverRandom);
+
+ boolean isTls = pv.getFullVersion() >= ProtocolVersion.TLSv10.getFullVersion();
+
+ if (isTls)
+ {
+ return PRF(pms, "master secret", random, 48);
+ }
+
+ Digest md5 = new MD5Digest();
+ Digest sha1 = new SHA1Digest();
+ int md5Size = md5.getDigestSize();
+ byte[] shatmp = new byte[sha1.getDigestSize()];
+
+ byte[] rval = new byte[md5Size * 3];
+ int pos = 0;
+
+ for (int i = 0; i < 3; ++i)
+ {
+ byte[] ssl3Const = SSL3_CONST[i];
+
+ sha1.update(ssl3Const, 0, ssl3Const.length);
+ sha1.update(pms, 0, pms.length);
+ sha1.update(random, 0, random.length);
+ sha1.doFinal(shatmp, 0);
+
+ md5.update(pms, 0, pms.length);
+ md5.update(shatmp, 0, shatmp.length);
+ md5.doFinal(rval, pos);
+
+ pos += md5Size;
+ }
+
+ return rval;
+ }
+
+ static byte[] calculateVerifyData(TlsClientContext context, String asciiLabel, byte[] handshakeHash)
+ {
+ ProtocolVersion pv = context.getServerVersion();
+ SecurityParameters sp = context.getSecurityParameters();
+
+ boolean isTls = pv.getFullVersion() >= ProtocolVersion.TLSv10.getFullVersion();
+
+ if (isTls)
+ {
+ return PRF(sp.masterSecret, asciiLabel, handshakeHash, 12);
+ }
+
+ return handshakeHash;
+ }
+
+ static final byte[] SSL_CLIENT = { 0x43, 0x4C, 0x4E, 0x54 };
+ static final byte[] SSL_SERVER = { 0x53, 0x52, 0x56, 0x52 };
+
+ // SSL3 magic mix constants ("A", "BB", "CCC", ...)
+ static final byte[][] SSL3_CONST = genConst();
+
+ private static byte[][] genConst()
+ {
+ int n = 10;
+ byte[][] arr = new byte[n][];
+ for (int i = 0; i < n; i++)
+ {
+ byte[] b = new byte[i + 1];
+ Arrays.fill(b, (byte)('A' + i));
+ arr[i] = b;
+ }
+ return arr;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/util/Pack.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/util/Pack.java
new file mode 100644
index 0000000..c36d70c
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/util/Pack.java
@@ -0,0 +1,100 @@
+package org.bc.crypto.util;
+
+public abstract class Pack
+{
+ public static int bigEndianToInt(byte[] bs, int off)
+ {
+ int n = bs[ off] << 24;
+ n |= (bs[++off] & 0xff) << 16;
+ n |= (bs[++off] & 0xff) << 8;
+ n |= (bs[++off] & 0xff);
+ return n;
+ }
+
+ public static void bigEndianToInt(byte[] bs, int off, int[] ns)
+ {
+ for (int i = 0; i < ns.length; ++i)
+ {
+ ns[i] = bigEndianToInt(bs, off);
+ off += 4;
+ }
+ }
+
+ public static void intToBigEndian(int n, byte[] bs, int off)
+ {
+ bs[ off] = (byte)(n >>> 24);
+ bs[++off] = (byte)(n >>> 16);
+ bs[++off] = (byte)(n >>> 8);
+ bs[++off] = (byte)(n );
+ }
+
+ public static void intToBigEndian(int[] ns, byte[] bs, int off)
+ {
+ for (int i = 0; i < ns.length; ++i)
+ {
+ intToBigEndian(ns[i], bs, off);
+ off += 4;
+ }
+ }
+
+ public static long bigEndianToLong(byte[] bs, int off)
+ {
+ int hi = bigEndianToInt(bs, off);
+ int lo = bigEndianToInt(bs, off + 4);
+ return ((long)(hi & 0xffffffffL) << 32) | (long)(lo & 0xffffffffL);
+ }
+
+ public static void longToBigEndian(long n, byte[] bs, int off)
+ {
+ intToBigEndian((int)(n >>> 32), bs, off);
+ intToBigEndian((int)(n & 0xffffffffL), bs, off + 4);
+ }
+
+ public static int littleEndianToInt(byte[] bs, int off)
+ {
+ int n = bs[ off] & 0xff;
+ n |= (bs[++off] & 0xff) << 8;
+ n |= (bs[++off] & 0xff) << 16;
+ n |= bs[++off] << 24;
+ return n;
+ }
+
+ public static void littleEndianToInt(byte[] bs, int off, int[] ns)
+ {
+ for (int i = 0; i < ns.length; ++i)
+ {
+ ns[i] = littleEndianToInt(bs, off);
+ off += 4;
+ }
+ }
+
+ public static void intToLittleEndian(int n, byte[] bs, int off)
+ {
+ bs[ off] = (byte)(n );
+ bs[++off] = (byte)(n >>> 8);
+ bs[++off] = (byte)(n >>> 16);
+ bs[++off] = (byte)(n >>> 24);
+ }
+
+ public static void intToLittleEndian(int[] ns, byte[] bs, int off)
+ {
+ for (int i = 0; i < ns.length; ++i)
+ {
+ intToLittleEndian(ns[i], bs, off);
+ off += 4;
+ }
+ }
+
+ public static long littleEndianToLong(byte[] bs, int off)
+ {
+ int lo = littleEndianToInt(bs, off);
+ int hi = littleEndianToInt(bs, off + 4);
+ return ((long)(hi & 0xffffffffL) << 32) | (long)(lo & 0xffffffffL);
+ }
+
+ public static void longToLittleEndian(long n, byte[] bs, int off)
+ {
+ intToLittleEndian((int)(n & 0xffffffffL), bs, off);
+ intToLittleEndian((int)(n >>> 32), bs, off + 4);
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/util/PrivateKeyFactory.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/util/PrivateKeyFactory.java
new file mode 100644
index 0000000..c2a4691
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/util/PrivateKeyFactory.java
@@ -0,0 +1,170 @@
+package org.bc.crypto.util;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.math.BigInteger;
+
+import org.bc.asn1.ASN1Encodable;
+import org.bc.asn1.ASN1InputStream;
+import org.bc.asn1.ASN1Integer;
+import org.bc.asn1.ASN1ObjectIdentifier;
+import org.bc.asn1.ASN1Primitive;
+import org.bc.asn1.ASN1Sequence;
+import org.bc.asn1.nist.NISTNamedCurves;
+import org.bc.asn1.oiw.ElGamalParameter;
+import org.bc.asn1.oiw.OIWObjectIdentifiers;
+import org.bc.asn1.pkcs.DHParameter;
+import org.bc.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bc.asn1.pkcs.PrivateKeyInfo;
+import org.bc.asn1.pkcs.RSAPrivateKey;
+import org.bc.asn1.sec.ECPrivateKey;
+import org.bc.asn1.sec.SECNamedCurves;
+import org.bc.asn1.teletrust.TeleTrusTNamedCurves;
+import org.bc.asn1.x509.AlgorithmIdentifier;
+import org.bc.asn1.x509.DSAParameter;
+import org.bc.asn1.x9.X962NamedCurves;
+import org.bc.asn1.x9.X962Parameters;
+import org.bc.asn1.x9.X9ECParameters;
+import org.bc.asn1.x9.X9ObjectIdentifiers;
+import org.bc.crypto.params.AsymmetricKeyParameter;
+import org.bc.crypto.params.DHParameters;
+import org.bc.crypto.params.DHPrivateKeyParameters;
+import org.bc.crypto.params.DSAParameters;
+import org.bc.crypto.params.DSAPrivateKeyParameters;
+import org.bc.crypto.params.ECDomainParameters;
+import org.bc.crypto.params.ECPrivateKeyParameters;
+import org.bc.crypto.params.ElGamalParameters;
+import org.bc.crypto.params.ElGamalPrivateKeyParameters;
+import org.bc.crypto.params.RSAPrivateCrtKeyParameters;
+
+/**
+ * Factory for creating private key objects from PKCS8 PrivateKeyInfo objects.
+ */
+public class PrivateKeyFactory
+{
+ /**
+ * Create a private key parameter from a PKCS8 PrivateKeyInfo encoding.
+ *
+ * @param privateKeyInfoData the PrivateKeyInfo encoding
+ * @return a suitable private key parameter
+ * @throws IOException on an error decoding the key
+ */
+ public static AsymmetricKeyParameter createKey(byte[] privateKeyInfoData) throws IOException
+ {
+ return createKey(PrivateKeyInfo.getInstance(ASN1Primitive.fromByteArray(privateKeyInfoData)));
+ }
+
+ /**
+ * Create a private key parameter from a PKCS8 PrivateKeyInfo encoding read from a
+ * stream.
+ *
+ * @param inStr the stream to read the PrivateKeyInfo encoding from
+ * @return a suitable private key parameter
+ * @throws IOException on an error decoding the key
+ */
+ public static AsymmetricKeyParameter createKey(InputStream inStr) throws IOException
+ {
+ return createKey(PrivateKeyInfo.getInstance(new ASN1InputStream(inStr).readObject()));
+ }
+
+ /**
+ * Create a private key parameter from the passed in PKCS8 PrivateKeyInfo object.
+ *
+ * @param keyInfo the PrivateKeyInfo object containing the key material
+ * @return a suitable private key parameter
+ * @throws IOException on an error decoding the key
+ */
+ public static AsymmetricKeyParameter createKey(PrivateKeyInfo keyInfo) throws IOException
+ {
+ AlgorithmIdentifier algId = keyInfo.getPrivateKeyAlgorithm();
+
+ if (algId.getAlgorithm().equals(PKCSObjectIdentifiers.rsaEncryption))
+ {
+ RSAPrivateKey keyStructure = RSAPrivateKey.getInstance(keyInfo.parsePrivateKey());
+
+ return new RSAPrivateCrtKeyParameters(keyStructure.getModulus(),
+ keyStructure.getPublicExponent(), keyStructure.getPrivateExponent(),
+ keyStructure.getPrime1(), keyStructure.getPrime2(), keyStructure.getExponent1(),
+ keyStructure.getExponent2(), keyStructure.getCoefficient());
+ }
+ // TODO?
+// else if (algId.getObjectId().equals(X9ObjectIdentifiers.dhpublicnumber))
+ else if (algId.getAlgorithm().equals(PKCSObjectIdentifiers.dhKeyAgreement))
+ {
+ DHParameter params = DHParameter.getInstance(algId.getParameters());
+ ASN1Integer derX = (ASN1Integer)keyInfo.parsePrivateKey();
+
+ BigInteger lVal = params.getL();
+ int l = lVal == null ? 0 : lVal.intValue();
+ DHParameters dhParams = new DHParameters(params.getP(), params.getG(), null, l);
+
+ return new DHPrivateKeyParameters(derX.getValue(), dhParams);
+ }
+ else if (algId.getAlgorithm().equals(OIWObjectIdentifiers.elGamalAlgorithm))
+ {
+ ElGamalParameter params = new ElGamalParameter((ASN1Sequence)algId.getParameters());
+ ASN1Integer derX = (ASN1Integer)keyInfo.parsePrivateKey();
+
+ return new ElGamalPrivateKeyParameters(derX.getValue(), new ElGamalParameters(
+ params.getP(), params.getG()));
+ }
+ else if (algId.getAlgorithm().equals(X9ObjectIdentifiers.id_dsa))
+ {
+ ASN1Integer derX = (ASN1Integer)keyInfo.parsePrivateKey();
+ ASN1Encodable de = algId.getParameters();
+
+ DSAParameters parameters = null;
+ if (de != null)
+ {
+ DSAParameter params = DSAParameter.getInstance(de.toASN1Primitive());
+ parameters = new DSAParameters(params.getP(), params.getQ(), params.getG());
+ }
+
+ return new DSAPrivateKeyParameters(derX.getValue(), parameters);
+ }
+ else if (algId.getAlgorithm().equals(X9ObjectIdentifiers.id_ecPublicKey))
+ {
+ X962Parameters params = new X962Parameters((ASN1Primitive)algId.getParameters());
+
+ X9ECParameters x9;
+ if (params.isNamedCurve())
+ {
+ ASN1ObjectIdentifier oid = ASN1ObjectIdentifier.getInstance(params.getParameters());
+ x9 = X962NamedCurves.getByOID(oid);
+
+ if (x9 == null)
+ {
+ x9 = SECNamedCurves.getByOID(oid);
+
+ if (x9 == null)
+ {
+ x9 = NISTNamedCurves.getByOID(oid);
+
+ if (x9 == null)
+ {
+ x9 = TeleTrusTNamedCurves.getByOID(oid);
+ }
+ }
+ }
+ }
+ else
+ {
+ x9 = X9ECParameters.getInstance(params.getParameters());
+ }
+
+ ECPrivateKey ec = ECPrivateKey.getInstance(keyInfo.parsePrivateKey());
+ BigInteger d = ec.getKey();
+
+ // TODO We lose any named parameters here
+
+ ECDomainParameters dParams = new ECDomainParameters(
+ x9.getCurve(), x9.getG(), x9.getN(), x9.getH(), x9.getSeed());
+
+ return new ECPrivateKeyParameters(d, dParams);
+ }
+ else
+ {
+ throw new RuntimeException("algorithm identifier in key not recognised");
+ }
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/util/PrivateKeyInfoFactory.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/util/PrivateKeyInfoFactory.java
new file mode 100644
index 0000000..e960034
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/util/PrivateKeyInfoFactory.java
@@ -0,0 +1,51 @@
+package org.bc.crypto.util;
+
+import java.io.IOException;
+
+import org.bc.asn1.ASN1Integer;
+import org.bc.asn1.DERNull;
+import org.bc.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bc.asn1.pkcs.PrivateKeyInfo;
+import org.bc.asn1.pkcs.RSAPrivateKey;
+import org.bc.asn1.x509.AlgorithmIdentifier;
+import org.bc.asn1.x509.DSAParameter;
+import org.bc.asn1.x9.X9ObjectIdentifiers;
+import org.bc.crypto.params.AsymmetricKeyParameter;
+import org.bc.crypto.params.DSAParameters;
+import org.bc.crypto.params.DSAPrivateKeyParameters;
+import org.bc.crypto.params.RSAKeyParameters;
+import org.bc.crypto.params.RSAPrivateCrtKeyParameters;
+
+/**
+ * Factory to create ASN.1 private key info objects from lightweight private keys.
+ */
+public class PrivateKeyInfoFactory
+{
+ /**
+ * Create a PrivateKeyInfo representation of a private key.
+ *
+ * @param privateKey the SubjectPublicKeyInfo encoding
+ * @return the appropriate key parameter
+ * @throws java.io.IOException on an error encoding the key
+ */
+ public static PrivateKeyInfo createPrivateKeyInfo(AsymmetricKeyParameter privateKey) throws IOException
+ {
+ if (privateKey instanceof RSAKeyParameters)
+ {
+ RSAPrivateCrtKeyParameters priv = (RSAPrivateCrtKeyParameters)privateKey;
+
+ return new PrivateKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE), new RSAPrivateKey(priv.getModulus(), priv.getPublicExponent(), priv.getExponent(), priv.getP(), priv.getQ(), priv.getDP(), priv.getDQ(), priv.getQInv()));
+ }
+ else if (privateKey instanceof DSAPrivateKeyParameters)
+ {
+ DSAPrivateKeyParameters priv = (DSAPrivateKeyParameters)privateKey;
+ DSAParameters params = priv.getParameters();
+
+ return new PrivateKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_dsa, new DSAParameter(params.getP(), params.getQ(), params.getG())), new ASN1Integer(priv.getX()));
+ }
+ else
+ {
+ throw new IOException("key parameters not recognised.");
+ }
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/util/PublicKeyFactory.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/util/PublicKeyFactory.java
new file mode 100644
index 0000000..85db012
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/util/PublicKeyFactory.java
@@ -0,0 +1,207 @@
+package org.bc.crypto.util;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.math.BigInteger;
+
+import org.bc.asn1.ASN1Encodable;
+import org.bc.asn1.ASN1InputStream;
+import org.bc.asn1.ASN1Integer;
+import org.bc.asn1.ASN1ObjectIdentifier;
+import org.bc.asn1.ASN1OctetString;
+import org.bc.asn1.ASN1Primitive;
+import org.bc.asn1.ASN1Sequence;
+import org.bc.asn1.DEROctetString;
+import org.bc.asn1.nist.NISTNamedCurves;
+import org.bc.asn1.oiw.ElGamalParameter;
+import org.bc.asn1.oiw.OIWObjectIdentifiers;
+import org.bc.asn1.pkcs.DHParameter;
+import org.bc.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bc.asn1.pkcs.RSAPublicKey;
+import org.bc.asn1.sec.SECNamedCurves;
+import org.bc.asn1.teletrust.TeleTrusTNamedCurves;
+import org.bc.asn1.x509.AlgorithmIdentifier;
+import org.bc.asn1.x509.DSAParameter;
+import org.bc.asn1.x509.SubjectPublicKeyInfo;
+import org.bc.asn1.x509.X509ObjectIdentifiers;
+import org.bc.asn1.x9.DHDomainParameters;
+import org.bc.asn1.x9.DHPublicKey;
+import org.bc.asn1.x9.DHValidationParms;
+import org.bc.asn1.x9.X962NamedCurves;
+import org.bc.asn1.x9.X962Parameters;
+import org.bc.asn1.x9.X9ECParameters;
+import org.bc.asn1.x9.X9ECPoint;
+import org.bc.asn1.x9.X9ObjectIdentifiers;
+import org.bc.crypto.params.AsymmetricKeyParameter;
+import org.bc.crypto.params.DHParameters;
+import org.bc.crypto.params.DHPublicKeyParameters;
+import org.bc.crypto.params.DHValidationParameters;
+import org.bc.crypto.params.DSAParameters;
+import org.bc.crypto.params.DSAPublicKeyParameters;
+import org.bc.crypto.params.ECDomainParameters;
+import org.bc.crypto.params.ECPublicKeyParameters;
+import org.bc.crypto.params.ElGamalParameters;
+import org.bc.crypto.params.ElGamalPublicKeyParameters;
+import org.bc.crypto.params.RSAKeyParameters;
+
+/**
+ * Factory to create asymmetric public key parameters for asymmetric ciphers from range of
+ * ASN.1 encoded SubjectPublicKeyInfo objects.
+ */
+public class PublicKeyFactory
+{
+ /**
+ * Create a public key from a SubjectPublicKeyInfo encoding
+ *
+ * @param keyInfoData the SubjectPublicKeyInfo encoding
+ * @return the appropriate key parameter
+ * @throws IOException on an error decoding the key
+ */
+ public static AsymmetricKeyParameter createKey(byte[] keyInfoData) throws IOException
+ {
+ return createKey(SubjectPublicKeyInfo.getInstance(ASN1Primitive.fromByteArray(keyInfoData)));
+ }
+
+ /**
+ * Create a public key from a SubjectPublicKeyInfo encoding read from a stream
+ *
+ * @param inStr the stream to read the SubjectPublicKeyInfo encoding from
+ * @return the appropriate key parameter
+ * @throws IOException on an error decoding the key
+ */
+ public static AsymmetricKeyParameter createKey(InputStream inStr) throws IOException
+ {
+ return createKey(SubjectPublicKeyInfo.getInstance(new ASN1InputStream(inStr).readObject()));
+ }
+
+ /**
+ * Create a public key from the passed in SubjectPublicKeyInfo
+ *
+ * @param keyInfo the SubjectPublicKeyInfo containing the key data
+ * @return the appropriate key parameter
+ * @throws IOException on an error decoding the key
+ */
+ public static AsymmetricKeyParameter createKey(SubjectPublicKeyInfo keyInfo) throws IOException
+ {
+ AlgorithmIdentifier algId = keyInfo.getAlgorithm();
+
+ if (algId.getAlgorithm().equals(PKCSObjectIdentifiers.rsaEncryption)
+ || algId.getAlgorithm().equals(X509ObjectIdentifiers.id_ea_rsa))
+ {
+ RSAPublicKey pubKey = RSAPublicKey.getInstance(keyInfo.parsePublicKey());
+
+ return new RSAKeyParameters(false, pubKey.getModulus(), pubKey.getPublicExponent());
+ }
+ else if (algId.getAlgorithm().equals(X9ObjectIdentifiers.dhpublicnumber))
+ {
+ DHPublicKey dhPublicKey = DHPublicKey.getInstance(keyInfo.parsePublicKey());
+
+ BigInteger y = dhPublicKey.getY().getValue();
+
+ DHDomainParameters dhParams = DHDomainParameters.getInstance(algId.getParameters());
+
+ BigInteger p = dhParams.getP().getValue();
+ BigInteger g = dhParams.getG().getValue();
+ BigInteger q = dhParams.getQ().getValue();
+
+ BigInteger j = null;
+ if (dhParams.getJ() != null)
+ {
+ j = dhParams.getJ().getValue();
+ }
+
+ DHValidationParameters validation = null;
+ DHValidationParms dhValidationParms = dhParams.getValidationParms();
+ if (dhValidationParms != null)
+ {
+ byte[] seed = dhValidationParms.getSeed().getBytes();
+ BigInteger pgenCounter = dhValidationParms.getPgenCounter().getValue();
+
+ // TODO Check pgenCounter size?
+
+ validation = new DHValidationParameters(seed, pgenCounter.intValue());
+ }
+
+ return new DHPublicKeyParameters(y, new DHParameters(p, g, q, j, validation));
+ }
+ else if (algId.getAlgorithm().equals(PKCSObjectIdentifiers.dhKeyAgreement))
+ {
+ DHParameter params = DHParameter.getInstance(algId.getParameters());
+ ASN1Integer derY = (ASN1Integer)keyInfo.parsePublicKey();
+
+ BigInteger lVal = params.getL();
+ int l = lVal == null ? 0 : lVal.intValue();
+ DHParameters dhParams = new DHParameters(params.getP(), params.getG(), null, l);
+
+ return new DHPublicKeyParameters(derY.getValue(), dhParams);
+ }
+ else if (algId.getAlgorithm().equals(OIWObjectIdentifiers.elGamalAlgorithm))
+ {
+ ElGamalParameter params = new ElGamalParameter((ASN1Sequence)algId.getParameters());
+ ASN1Integer derY = (ASN1Integer)keyInfo.parsePublicKey();
+
+ return new ElGamalPublicKeyParameters(derY.getValue(), new ElGamalParameters(
+ params.getP(), params.getG()));
+ }
+ else if (algId.getAlgorithm().equals(X9ObjectIdentifiers.id_dsa)
+ || algId.getAlgorithm().equals(OIWObjectIdentifiers.dsaWithSHA1))
+ {
+ ASN1Integer derY = (ASN1Integer)keyInfo.parsePublicKey();
+ ASN1Encodable de = algId.getParameters();
+
+ DSAParameters parameters = null;
+ if (de != null)
+ {
+ DSAParameter params = DSAParameter.getInstance(de.toASN1Primitive());
+ parameters = new DSAParameters(params.getP(), params.getQ(), params.getG());
+ }
+
+ return new DSAPublicKeyParameters(derY.getValue(), parameters);
+ }
+ else if (algId.getAlgorithm().equals(X9ObjectIdentifiers.id_ecPublicKey))
+ {
+ X962Parameters params = new X962Parameters(
+ (ASN1Primitive)algId.getParameters());
+
+ X9ECParameters x9;
+ if (params.isNamedCurve())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)params.getParameters();
+ x9 = X962NamedCurves.getByOID(oid);
+
+ if (x9 == null)
+ {
+ x9 = SECNamedCurves.getByOID(oid);
+
+ if (x9 == null)
+ {
+ x9 = NISTNamedCurves.getByOID(oid);
+
+ if (x9 == null)
+ {
+ x9 = TeleTrusTNamedCurves.getByOID(oid);
+ }
+ }
+ }
+ }
+ else
+ {
+ x9 = X9ECParameters.getInstance(params.getParameters());
+ }
+
+ ASN1OctetString key = new DEROctetString(keyInfo.getPublicKeyData().getBytes());
+ X9ECPoint derQ = new X9ECPoint(x9.getCurve(), key);
+
+ // TODO We lose any named parameters here
+
+ ECDomainParameters dParams = new ECDomainParameters(
+ x9.getCurve(), x9.getG(), x9.getN(), x9.getH(), x9.getSeed());
+
+ return new ECPublicKeyParameters(derQ.getPoint(), dParams);
+ }
+ else
+ {
+ throw new RuntimeException("algorithm identifier in key not recognised");
+ }
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/util/SubjectPublicKeyInfoFactory.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/util/SubjectPublicKeyInfoFactory.java
new file mode 100644
index 0000000..06a85c5
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/crypto/util/SubjectPublicKeyInfoFactory.java
@@ -0,0 +1,47 @@
+package org.bc.crypto.util;
+
+import java.io.IOException;
+
+import org.bc.asn1.ASN1Integer;
+import org.bc.asn1.DERNull;
+import org.bc.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bc.asn1.pkcs.RSAPublicKey;
+import org.bc.asn1.x509.AlgorithmIdentifier;
+import org.bc.asn1.x509.SubjectPublicKeyInfo;
+import org.bc.asn1.x9.X9ObjectIdentifiers;
+import org.bc.crypto.params.AsymmetricKeyParameter;
+import org.bc.crypto.params.DSAPublicKeyParameters;
+import org.bc.crypto.params.RSAKeyParameters;
+
+/**
+ * Factory to create ASN.1 subject public key info objects from lightweight public keys.
+ */
+public class SubjectPublicKeyInfoFactory
+{
+ /**
+ * Create a SubjectPublicKeyInfo public key.
+ *
+ * @param publicKey the SubjectPublicKeyInfo encoding
+ * @return the appropriate key parameter
+ * @throws java.io.IOException on an error encoding the key
+ */
+ public static SubjectPublicKeyInfo createSubjectPublicKeyInfo(AsymmetricKeyParameter publicKey) throws IOException
+ {
+ if (publicKey instanceof RSAKeyParameters)
+ {
+ RSAKeyParameters pub = (RSAKeyParameters)publicKey;
+
+ return new SubjectPublicKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE), new RSAPublicKey(pub.getModulus(), pub.getExponent()));
+ }
+ else if (publicKey instanceof DSAPublicKeyParameters)
+ {
+ DSAPublicKeyParameters pub = (DSAPublicKeyParameters)publicKey;
+
+ return new SubjectPublicKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_dsa), new ASN1Integer(pub.getY()));
+ }
+ else
+ {
+ throw new IOException("key parameters not recognised.");
+ }
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ec/ECAlgorithms.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ec/ECAlgorithms.java
new file mode 100644
index 0000000..0c7e3b8
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ec/ECAlgorithms.java
@@ -0,0 +1,92 @@
+package org.bc.math.ec;
+
+import java.math.BigInteger;
+
+public class ECAlgorithms
+{
+ public static ECPoint sumOfTwoMultiplies(ECPoint P, BigInteger a,
+ ECPoint Q, BigInteger b)
+ {
+ ECCurve c = P.getCurve();
+ if (!c.equals(Q.getCurve()))
+ {
+ throw new IllegalArgumentException("P and Q must be on same curve");
+ }
+
+ // Point multiplication for Koblitz curves (using WTNAF) beats Shamir's trick
+ if (c instanceof ECCurve.F2m)
+ {
+ ECCurve.F2m f2mCurve = (ECCurve.F2m)c;
+ if (f2mCurve.isKoblitz())
+ {
+ return P.multiply(a).add(Q.multiply(b));
+ }
+ }
+
+ return implShamirsTrick(P, a, Q, b);
+ }
+
+ /*
+ * "Shamir's Trick", originally due to E. G. Straus
+ * (Addition chains of vectors. American Mathematical Monthly,
+ * 71(7):806-808, Aug./Sept. 1964)
+ *
+ * Input: The points P, Q, scalar k = (km?, ... , k1, k0)
+ * and scalar l = (lm?, ... , l1, l0).
+ * Output: R = k * P + l * Q.
+ * 1: Z <- P + Q
+ * 2: R <- O
+ * 3: for i from m-1 down to 0 do
+ * 4: R <- R + R {point doubling}
+ * 5: if (ki = 1) and (li = 0) then R <- R + P end if
+ * 6: if (ki = 0) and (li = 1) then R <- R + Q end if
+ * 7: if (ki = 1) and (li = 1) then R <- R + Z end if
+ * 8: end for
+ * 9: return R
+ *
+ */
+ public static ECPoint shamirsTrick(ECPoint P, BigInteger k,
+ ECPoint Q, BigInteger l)
+ {
+ if (!P.getCurve().equals(Q.getCurve()))
+ {
+ throw new IllegalArgumentException("P and Q must be on same curve");
+ }
+
+ return implShamirsTrick(P, k, Q, l);
+ }
+
+ private static ECPoint implShamirsTrick(ECPoint P, BigInteger k,
+ ECPoint Q, BigInteger l)
+ {
+ int m = Math.max(k.bitLength(), l.bitLength());
+ ECPoint Z = P.add(Q);
+ ECPoint R = P.getCurve().getInfinity();
+
+ for (int i = m - 1; i >= 0; --i)
+ {
+ R = R.twice();
+
+ if (k.testBit(i))
+ {
+ if (l.testBit(i))
+ {
+ R = R.add(Z);
+ }
+ else
+ {
+ R = R.add(P);
+ }
+ }
+ else
+ {
+ if (l.testBit(i))
+ {
+ R = R.add(Q);
+ }
+ }
+ }
+
+ return R;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ec/ECConstants.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ec/ECConstants.java
new file mode 100644
index 0000000..b6dfbf7
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ec/ECConstants.java
@@ -0,0 +1,12 @@
+package org.bc.math.ec;
+
+import java.math.BigInteger;
+
+public interface ECConstants
+{
+ public static final BigInteger ZERO = BigInteger.valueOf(0);
+ public static final BigInteger ONE = BigInteger.valueOf(1);
+ public static final BigInteger TWO = BigInteger.valueOf(2);
+ public static final BigInteger THREE = BigInteger.valueOf(3);
+ public static final BigInteger FOUR = BigInteger.valueOf(4);
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ec/ECCurve.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ec/ECCurve.java
new file mode 100644
index 0000000..b626ae8
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ec/ECCurve.java
@@ -0,0 +1,668 @@
+package org.bc.math.ec;
+
+import java.math.BigInteger;
+import java.util.Random;
+
+/**
+ * base class for an elliptic curve
+ */
+public abstract class ECCurve
+{
+ ECFieldElement a, b;
+
+ public abstract int getFieldSize();
+
+ public abstract ECFieldElement fromBigInteger(BigInteger x);
+
+ public abstract ECPoint createPoint(BigInteger x, BigInteger y, boolean withCompression);
+
+ public abstract ECPoint decodePoint(byte[] encoded);
+
+ public abstract ECPoint getInfinity();
+
+ public ECFieldElement getA()
+ {
+ return a;
+ }
+
+ public ECFieldElement getB()
+ {
+ return b;
+ }
+
+ /**
+ * Elliptic curve over Fp
+ */
+ public static class Fp extends ECCurve
+ {
+ BigInteger q;
+ ECPoint.Fp infinity;
+
+ public Fp(BigInteger q, BigInteger a, BigInteger b)
+ {
+ this.q = q;
+ this.a = fromBigInteger(a);
+ this.b = fromBigInteger(b);
+ this.infinity = new ECPoint.Fp(this, null, null);
+ }
+
+ public BigInteger getQ()
+ {
+ return q;
+ }
+
+ public int getFieldSize()
+ {
+ return q.bitLength();
+ }
+
+ public ECFieldElement fromBigInteger(BigInteger x)
+ {
+ return new ECFieldElement.Fp(this.q, x);
+ }
+
+ public ECPoint createPoint(BigInteger x, BigInteger y, boolean withCompression)
+ {
+ return new ECPoint.Fp(this, fromBigInteger(x), fromBigInteger(y), withCompression);
+ }
+
+ /**
+ * Decode a point on this curve from its ASN.1 encoding. The different
+ * encodings are taken account of, including point compression for
+ * Fp
(X9.62 s 4.2.1 pg 17).
+ * @return The decoded point.
+ */
+ public ECPoint decodePoint(byte[] encoded)
+ {
+ ECPoint p = null;
+
+ switch (encoded[0])
+ {
+ // infinity
+ case 0x00:
+ if (encoded.length > 1)
+ {
+ throw new RuntimeException("Invalid point encoding");
+ }
+ p = getInfinity();
+ break;
+ // compressed
+ case 0x02:
+ case 0x03:
+ int ytilde = encoded[0] & 1;
+ byte[] i = new byte[encoded.length - 1];
+
+ System.arraycopy(encoded, 1, i, 0, i.length);
+
+ ECFieldElement x = new ECFieldElement.Fp(this.q, new BigInteger(1, i));
+ ECFieldElement alpha = x.multiply(x.square().add(a)).add(b);
+ ECFieldElement beta = alpha.sqrt();
+
+ //
+ // if we can't find a sqrt we haven't got a point on the
+ // curve - run!
+ //
+ if (beta == null)
+ {
+ throw new RuntimeException("Invalid point compression");
+ }
+
+ int bit0 = (beta.toBigInteger().testBit(0) ? 1 : 0);
+
+ if (bit0 == ytilde)
+ {
+ p = new ECPoint.Fp(this, x, beta, true);
+ }
+ else
+ {
+ p = new ECPoint.Fp(this, x,
+ new ECFieldElement.Fp(this.q, q.subtract(beta.toBigInteger())), true);
+ }
+ break;
+ // uncompressed
+ case 0x04:
+ // hybrid
+ case 0x06:
+ case 0x07:
+ byte[] xEnc = new byte[(encoded.length - 1) / 2];
+ byte[] yEnc = new byte[(encoded.length - 1) / 2];
+
+ System.arraycopy(encoded, 1, xEnc, 0, xEnc.length);
+ System.arraycopy(encoded, xEnc.length + 1, yEnc, 0, yEnc.length);
+
+ p = new ECPoint.Fp(this,
+ new ECFieldElement.Fp(this.q, new BigInteger(1, xEnc)),
+ new ECFieldElement.Fp(this.q, new BigInteger(1, yEnc)));
+ break;
+ default:
+ throw new RuntimeException("Invalid point encoding 0x" + Integer.toString(encoded[0], 16));
+ }
+
+ return p;
+ }
+
+ public ECPoint getInfinity()
+ {
+ return infinity;
+ }
+
+ public boolean equals(
+ Object anObject)
+ {
+ if (anObject == this)
+ {
+ return true;
+ }
+
+ if (!(anObject instanceof ECCurve.Fp))
+ {
+ return false;
+ }
+
+ ECCurve.Fp other = (ECCurve.Fp) anObject;
+
+ return this.q.equals(other.q)
+ && a.equals(other.a) && b.equals(other.b);
+ }
+
+ public int hashCode()
+ {
+ return a.hashCode() ^ b.hashCode() ^ q.hashCode();
+ }
+ }
+
+ /**
+ * Elliptic curves over F2m. The Weierstrass equation is given by
+ * y2 + xy = x3 + ax2 + b
.
+ */
+ public static class F2m extends ECCurve
+ {
+ /**
+ * The exponent m
of F2m
.
+ */
+ private int m; // can't be final - JDK 1.1
+
+ /**
+ * TPB: The integer k
where xm +
+ * xk + 1
represents the reduction polynomial
+ * f(z)
.
+ * PPB: The integer k1
where xm +
+ * xk3 + xk2 + xk1 + 1
+ * represents the reduction polynomial f(z)
.
+ */
+ private int k1; // can't be final - JDK 1.1
+
+ /**
+ * TPB: Always set to 0
+ * PPB: The integer k2
where xm +
+ * xk3 + xk2 + xk1 + 1
+ * represents the reduction polynomial f(z)
.
+ */
+ private int k2; // can't be final - JDK 1.1
+
+ /**
+ * TPB: Always set to 0
+ * PPB: The integer k3
where xm +
+ * xk3 + xk2 + xk1 + 1
+ * represents the reduction polynomial f(z)
.
+ */
+ private int k3; // can't be final - JDK 1.1
+
+ /**
+ * The order of the base point of the curve.
+ */
+ private BigInteger n; // can't be final - JDK 1.1
+
+ /**
+ * The cofactor of the curve.
+ */
+ private BigInteger h; // can't be final - JDK 1.1
+
+ /**
+ * The point at infinity on this curve.
+ */
+ private ECPoint.F2m infinity; // can't be final - JDK 1.1
+
+ /**
+ * The parameter μ
of the elliptic curve if this is
+ * a Koblitz curve.
+ */
+ private byte mu = 0;
+
+ /**
+ * The auxiliary values s0
and
+ * s1
used for partial modular reduction for
+ * Koblitz curves.
+ */
+ private BigInteger[] si = null;
+
+ /**
+ * Constructor for Trinomial Polynomial Basis (TPB).
+ * @param m The exponent m
of
+ * F2m
.
+ * @param k The integer k
where xm +
+ * xk + 1
represents the reduction
+ * polynomial f(z)
.
+ * @param a The coefficient a
in the Weierstrass equation
+ * for non-supersingular elliptic curves over
+ * F2m
.
+ * @param b The coefficient b
in the Weierstrass equation
+ * for non-supersingular elliptic curves over
+ * F2m
.
+ */
+ public F2m(
+ int m,
+ int k,
+ BigInteger a,
+ BigInteger b)
+ {
+ this(m, k, 0, 0, a, b, null, null);
+ }
+
+ /**
+ * Constructor for Trinomial Polynomial Basis (TPB).
+ * @param m The exponent m
of
+ * F2m
.
+ * @param k The integer k
where xm +
+ * xk + 1
represents the reduction
+ * polynomial f(z)
.
+ * @param a The coefficient a
in the Weierstrass equation
+ * for non-supersingular elliptic curves over
+ * F2m
.
+ * @param b The coefficient b
in the Weierstrass equation
+ * for non-supersingular elliptic curves over
+ * F2m
.
+ * @param n The order of the main subgroup of the elliptic curve.
+ * @param h The cofactor of the elliptic curve, i.e.
+ * #Ea(F2m) = h * n
.
+ */
+ public F2m(
+ int m,
+ int k,
+ BigInteger a,
+ BigInteger b,
+ BigInteger n,
+ BigInteger h)
+ {
+ this(m, k, 0, 0, a, b, n, h);
+ }
+
+ /**
+ * Constructor for Pentanomial Polynomial Basis (PPB).
+ * @param m The exponent m
of
+ * F2m
.
+ * @param k1 The integer k1
where xm +
+ * xk3 + xk2 + xk1 + 1
+ * represents the reduction polynomial f(z)
.
+ * @param k2 The integer k2
where xm +
+ * xk3 + xk2 + xk1 + 1
+ * represents the reduction polynomial f(z)
.
+ * @param k3 The integer k3
where xm +
+ * xk3 + xk2 + xk1 + 1
+ * represents the reduction polynomial f(z)
.
+ * @param a The coefficient a
in the Weierstrass equation
+ * for non-supersingular elliptic curves over
+ * F2m
.
+ * @param b The coefficient b
in the Weierstrass equation
+ * for non-supersingular elliptic curves over
+ * F2m
.
+ */
+ public F2m(
+ int m,
+ int k1,
+ int k2,
+ int k3,
+ BigInteger a,
+ BigInteger b)
+ {
+ this(m, k1, k2, k3, a, b, null, null);
+ }
+
+ /**
+ * Constructor for Pentanomial Polynomial Basis (PPB).
+ * @param m The exponent m
of
+ * F2m
.
+ * @param k1 The integer k1
where xm +
+ * xk3 + xk2 + xk1 + 1
+ * represents the reduction polynomial f(z)
.
+ * @param k2 The integer k2
where xm +
+ * xk3 + xk2 + xk1 + 1
+ * represents the reduction polynomial f(z)
.
+ * @param k3 The integer k3
where xm +
+ * xk3 + xk2 + xk1 + 1
+ * represents the reduction polynomial f(z)
.
+ * @param a The coefficient a
in the Weierstrass equation
+ * for non-supersingular elliptic curves over
+ * F2m
.
+ * @param b The coefficient b
in the Weierstrass equation
+ * for non-supersingular elliptic curves over
+ * F2m
.
+ * @param n The order of the main subgroup of the elliptic curve.
+ * @param h The cofactor of the elliptic curve, i.e.
+ * #Ea(F2m) = h * n
.
+ */
+ public F2m(
+ int m,
+ int k1,
+ int k2,
+ int k3,
+ BigInteger a,
+ BigInteger b,
+ BigInteger n,
+ BigInteger h)
+ {
+ this.m = m;
+ this.k1 = k1;
+ this.k2 = k2;
+ this.k3 = k3;
+ this.n = n;
+ this.h = h;
+
+ if (k1 == 0)
+ {
+ throw new IllegalArgumentException("k1 must be > 0");
+ }
+
+ if (k2 == 0)
+ {
+ if (k3 != 0)
+ {
+ throw new IllegalArgumentException("k3 must be 0 if k2 == 0");
+ }
+ }
+ else
+ {
+ if (k2 <= k1)
+ {
+ throw new IllegalArgumentException("k2 must be > k1");
+ }
+
+ if (k3 <= k2)
+ {
+ throw new IllegalArgumentException("k3 must be > k2");
+ }
+ }
+
+ this.a = fromBigInteger(a);
+ this.b = fromBigInteger(b);
+ this.infinity = new ECPoint.F2m(this, null, null);
+ }
+
+ public int getFieldSize()
+ {
+ return m;
+ }
+
+ public ECFieldElement fromBigInteger(BigInteger x)
+ {
+ return new ECFieldElement.F2m(this.m, this.k1, this.k2, this.k3, x);
+ }
+
+ public ECPoint createPoint(BigInteger x, BigInteger y, boolean withCompression)
+ {
+ return new ECPoint.F2m(this, fromBigInteger(x), fromBigInteger(y), withCompression);
+ }
+
+ /* (non-Javadoc)
+ * @see org.bouncycastle.math.ec.ECCurve#decodePoint(byte[])
+ */
+ public ECPoint decodePoint(byte[] encoded)
+ {
+ ECPoint p = null;
+
+ switch (encoded[0])
+ {
+ // infinity
+ case 0x00:
+ if (encoded.length > 1)
+ {
+ throw new RuntimeException("Invalid point encoding");
+ }
+ p = getInfinity();
+ break;
+ // compressed
+ case 0x02:
+ case 0x03:
+ byte[] enc = new byte[encoded.length - 1];
+ System.arraycopy(encoded, 1, enc, 0, enc.length);
+ if (encoded[0] == 0x02)
+ {
+ p = decompressPoint(enc, 0);
+ }
+ else
+ {
+ p = decompressPoint(enc, 1);
+ }
+ break;
+ // uncompressed
+ case 0x04:
+ // hybrid
+ case 0x06:
+ case 0x07:
+ byte[] xEnc = new byte[(encoded.length - 1) / 2];
+ byte[] yEnc = new byte[(encoded.length - 1) / 2];
+
+ System.arraycopy(encoded, 1, xEnc, 0, xEnc.length);
+ System.arraycopy(encoded, xEnc.length + 1, yEnc, 0, yEnc.length);
+
+ p = new ECPoint.F2m(this,
+ new ECFieldElement.F2m(this.m, this.k1, this.k2, this.k3,
+ new BigInteger(1, xEnc)),
+ new ECFieldElement.F2m(this.m, this.k1, this.k2, this.k3,
+ new BigInteger(1, yEnc)), false);
+ break;
+
+ default:
+ throw new RuntimeException("Invalid point encoding 0x" + Integer.toString(encoded[0], 16));
+ }
+
+ return p;
+ }
+
+ public ECPoint getInfinity()
+ {
+ return infinity;
+ }
+
+ /**
+ * Returns true if this is a Koblitz curve (ABC curve).
+ * @return true if this is a Koblitz curve (ABC curve), false otherwise
+ */
+ public boolean isKoblitz()
+ {
+ return ((n != null) && (h != null) &&
+ ((a.toBigInteger().equals(ECConstants.ZERO)) ||
+ (a.toBigInteger().equals(ECConstants.ONE))) &&
+ (b.toBigInteger().equals(ECConstants.ONE)));
+ }
+
+ /**
+ * Returns the parameter μ
of the elliptic curve.
+ * @return μ
of the elliptic curve.
+ * @throws IllegalArgumentException if the given ECCurve is not a
+ * Koblitz curve.
+ */
+ synchronized byte getMu()
+ {
+ if (mu == 0)
+ {
+ mu = Tnaf.getMu(this);
+ }
+ return mu;
+ }
+
+ /**
+ * @return the auxiliary values s0
and
+ * s1
used for partial modular reduction for
+ * Koblitz curves.
+ */
+ synchronized BigInteger[] getSi()
+ {
+ if (si == null)
+ {
+ si = Tnaf.getSi(this);
+ }
+ return si;
+ }
+
+ /**
+ * Decompresses a compressed point P = (xp, yp) (X9.62 s 4.2.2).
+ *
+ * @param xEnc
+ * The encoding of field element xp.
+ * @param ypBit
+ * ~yp, an indication bit for the decompression of yp.
+ * @return the decompressed point.
+ */
+ private ECPoint decompressPoint(
+ byte[] xEnc,
+ int ypBit)
+ {
+ ECFieldElement xp = new ECFieldElement.F2m(
+ this.m, this.k1, this.k2, this.k3, new BigInteger(1, xEnc));
+ ECFieldElement yp = null;
+ if (xp.toBigInteger().equals(ECConstants.ZERO))
+ {
+ yp = (ECFieldElement.F2m)b;
+ for (int i = 0; i < m - 1; i++)
+ {
+ yp = yp.square();
+ }
+ }
+ else
+ {
+ ECFieldElement beta = xp.add(a).add(
+ b.multiply(xp.square().invert()));
+ ECFieldElement z = solveQuadradicEquation(beta);
+ if (z == null)
+ {
+ throw new RuntimeException("Invalid point compression");
+ }
+ int zBit = 0;
+ if (z.toBigInteger().testBit(0))
+ {
+ zBit = 1;
+ }
+ if (zBit != ypBit)
+ {
+ z = z.add(new ECFieldElement.F2m(this.m, this.k1, this.k2,
+ this.k3, ECConstants.ONE));
+ }
+ yp = xp.multiply(z);
+ }
+
+ return new ECPoint.F2m(this, xp, yp);
+ }
+
+ /**
+ * Solves a quadratic equation z2 + z = beta
(X9.62
+ * D.1.6) The other solution is z + 1
.
+ *
+ * @param beta
+ * The value to solve the qradratic equation for.
+ * @return the solution for z2 + z = beta
or
+ * null
if no solution exists.
+ */
+ private ECFieldElement solveQuadradicEquation(ECFieldElement beta)
+ {
+ ECFieldElement zeroElement = new ECFieldElement.F2m(
+ this.m, this.k1, this.k2, this.k3, ECConstants.ZERO);
+
+ if (beta.toBigInteger().equals(ECConstants.ZERO))
+ {
+ return zeroElement;
+ }
+
+ ECFieldElement z = null;
+ ECFieldElement gamma = zeroElement;
+
+ Random rand = new Random();
+ do
+ {
+ ECFieldElement t = new ECFieldElement.F2m(this.m, this.k1,
+ this.k2, this.k3, new BigInteger(m, rand));
+ z = zeroElement;
+ ECFieldElement w = beta;
+ for (int i = 1; i <= m - 1; i++)
+ {
+ ECFieldElement w2 = w.square();
+ z = z.square().add(w2.multiply(t));
+ w = w2.add(beta);
+ }
+ if (!w.toBigInteger().equals(ECConstants.ZERO))
+ {
+ return null;
+ }
+ gamma = z.square().add(z);
+ }
+ while (gamma.toBigInteger().equals(ECConstants.ZERO));
+
+ return z;
+ }
+
+ public boolean equals(
+ Object anObject)
+ {
+ if (anObject == this)
+ {
+ return true;
+ }
+
+ if (!(anObject instanceof ECCurve.F2m))
+ {
+ return false;
+ }
+
+ ECCurve.F2m other = (ECCurve.F2m)anObject;
+
+ return (this.m == other.m) && (this.k1 == other.k1)
+ && (this.k2 == other.k2) && (this.k3 == other.k3)
+ && a.equals(other.a) && b.equals(other.b);
+ }
+
+ public int hashCode()
+ {
+ return this.a.hashCode() ^ this.b.hashCode() ^ m ^ k1 ^ k2 ^ k3;
+ }
+
+ public int getM()
+ {
+ return m;
+ }
+
+ /**
+ * Return true if curve uses a Trinomial basis.
+ *
+ * @return true if curve Trinomial, false otherwise.
+ */
+ public boolean isTrinomial()
+ {
+ return k2 == 0 && k3 == 0;
+ }
+
+ public int getK1()
+ {
+ return k1;
+ }
+
+ public int getK2()
+ {
+ return k2;
+ }
+
+ public int getK3()
+ {
+ return k3;
+ }
+
+ public BigInteger getN()
+ {
+ return n;
+ }
+
+ public BigInteger getH()
+ {
+ return h;
+ }
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ec/ECFieldElement.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ec/ECFieldElement.java
new file mode 100644
index 0000000..da77e44
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ec/ECFieldElement.java
@@ -0,0 +1,1196 @@
+package org.bc.math.ec;
+
+import java.math.BigInteger;
+import java.util.Random;
+
+public abstract class ECFieldElement
+ implements ECConstants
+{
+
+ public abstract BigInteger toBigInteger();
+ public abstract String getFieldName();
+ public abstract int getFieldSize();
+ public abstract ECFieldElement add(ECFieldElement b);
+ public abstract ECFieldElement subtract(ECFieldElement b);
+ public abstract ECFieldElement multiply(ECFieldElement b);
+ public abstract ECFieldElement divide(ECFieldElement b);
+ public abstract ECFieldElement negate();
+ public abstract ECFieldElement square();
+ public abstract ECFieldElement invert();
+ public abstract ECFieldElement sqrt();
+
+ public String toString()
+ {
+ return this.toBigInteger().toString(2);
+ }
+
+ public static class Fp extends ECFieldElement
+ {
+ BigInteger x;
+
+ BigInteger q;
+
+ public Fp(BigInteger q, BigInteger x)
+ {
+ this.x = x;
+
+ if (x.compareTo(q) >= 0)
+ {
+ throw new IllegalArgumentException("x value too large in field element");
+ }
+
+ this.q = q;
+ }
+
+ public BigInteger toBigInteger()
+ {
+ return x;
+ }
+
+ /**
+ * return the field name for this field.
+ *
+ * @return the string "Fp".
+ */
+ public String getFieldName()
+ {
+ return "Fp";
+ }
+
+ public int getFieldSize()
+ {
+ return q.bitLength();
+ }
+
+ public BigInteger getQ()
+ {
+ return q;
+ }
+
+ public ECFieldElement add(ECFieldElement b)
+ {
+ return new Fp(q, x.add(b.toBigInteger()).mod(q));
+ }
+
+ public ECFieldElement subtract(ECFieldElement b)
+ {
+ return new Fp(q, x.subtract(b.toBigInteger()).mod(q));
+ }
+
+ public ECFieldElement multiply(ECFieldElement b)
+ {
+ return new Fp(q, x.multiply(b.toBigInteger()).mod(q));
+ }
+
+ public ECFieldElement divide(ECFieldElement b)
+ {
+ return new Fp(q, x.multiply(b.toBigInteger().modInverse(q)).mod(q));
+ }
+
+ public ECFieldElement negate()
+ {
+ return new Fp(q, x.negate().mod(q));
+ }
+
+ public ECFieldElement square()
+ {
+ return new Fp(q, x.multiply(x).mod(q));
+ }
+
+ public ECFieldElement invert()
+ {
+ return new Fp(q, x.modInverse(q));
+ }
+
+ // D.1.4 91
+ /**
+ * return a sqrt root - the routine verifies that the calculation
+ * returns the right value - if none exists it returns null.
+ */
+ public ECFieldElement sqrt()
+ {
+ if (!q.testBit(0))
+ {
+ throw new RuntimeException("not done yet");
+ }
+
+ // note: even though this class implements ECConstants don't be tempted to
+ // remove the explicit declaration, some J2ME environments don't cope.
+ // p mod 4 == 3
+ if (q.testBit(1))
+ {
+ // z = g^(u+1) + p, p = 4u + 3
+ ECFieldElement z = new Fp(q, x.modPow(q.shiftRight(2).add(ECConstants.ONE), q));
+
+ return z.square().equals(this) ? z : null;
+ }
+
+ // p mod 4 == 1
+ BigInteger qMinusOne = q.subtract(ECConstants.ONE);
+
+ BigInteger legendreExponent = qMinusOne.shiftRight(1);
+ if (!(x.modPow(legendreExponent, q).equals(ECConstants.ONE)))
+ {
+ return null;
+ }
+
+ BigInteger u = qMinusOne.shiftRight(2);
+ BigInteger k = u.shiftLeft(1).add(ECConstants.ONE);
+
+ BigInteger Q = this.x;
+ BigInteger fourQ = Q.shiftLeft(2).mod(q);
+
+ BigInteger U, V;
+ Random rand = new Random();
+ do
+ {
+ BigInteger P;
+ do
+ {
+ P = new BigInteger(q.bitLength(), rand);
+ }
+ while (P.compareTo(q) >= 0
+ || !(P.multiply(P).subtract(fourQ).modPow(legendreExponent, q).equals(qMinusOne)));
+
+ BigInteger[] result = lucasSequence(q, P, Q, k);
+ U = result[0];
+ V = result[1];
+
+ if (V.multiply(V).mod(q).equals(fourQ))
+ {
+ // Integer division by 2, mod q
+ if (V.testBit(0))
+ {
+ V = V.add(q);
+ }
+
+ V = V.shiftRight(1);
+
+ //assert V.multiply(V).mod(q).equals(x);
+
+ return new ECFieldElement.Fp(q, V);
+ }
+ }
+ while (U.equals(ECConstants.ONE) || U.equals(qMinusOne));
+
+ return null;
+
+// BigInteger qMinusOne = q.subtract(ECConstants.ONE);
+// BigInteger legendreExponent = qMinusOne.shiftRight(1); //divide(ECConstants.TWO);
+// if (!(x.modPow(legendreExponent, q).equals(ECConstants.ONE)))
+// {
+// return null;
+// }
+//
+// Random rand = new Random();
+// BigInteger fourX = x.shiftLeft(2);
+//
+// BigInteger r;
+// do
+// {
+// r = new BigInteger(q.bitLength(), rand);
+// }
+// while (r.compareTo(q) >= 0
+// || !(r.multiply(r).subtract(fourX).modPow(legendreExponent, q).equals(qMinusOne)));
+//
+// BigInteger n1 = qMinusOne.shiftRight(2); //.divide(ECConstants.FOUR);
+// BigInteger n2 = n1.add(ECConstants.ONE); //q.add(ECConstants.THREE).divide(ECConstants.FOUR);
+//
+// BigInteger wOne = WOne(r, x, q);
+// BigInteger wSum = W(n1, wOne, q).add(W(n2, wOne, q)).mod(q);
+// BigInteger twoR = r.shiftLeft(1); //ECConstants.TWO.multiply(r);
+//
+// BigInteger root = twoR.modPow(q.subtract(ECConstants.TWO), q)
+// .multiply(x).mod(q)
+// .multiply(wSum).mod(q);
+//
+// return new Fp(q, root);
+ }
+
+// private static BigInteger W(BigInteger n, BigInteger wOne, BigInteger p)
+// {
+// if (n.equals(ECConstants.ONE))
+// {
+// return wOne;
+// }
+// boolean isEven = !n.testBit(0);
+// n = n.shiftRight(1);//divide(ECConstants.TWO);
+// if (isEven)
+// {
+// BigInteger w = W(n, wOne, p);
+// return w.multiply(w).subtract(ECConstants.TWO).mod(p);
+// }
+// BigInteger w1 = W(n.add(ECConstants.ONE), wOne, p);
+// BigInteger w2 = W(n, wOne, p);
+// return w1.multiply(w2).subtract(wOne).mod(p);
+// }
+//
+// private BigInteger WOne(BigInteger r, BigInteger x, BigInteger p)
+// {
+// return r.multiply(r).multiply(x.modPow(q.subtract(ECConstants.TWO), q)).subtract(ECConstants.TWO).mod(p);
+// }
+
+ private static BigInteger[] lucasSequence(
+ BigInteger p,
+ BigInteger P,
+ BigInteger Q,
+ BigInteger k)
+ {
+ int n = k.bitLength();
+ int s = k.getLowestSetBit();
+
+ BigInteger Uh = ECConstants.ONE;
+ BigInteger Vl = ECConstants.TWO;
+ BigInteger Vh = P;
+ BigInteger Ql = ECConstants.ONE;
+ BigInteger Qh = ECConstants.ONE;
+
+ for (int j = n - 1; j >= s + 1; --j)
+ {
+ Ql = Ql.multiply(Qh).mod(p);
+
+ if (k.testBit(j))
+ {
+ Qh = Ql.multiply(Q).mod(p);
+ Uh = Uh.multiply(Vh).mod(p);
+ Vl = Vh.multiply(Vl).subtract(P.multiply(Ql)).mod(p);
+ Vh = Vh.multiply(Vh).subtract(Qh.shiftLeft(1)).mod(p);
+ }
+ else
+ {
+ Qh = Ql;
+ Uh = Uh.multiply(Vl).subtract(Ql).mod(p);
+ Vh = Vh.multiply(Vl).subtract(P.multiply(Ql)).mod(p);
+ Vl = Vl.multiply(Vl).subtract(Ql.shiftLeft(1)).mod(p);
+ }
+ }
+
+ Ql = Ql.multiply(Qh).mod(p);
+ Qh = Ql.multiply(Q).mod(p);
+ Uh = Uh.multiply(Vl).subtract(Ql).mod(p);
+ Vl = Vh.multiply(Vl).subtract(P.multiply(Ql)).mod(p);
+ Ql = Ql.multiply(Qh).mod(p);
+
+ for (int j = 1; j <= s; ++j)
+ {
+ Uh = Uh.multiply(Vl).mod(p);
+ Vl = Vl.multiply(Vl).subtract(Ql.shiftLeft(1)).mod(p);
+ Ql = Ql.multiply(Ql).mod(p);
+ }
+
+ return new BigInteger[]{ Uh, Vl };
+ }
+
+ public boolean equals(Object other)
+ {
+ if (other == this)
+ {
+ return true;
+ }
+
+ if (!(other instanceof ECFieldElement.Fp))
+ {
+ return false;
+ }
+
+ ECFieldElement.Fp o = (ECFieldElement.Fp)other;
+ return q.equals(o.q) && x.equals(o.x);
+ }
+
+ public int hashCode()
+ {
+ return q.hashCode() ^ x.hashCode();
+ }
+ }
+
+// /**
+// * Class representing the Elements of the finite field
+// * F2m
in polynomial basis (PB)
+// * representation. Both trinomial (TPB) and pentanomial (PPB) polynomial
+// * basis representations are supported. Gaussian normal basis (GNB)
+// * representation is not supported.
+// */
+// public static class F2m extends ECFieldElement
+// {
+// BigInteger x;
+//
+// /**
+// * Indicates gaussian normal basis representation (GNB). Number chosen
+// * according to X9.62. GNB is not implemented at present.
+// */
+// public static final int GNB = 1;
+//
+// /**
+// * Indicates trinomial basis representation (TPB). Number chosen
+// * according to X9.62.
+// */
+// public static final int TPB = 2;
+//
+// /**
+// * Indicates pentanomial basis representation (PPB). Number chosen
+// * according to X9.62.
+// */
+// public static final int PPB = 3;
+//
+// /**
+// * TPB or PPB.
+// */
+// private int representation;
+//
+// /**
+// * The exponent m
of F2m
.
+// */
+// private int m;
+//
+// /**
+// * TPB: The integer k
where xm +
+// * xk + 1
represents the reduction polynomial
+// * f(z)
.
+// * PPB: The integer k1
where xm +
+// * xk3 + xk2 + xk1 + 1
+// * represents the reduction polynomial f(z)
.
+// */
+// private int k1;
+//
+// /**
+// * TPB: Always set to 0
+// * PPB: The integer k2
where xm +
+// * xk3 + xk2 + xk1 + 1
+// * represents the reduction polynomial f(z)
.
+// */
+// private int k2;
+//
+// /**
+// * TPB: Always set to 0
+// * PPB: The integer k3
where xm +
+// * xk3 + xk2 + xk1 + 1
+// * represents the reduction polynomial f(z)
.
+// */
+// private int k3;
+//
+// /**
+// * Constructor for PPB.
+// * @param m The exponent m
of
+// * F2m
.
+// * @param k1 The integer k1
where xm +
+// * xk3 + xk2 + xk1 + 1
+// * represents the reduction polynomial f(z)
.
+// * @param k2 The integer k2
where xm +
+// * xk3 + xk2 + xk1 + 1
+// * represents the reduction polynomial f(z)
.
+// * @param k3 The integer k3
where xm +
+// * xk3 + xk2 + xk1 + 1
+// * represents the reduction polynomial f(z)
.
+// * @param x The BigInteger representing the value of the field element.
+// */
+// public F2m(
+// int m,
+// int k1,
+// int k2,
+// int k3,
+// BigInteger x)
+// {
+//// super(x);
+// this.x = x;
+//
+// if ((k2 == 0) && (k3 == 0))
+// {
+// this.representation = TPB;
+// }
+// else
+// {
+// if (k2 >= k3)
+// {
+// throw new IllegalArgumentException(
+// "k2 must be smaller than k3");
+// }
+// if (k2 <= 0)
+// {
+// throw new IllegalArgumentException(
+// "k2 must be larger than 0");
+// }
+// this.representation = PPB;
+// }
+//
+// if (x.signum() < 0)
+// {
+// throw new IllegalArgumentException("x value cannot be negative");
+// }
+//
+// this.m = m;
+// this.k1 = k1;
+// this.k2 = k2;
+// this.k3 = k3;
+// }
+//
+// /**
+// * Constructor for TPB.
+// * @param m The exponent m
of
+// * F2m
.
+// * @param k The integer k
where xm +
+// * xk + 1
represents the reduction
+// * polynomial f(z)
.
+// * @param x The BigInteger representing the value of the field element.
+// */
+// public F2m(int m, int k, BigInteger x)
+// {
+// // Set k1 to k, and set k2 and k3 to 0
+// this(m, k, 0, 0, x);
+// }
+//
+// public BigInteger toBigInteger()
+// {
+// return x;
+// }
+//
+// public String getFieldName()
+// {
+// return "F2m";
+// }
+//
+// public int getFieldSize()
+// {
+// return m;
+// }
+//
+// /**
+// * Checks, if the ECFieldElements a
and b
+// * are elements of the same field F2m
+// * (having the same representation).
+// * @param a field element.
+// * @param b field element to be compared.
+// * @throws IllegalArgumentException if a
and b
+// * are not elements of the same field
+// * F2m
(having the same
+// * representation).
+// */
+// public static void checkFieldElements(
+// ECFieldElement a,
+// ECFieldElement b)
+// {
+// if ((!(a instanceof F2m)) || (!(b instanceof F2m)))
+// {
+// throw new IllegalArgumentException("Field elements are not "
+// + "both instances of ECFieldElement.F2m");
+// }
+//
+// if ((a.toBigInteger().signum() < 0) || (b.toBigInteger().signum() < 0))
+// {
+// throw new IllegalArgumentException(
+// "x value may not be negative");
+// }
+//
+// ECFieldElement.F2m aF2m = (ECFieldElement.F2m)a;
+// ECFieldElement.F2m bF2m = (ECFieldElement.F2m)b;
+//
+// if ((aF2m.m != bF2m.m) || (aF2m.k1 != bF2m.k1)
+// || (aF2m.k2 != bF2m.k2) || (aF2m.k3 != bF2m.k3))
+// {
+// throw new IllegalArgumentException("Field elements are not "
+// + "elements of the same field F2m");
+// }
+//
+// if (aF2m.representation != bF2m.representation)
+// {
+// // Should never occur
+// throw new IllegalArgumentException(
+// "One of the field "
+// + "elements are not elements has incorrect representation");
+// }
+// }
+//
+// /**
+// * Computes z * a(z) mod f(z)
, where f(z)
is
+// * the reduction polynomial of this
.
+// * @param a The polynomial a(z)
to be multiplied by
+// * z mod f(z)
.
+// * @return z * a(z) mod f(z)
+// */
+// private BigInteger multZModF(final BigInteger a)
+// {
+// // Left-shift of a(z)
+// BigInteger az = a.shiftLeft(1);
+// if (az.testBit(this.m))
+// {
+// // If the coefficient of z^m in a(z) equals 1, reduction
+// // modulo f(z) is performed: Add f(z) to to a(z):
+// // Step 1: Unset mth coeffient of a(z)
+// az = az.clearBit(this.m);
+//
+// // Step 2: Add r(z) to a(z), where r(z) is defined as
+// // f(z) = z^m + r(z), and k1, k2, k3 are the positions of
+// // the non-zero coefficients in r(z)
+// az = az.flipBit(0);
+// az = az.flipBit(this.k1);
+// if (this.representation == PPB)
+// {
+// az = az.flipBit(this.k2);
+// az = az.flipBit(this.k3);
+// }
+// }
+// return az;
+// }
+//
+// public ECFieldElement add(final ECFieldElement b)
+// {
+// // No check performed here for performance reasons. Instead the
+// // elements involved are checked in ECPoint.F2m
+// // checkFieldElements(this, b);
+// if (b.toBigInteger().signum() == 0)
+// {
+// return this;
+// }
+//
+// return new F2m(this.m, this.k1, this.k2, this.k3, this.x.xor(b.toBigInteger()));
+// }
+//
+// public ECFieldElement subtract(final ECFieldElement b)
+// {
+// // Addition and subtraction are the same in F2m
+// return add(b);
+// }
+//
+//
+// public ECFieldElement multiply(final ECFieldElement b)
+// {
+// // Left-to-right shift-and-add field multiplication in F2m
+// // Input: Binary polynomials a(z) and b(z) of degree at most m-1
+// // Output: c(z) = a(z) * b(z) mod f(z)
+//
+// // No check performed here for performance reasons. Instead the
+// // elements involved are checked in ECPoint.F2m
+// // checkFieldElements(this, b);
+// final BigInteger az = this.x;
+// BigInteger bz = b.toBigInteger();
+// BigInteger cz;
+//
+// // Compute c(z) = a(z) * b(z) mod f(z)
+// if (az.testBit(0))
+// {
+// cz = bz;
+// }
+// else
+// {
+// cz = ECConstants.ZERO;
+// }
+//
+// for (int i = 1; i < this.m; i++)
+// {
+// // b(z) := z * b(z) mod f(z)
+// bz = multZModF(bz);
+//
+// if (az.testBit(i))
+// {
+// // If the coefficient of x^i in a(z) equals 1, b(z) is added
+// // to c(z)
+// cz = cz.xor(bz);
+// }
+// }
+// return new ECFieldElement.F2m(m, this.k1, this.k2, this.k3, cz);
+// }
+//
+//
+// public ECFieldElement divide(final ECFieldElement b)
+// {
+// // There may be more efficient implementations
+// ECFieldElement bInv = b.invert();
+// return multiply(bInv);
+// }
+//
+// public ECFieldElement negate()
+// {
+// // -x == x holds for all x in F2m
+// return this;
+// }
+//
+// public ECFieldElement square()
+// {
+// // Naive implementation, can probably be speeded up using modular
+// // reduction
+// return multiply(this);
+// }
+//
+// public ECFieldElement invert()
+// {
+// // Inversion in F2m using the extended Euclidean algorithm
+// // Input: A nonzero polynomial a(z) of degree at most m-1
+// // Output: a(z)^(-1) mod f(z)
+//
+// // u(z) := a(z)
+// BigInteger uz = this.x;
+// if (uz.signum() <= 0)
+// {
+// throw new ArithmeticException("x is zero or negative, " +
+// "inversion is impossible");
+// }
+//
+// // v(z) := f(z)
+// BigInteger vz = ECConstants.ZERO.setBit(m);
+// vz = vz.setBit(0);
+// vz = vz.setBit(this.k1);
+// if (this.representation == PPB)
+// {
+// vz = vz.setBit(this.k2);
+// vz = vz.setBit(this.k3);
+// }
+//
+// // g1(z) := 1, g2(z) := 0
+// BigInteger g1z = ECConstants.ONE;
+// BigInteger g2z = ECConstants.ZERO;
+//
+// // while u != 1
+// while (!(uz.equals(ECConstants.ZERO)))
+// {
+// // j := deg(u(z)) - deg(v(z))
+// int j = uz.bitLength() - vz.bitLength();
+//
+// // If j < 0 then: u(z) <-> v(z), g1(z) <-> g2(z), j := -j
+// if (j < 0)
+// {
+// final BigInteger uzCopy = uz;
+// uz = vz;
+// vz = uzCopy;
+//
+// final BigInteger g1zCopy = g1z;
+// g1z = g2z;
+// g2z = g1zCopy;
+//
+// j = -j;
+// }
+//
+// // u(z) := u(z) + z^j * v(z)
+// // Note, that no reduction modulo f(z) is required, because
+// // deg(u(z) + z^j * v(z)) <= max(deg(u(z)), j + deg(v(z)))
+// // = max(deg(u(z)), deg(u(z)) - deg(v(z)) + deg(v(z))
+// // = deg(u(z))
+// uz = uz.xor(vz.shiftLeft(j));
+//
+// // g1(z) := g1(z) + z^j * g2(z)
+// g1z = g1z.xor(g2z.shiftLeft(j));
+//// if (g1z.bitLength() > this.m) {
+//// throw new ArithmeticException(
+//// "deg(g1z) >= m, g1z = " + g1z.toString(2));
+//// }
+// }
+// return new ECFieldElement.F2m(
+// this.m, this.k1, this.k2, this.k3, g2z);
+// }
+//
+// public ECFieldElement sqrt()
+// {
+// throw new RuntimeException("Not implemented");
+// }
+//
+// /**
+// * @return the representation of the field
+// * F2m
, either of
+// * TPB (trinomial
+// * basis representation) or
+// * PPB (pentanomial
+// * basis representation).
+// */
+// public int getRepresentation()
+// {
+// return this.representation;
+// }
+//
+// /**
+// * @return the degree m
of the reduction polynomial
+// * f(z)
.
+// */
+// public int getM()
+// {
+// return this.m;
+// }
+//
+// /**
+// * @return TPB: The integer k
where xm +
+// * xk + 1
represents the reduction polynomial
+// * f(z)
.
+// * PPB: The integer k1
where xm +
+// * xk3 + xk2 + xk1 + 1
+// * represents the reduction polynomial f(z)
.
+// */
+// public int getK1()
+// {
+// return this.k1;
+// }
+//
+// /**
+// * @return TPB: Always returns 0
+// * PPB: The integer k2
where xm +
+// * xk3 + xk2 + xk1 + 1
+// * represents the reduction polynomial f(z)
.
+// */
+// public int getK2()
+// {
+// return this.k2;
+// }
+//
+// /**
+// * @return TPB: Always set to 0
+// * PPB: The integer k3
where xm +
+// * xk3 + xk2 + xk1 + 1
+// * represents the reduction polynomial f(z)
.
+// */
+// public int getK3()
+// {
+// return this.k3;
+// }
+//
+// public boolean equals(Object anObject)
+// {
+// if (anObject == this)
+// {
+// return true;
+// }
+//
+// if (!(anObject instanceof ECFieldElement.F2m))
+// {
+// return false;
+// }
+//
+// ECFieldElement.F2m b = (ECFieldElement.F2m)anObject;
+//
+// return ((this.m == b.m) && (this.k1 == b.k1) && (this.k2 == b.k2)
+// && (this.k3 == b.k3)
+// && (this.representation == b.representation)
+// && (this.x.equals(b.x)));
+// }
+//
+// public int hashCode()
+// {
+// return x.hashCode() ^ m ^ k1 ^ k2 ^ k3;
+// }
+// }
+
+ /**
+ * Class representing the Elements of the finite field
+ * F2m
in polynomial basis (PB)
+ * representation. Both trinomial (TPB) and pentanomial (PPB) polynomial
+ * basis representations are supported. Gaussian normal basis (GNB)
+ * representation is not supported.
+ */
+ public static class F2m extends ECFieldElement
+ {
+ /**
+ * Indicates gaussian normal basis representation (GNB). Number chosen
+ * according to X9.62. GNB is not implemented at present.
+ */
+ public static final int GNB = 1;
+
+ /**
+ * Indicates trinomial basis representation (TPB). Number chosen
+ * according to X9.62.
+ */
+ public static final int TPB = 2;
+
+ /**
+ * Indicates pentanomial basis representation (PPB). Number chosen
+ * according to X9.62.
+ */
+ public static final int PPB = 3;
+
+ /**
+ * TPB or PPB.
+ */
+ private int representation;
+
+ /**
+ * The exponent m
of F2m
.
+ */
+ private int m;
+
+ /**
+ * TPB: The integer k
where xm +
+ * xk + 1
represents the reduction polynomial
+ * f(z)
.
+ * PPB: The integer k1
where xm +
+ * xk3 + xk2 + xk1 + 1
+ * represents the reduction polynomial f(z)
.
+ */
+ private int k1;
+
+ /**
+ * TPB: Always set to 0
+ * PPB: The integer k2
where xm +
+ * xk3 + xk2 + xk1 + 1
+ * represents the reduction polynomial f(z)
.
+ */
+ private int k2;
+
+ /**
+ * TPB: Always set to 0
+ * PPB: The integer k3
where xm +
+ * xk3 + xk2 + xk1 + 1
+ * represents the reduction polynomial f(z)
.
+ */
+ private int k3;
+
+ /**
+ * The IntArray
holding the bits.
+ */
+ private IntArray x;
+
+ /**
+ * The number of int
s required to hold m
bits.
+ */
+ private int t;
+
+ /**
+ * Constructor for PPB.
+ * @param m The exponent m
of
+ * F2m
.
+ * @param k1 The integer k1
where xm +
+ * xk3 + xk2 + xk1 + 1
+ * represents the reduction polynomial f(z)
.
+ * @param k2 The integer k2
where xm +
+ * xk3 + xk2 + xk1 + 1
+ * represents the reduction polynomial f(z)
.
+ * @param k3 The integer k3
where xm +
+ * xk3 + xk2 + xk1 + 1
+ * represents the reduction polynomial f(z)
.
+ * @param x The BigInteger representing the value of the field element.
+ */
+ public F2m(
+ int m,
+ int k1,
+ int k2,
+ int k3,
+ BigInteger x)
+ {
+ // t = m / 32 rounded up to the next integer
+ t = (m + 31) >> 5;
+ this.x = new IntArray(x, t);
+
+ if ((k2 == 0) && (k3 == 0))
+ {
+ this.representation = TPB;
+ }
+ else
+ {
+ if (k2 >= k3)
+ {
+ throw new IllegalArgumentException(
+ "k2 must be smaller than k3");
+ }
+ if (k2 <= 0)
+ {
+ throw new IllegalArgumentException(
+ "k2 must be larger than 0");
+ }
+ this.representation = PPB;
+ }
+
+ if (x.signum() < 0)
+ {
+ throw new IllegalArgumentException("x value cannot be negative");
+ }
+
+ this.m = m;
+ this.k1 = k1;
+ this.k2 = k2;
+ this.k3 = k3;
+ }
+
+ /**
+ * Constructor for TPB.
+ * @param m The exponent m
of
+ * F2m
.
+ * @param k The integer k
where xm +
+ * xk + 1
represents the reduction
+ * polynomial f(z)
.
+ * @param x The BigInteger representing the value of the field element.
+ */
+ public F2m(int m, int k, BigInteger x)
+ {
+ // Set k1 to k, and set k2 and k3 to 0
+ this(m, k, 0, 0, x);
+ }
+
+ private F2m(int m, int k1, int k2, int k3, IntArray x)
+ {
+ t = (m + 31) >> 5;
+ this.x = x;
+ this.m = m;
+ this.k1 = k1;
+ this.k2 = k2;
+ this.k3 = k3;
+
+ if ((k2 == 0) && (k3 == 0))
+ {
+ this.representation = TPB;
+ }
+ else
+ {
+ this.representation = PPB;
+ }
+
+ }
+
+ public BigInteger toBigInteger()
+ {
+ return x.toBigInteger();
+ }
+
+ public String getFieldName()
+ {
+ return "F2m";
+ }
+
+ public int getFieldSize()
+ {
+ return m;
+ }
+
+ /**
+ * Checks, if the ECFieldElements a
and b
+ * are elements of the same field F2m
+ * (having the same representation).
+ * @param a field element.
+ * @param b field element to be compared.
+ * @throws IllegalArgumentException if a
and b
+ * are not elements of the same field
+ * F2m
(having the same
+ * representation).
+ */
+ public static void checkFieldElements(
+ ECFieldElement a,
+ ECFieldElement b)
+ {
+ if ((!(a instanceof F2m)) || (!(b instanceof F2m)))
+ {
+ throw new IllegalArgumentException("Field elements are not "
+ + "both instances of ECFieldElement.F2m");
+ }
+
+ ECFieldElement.F2m aF2m = (ECFieldElement.F2m)a;
+ ECFieldElement.F2m bF2m = (ECFieldElement.F2m)b;
+
+ if ((aF2m.m != bF2m.m) || (aF2m.k1 != bF2m.k1)
+ || (aF2m.k2 != bF2m.k2) || (aF2m.k3 != bF2m.k3))
+ {
+ throw new IllegalArgumentException("Field elements are not "
+ + "elements of the same field F2m");
+ }
+
+ if (aF2m.representation != bF2m.representation)
+ {
+ // Should never occur
+ throw new IllegalArgumentException(
+ "One of the field "
+ + "elements are not elements has incorrect representation");
+ }
+ }
+
+ public ECFieldElement add(final ECFieldElement b)
+ {
+ // No check performed here for performance reasons. Instead the
+ // elements involved are checked in ECPoint.F2m
+ // checkFieldElements(this, b);
+ IntArray iarrClone = (IntArray)this.x.clone();
+ F2m bF2m = (F2m)b;
+ iarrClone.addShifted(bF2m.x, 0);
+ return new F2m(m, k1, k2, k3, iarrClone);
+ }
+
+ public ECFieldElement subtract(final ECFieldElement b)
+ {
+ // Addition and subtraction are the same in F2m
+ return add(b);
+ }
+
+ public ECFieldElement multiply(final ECFieldElement b)
+ {
+ // Right-to-left comb multiplication in the IntArray
+ // Input: Binary polynomials a(z) and b(z) of degree at most m-1
+ // Output: c(z) = a(z) * b(z) mod f(z)
+
+ // No check performed here for performance reasons. Instead the
+ // elements involved are checked in ECPoint.F2m
+ // checkFieldElements(this, b);
+ F2m bF2m = (F2m)b;
+ IntArray mult = x.multiply(bF2m.x, m);
+ mult.reduce(m, new int[]{k1, k2, k3});
+ return new F2m(m, k1, k2, k3, mult);
+ }
+
+ public ECFieldElement divide(final ECFieldElement b)
+ {
+ // There may be more efficient implementations
+ ECFieldElement bInv = b.invert();
+ return multiply(bInv);
+ }
+
+ public ECFieldElement negate()
+ {
+ // -x == x holds for all x in F2m
+ return this;
+ }
+
+ public ECFieldElement square()
+ {
+ IntArray squared = x.square(m);
+ squared.reduce(m, new int[]{k1, k2, k3});
+ return new F2m(m, k1, k2, k3, squared);
+ }
+
+
+ public ECFieldElement invert()
+ {
+ // Inversion in F2m using the extended Euclidean algorithm
+ // Input: A nonzero polynomial a(z) of degree at most m-1
+ // Output: a(z)^(-1) mod f(z)
+
+ // u(z) := a(z)
+ IntArray uz = (IntArray)this.x.clone();
+
+ // v(z) := f(z)
+ IntArray vz = new IntArray(t);
+ vz.setBit(m);
+ vz.setBit(0);
+ vz.setBit(this.k1);
+ if (this.representation == PPB)
+ {
+ vz.setBit(this.k2);
+ vz.setBit(this.k3);
+ }
+
+ // g1(z) := 1, g2(z) := 0
+ IntArray g1z = new IntArray(t);
+ g1z.setBit(0);
+ IntArray g2z = new IntArray(t);
+
+ // while u != 0
+ while (!uz.isZero())
+// while (uz.getUsedLength() > 0)
+// while (uz.bitLength() > 1)
+ {
+ // j := deg(u(z)) - deg(v(z))
+ int j = uz.bitLength() - vz.bitLength();
+
+ // If j < 0 then: u(z) <-> v(z), g1(z) <-> g2(z), j := -j
+ if (j < 0)
+ {
+ final IntArray uzCopy = uz;
+ uz = vz;
+ vz = uzCopy;
+
+ final IntArray g1zCopy = g1z;
+ g1z = g2z;
+ g2z = g1zCopy;
+
+ j = -j;
+ }
+
+ // u(z) := u(z) + z^j * v(z)
+ // Note, that no reduction modulo f(z) is required, because
+ // deg(u(z) + z^j * v(z)) <= max(deg(u(z)), j + deg(v(z)))
+ // = max(deg(u(z)), deg(u(z)) - deg(v(z)) + deg(v(z))
+ // = deg(u(z))
+ // uz = uz.xor(vz.shiftLeft(j));
+ // jInt = n / 32
+ int jInt = j >> 5;
+ // jInt = n % 32
+ int jBit = j & 0x1F;
+ IntArray vzShift = vz.shiftLeft(jBit);
+ uz.addShifted(vzShift, jInt);
+
+ // g1(z) := g1(z) + z^j * g2(z)
+// g1z = g1z.xor(g2z.shiftLeft(j));
+ IntArray g2zShift = g2z.shiftLeft(jBit);
+ g1z.addShifted(g2zShift, jInt);
+
+ }
+ return new ECFieldElement.F2m(
+ this.m, this.k1, this.k2, this.k3, g2z);
+ }
+
+ public ECFieldElement sqrt()
+ {
+ throw new RuntimeException("Not implemented");
+ }
+
+ /**
+ * @return the representation of the field
+ * F2m
, either of
+ * TPB (trinomial
+ * basis representation) or
+ * PPB (pentanomial
+ * basis representation).
+ */
+ public int getRepresentation()
+ {
+ return this.representation;
+ }
+
+ /**
+ * @return the degree m
of the reduction polynomial
+ * f(z)
.
+ */
+ public int getM()
+ {
+ return this.m;
+ }
+
+ /**
+ * @return TPB: The integer k
where xm +
+ * xk + 1
represents the reduction polynomial
+ * f(z)
.
+ * PPB: The integer k1
where xm +
+ * xk3 + xk2 + xk1 + 1
+ * represents the reduction polynomial f(z)
.
+ */
+ public int getK1()
+ {
+ return this.k1;
+ }
+
+ /**
+ * @return TPB: Always returns 0
+ * PPB: The integer k2
where xm +
+ * xk3 + xk2 + xk1 + 1
+ * represents the reduction polynomial f(z)
.
+ */
+ public int getK2()
+ {
+ return this.k2;
+ }
+
+ /**
+ * @return TPB: Always set to 0
+ * PPB: The integer k3
where xm +
+ * xk3 + xk2 + xk1 + 1
+ * represents the reduction polynomial f(z)
.
+ */
+ public int getK3()
+ {
+ return this.k3;
+ }
+
+ public boolean equals(Object anObject)
+ {
+ if (anObject == this)
+ {
+ return true;
+ }
+
+ if (!(anObject instanceof ECFieldElement.F2m))
+ {
+ return false;
+ }
+
+ ECFieldElement.F2m b = (ECFieldElement.F2m)anObject;
+
+ return ((this.m == b.m) && (this.k1 == b.k1) && (this.k2 == b.k2)
+ && (this.k3 == b.k3)
+ && (this.representation == b.representation)
+ && (this.x.equals(b.x)));
+ }
+
+ public int hashCode()
+ {
+ return x.hashCode() ^ m ^ k1 ^ k2 ^ k3;
+ }
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ec/ECMultiplier.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ec/ECMultiplier.java
new file mode 100644
index 0000000..0e8e292
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ec/ECMultiplier.java
@@ -0,0 +1,19 @@
+package org.bc.math.ec;
+
+import java.math.BigInteger;
+
+/**
+ * Interface for classes encapsulating a point multiplication algorithm
+ * for ECPoint
s.
+ */
+interface ECMultiplier
+{
+ /**
+ * Multiplies the ECPoint p
by k
, i.e.
+ * p
is added k
times to itself.
+ * @param p The ECPoint
to be multiplied.
+ * @param k The factor by which p
i multiplied.
+ * @return p
multiplied by k
.
+ */
+ ECPoint multiply(ECPoint p, BigInteger k, PreCompInfo preCompInfo);
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ec/ECPoint.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ec/ECPoint.java
new file mode 100644
index 0000000..37a646f
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ec/ECPoint.java
@@ -0,0 +1,588 @@
+package org.bc.math.ec;
+
+import java.math.BigInteger;
+
+import org.bc.asn1.x9.X9IntegerConverter;
+
+/**
+ * base class for points on elliptic curves.
+ */
+public abstract class ECPoint
+{
+ ECCurve curve;
+ ECFieldElement x;
+ ECFieldElement y;
+
+ protected boolean withCompression;
+
+ protected ECMultiplier multiplier = null;
+
+ protected PreCompInfo preCompInfo = null;
+
+ private static X9IntegerConverter converter = new X9IntegerConverter();
+
+ protected ECPoint(ECCurve curve, ECFieldElement x, ECFieldElement y)
+ {
+ this.curve = curve;
+ this.x = x;
+ this.y = y;
+ }
+
+ public ECCurve getCurve()
+ {
+ return curve;
+ }
+
+ public ECFieldElement getX()
+ {
+ return x;
+ }
+
+ public ECFieldElement getY()
+ {
+ return y;
+ }
+
+ public boolean isInfinity()
+ {
+ return x == null && y == null;
+ }
+
+ public boolean isCompressed()
+ {
+ return withCompression;
+ }
+
+ public boolean equals(
+ Object other)
+ {
+ if (other == this)
+ {
+ return true;
+ }
+
+ if (!(other instanceof ECPoint))
+ {
+ return false;
+ }
+
+ ECPoint o = (ECPoint)other;
+
+ if (this.isInfinity())
+ {
+ return o.isInfinity();
+ }
+
+ return x.equals(o.x) && y.equals(o.y);
+ }
+
+ public int hashCode()
+ {
+ if (this.isInfinity())
+ {
+ return 0;
+ }
+
+ return x.hashCode() ^ y.hashCode();
+ }
+
+// /**
+// * Mainly for testing. Explicitly set the ECMultiplier
.
+// * @param multiplier The ECMultiplier
to be used to multiply
+// * this ECPoint
.
+// */
+// public void setECMultiplier(ECMultiplier multiplier)
+// {
+// this.multiplier = multiplier;
+// }
+
+ /**
+ * Sets the PreCompInfo
. Used by ECMultiplier
s
+ * to save the precomputation for this ECPoint
to store the
+ * precomputation result for use by subsequent multiplication.
+ * @param preCompInfo The values precomputed by the
+ * ECMultiplier
.
+ */
+ void setPreCompInfo(PreCompInfo preCompInfo)
+ {
+ this.preCompInfo = preCompInfo;
+ }
+
+ public abstract byte[] getEncoded();
+
+ public abstract ECPoint add(ECPoint b);
+ public abstract ECPoint subtract(ECPoint b);
+ public abstract ECPoint negate();
+ public abstract ECPoint twice();
+
+ /**
+ * Sets the default ECMultiplier
, unless already set.
+ */
+ synchronized void assertECMultiplier()
+ {
+ if (this.multiplier == null)
+ {
+ this.multiplier = new FpNafMultiplier();
+ }
+ }
+
+ /**
+ * Multiplies this ECPoint
by the given number.
+ * @param k The multiplicator.
+ * @return k * this
.
+ */
+ public ECPoint multiply(BigInteger k)
+ {
+ if (k.signum() < 0)
+ {
+ throw new IllegalArgumentException("The multiplicator cannot be negative");
+ }
+
+ if (this.isInfinity())
+ {
+ return this;
+ }
+
+ if (k.signum() == 0)
+ {
+ return this.curve.getInfinity();
+ }
+
+ assertECMultiplier();
+ return this.multiplier.multiply(this, k, preCompInfo);
+ }
+
+ /**
+ * Elliptic curve points over Fp
+ */
+ public static class Fp extends ECPoint
+ {
+
+ /**
+ * Create a point which encodes with point compression.
+ *
+ * @param curve the curve to use
+ * @param x affine x co-ordinate
+ * @param y affine y co-ordinate
+ */
+ public Fp(ECCurve curve, ECFieldElement x, ECFieldElement y)
+ {
+ this(curve, x, y, false);
+ }
+
+ /**
+ * Create a point that encodes with or without point compresion.
+ *
+ * @param curve the curve to use
+ * @param x affine x co-ordinate
+ * @param y affine y co-ordinate
+ * @param withCompression if true encode with point compression
+ */
+ public Fp(ECCurve curve, ECFieldElement x, ECFieldElement y, boolean withCompression)
+ {
+ super(curve, x, y);
+
+ if ((x != null && y == null) || (x == null && y != null))
+ {
+ throw new IllegalArgumentException("Exactly one of the field elements is null");
+ }
+
+ this.withCompression = withCompression;
+ }
+
+ /**
+ * return the field element encoded with point compression. (S 4.3.6)
+ */
+ public byte[] getEncoded()
+ {
+ if (this.isInfinity())
+ {
+ return new byte[1];
+ }
+
+ int qLength = converter.getByteLength(x);
+
+ if (withCompression)
+ {
+ byte PC;
+
+ if (this.getY().toBigInteger().testBit(0))
+ {
+ PC = 0x03;
+ }
+ else
+ {
+ PC = 0x02;
+ }
+
+ byte[] X = converter.integerToBytes(this.getX().toBigInteger(), qLength);
+ byte[] PO = new byte[X.length + 1];
+
+ PO[0] = PC;
+ System.arraycopy(X, 0, PO, 1, X.length);
+
+ return PO;
+ }
+ else
+ {
+ byte[] X = converter.integerToBytes(this.getX().toBigInteger(), qLength);
+ byte[] Y = converter.integerToBytes(this.getY().toBigInteger(), qLength);
+ byte[] PO = new byte[X.length + Y.length + 1];
+
+ PO[0] = 0x04;
+ System.arraycopy(X, 0, PO, 1, X.length);
+ System.arraycopy(Y, 0, PO, X.length + 1, Y.length);
+
+ return PO;
+ }
+ }
+
+ // B.3 pg 62
+ public ECPoint add(ECPoint b)
+ {
+ if (this.isInfinity())
+ {
+ return b;
+ }
+
+ if (b.isInfinity())
+ {
+ return this;
+ }
+
+ // Check if b = this or b = -this
+ if (this.x.equals(b.x))
+ {
+ if (this.y.equals(b.y))
+ {
+ // this = b, i.e. this must be doubled
+ return this.twice();
+ }
+
+ // this = -b, i.e. the result is the point at infinity
+ return this.curve.getInfinity();
+ }
+
+ ECFieldElement gamma = b.y.subtract(this.y).divide(b.x.subtract(this.x));
+
+ ECFieldElement x3 = gamma.square().subtract(this.x).subtract(b.x);
+ ECFieldElement y3 = gamma.multiply(this.x.subtract(x3)).subtract(this.y);
+
+ return new ECPoint.Fp(curve, x3, y3);
+ }
+
+ // B.3 pg 62
+ public ECPoint twice()
+ {
+ if (this.isInfinity())
+ {
+ // Twice identity element (point at infinity) is identity
+ return this;
+ }
+
+ if (this.y.toBigInteger().signum() == 0)
+ {
+ // if y1 == 0, then (x1, y1) == (x1, -y1)
+ // and hence this = -this and thus 2(x1, y1) == infinity
+ return this.curve.getInfinity();
+ }
+
+ ECFieldElement TWO = this.curve.fromBigInteger(BigInteger.valueOf(2));
+ ECFieldElement THREE = this.curve.fromBigInteger(BigInteger.valueOf(3));
+ ECFieldElement gamma = this.x.square().multiply(THREE).add(curve.a).divide(y.multiply(TWO));
+
+ ECFieldElement x3 = gamma.square().subtract(this.x.multiply(TWO));
+ ECFieldElement y3 = gamma.multiply(this.x.subtract(x3)).subtract(this.y);
+
+ return new ECPoint.Fp(curve, x3, y3, this.withCompression);
+ }
+
+ // D.3.2 pg 102 (see Note:)
+ public ECPoint subtract(ECPoint b)
+ {
+ if (b.isInfinity())
+ {
+ return this;
+ }
+
+ // Add -b
+ return add(b.negate());
+ }
+
+ public ECPoint negate()
+ {
+ return new ECPoint.Fp(curve, this.x, this.y.negate(), this.withCompression);
+ }
+
+ /**
+ * Sets the default ECMultiplier
, unless already set.
+ */
+ synchronized void assertECMultiplier()
+ {
+ if (this.multiplier == null)
+ {
+ this.multiplier = new WNafMultiplier();
+ }
+ }
+ }
+
+ /**
+ * Elliptic curve points over F2m
+ */
+ public static class F2m extends ECPoint
+ {
+ /**
+ * @param curve base curve
+ * @param x x point
+ * @param y y point
+ */
+ public F2m(ECCurve curve, ECFieldElement x, ECFieldElement y)
+ {
+ this(curve, x, y, false);
+ }
+
+ /**
+ * @param curve base curve
+ * @param x x point
+ * @param y y point
+ * @param withCompression true if encode with point compression.
+ */
+ public F2m(ECCurve curve, ECFieldElement x, ECFieldElement y, boolean withCompression)
+ {
+ super(curve, x, y);
+
+ if ((x != null && y == null) || (x == null && y != null))
+ {
+ throw new IllegalArgumentException("Exactly one of the field elements is null");
+ }
+
+ if (x != null)
+ {
+ // Check if x and y are elements of the same field
+ ECFieldElement.F2m.checkFieldElements(this.x, this.y);
+
+ // Check if x and a are elements of the same field
+ if (curve != null)
+ {
+ ECFieldElement.F2m.checkFieldElements(this.x, this.curve.getA());
+ }
+ }
+
+ this.withCompression = withCompression;
+ }
+
+ /* (non-Javadoc)
+ * @see org.bouncycastle.math.ec.ECPoint#getEncoded()
+ */
+ public byte[] getEncoded()
+ {
+ if (this.isInfinity())
+ {
+ return new byte[1];
+ }
+
+ int byteCount = converter.getByteLength(this.x);
+ byte[] X = converter.integerToBytes(this.getX().toBigInteger(), byteCount);
+ byte[] PO;
+
+ if (withCompression)
+ {
+ // See X9.62 4.3.6 and 4.2.2
+ PO = new byte[byteCount + 1];
+
+ PO[0] = 0x02;
+ // X9.62 4.2.2 and 4.3.6:
+ // if x = 0 then ypTilde := 0, else ypTilde is the rightmost
+ // bit of y * x^(-1)
+ // if ypTilde = 0, then PC := 02, else PC := 03
+ // Note: PC === PO[0]
+ if (!(this.getX().toBigInteger().equals(ECConstants.ZERO)))
+ {
+ if (this.getY().multiply(this.getX().invert())
+ .toBigInteger().testBit(0))
+ {
+ // ypTilde = 1, hence PC = 03
+ PO[0] = 0x03;
+ }
+ }
+
+ System.arraycopy(X, 0, PO, 1, byteCount);
+ }
+ else
+ {
+ byte[] Y = converter.integerToBytes(this.getY().toBigInteger(), byteCount);
+
+ PO = new byte[byteCount + byteCount + 1];
+
+ PO[0] = 0x04;
+ System.arraycopy(X, 0, PO, 1, byteCount);
+ System.arraycopy(Y, 0, PO, byteCount + 1, byteCount);
+ }
+
+ return PO;
+ }
+
+ /**
+ * Check, if two ECPoint
s can be added or subtracted.
+ * @param a The first ECPoint
to check.
+ * @param b The second ECPoint
to check.
+ * @throws IllegalArgumentException if a
and b
+ * cannot be added.
+ */
+ private static void checkPoints(ECPoint a, ECPoint b)
+ {
+ // Check, if points are on the same curve
+ if (!(a.curve.equals(b.curve)))
+ {
+ throw new IllegalArgumentException("Only points on the same "
+ + "curve can be added or subtracted");
+ }
+
+// ECFieldElement.F2m.checkFieldElements(a.x, b.x);
+ }
+
+ /* (non-Javadoc)
+ * @see org.bouncycastle.math.ec.ECPoint#add(org.bouncycastle.math.ec.ECPoint)
+ */
+ public ECPoint add(ECPoint b)
+ {
+ checkPoints(this, b);
+ return addSimple((ECPoint.F2m)b);
+ }
+
+ /**
+ * Adds another ECPoints.F2m
to this
without
+ * checking if both points are on the same curve. Used by multiplication
+ * algorithms, because there all points are a multiple of the same point
+ * and hence the checks can be omitted.
+ * @param b The other ECPoints.F2m
to add to
+ * this
.
+ * @return this + b
+ */
+ public ECPoint.F2m addSimple(ECPoint.F2m b)
+ {
+ ECPoint.F2m other = b;
+ if (this.isInfinity())
+ {
+ return other;
+ }
+
+ if (other.isInfinity())
+ {
+ return this;
+ }
+
+ ECFieldElement.F2m x2 = (ECFieldElement.F2m)other.getX();
+ ECFieldElement.F2m y2 = (ECFieldElement.F2m)other.getY();
+
+ // Check if other = this or other = -this
+ if (this.x.equals(x2))
+ {
+ if (this.y.equals(y2))
+ {
+ // this = other, i.e. this must be doubled
+ return (ECPoint.F2m)this.twice();
+ }
+
+ // this = -other, i.e. the result is the point at infinity
+ return (ECPoint.F2m)this.curve.getInfinity();
+ }
+
+ ECFieldElement.F2m lambda
+ = (ECFieldElement.F2m)(this.y.add(y2)).divide(this.x.add(x2));
+
+ ECFieldElement.F2m x3
+ = (ECFieldElement.F2m)lambda.square().add(lambda).add(this.x).add(x2).add(this.curve.getA());
+
+ ECFieldElement.F2m y3
+ = (ECFieldElement.F2m)lambda.multiply(this.x.add(x3)).add(x3).add(this.y);
+
+ return new ECPoint.F2m(curve, x3, y3, withCompression);
+ }
+
+ /* (non-Javadoc)
+ * @see org.bouncycastle.math.ec.ECPoint#subtract(org.bouncycastle.math.ec.ECPoint)
+ */
+ public ECPoint subtract(ECPoint b)
+ {
+ checkPoints(this, b);
+ return subtractSimple((ECPoint.F2m)b);
+ }
+
+ /**
+ * Subtracts another ECPoints.F2m
from this
+ * without checking if both points are on the same curve. Used by
+ * multiplication algorithms, because there all points are a multiple
+ * of the same point and hence the checks can be omitted.
+ * @param b The other ECPoints.F2m
to subtract from
+ * this
.
+ * @return this - b
+ */
+ public ECPoint.F2m subtractSimple(ECPoint.F2m b)
+ {
+ if (b.isInfinity())
+ {
+ return this;
+ }
+
+ // Add -b
+ return addSimple((ECPoint.F2m)b.negate());
+ }
+
+ /* (non-Javadoc)
+ * @see org.bouncycastle.math.ec.ECPoint#twice()
+ */
+ public ECPoint twice()
+ {
+ if (this.isInfinity())
+ {
+ // Twice identity element (point at infinity) is identity
+ return this;
+ }
+
+ if (this.x.toBigInteger().signum() == 0)
+ {
+ // if x1 == 0, then (x1, y1) == (x1, x1 + y1)
+ // and hence this = -this and thus 2(x1, y1) == infinity
+ return this.curve.getInfinity();
+ }
+
+ ECFieldElement.F2m lambda
+ = (ECFieldElement.F2m)this.x.add(this.y.divide(this.x));
+
+ ECFieldElement.F2m x3
+ = (ECFieldElement.F2m)lambda.square().add(lambda).
+ add(this.curve.getA());
+
+ ECFieldElement ONE = this.curve.fromBigInteger(ECConstants.ONE);
+ ECFieldElement.F2m y3
+ = (ECFieldElement.F2m)this.x.square().add(
+ x3.multiply(lambda.add(ONE)));
+
+ return new ECPoint.F2m(this.curve, x3, y3, withCompression);
+ }
+
+ public ECPoint negate()
+ {
+ return new ECPoint.F2m(curve, this.getX(), this.getY().add(this.getX()), withCompression);
+ }
+
+ /**
+ * Sets the appropriate ECMultiplier
, unless already set.
+ */
+ synchronized void assertECMultiplier()
+ {
+ if (this.multiplier == null)
+ {
+ if (((ECCurve.F2m)this.curve).isKoblitz())
+ {
+ this.multiplier = new WTauNafMultiplier();
+ }
+ else
+ {
+ this.multiplier = new WNafMultiplier();
+ }
+ }
+ }
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ec/FpNafMultiplier.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ec/FpNafMultiplier.java
new file mode 100644
index 0000000..cf567e2
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ec/FpNafMultiplier.java
@@ -0,0 +1,39 @@
+package org.bc.math.ec;
+
+import java.math.BigInteger;
+
+/**
+ * Class implementing the NAF (Non-Adjacent Form) multiplication algorithm.
+ */
+class FpNafMultiplier implements ECMultiplier
+{
+ /**
+ * D.3.2 pg 101
+ * @see org.bc.math.ec.ECMultiplier#multiply(org.bc.math.ec.ECPoint, java.math.BigInteger)
+ */
+ public ECPoint multiply(ECPoint p, BigInteger k, PreCompInfo preCompInfo)
+ {
+ // TODO Probably should try to add this
+ // BigInteger e = k.mod(n); // n == order of p
+ BigInteger e = k;
+ BigInteger h = e.multiply(BigInteger.valueOf(3));
+
+ ECPoint neg = p.negate();
+ ECPoint R = p;
+
+ for (int i = h.bitLength() - 2; i > 0; --i)
+ {
+ R = R.twice();
+
+ boolean hBit = h.testBit(i);
+ boolean eBit = e.testBit(i);
+
+ if (hBit != eBit)
+ {
+ R = R.add(hBit ? p : neg);
+ }
+ }
+
+ return R;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ec/IntArray.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ec/IntArray.java
new file mode 100644
index 0000000..f041478
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ec/IntArray.java
@@ -0,0 +1,518 @@
+package org.bc.math.ec;
+
+import org.bc.util.Arrays;
+
+import java.math.BigInteger;
+
+class IntArray
+{
+ // TODO make m fixed for the IntArray, and hence compute T once and for all
+
+ private int[] m_ints;
+
+ public IntArray(int intLen)
+ {
+ m_ints = new int[intLen];
+ }
+
+ public IntArray(int[] ints)
+ {
+ m_ints = ints;
+ }
+
+ public IntArray(BigInteger bigInt)
+ {
+ this(bigInt, 0);
+ }
+
+ public IntArray(BigInteger bigInt, int minIntLen)
+ {
+ if (bigInt.signum() == -1)
+ {
+ throw new IllegalArgumentException("Only positive Integers allowed");
+ }
+ if (bigInt.equals(ECConstants.ZERO))
+ {
+ m_ints = new int[] { 0 };
+ return;
+ }
+
+ byte[] barr = bigInt.toByteArray();
+ int barrLen = barr.length;
+ int barrStart = 0;
+ if (barr[0] == 0)
+ {
+ // First byte is 0 to enforce highest (=sign) bit is zero.
+ // In this case ignore barr[0].
+ barrLen--;
+ barrStart = 1;
+ }
+ int intLen = (barrLen + 3) / 4;
+ if (intLen < minIntLen)
+ {
+ m_ints = new int[minIntLen];
+ }
+ else
+ {
+ m_ints = new int[intLen];
+ }
+
+ int iarrJ = intLen - 1;
+ int rem = barrLen % 4 + barrStart;
+ int temp = 0;
+ int barrI = barrStart;
+ if (barrStart < rem)
+ {
+ for (; barrI < rem; barrI++)
+ {
+ temp <<= 8;
+ int barrBarrI = barr[barrI];
+ if (barrBarrI < 0)
+ {
+ barrBarrI += 256;
+ }
+ temp |= barrBarrI;
+ }
+ m_ints[iarrJ--] = temp;
+ }
+
+ for (; iarrJ >= 0; iarrJ--)
+ {
+ temp = 0;
+ for (int i = 0; i < 4; i++)
+ {
+ temp <<= 8;
+ int barrBarrI = barr[barrI++];
+ if (barrBarrI < 0)
+ {
+ barrBarrI += 256;
+ }
+ temp |= barrBarrI;
+ }
+ m_ints[iarrJ] = temp;
+ }
+ }
+
+ public boolean isZero()
+ {
+ return m_ints.length == 0
+ || (m_ints[0] == 0 && getUsedLength() == 0);
+ }
+
+ public int getUsedLength()
+ {
+ int highestIntPos = m_ints.length;
+
+ if (highestIntPos < 1)
+ {
+ return 0;
+ }
+
+ // Check if first element will act as sentinel
+ if (m_ints[0] != 0)
+ {
+ while (m_ints[--highestIntPos] == 0)
+ {
+ }
+ return highestIntPos + 1;
+ }
+
+ do
+ {
+ if (m_ints[--highestIntPos] != 0)
+ {
+ return highestIntPos + 1;
+ }
+ }
+ while (highestIntPos > 0);
+
+ return 0;
+ }
+
+ public int bitLength()
+ {
+ // JDK 1.5: see Integer.numberOfLeadingZeros()
+ int intLen = getUsedLength();
+ if (intLen == 0)
+ {
+ return 0;
+ }
+
+ int last = intLen - 1;
+ int highest = m_ints[last];
+ int bits = (last << 5) + 1;
+
+ // A couple of binary search steps
+ if ((highest & 0xffff0000) != 0)
+ {
+ if ((highest & 0xff000000) != 0)
+ {
+ bits += 24;
+ highest >>>= 24;
+ }
+ else
+ {
+ bits += 16;
+ highest >>>= 16;
+ }
+ }
+ else if (highest > 0x000000ff)
+ {
+ bits += 8;
+ highest >>>= 8;
+ }
+
+ while (highest != 1)
+ {
+ ++bits;
+ highest >>>= 1;
+ }
+
+ return bits;
+ }
+
+ private int[] resizedInts(int newLen)
+ {
+ int[] newInts = new int[newLen];
+ int oldLen = m_ints.length;
+ int copyLen = oldLen < newLen ? oldLen : newLen;
+ System.arraycopy(m_ints, 0, newInts, 0, copyLen);
+ return newInts;
+ }
+
+ public BigInteger toBigInteger()
+ {
+ int usedLen = getUsedLength();
+ if (usedLen == 0)
+ {
+ return ECConstants.ZERO;
+ }
+
+ int highestInt = m_ints[usedLen - 1];
+ byte[] temp = new byte[4];
+ int barrI = 0;
+ boolean trailingZeroBytesDone = false;
+ for (int j = 3; j >= 0; j--)
+ {
+ byte thisByte = (byte) (highestInt >>> (8 * j));
+ if (trailingZeroBytesDone || (thisByte != 0))
+ {
+ trailingZeroBytesDone = true;
+ temp[barrI++] = thisByte;
+ }
+ }
+
+ int barrLen = 4 * (usedLen - 1) + barrI;
+ byte[] barr = new byte[barrLen];
+ for (int j = 0; j < barrI; j++)
+ {
+ barr[j] = temp[j];
+ }
+ // Highest value int is done now
+
+ for (int iarrJ = usedLen - 2; iarrJ >= 0; iarrJ--)
+ {
+ for (int j = 3; j >= 0; j--)
+ {
+ barr[barrI++] = (byte) (m_ints[iarrJ] >>> (8 * j));
+ }
+ }
+ return new BigInteger(1, barr);
+ }
+
+ public void shiftLeft()
+ {
+ int usedLen = getUsedLength();
+ if (usedLen == 0)
+ {
+ return;
+ }
+ if (m_ints[usedLen - 1] < 0)
+ {
+ // highest bit of highest used byte is set, so shifting left will
+ // make the IntArray one byte longer
+ usedLen++;
+ if (usedLen > m_ints.length)
+ {
+ // make the m_ints one byte longer, because we need one more
+ // byte which is not available in m_ints
+ m_ints = resizedInts(m_ints.length + 1);
+ }
+ }
+
+ boolean carry = false;
+ for (int i = 0; i < usedLen; i++)
+ {
+ // nextCarry is true if highest bit is set
+ boolean nextCarry = m_ints[i] < 0;
+ m_ints[i] <<= 1;
+ if (carry)
+ {
+ // set lowest bit
+ m_ints[i] |= 1;
+ }
+ carry = nextCarry;
+ }
+ }
+
+ public IntArray shiftLeft(int n)
+ {
+ int usedLen = getUsedLength();
+ if (usedLen == 0)
+ {
+ return this;
+ }
+
+ if (n == 0)
+ {
+ return this;
+ }
+
+ if (n > 31)
+ {
+ throw new IllegalArgumentException("shiftLeft() for max 31 bits "
+ + ", " + n + "bit shift is not possible");
+ }
+
+ int[] newInts = new int[usedLen + 1];
+
+ int nm32 = 32 - n;
+ newInts[0] = m_ints[0] << n;
+ for (int i = 1; i < usedLen; i++)
+ {
+ newInts[i] = (m_ints[i] << n) | (m_ints[i - 1] >>> nm32);
+ }
+ newInts[usedLen] = m_ints[usedLen - 1] >>> nm32;
+
+ return new IntArray(newInts);
+ }
+
+ public void addShifted(IntArray other, int shift)
+ {
+ int usedLenOther = other.getUsedLength();
+ int newMinUsedLen = usedLenOther + shift;
+ if (newMinUsedLen > m_ints.length)
+ {
+ m_ints = resizedInts(newMinUsedLen);
+ //System.out.println("Resize required");
+ }
+
+ for (int i = 0; i < usedLenOther; i++)
+ {
+ m_ints[i + shift] ^= other.m_ints[i];
+ }
+ }
+
+ public int getLength()
+ {
+ return m_ints.length;
+ }
+
+ public boolean testBit(int n)
+ {
+ // theInt = n / 32
+ int theInt = n >> 5;
+ // theBit = n % 32
+ int theBit = n & 0x1F;
+ int tester = 1 << theBit;
+ return ((m_ints[theInt] & tester) != 0);
+ }
+
+ public void flipBit(int n)
+ {
+ // theInt = n / 32
+ int theInt = n >> 5;
+ // theBit = n % 32
+ int theBit = n & 0x1F;
+ int flipper = 1 << theBit;
+ m_ints[theInt] ^= flipper;
+ }
+
+ public void setBit(int n)
+ {
+ // theInt = n / 32
+ int theInt = n >> 5;
+ // theBit = n % 32
+ int theBit = n & 0x1F;
+ int setter = 1 << theBit;
+ m_ints[theInt] |= setter;
+ }
+
+ public IntArray multiply(IntArray other, int m)
+ {
+ // Lenght of c is 2m bits rounded up to the next int (32 bit)
+ int t = (m + 31) >> 5;
+ if (m_ints.length < t)
+ {
+ m_ints = resizedInts(t);
+ }
+
+ IntArray b = new IntArray(other.resizedInts(other.getLength() + 1));
+ IntArray c = new IntArray((m + m + 31) >> 5);
+ // IntArray c = new IntArray(t + t);
+ int testBit = 1;
+ for (int k = 0; k < 32; k++)
+ {
+ for (int j = 0; j < t; j++)
+ {
+ if ((m_ints[j] & testBit) != 0)
+ {
+ // The kth bit of m_ints[j] is set
+ c.addShifted(b, j);
+ }
+ }
+ testBit <<= 1;
+ b.shiftLeft();
+ }
+ return c;
+ }
+
+ // public IntArray multiplyLeftToRight(IntArray other, int m) {
+ // // Lenght of c is 2m bits rounded up to the next int (32 bit)
+ // int t = (m + 31) / 32;
+ // if (m_ints.length < t) {
+ // m_ints = resizedInts(t);
+ // }
+ //
+ // IntArray b = new IntArray(other.resizedInts(other.getLength() + 1));
+ // IntArray c = new IntArray((m + m + 31) / 32);
+ // // IntArray c = new IntArray(t + t);
+ // int testBit = 1 << 31;
+ // for (int k = 31; k >= 0; k--) {
+ // for (int j = 0; j < t; j++) {
+ // if ((m_ints[j] & testBit) != 0) {
+ // // The kth bit of m_ints[j] is set
+ // c.addShifted(b, j);
+ // }
+ // }
+ // testBit >>>= 1;
+ // if (k > 0) {
+ // c.shiftLeft();
+ // }
+ // }
+ // return c;
+ // }
+
+ // TODO note, redPol.length must be 3 for TPB and 5 for PPB
+ public void reduce(int m, int[] redPol)
+ {
+ for (int i = m + m - 2; i >= m; i--)
+ {
+ if (testBit(i))
+ {
+ int bit = i - m;
+ flipBit(bit);
+ flipBit(i);
+ int l = redPol.length;
+ while (--l >= 0)
+ {
+ flipBit(redPol[l] + bit);
+ }
+ }
+ }
+ m_ints = resizedInts((m + 31) >> 5);
+ }
+
+ public IntArray square(int m)
+ {
+ // TODO make the table static final
+ final int[] table = { 0x0, 0x1, 0x4, 0x5, 0x10, 0x11, 0x14, 0x15, 0x40,
+ 0x41, 0x44, 0x45, 0x50, 0x51, 0x54, 0x55 };
+
+ int t = (m + 31) >> 5;
+ if (m_ints.length < t)
+ {
+ m_ints = resizedInts(t);
+ }
+
+ IntArray c = new IntArray(t + t);
+
+ // TODO twice the same code, put in separate private method
+ for (int i = 0; i < t; i++)
+ {
+ int v0 = 0;
+ for (int j = 0; j < 4; j++)
+ {
+ v0 = v0 >>> 8;
+ int u = (m_ints[i] >>> (j * 4)) & 0xF;
+ int w = table[u] << 24;
+ v0 |= w;
+ }
+ c.m_ints[i + i] = v0;
+
+ v0 = 0;
+ int upper = m_ints[i] >>> 16;
+ for (int j = 0; j < 4; j++)
+ {
+ v0 = v0 >>> 8;
+ int u = (upper >>> (j * 4)) & 0xF;
+ int w = table[u] << 24;
+ v0 |= w;
+ }
+ c.m_ints[i + i + 1] = v0;
+ }
+ return c;
+ }
+
+ public boolean equals(Object o)
+ {
+ if (!(o instanceof IntArray))
+ {
+ return false;
+ }
+ IntArray other = (IntArray) o;
+ int usedLen = getUsedLength();
+ if (other.getUsedLength() != usedLen)
+ {
+ return false;
+ }
+ for (int i = 0; i < usedLen; i++)
+ {
+ if (m_ints[i] != other.m_ints[i])
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public int hashCode()
+ {
+ int usedLen = getUsedLength();
+ int hash = 1;
+ for (int i = 0; i < usedLen; i++)
+ {
+ hash = hash * 31 + m_ints[i];
+ }
+ return hash;
+ }
+
+ public Object clone()
+ {
+ return new IntArray(Arrays.clone(m_ints));
+ }
+
+ public String toString()
+ {
+ int usedLen = getUsedLength();
+ if (usedLen == 0)
+ {
+ return "0";
+ }
+
+ StringBuffer sb = new StringBuffer(Integer
+ .toBinaryString(m_ints[usedLen - 1]));
+ for (int iarrJ = usedLen - 2; iarrJ >= 0; iarrJ--)
+ {
+ String hexString = Integer.toBinaryString(m_ints[iarrJ]);
+
+ // Add leading zeroes, except for highest significant int
+ for (int i = hexString.length(); i < 8; i++)
+ {
+ hexString = "0" + hexString;
+ }
+ sb.append(hexString);
+ }
+ return sb.toString();
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ec/PreCompInfo.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ec/PreCompInfo.java
new file mode 100644
index 0000000..fc693dc
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ec/PreCompInfo.java
@@ -0,0 +1,10 @@
+package org.bc.math.ec;
+
+/**
+ * Interface for classes storing precomputation data for multiplication
+ * algorithms. Used as a Memento (see GOF patterns) for
+ * WNafMultiplier
.
+ */
+interface PreCompInfo
+{
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ec/ReferenceMultiplier.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ec/ReferenceMultiplier.java
new file mode 100644
index 0000000..426b097
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ec/ReferenceMultiplier.java
@@ -0,0 +1,30 @@
+package org.bc.math.ec;
+
+import java.math.BigInteger;
+
+class ReferenceMultiplier implements ECMultiplier
+{
+ /**
+ * Simple shift-and-add multiplication. Serves as reference implementation
+ * to verify (possibly faster) implementations in
+ * {@link org.bc.math.ec.ECPoint ECPoint}.
+ *
+ * @param p The point to multiply.
+ * @param k The factor by which to multiply.
+ * @return The result of the point multiplication k * p
.
+ */
+ public ECPoint multiply(ECPoint p, BigInteger k, PreCompInfo preCompInfo)
+ {
+ ECPoint q = p.getCurve().getInfinity();
+ int t = k.bitLength();
+ for (int i = 0; i < t; i++)
+ {
+ if (k.testBit(i))
+ {
+ q = q.add(p);
+ }
+ p = p.twice();
+ }
+ return q;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ec/SimpleBigDecimal.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ec/SimpleBigDecimal.java
new file mode 100644
index 0000000..08d8dd5
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ec/SimpleBigDecimal.java
@@ -0,0 +1,253 @@
+package org.bc.math.ec;
+
+import java.math.BigInteger;
+
+/**
+ * Class representing a simple version of a big decimal. A
+ * SimpleBigDecimal
is basically a
+ * {@link java.math.BigInteger BigInteger} with a few digits on the right of
+ * the decimal point. The number of (binary) digits on the right of the decimal
+ * point is called the scale
of the SimpleBigDecimal
.
+ * Unlike in {@link java.math.BigDecimal BigDecimal}, the scale is not adjusted
+ * automatically, but must be set manually. All SimpleBigDecimal
s
+ * taking part in the same arithmetic operation must have equal scale. The
+ * result of a multiplication of two SimpleBigDecimal
s returns a
+ * SimpleBigDecimal
with double scale.
+ */
+class SimpleBigDecimal
+ //extends Number // not in J2ME - add compatibility class?
+{
+ private static final long serialVersionUID = 1L;
+
+ private final BigInteger bigInt;
+ private final int scale;
+
+ /**
+ * Returns a SimpleBigDecimal
representing the same numerical
+ * value as value
.
+ * @param value The value of the SimpleBigDecimal
to be
+ * created.
+ * @param scale The scale of the SimpleBigDecimal
to be
+ * created.
+ * @return The such created SimpleBigDecimal
.
+ */
+ public static SimpleBigDecimal getInstance(BigInteger value, int scale)
+ {
+ return new SimpleBigDecimal(value.shiftLeft(scale), scale);
+ }
+
+ /**
+ * Constructor for SimpleBigDecimal
. The value of the
+ * constructed SimpleBigDecimal
equals bigInt /
+ * 2scale
.
+ * @param bigInt The bigInt
value parameter.
+ * @param scale The scale of the constructed SimpleBigDecimal
.
+ */
+ public SimpleBigDecimal(BigInteger bigInt, int scale)
+ {
+ if (scale < 0)
+ {
+ throw new IllegalArgumentException("scale may not be negative");
+ }
+
+ this.bigInt = bigInt;
+ this.scale = scale;
+ }
+
+ private SimpleBigDecimal(SimpleBigDecimal limBigDec)
+ {
+ bigInt = limBigDec.bigInt;
+ scale = limBigDec.scale;
+ }
+
+ private void checkScale(SimpleBigDecimal b)
+ {
+ if (scale != b.scale)
+ {
+ throw new IllegalArgumentException("Only SimpleBigDecimal of " +
+ "same scale allowed in arithmetic operations");
+ }
+ }
+
+ public SimpleBigDecimal adjustScale(int newScale)
+ {
+ if (newScale < 0)
+ {
+ throw new IllegalArgumentException("scale may not be negative");
+ }
+
+ if (newScale == scale)
+ {
+ return new SimpleBigDecimal(this);
+ }
+
+ return new SimpleBigDecimal(bigInt.shiftLeft(newScale - scale),
+ newScale);
+ }
+
+ public SimpleBigDecimal add(SimpleBigDecimal b)
+ {
+ checkScale(b);
+ return new SimpleBigDecimal(bigInt.add(b.bigInt), scale);
+ }
+
+ public SimpleBigDecimal add(BigInteger b)
+ {
+ return new SimpleBigDecimal(bigInt.add(b.shiftLeft(scale)), scale);
+ }
+
+ public SimpleBigDecimal negate()
+ {
+ return new SimpleBigDecimal(bigInt.negate(), scale);
+ }
+
+ public SimpleBigDecimal subtract(SimpleBigDecimal b)
+ {
+ return add(b.negate());
+ }
+
+ public SimpleBigDecimal subtract(BigInteger b)
+ {
+ return new SimpleBigDecimal(bigInt.subtract(b.shiftLeft(scale)),
+ scale);
+ }
+
+ public SimpleBigDecimal multiply(SimpleBigDecimal b)
+ {
+ checkScale(b);
+ return new SimpleBigDecimal(bigInt.multiply(b.bigInt), scale + scale);
+ }
+
+ public SimpleBigDecimal multiply(BigInteger b)
+ {
+ return new SimpleBigDecimal(bigInt.multiply(b), scale);
+ }
+
+ public SimpleBigDecimal divide(SimpleBigDecimal b)
+ {
+ checkScale(b);
+ BigInteger dividend = bigInt.shiftLeft(scale);
+ return new SimpleBigDecimal(dividend.divide(b.bigInt), scale);
+ }
+
+ public SimpleBigDecimal divide(BigInteger b)
+ {
+ return new SimpleBigDecimal(bigInt.divide(b), scale);
+ }
+
+ public SimpleBigDecimal shiftLeft(int n)
+ {
+ return new SimpleBigDecimal(bigInt.shiftLeft(n), scale);
+ }
+
+ public int compareTo(SimpleBigDecimal val)
+ {
+ checkScale(val);
+ return bigInt.compareTo(val.bigInt);
+ }
+
+ public int compareTo(BigInteger val)
+ {
+ return bigInt.compareTo(val.shiftLeft(scale));
+ }
+
+ public BigInteger floor()
+ {
+ return bigInt.shiftRight(scale);
+ }
+
+ public BigInteger round()
+ {
+ SimpleBigDecimal oneHalf = new SimpleBigDecimal(ECConstants.ONE, 1);
+ return add(oneHalf.adjustScale(scale)).floor();
+ }
+
+ public int intValue()
+ {
+ return floor().intValue();
+ }
+
+ public long longValue()
+ {
+ return floor().longValue();
+ }
+ /* NON-J2ME compliant.
+ public double doubleValue()
+ {
+ return Double.valueOf(toString()).doubleValue();
+ }
+
+ public float floatValue()
+ {
+ return Float.valueOf(toString()).floatValue();
+ }
+ */
+ public int getScale()
+ {
+ return scale;
+ }
+
+ public String toString()
+ {
+ if (scale == 0)
+ {
+ return bigInt.toString();
+ }
+
+ BigInteger floorBigInt = floor();
+
+ BigInteger fract = bigInt.subtract(floorBigInt.shiftLeft(scale));
+ if (bigInt.signum() == -1)
+ {
+ fract = ECConstants.ONE.shiftLeft(scale).subtract(fract);
+ }
+
+ if ((floorBigInt.signum() == -1) && (!(fract.equals(ECConstants.ZERO))))
+ {
+ floorBigInt = floorBigInt.add(ECConstants.ONE);
+ }
+ String leftOfPoint = floorBigInt.toString();
+
+ char[] fractCharArr = new char[scale];
+ String fractStr = fract.toString(2);
+ int fractLen = fractStr.length();
+ int zeroes = scale - fractLen;
+ for (int i = 0; i < zeroes; i++)
+ {
+ fractCharArr[i] = '0';
+ }
+ for (int j = 0; j < fractLen; j++)
+ {
+ fractCharArr[zeroes + j] = fractStr.charAt(j);
+ }
+ String rightOfPoint = new String(fractCharArr);
+
+ StringBuffer sb = new StringBuffer(leftOfPoint);
+ sb.append(".");
+ sb.append(rightOfPoint);
+
+ return sb.toString();
+ }
+
+ public boolean equals(Object o)
+ {
+ if (this == o)
+ {
+ return true;
+ }
+
+ if (!(o instanceof SimpleBigDecimal))
+ {
+ return false;
+ }
+
+ SimpleBigDecimal other = (SimpleBigDecimal)o;
+ return ((bigInt.equals(other.bigInt)) && (scale == other.scale));
+ }
+
+ public int hashCode()
+ {
+ return bigInt.hashCode() ^ scale;
+ }
+
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ec/Tnaf.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ec/Tnaf.java
new file mode 100644
index 0000000..a5586e4
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ec/Tnaf.java
@@ -0,0 +1,844 @@
+package org.bc.math.ec;
+
+import java.math.BigInteger;
+
+/**
+ * Class holding methods for point multiplication based on the window
+ * τ-adic nonadjacent form (WTNAF). The algorithms are based on the
+ * paper "Improved Algorithms for Arithmetic on Anomalous Binary Curves"
+ * by Jerome A. Solinas. The paper first appeared in the Proceedings of
+ * Crypto 1997.
+ */
+class Tnaf
+{
+ private static final BigInteger MINUS_ONE = ECConstants.ONE.negate();
+ private static final BigInteger MINUS_TWO = ECConstants.TWO.negate();
+ private static final BigInteger MINUS_THREE = ECConstants.THREE.negate();
+
+ /**
+ * The window width of WTNAF. The standard value of 4 is slightly less
+ * than optimal for running time, but keeps space requirements for
+ * precomputation low. For typical curves, a value of 5 or 6 results in
+ * a better running time. When changing this value, the
+ * αu
's must be computed differently, see
+ * e.g. "Guide to Elliptic Curve Cryptography", Darrel Hankerson,
+ * Alfred Menezes, Scott Vanstone, Springer-Verlag New York Inc., 2004,
+ * p. 121-122
+ */
+ public static final byte WIDTH = 4;
+
+ /**
+ * 24
+ */
+ public static final byte POW_2_WIDTH = 16;
+
+ /**
+ * The αu
's for a=0
as an array
+ * of ZTauElement
s.
+ */
+ public static final ZTauElement[] alpha0 = {
+ null,
+ new ZTauElement(ECConstants.ONE, ECConstants.ZERO), null,
+ new ZTauElement(MINUS_THREE, MINUS_ONE), null,
+ new ZTauElement(MINUS_ONE, MINUS_ONE), null,
+ new ZTauElement(ECConstants.ONE, MINUS_ONE), null
+ };
+
+ /**
+ * The αu
's for a=0
as an array
+ * of TNAFs.
+ */
+ public static final byte[][] alpha0Tnaf = {
+ null, {1}, null, {-1, 0, 1}, null, {1, 0, 1}, null, {-1, 0, 0, 1}
+ };
+
+ /**
+ * The αu
's for a=1
as an array
+ * of ZTauElement
s.
+ */
+ public static final ZTauElement[] alpha1 = {null,
+ new ZTauElement(ECConstants.ONE, ECConstants.ZERO), null,
+ new ZTauElement(MINUS_THREE, ECConstants.ONE), null,
+ new ZTauElement(MINUS_ONE, ECConstants.ONE), null,
+ new ZTauElement(ECConstants.ONE, ECConstants.ONE), null
+ };
+
+ /**
+ * The αu
's for a=1
as an array
+ * of TNAFs.
+ */
+ public static final byte[][] alpha1Tnaf = {
+ null, {1}, null, {-1, 0, 1}, null, {1, 0, 1}, null, {-1, 0, 0, -1}
+ };
+
+ /**
+ * Computes the norm of an element λ
of
+ * Z[τ]
.
+ * @param mu The parameter μ
of the elliptic curve.
+ * @param lambda The element λ
of
+ * Z[τ]
.
+ * @return The norm of λ
.
+ */
+ public static BigInteger norm(final byte mu, ZTauElement lambda)
+ {
+ BigInteger norm;
+
+ // s1 = u^2
+ BigInteger s1 = lambda.u.multiply(lambda.u);
+
+ // s2 = u * v
+ BigInteger s2 = lambda.u.multiply(lambda.v);
+
+ // s3 = 2 * v^2
+ BigInteger s3 = lambda.v.multiply(lambda.v).shiftLeft(1);
+
+ if (mu == 1)
+ {
+ norm = s1.add(s2).add(s3);
+ }
+ else if (mu == -1)
+ {
+ norm = s1.subtract(s2).add(s3);
+ }
+ else
+ {
+ throw new IllegalArgumentException("mu must be 1 or -1");
+ }
+
+ return norm;
+ }
+
+ /**
+ * Computes the norm of an element λ
of
+ * R[τ]
, where λ = u + vτ
+ * and u
and u
are real numbers (elements of
+ * R
).
+ * @param mu The parameter μ
of the elliptic curve.
+ * @param u The real part of the element λ
of
+ * R[τ]
.
+ * @param v The τ
-adic part of the element
+ * λ
of R[τ]
.
+ * @return The norm of λ
.
+ */
+ public static SimpleBigDecimal norm(final byte mu, SimpleBigDecimal u,
+ SimpleBigDecimal v)
+ {
+ SimpleBigDecimal norm;
+
+ // s1 = u^2
+ SimpleBigDecimal s1 = u.multiply(u);
+
+ // s2 = u * v
+ SimpleBigDecimal s2 = u.multiply(v);
+
+ // s3 = 2 * v^2
+ SimpleBigDecimal s3 = v.multiply(v).shiftLeft(1);
+
+ if (mu == 1)
+ {
+ norm = s1.add(s2).add(s3);
+ }
+ else if (mu == -1)
+ {
+ norm = s1.subtract(s2).add(s3);
+ }
+ else
+ {
+ throw new IllegalArgumentException("mu must be 1 or -1");
+ }
+
+ return norm;
+ }
+
+ /**
+ * Rounds an element λ
of R[τ]
+ * to an element of Z[τ]
, such that their difference
+ * has minimal norm. λ
is given as
+ * λ = λ0 + λ1τ
.
+ * @param lambda0 The component λ0
.
+ * @param lambda1 The component λ1
.
+ * @param mu The parameter μ
of the elliptic curve. Must
+ * equal 1 or -1.
+ * @return The rounded element of Z[τ]
.
+ * @throws IllegalArgumentException if lambda0
and
+ * lambda1
do not have same scale.
+ */
+ public static ZTauElement round(SimpleBigDecimal lambda0,
+ SimpleBigDecimal lambda1, byte mu)
+ {
+ int scale = lambda0.getScale();
+ if (lambda1.getScale() != scale)
+ {
+ throw new IllegalArgumentException("lambda0 and lambda1 do not " +
+ "have same scale");
+ }
+
+ if (!((mu == 1) || (mu == -1)))
+ {
+ throw new IllegalArgumentException("mu must be 1 or -1");
+ }
+
+ BigInteger f0 = lambda0.round();
+ BigInteger f1 = lambda1.round();
+
+ SimpleBigDecimal eta0 = lambda0.subtract(f0);
+ SimpleBigDecimal eta1 = lambda1.subtract(f1);
+
+ // eta = 2*eta0 + mu*eta1
+ SimpleBigDecimal eta = eta0.add(eta0);
+ if (mu == 1)
+ {
+ eta = eta.add(eta1);
+ }
+ else
+ {
+ // mu == -1
+ eta = eta.subtract(eta1);
+ }
+
+ // check1 = eta0 - 3*mu*eta1
+ // check2 = eta0 + 4*mu*eta1
+ SimpleBigDecimal threeEta1 = eta1.add(eta1).add(eta1);
+ SimpleBigDecimal fourEta1 = threeEta1.add(eta1);
+ SimpleBigDecimal check1;
+ SimpleBigDecimal check2;
+ if (mu == 1)
+ {
+ check1 = eta0.subtract(threeEta1);
+ check2 = eta0.add(fourEta1);
+ }
+ else
+ {
+ // mu == -1
+ check1 = eta0.add(threeEta1);
+ check2 = eta0.subtract(fourEta1);
+ }
+
+ byte h0 = 0;
+ byte h1 = 0;
+
+ // if eta >= 1
+ if (eta.compareTo(ECConstants.ONE) >= 0)
+ {
+ if (check1.compareTo(MINUS_ONE) < 0)
+ {
+ h1 = mu;
+ }
+ else
+ {
+ h0 = 1;
+ }
+ }
+ else
+ {
+ // eta < 1
+ if (check2.compareTo(ECConstants.TWO) >= 0)
+ {
+ h1 = mu;
+ }
+ }
+
+ // if eta < -1
+ if (eta.compareTo(MINUS_ONE) < 0)
+ {
+ if (check1.compareTo(ECConstants.ONE) >= 0)
+ {
+ h1 = (byte)-mu;
+ }
+ else
+ {
+ h0 = -1;
+ }
+ }
+ else
+ {
+ // eta >= -1
+ if (check2.compareTo(MINUS_TWO) < 0)
+ {
+ h1 = (byte)-mu;
+ }
+ }
+
+ BigInteger q0 = f0.add(BigInteger.valueOf(h0));
+ BigInteger q1 = f1.add(BigInteger.valueOf(h1));
+ return new ZTauElement(q0, q1);
+ }
+
+ /**
+ * Approximate division by n
. For an integer
+ * k
, the value λ = s k / n
is
+ * computed to c
bits of accuracy.
+ * @param k The parameter k
.
+ * @param s The curve parameter s0
or
+ * s1
.
+ * @param vm The Lucas Sequence element Vm
.
+ * @param a The parameter a
of the elliptic curve.
+ * @param m The bit length of the finite field
+ * Fm
.
+ * @param c The number of bits of accuracy, i.e. the scale of the returned
+ * SimpleBigDecimal
.
+ * @return The value λ = s k / n
computed to
+ * c
bits of accuracy.
+ */
+ public static SimpleBigDecimal approximateDivisionByN(BigInteger k,
+ BigInteger s, BigInteger vm, byte a, int m, int c)
+ {
+ int _k = (m + 5)/2 + c;
+ BigInteger ns = k.shiftRight(m - _k - 2 + a);
+
+ BigInteger gs = s.multiply(ns);
+
+ BigInteger hs = gs.shiftRight(m);
+
+ BigInteger js = vm.multiply(hs);
+
+ BigInteger gsPlusJs = gs.add(js);
+ BigInteger ls = gsPlusJs.shiftRight(_k-c);
+ if (gsPlusJs.testBit(_k-c-1))
+ {
+ // round up
+ ls = ls.add(ECConstants.ONE);
+ }
+
+ return new SimpleBigDecimal(ls, c);
+ }
+
+ /**
+ * Computes the τ
-adic NAF (non-adjacent form) of an
+ * element λ
of Z[τ]
.
+ * @param mu The parameter μ
of the elliptic curve.
+ * @param lambda The element λ
of
+ * Z[τ]
.
+ * @return The τ
-adic NAF of λ
.
+ */
+ public static byte[] tauAdicNaf(byte mu, ZTauElement lambda)
+ {
+ if (!((mu == 1) || (mu == -1)))
+ {
+ throw new IllegalArgumentException("mu must be 1 or -1");
+ }
+
+ BigInteger norm = norm(mu, lambda);
+
+ // Ceiling of log2 of the norm
+ int log2Norm = norm.bitLength();
+
+ // If length(TNAF) > 30, then length(TNAF) < log2Norm + 3.52
+ int maxLength = log2Norm > 30 ? log2Norm + 4 : 34;
+
+ // The array holding the TNAF
+ byte[] u = new byte[maxLength];
+ int i = 0;
+
+ // The actual length of the TNAF
+ int length = 0;
+
+ BigInteger r0 = lambda.u;
+ BigInteger r1 = lambda.v;
+
+ while(!((r0.equals(ECConstants.ZERO)) && (r1.equals(ECConstants.ZERO))))
+ {
+ // If r0 is odd
+ if (r0.testBit(0))
+ {
+ u[i] = (byte) ECConstants.TWO.subtract((r0.subtract(r1.shiftLeft(1))).mod(ECConstants.FOUR)).intValue();
+
+ // r0 = r0 - u[i]
+ if (u[i] == 1)
+ {
+ r0 = r0.clearBit(0);
+ }
+ else
+ {
+ // u[i] == -1
+ r0 = r0.add(ECConstants.ONE);
+ }
+ length = i;
+ }
+ else
+ {
+ u[i] = 0;
+ }
+
+ BigInteger t = r0;
+ BigInteger s = r0.shiftRight(1);
+ if (mu == 1)
+ {
+ r0 = r1.add(s);
+ }
+ else
+ {
+ // mu == -1
+ r0 = r1.subtract(s);
+ }
+
+ r1 = t.shiftRight(1).negate();
+ i++;
+ }
+
+ length++;
+
+ // Reduce the TNAF array to its actual length
+ byte[] tnaf = new byte[length];
+ System.arraycopy(u, 0, tnaf, 0, length);
+ return tnaf;
+ }
+
+ /**
+ * Applies the operation τ()
to an
+ * ECPoint.F2m
.
+ * @param p The ECPoint.F2m to which τ()
is applied.
+ * @return τ(p)
+ */
+ public static ECPoint.F2m tau(ECPoint.F2m p)
+ {
+ if (p.isInfinity())
+ {
+ return p;
+ }
+
+ ECFieldElement x = p.getX();
+ ECFieldElement y = p.getY();
+
+ return new ECPoint.F2m(p.getCurve(), x.square(), y.square(), p.isCompressed());
+ }
+
+ /**
+ * Returns the parameter μ
of the elliptic curve.
+ * @param curve The elliptic curve from which to obtain μ
.
+ * The curve must be a Koblitz curve, i.e. a
equals
+ * 0
or 1
and b
equals
+ * 1
.
+ * @return μ
of the elliptic curve.
+ * @throws IllegalArgumentException if the given ECCurve is not a Koblitz
+ * curve.
+ */
+ public static byte getMu(ECCurve.F2m curve)
+ {
+ BigInteger a = curve.getA().toBigInteger();
+ byte mu;
+
+ if (a.equals(ECConstants.ZERO))
+ {
+ mu = -1;
+ }
+ else if (a.equals(ECConstants.ONE))
+ {
+ mu = 1;
+ }
+ else
+ {
+ throw new IllegalArgumentException("No Koblitz curve (ABC), " +
+ "TNAF multiplication not possible");
+ }
+ return mu;
+ }
+
+ /**
+ * Calculates the Lucas Sequence elements Uk-1
and
+ * Uk
or Vk-1
and
+ * Vk
.
+ * @param mu The parameter μ
of the elliptic curve.
+ * @param k The index of the second element of the Lucas Sequence to be
+ * returned.
+ * @param doV If set to true, computes Vk-1
and
+ * Vk
, otherwise Uk-1
and
+ * Uk
.
+ * @return An array with 2 elements, containing Uk-1
+ * and Uk
or Vk-1
+ * and Vk
.
+ */
+ public static BigInteger[] getLucas(byte mu, int k, boolean doV)
+ {
+ if (!((mu == 1) || (mu == -1)))
+ {
+ throw new IllegalArgumentException("mu must be 1 or -1");
+ }
+
+ BigInteger u0;
+ BigInteger u1;
+ BigInteger u2;
+
+ if (doV)
+ {
+ u0 = ECConstants.TWO;
+ u1 = BigInteger.valueOf(mu);
+ }
+ else
+ {
+ u0 = ECConstants.ZERO;
+ u1 = ECConstants.ONE;
+ }
+
+ for (int i = 1; i < k; i++)
+ {
+ // u2 = mu*u1 - 2*u0;
+ BigInteger s = null;
+ if (mu == 1)
+ {
+ s = u1;
+ }
+ else
+ {
+ // mu == -1
+ s = u1.negate();
+ }
+
+ u2 = s.subtract(u0.shiftLeft(1));
+ u0 = u1;
+ u1 = u2;
+// System.out.println(i + ": " + u2);
+// System.out.println();
+ }
+
+ BigInteger[] retVal = {u0, u1};
+ return retVal;
+ }
+
+ /**
+ * Computes the auxiliary value tw
. If the width is
+ * 4, then for mu = 1
, tw = 6
and for
+ * mu = -1
, tw = 10
+ * @param mu The parameter μ
of the elliptic curve.
+ * @param w The window width of the WTNAF.
+ * @return the auxiliary value tw
+ */
+ public static BigInteger getTw(byte mu, int w)
+ {
+ if (w == 4)
+ {
+ if (mu == 1)
+ {
+ return BigInteger.valueOf(6);
+ }
+ else
+ {
+ // mu == -1
+ return BigInteger.valueOf(10);
+ }
+ }
+ else
+ {
+ // For w <> 4, the values must be computed
+ BigInteger[] us = getLucas(mu, w, false);
+ BigInteger twoToW = ECConstants.ZERO.setBit(w);
+ BigInteger u1invert = us[1].modInverse(twoToW);
+ BigInteger tw;
+ tw = ECConstants.TWO.multiply(us[0]).multiply(u1invert).mod(twoToW);
+// System.out.println("mu = " + mu);
+// System.out.println("tw = " + tw);
+ return tw;
+ }
+ }
+
+ /**
+ * Computes the auxiliary values s0
and
+ * s1
used for partial modular reduction.
+ * @param curve The elliptic curve for which to compute
+ * s0
and s1
.
+ * @throws IllegalArgumentException if curve
is not a
+ * Koblitz curve (Anomalous Binary Curve, ABC).
+ */
+ public static BigInteger[] getSi(ECCurve.F2m curve)
+ {
+ if (!curve.isKoblitz())
+ {
+ throw new IllegalArgumentException("si is defined for Koblitz curves only");
+ }
+
+ int m = curve.getM();
+ int a = curve.getA().toBigInteger().intValue();
+ byte mu = curve.getMu();
+ int h = curve.getH().intValue();
+ int index = m + 3 - a;
+ BigInteger[] ui = getLucas(mu, index, false);
+
+ BigInteger dividend0;
+ BigInteger dividend1;
+ if (mu == 1)
+ {
+ dividend0 = ECConstants.ONE.subtract(ui[1]);
+ dividend1 = ECConstants.ONE.subtract(ui[0]);
+ }
+ else if (mu == -1)
+ {
+ dividend0 = ECConstants.ONE.add(ui[1]);
+ dividend1 = ECConstants.ONE.add(ui[0]);
+ }
+ else
+ {
+ throw new IllegalArgumentException("mu must be 1 or -1");
+ }
+
+ BigInteger[] si = new BigInteger[2];
+
+ if (h == 2)
+ {
+ si[0] = dividend0.shiftRight(1);
+ si[1] = dividend1.shiftRight(1).negate();
+ }
+ else if (h == 4)
+ {
+ si[0] = dividend0.shiftRight(2);
+ si[1] = dividend1.shiftRight(2).negate();
+ }
+ else
+ {
+ throw new IllegalArgumentException("h (Cofactor) must be 2 or 4");
+ }
+
+ return si;
+ }
+
+ /**
+ * Partial modular reduction modulo
+ * (τm - 1)/(τ - 1)
.
+ * @param k The integer to be reduced.
+ * @param m The bitlength of the underlying finite field.
+ * @param a The parameter a
of the elliptic curve.
+ * @param s The auxiliary values s0
and
+ * s1
.
+ * @param mu The parameter μ of the elliptic curve.
+ * @param c The precision (number of bits of accuracy) of the partial
+ * modular reduction.
+ * @return ρ := k partmod (τm - 1)/(τ - 1)
+ */
+ public static ZTauElement partModReduction(BigInteger k, int m, byte a,
+ BigInteger[] s, byte mu, byte c)
+ {
+ // d0 = s[0] + mu*s[1]; mu is either 1 or -1
+ BigInteger d0;
+ if (mu == 1)
+ {
+ d0 = s[0].add(s[1]);
+ }
+ else
+ {
+ d0 = s[0].subtract(s[1]);
+ }
+
+ BigInteger[] v = getLucas(mu, m, true);
+ BigInteger vm = v[1];
+
+ SimpleBigDecimal lambda0 = approximateDivisionByN(
+ k, s[0], vm, a, m, c);
+
+ SimpleBigDecimal lambda1 = approximateDivisionByN(
+ k, s[1], vm, a, m, c);
+
+ ZTauElement q = round(lambda0, lambda1, mu);
+
+ // r0 = n - d0*q0 - 2*s1*q1
+ BigInteger r0 = k.subtract(d0.multiply(q.u)).subtract(
+ BigInteger.valueOf(2).multiply(s[1]).multiply(q.v));
+
+ // r1 = s1*q0 - s0*q1
+ BigInteger r1 = s[1].multiply(q.u).subtract(s[0].multiply(q.v));
+
+ return new ZTauElement(r0, r1);
+ }
+
+ /**
+ * Multiplies a {@link org.bc.math.ec.ECPoint.F2m ECPoint.F2m}
+ * by a BigInteger
using the reduced τ
-adic
+ * NAF (RTNAF) method.
+ * @param p The ECPoint.F2m to multiply.
+ * @param k The BigInteger
by which to multiply p
.
+ * @return k * p
+ */
+ public static ECPoint.F2m multiplyRTnaf(ECPoint.F2m p, BigInteger k)
+ {
+ ECCurve.F2m curve = (ECCurve.F2m) p.getCurve();
+ int m = curve.getM();
+ byte a = (byte) curve.getA().toBigInteger().intValue();
+ byte mu = curve.getMu();
+ BigInteger[] s = curve.getSi();
+ ZTauElement rho = partModReduction(k, m, a, s, mu, (byte)10);
+
+ return multiplyTnaf(p, rho);
+ }
+
+ /**
+ * Multiplies a {@link org.bc.math.ec.ECPoint.F2m ECPoint.F2m}
+ * by an element λ
of Z[τ]
+ * using the τ
-adic NAF (TNAF) method.
+ * @param p The ECPoint.F2m to multiply.
+ * @param lambda The element λ
of
+ * Z[τ]
.
+ * @return λ * p
+ */
+ public static ECPoint.F2m multiplyTnaf(ECPoint.F2m p, ZTauElement lambda)
+ {
+ ECCurve.F2m curve = (ECCurve.F2m)p.getCurve();
+ byte mu = curve.getMu();
+ byte[] u = tauAdicNaf(mu, lambda);
+
+ ECPoint.F2m q = multiplyFromTnaf(p, u);
+
+ return q;
+ }
+
+ /**
+ * Multiplies a {@link org.bc.math.ec.ECPoint.F2m ECPoint.F2m}
+ * by an element λ
of Z[τ]
+ * using the τ
-adic NAF (TNAF) method, given the TNAF
+ * of λ
.
+ * @param p The ECPoint.F2m to multiply.
+ * @param u The the TNAF of λ
..
+ * @return λ * p
+ */
+ public static ECPoint.F2m multiplyFromTnaf(ECPoint.F2m p, byte[] u)
+ {
+ ECCurve.F2m curve = (ECCurve.F2m)p.getCurve();
+ ECPoint.F2m q = (ECPoint.F2m) curve.getInfinity();
+ for (int i = u.length - 1; i >= 0; i--)
+ {
+ q = tau(q);
+ if (u[i] == 1)
+ {
+ q = (ECPoint.F2m)q.addSimple(p);
+ }
+ else if (u[i] == -1)
+ {
+ q = (ECPoint.F2m)q.subtractSimple(p);
+ }
+ }
+ return q;
+ }
+
+ /**
+ * Computes the [τ]
-adic window NAF of an element
+ * λ
of Z[τ]
.
+ * @param mu The parameter μ of the elliptic curve.
+ * @param lambda The element λ
of
+ * Z[τ]
of which to compute the
+ * [τ]
-adic NAF.
+ * @param width The window width of the resulting WNAF.
+ * @param pow2w 2width.
+ * @param tw The auxiliary value tw
.
+ * @param alpha The αu
's for the window width.
+ * @return The [τ]
-adic window NAF of
+ * λ
.
+ */
+ public static byte[] tauAdicWNaf(byte mu, ZTauElement lambda,
+ byte width, BigInteger pow2w, BigInteger tw, ZTauElement[] alpha)
+ {
+ if (!((mu == 1) || (mu == -1)))
+ {
+ throw new IllegalArgumentException("mu must be 1 or -1");
+ }
+
+ BigInteger norm = norm(mu, lambda);
+
+ // Ceiling of log2 of the norm
+ int log2Norm = norm.bitLength();
+
+ // If length(TNAF) > 30, then length(TNAF) < log2Norm + 3.52
+ int maxLength = log2Norm > 30 ? log2Norm + 4 + width : 34 + width;
+
+ // The array holding the TNAF
+ byte[] u = new byte[maxLength];
+
+ // 2^(width - 1)
+ BigInteger pow2wMin1 = pow2w.shiftRight(1);
+
+ // Split lambda into two BigIntegers to simplify calculations
+ BigInteger r0 = lambda.u;
+ BigInteger r1 = lambda.v;
+ int i = 0;
+
+ // while lambda <> (0, 0)
+ while (!((r0.equals(ECConstants.ZERO))&&(r1.equals(ECConstants.ZERO))))
+ {
+ // if r0 is odd
+ if (r0.testBit(0))
+ {
+ // uUnMod = r0 + r1*tw mod 2^width
+ BigInteger uUnMod
+ = r0.add(r1.multiply(tw)).mod(pow2w);
+
+ byte uLocal;
+ // if uUnMod >= 2^(width - 1)
+ if (uUnMod.compareTo(pow2wMin1) >= 0)
+ {
+ uLocal = (byte) uUnMod.subtract(pow2w).intValue();
+ }
+ else
+ {
+ uLocal = (byte) uUnMod.intValue();
+ }
+ // uLocal is now in [-2^(width-1), 2^(width-1)-1]
+
+ u[i] = uLocal;
+ boolean s = true;
+ if (uLocal < 0)
+ {
+ s = false;
+ uLocal = (byte)-uLocal;
+ }
+ // uLocal is now >= 0
+
+ if (s)
+ {
+ r0 = r0.subtract(alpha[uLocal].u);
+ r1 = r1.subtract(alpha[uLocal].v);
+ }
+ else
+ {
+ r0 = r0.add(alpha[uLocal].u);
+ r1 = r1.add(alpha[uLocal].v);
+ }
+ }
+ else
+ {
+ u[i] = 0;
+ }
+
+ BigInteger t = r0;
+
+ if (mu == 1)
+ {
+ r0 = r1.add(r0.shiftRight(1));
+ }
+ else
+ {
+ // mu == -1
+ r0 = r1.subtract(r0.shiftRight(1));
+ }
+ r1 = t.shiftRight(1).negate();
+ i++;
+ }
+ return u;
+ }
+
+ /**
+ * Does the precomputation for WTNAF multiplication.
+ * @param p The ECPoint
for which to do the precomputation.
+ * @param a The parameter a
of the elliptic curve.
+ * @return The precomputation array for p
.
+ */
+ public static ECPoint.F2m[] getPreComp(ECPoint.F2m p, byte a)
+ {
+ ECPoint.F2m[] pu;
+ pu = new ECPoint.F2m[16];
+ pu[1] = p;
+ byte[][] alphaTnaf;
+ if (a == 0)
+ {
+ alphaTnaf = Tnaf.alpha0Tnaf;
+ }
+ else
+ {
+ // a == 1
+ alphaTnaf = Tnaf.alpha1Tnaf;
+ }
+
+ int precompLen = alphaTnaf.length;
+ for (int i = 3; i < precompLen; i = i + 2)
+ {
+ pu[i] = Tnaf.multiplyFromTnaf(p, alphaTnaf[i]);
+ }
+
+ return pu;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ec/WNafMultiplier.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ec/WNafMultiplier.java
new file mode 100644
index 0000000..6d43abd
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ec/WNafMultiplier.java
@@ -0,0 +1,240 @@
+package org.bc.math.ec;
+
+import java.math.BigInteger;
+
+/**
+ * Class implementing the WNAF (Window Non-Adjacent Form) multiplication
+ * algorithm.
+ */
+class WNafMultiplier implements ECMultiplier
+{
+ /**
+ * Computes the Window NAF (non-adjacent Form) of an integer.
+ * @param width The width w
of the Window NAF. The width is
+ * defined as the minimal number w
, such that for any
+ * w
consecutive digits in the resulting representation, at
+ * most one is non-zero.
+ * @param k The integer of which the Window NAF is computed.
+ * @return The Window NAF of the given width, such that the following holds:
+ * k = ∑i=0l-1 ki2i
+ *
, where the ki
denote the elements of the
+ * returned byte[]
.
+ */
+ public byte[] windowNaf(byte width, BigInteger k)
+ {
+ // The window NAF is at most 1 element longer than the binary
+ // representation of the integer k. byte can be used instead of short or
+ // int unless the window width is larger than 8. For larger width use
+ // short or int. However, a width of more than 8 is not efficient for
+ // m = log2(q) smaller than 2305 Bits. Note: Values for m larger than
+ // 1000 Bits are currently not used in practice.
+ byte[] wnaf = new byte[k.bitLength() + 1];
+
+ // 2^width as short and BigInteger
+ short pow2wB = (short)(1 << width);
+ BigInteger pow2wBI = BigInteger.valueOf(pow2wB);
+
+ int i = 0;
+
+ // The actual length of the WNAF
+ int length = 0;
+
+ // while k >= 1
+ while (k.signum() > 0)
+ {
+ // if k is odd
+ if (k.testBit(0))
+ {
+ // k mod 2^width
+ BigInteger remainder = k.mod(pow2wBI);
+
+ // if remainder > 2^(width - 1) - 1
+ if (remainder.testBit(width - 1))
+ {
+ wnaf[i] = (byte)(remainder.intValue() - pow2wB);
+ }
+ else
+ {
+ wnaf[i] = (byte)remainder.intValue();
+ }
+ // wnaf[i] is now in [-2^(width-1), 2^(width-1)-1]
+
+ k = k.subtract(BigInteger.valueOf(wnaf[i]));
+ length = i;
+ }
+ else
+ {
+ wnaf[i] = 0;
+ }
+
+ // k = k/2
+ k = k.shiftRight(1);
+ i++;
+ }
+
+ length++;
+
+ // Reduce the WNAF array to its actual length
+ byte[] wnafShort = new byte[length];
+ System.arraycopy(wnaf, 0, wnafShort, 0, length);
+ return wnafShort;
+ }
+
+ /**
+ * Multiplies this
by an integer k
using the
+ * Window NAF method.
+ * @param k The integer by which this
is multiplied.
+ * @return A new ECPoint
which equals this
+ * multiplied by k
.
+ */
+ public ECPoint multiply(ECPoint p, BigInteger k, PreCompInfo preCompInfo)
+ {
+ WNafPreCompInfo wnafPreCompInfo;
+
+ if ((preCompInfo != null) && (preCompInfo instanceof WNafPreCompInfo))
+ {
+ wnafPreCompInfo = (WNafPreCompInfo)preCompInfo;
+ }
+ else
+ {
+ // Ignore empty PreCompInfo or PreCompInfo of incorrect type
+ wnafPreCompInfo = new WNafPreCompInfo();
+ }
+
+ // floor(log2(k))
+ int m = k.bitLength();
+
+ // width of the Window NAF
+ byte width;
+
+ // Required length of precomputation array
+ int reqPreCompLen;
+
+ // Determine optimal width and corresponding length of precomputation
+ // array based on literature values
+ if (m < 13)
+ {
+ width = 2;
+ reqPreCompLen = 1;
+ }
+ else
+ {
+ if (m < 41)
+ {
+ width = 3;
+ reqPreCompLen = 2;
+ }
+ else
+ {
+ if (m < 121)
+ {
+ width = 4;
+ reqPreCompLen = 4;
+ }
+ else
+ {
+ if (m < 337)
+ {
+ width = 5;
+ reqPreCompLen = 8;
+ }
+ else
+ {
+ if (m < 897)
+ {
+ width = 6;
+ reqPreCompLen = 16;
+ }
+ else
+ {
+ if (m < 2305)
+ {
+ width = 7;
+ reqPreCompLen = 32;
+ }
+ else
+ {
+ width = 8;
+ reqPreCompLen = 127;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // The length of the precomputation array
+ int preCompLen = 1;
+
+ ECPoint[] preComp = wnafPreCompInfo.getPreComp();
+ ECPoint twiceP = wnafPreCompInfo.getTwiceP();
+
+ // Check if the precomputed ECPoints already exist
+ if (preComp == null)
+ {
+ // Precomputation must be performed from scratch, create an empty
+ // precomputation array of desired length
+ preComp = new ECPoint[]{ p };
+ }
+ else
+ {
+ // Take the already precomputed ECPoints to start with
+ preCompLen = preComp.length;
+ }
+
+ if (twiceP == null)
+ {
+ // Compute twice(p)
+ twiceP = p.twice();
+ }
+
+ if (preCompLen < reqPreCompLen)
+ {
+ // Precomputation array must be made bigger, copy existing preComp
+ // array into the larger new preComp array
+ ECPoint[] oldPreComp = preComp;
+ preComp = new ECPoint[reqPreCompLen];
+ System.arraycopy(oldPreComp, 0, preComp, 0, preCompLen);
+
+ for (int i = preCompLen; i < reqPreCompLen; i++)
+ {
+ // Compute the new ECPoints for the precomputation array.
+ // The values 1, 3, 5, ..., 2^(width-1)-1 times p are
+ // computed
+ preComp[i] = twiceP.add(preComp[i - 1]);
+ }
+ }
+
+ // Compute the Window NAF of the desired width
+ byte[] wnaf = windowNaf(width, k);
+ int l = wnaf.length;
+
+ // Apply the Window NAF to p using the precomputed ECPoint values.
+ ECPoint q = p.getCurve().getInfinity();
+ for (int i = l - 1; i >= 0; i--)
+ {
+ q = q.twice();
+
+ if (wnaf[i] != 0)
+ {
+ if (wnaf[i] > 0)
+ {
+ q = q.add(preComp[(wnaf[i] - 1)/2]);
+ }
+ else
+ {
+ // wnaf[i] < 0
+ q = q.subtract(preComp[(-wnaf[i] - 1)/2]);
+ }
+ }
+ }
+
+ // Set PreCompInfo in ECPoint, such that it is available for next
+ // multiplication.
+ wnafPreCompInfo.setPreComp(preComp);
+ wnafPreCompInfo.setTwiceP(twiceP);
+ p.setPreCompInfo(wnafPreCompInfo);
+ return q;
+ }
+
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ec/WNafPreCompInfo.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ec/WNafPreCompInfo.java
new file mode 100644
index 0000000..c969bcf
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ec/WNafPreCompInfo.java
@@ -0,0 +1,44 @@
+package org.bc.math.ec;
+
+/**
+ * Class holding precomputation data for the WNAF (Window Non-Adjacent Form)
+ * algorithm.
+ */
+class WNafPreCompInfo implements PreCompInfo
+{
+ /**
+ * Array holding the precomputed ECPoint
s used for the Window
+ * NAF multiplication in
+ * {@link org.bouncycastle.math.ec.multiplier.WNafMultiplier.multiply()
+ * WNafMultiplier.multiply()}
.
+ */
+ private ECPoint[] preComp = null;
+
+ /**
+ * Holds an ECPoint
representing twice(this). Used for the
+ * Window NAF multiplication in
+ * {@link org.bouncycastle.math.ec.multiplier.WNafMultiplier.multiply()
+ * WNafMultiplier.multiply()}
.
+ */
+ private ECPoint twiceP = null;
+
+ protected ECPoint[] getPreComp()
+ {
+ return preComp;
+ }
+
+ protected void setPreComp(ECPoint[] preComp)
+ {
+ this.preComp = preComp;
+ }
+
+ protected ECPoint getTwiceP()
+ {
+ return twiceP;
+ }
+
+ protected void setTwiceP(ECPoint twiceThis)
+ {
+ this.twiceP = twiceThis;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ec/WTauNafMultiplier.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ec/WTauNafMultiplier.java
new file mode 100644
index 0000000..6ef0052
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ec/WTauNafMultiplier.java
@@ -0,0 +1,119 @@
+package org.bc.math.ec;
+
+import java.math.BigInteger;
+
+/**
+ * Class implementing the WTNAF (Window
+ * τ
-adic Non-Adjacent Form) algorithm.
+ */
+class WTauNafMultiplier implements ECMultiplier
+{
+ /**
+ * Multiplies a {@link org.bc.math.ec.ECPoint.F2m ECPoint.F2m}
+ * by k
using the reduced τ
-adic NAF (RTNAF)
+ * method.
+ * @param p The ECPoint.F2m to multiply.
+ * @param k The integer by which to multiply k
.
+ * @return p
multiplied by k
.
+ */
+ public ECPoint multiply(ECPoint point, BigInteger k, PreCompInfo preCompInfo)
+ {
+ if (!(point instanceof ECPoint.F2m))
+ {
+ throw new IllegalArgumentException("Only ECPoint.F2m can be " +
+ "used in WTauNafMultiplier");
+ }
+
+ ECPoint.F2m p = (ECPoint.F2m)point;
+
+ ECCurve.F2m curve = (ECCurve.F2m) p.getCurve();
+ int m = curve.getM();
+ byte a = curve.getA().toBigInteger().byteValue();
+ byte mu = curve.getMu();
+ BigInteger[] s = curve.getSi();
+
+ ZTauElement rho = Tnaf.partModReduction(k, m, a, s, mu, (byte)10);
+
+ return multiplyWTnaf(p, rho, preCompInfo, a, mu);
+ }
+
+ /**
+ * Multiplies a {@link org.bc.math.ec.ECPoint.F2m ECPoint.F2m}
+ * by an element λ
of Z[τ]
using
+ * the τ
-adic NAF (TNAF) method.
+ * @param p The ECPoint.F2m to multiply.
+ * @param lambda The element λ
of
+ * Z[τ]
of which to compute the
+ * [τ]
-adic NAF.
+ * @return p
multiplied by λ
.
+ */
+ private ECPoint.F2m multiplyWTnaf(ECPoint.F2m p, ZTauElement lambda,
+ PreCompInfo preCompInfo, byte a, byte mu)
+ {
+ ZTauElement[] alpha;
+ if (a == 0)
+ {
+ alpha = Tnaf.alpha0;
+ }
+ else
+ {
+ // a == 1
+ alpha = Tnaf.alpha1;
+ }
+
+ BigInteger tw = Tnaf.getTw(mu, Tnaf.WIDTH);
+
+ byte[]u = Tnaf.tauAdicWNaf(mu, lambda, Tnaf.WIDTH,
+ BigInteger.valueOf(Tnaf.POW_2_WIDTH), tw, alpha);
+
+ return multiplyFromWTnaf(p, u, preCompInfo);
+ }
+
+ /**
+ * Multiplies a {@link org.bc.math.ec.ECPoint.F2m ECPoint.F2m}
+ * by an element λ
of Z[τ]
+ * using the window τ
-adic NAF (TNAF) method, given the
+ * WTNAF of λ
.
+ * @param p The ECPoint.F2m to multiply.
+ * @param u The the WTNAF of λ
..
+ * @return λ * p
+ */
+ private static ECPoint.F2m multiplyFromWTnaf(ECPoint.F2m p, byte[] u,
+ PreCompInfo preCompInfo)
+ {
+ ECCurve.F2m curve = (ECCurve.F2m)p.getCurve();
+ byte a = curve.getA().toBigInteger().byteValue();
+
+ ECPoint.F2m[] pu;
+ if ((preCompInfo == null) || !(preCompInfo instanceof WTauNafPreCompInfo))
+ {
+ pu = Tnaf.getPreComp(p, a);
+ p.setPreCompInfo(new WTauNafPreCompInfo(pu));
+ }
+ else
+ {
+ pu = ((WTauNafPreCompInfo)preCompInfo).getPreComp();
+ }
+
+ // q = infinity
+ ECPoint.F2m q = (ECPoint.F2m) p.getCurve().getInfinity();
+ for (int i = u.length - 1; i >= 0; i--)
+ {
+ q = Tnaf.tau(q);
+ if (u[i] != 0)
+ {
+ if (u[i] > 0)
+ {
+ q = q.addSimple(pu[u[i]]);
+ }
+ else
+ {
+ // u[i] < 0
+ q = q.subtractSimple(pu[-u[i]]);
+ }
+ }
+ }
+
+ return q;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ec/WTauNafPreCompInfo.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ec/WTauNafPreCompInfo.java
new file mode 100644
index 0000000..19b8657
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ec/WTauNafPreCompInfo.java
@@ -0,0 +1,39 @@
+package org.bc.math.ec;
+
+/**
+ * Class holding precomputation data for the WTNAF (Window
+ * τ
-adic Non-Adjacent Form) algorithm.
+ */
+class WTauNafPreCompInfo implements PreCompInfo
+{
+ /**
+ * Array holding the precomputed ECPoint.F2m
s used for the
+ * WTNAF multiplication in
+ * {@link org.bouncycastle.math.ec.multiplier.WTauNafMultiplier.multiply()
+ * WTauNafMultiplier.multiply()}
.
+ */
+ private ECPoint.F2m[] preComp = null;
+
+ /**
+ * Constructor for WTauNafPreCompInfo
+ * @param preComp Array holding the precomputed ECPoint.F2m
s
+ * used for the WTNAF multiplication in
+ * {@link org.bouncycastle.math.ec.multiplier.WTauNafMultiplier.multiply()
+ * WTauNafMultiplier.multiply()}
.
+ */
+ WTauNafPreCompInfo(ECPoint.F2m[] preComp)
+ {
+ this.preComp = preComp;
+ }
+
+ /**
+ * @return the array holding the precomputed ECPoint.F2m
s
+ * used for the WTNAF multiplication in
+ * {@link org.bouncycastle.math.ec.multiplier.WTauNafMultiplier.multiply()
+ * WTauNafMultiplier.multiply()}
.
+ */
+ protected ECPoint.F2m[] getPreComp()
+ {
+ return preComp;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ec/ZTauElement.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ec/ZTauElement.java
new file mode 100644
index 0000000..9c13384
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ec/ZTauElement.java
@@ -0,0 +1,37 @@
+package org.bc.math.ec;
+
+import java.math.BigInteger;
+
+/**
+ * Class representing an element of Z[τ]
. Let
+ * λ
be an element of Z[τ]
. Then
+ * λ
is given as λ = u + vτ
. The
+ * components u
and v
may be used directly, there
+ * are no accessor methods.
+ * Immutable class.
+ */
+class ZTauElement
+{
+ /**
+ * The "real" part of λ
.
+ */
+ public final BigInteger u;
+
+ /**
+ * The "τ
-adic" part of λ
.
+ */
+ public final BigInteger v;
+
+ /**
+ * Constructor for an element λ
of
+ * Z[τ]
.
+ * @param u The "real" part of λ
.
+ * @param v The "τ
-adic" part of
+ * λ
.
+ */
+ public ZTauElement(BigInteger u, BigInteger v)
+ {
+ this.u = u;
+ this.v = v;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ntru/euclid/BigIntEuclidean.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ntru/euclid/BigIntEuclidean.java
new file mode 100644
index 0000000..5938fb8
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ntru/euclid/BigIntEuclidean.java
@@ -0,0 +1,54 @@
+package org.bc.math.ntru.euclid;
+
+import java.math.BigInteger;
+
+/**
+ * Extended Euclidean Algorithm in BigInteger
s
+ */
+public class BigIntEuclidean
+{
+ public BigInteger x, y, gcd;
+
+ private BigIntEuclidean()
+ {
+ }
+
+ /**
+ * Runs the EEA on two BigInteger
s
+ * Implemented from pseudocode on Wikipedia.
+ *
+ * @param a
+ * @param b
+ * @return a BigIntEuclidean
object that contains the result in the variables x
, y
, and gcd
+ */
+ public static BigIntEuclidean calculate(BigInteger a, BigInteger b)
+ {
+ BigInteger x = BigInteger.ZERO;
+ BigInteger lastx = BigInteger.ONE;
+ BigInteger y = BigInteger.ONE;
+ BigInteger lasty = BigInteger.ZERO;
+ while (!b.equals(BigInteger.ZERO))
+ {
+ BigInteger[] quotientAndRemainder = a.divideAndRemainder(b);
+ BigInteger quotient = quotientAndRemainder[0];
+
+ BigInteger temp = a;
+ a = b;
+ b = quotientAndRemainder[1];
+
+ temp = x;
+ x = lastx.subtract(quotient.multiply(x));
+ lastx = temp;
+
+ temp = y;
+ y = lasty.subtract(quotient.multiply(y));
+ lasty = temp;
+ }
+
+ BigIntEuclidean result = new BigIntEuclidean();
+ result.x = lastx;
+ result.y = lasty;
+ result.gcd = a;
+ return result;
+ }
+}
\ No newline at end of file
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ntru/euclid/IntEuclidean.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ntru/euclid/IntEuclidean.java
new file mode 100644
index 0000000..d1a8a0e
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ntru/euclid/IntEuclidean.java
@@ -0,0 +1,51 @@
+package org.bc.math.ntru.euclid;
+
+/**
+ * Extended Euclidean Algorithm in int
s
+ */
+public class IntEuclidean
+{
+ public int x, y, gcd;
+
+ private IntEuclidean()
+ {
+ }
+
+ /**
+ * Runs the EEA on two int
s
+ * Implemented from pseudocode on Wikipedia.
+ *
+ * @param a
+ * @param b
+ * @return a IntEuclidean
object that contains the result in the variables x
, y
, and gcd
+ */
+ public static IntEuclidean calculate(int a, int b)
+ {
+ int x = 0;
+ int lastx = 1;
+ int y = 1;
+ int lasty = 0;
+ while (b != 0)
+ {
+ int quotient = a / b;
+
+ int temp = a;
+ a = b;
+ b = temp % b;
+
+ temp = x;
+ x = lastx - quotient * x;
+ lastx = temp;
+
+ temp = y;
+ y = lasty - quotient * y;
+ lasty = temp;
+ }
+
+ IntEuclidean result = new IntEuclidean();
+ result.x = lastx;
+ result.y = lasty;
+ result.gcd = a;
+ return result;
+ }
+}
\ No newline at end of file
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ntru/polynomial/BigDecimalPolynomial.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ntru/polynomial/BigDecimalPolynomial.java
new file mode 100644
index 0000000..3d3d0c9
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ntru/polynomial/BigDecimalPolynomial.java
@@ -0,0 +1,258 @@
+package org.bc.math.ntru.polynomial;
+
+import java.math.BigDecimal;
+
+/**
+ * A polynomial with {@link BigDecimal} coefficients.
+ * Some methods (like add
) change the polynomial, others (like mult
) do
+ * not but return the result as a new polynomial.
+ */
+public class BigDecimalPolynomial
+{
+ private static final BigDecimal ZERO = new BigDecimal("0");
+ private static final BigDecimal ONE_HALF = new BigDecimal("0.5");
+
+ BigDecimal[] coeffs;
+
+ /**
+ * Constructs a new polynomial with N
coefficients initialized to 0.
+ *
+ * @param N the number of coefficients
+ */
+ BigDecimalPolynomial(int N)
+ {
+ coeffs = new BigDecimal[N];
+ for (int i = 0; i < N; i++)
+ {
+ coeffs[i] = ZERO;
+ }
+ }
+
+ /**
+ * Constructs a new polynomial with a given set of coefficients.
+ *
+ * @param coeffs the coefficients
+ */
+ BigDecimalPolynomial(BigDecimal[] coeffs)
+ {
+ this.coeffs = coeffs;
+ }
+
+ /**
+ * Constructs a BigDecimalPolynomial
from a BigIntPolynomial
. The two polynomials are independent of each other.
+ *
+ * @param p the original polynomial
+ */
+ public BigDecimalPolynomial(BigIntPolynomial p)
+ {
+ int N = p.coeffs.length;
+ coeffs = new BigDecimal[N];
+ for (int i = 0; i < N; i++)
+ {
+ coeffs[i] = new BigDecimal(p.coeffs[i]);
+ }
+ }
+
+ /**
+ * Divides all coefficients by 2.
+ */
+ public void halve()
+ {
+ for (int i = 0; i < coeffs.length; i++)
+ {
+ coeffs[i] = coeffs[i].multiply(ONE_HALF);
+ }
+ }
+
+ /**
+ * Multiplies the polynomial by another. Does not change this polynomial
+ * but returns the result as a new polynomial.
+ *
+ * @param poly2 the polynomial to multiply by
+ * @return a new polynomial
+ */
+ public BigDecimalPolynomial mult(BigIntPolynomial poly2)
+ {
+ return mult(new BigDecimalPolynomial(poly2));
+ }
+
+ /**
+ * Multiplies the polynomial by another, taking the indices mod N. Does not
+ * change this polynomial but returns the result as a new polynomial.
+ *
+ * @param poly2 the polynomial to multiply by
+ * @return a new polynomial
+ */
+ public BigDecimalPolynomial mult(BigDecimalPolynomial poly2)
+ {
+ int N = coeffs.length;
+ if (poly2.coeffs.length != N)
+ {
+ throw new IllegalArgumentException("Number of coefficients must be the same");
+ }
+
+ BigDecimalPolynomial c = multRecursive(poly2);
+
+ if (c.coeffs.length > N)
+ {
+ for (int k = N; k < c.coeffs.length; k++)
+ {
+ c.coeffs[k - N] = c.coeffs[k - N].add(c.coeffs[k]);
+ }
+ c.coeffs = copyOf(c.coeffs, N);
+ }
+ return c;
+ }
+
+ /**
+ * Karazuba multiplication
+ */
+ private BigDecimalPolynomial multRecursive(BigDecimalPolynomial poly2)
+ {
+ BigDecimal[] a = coeffs;
+ BigDecimal[] b = poly2.coeffs;
+
+ int n = poly2.coeffs.length;
+ if (n <= 1)
+ {
+ BigDecimal[] c = coeffs.clone();
+ for (int i = 0; i < coeffs.length; i++)
+ {
+ c[i] = c[i].multiply(poly2.coeffs[0]);
+ }
+ return new BigDecimalPolynomial(c);
+ }
+ else
+ {
+ int n1 = n / 2;
+
+ BigDecimalPolynomial a1 = new BigDecimalPolynomial(copyOf(a, n1));
+ BigDecimalPolynomial a2 = new BigDecimalPolynomial(copyOfRange(a, n1, n));
+ BigDecimalPolynomial b1 = new BigDecimalPolynomial(copyOf(b, n1));
+ BigDecimalPolynomial b2 = new BigDecimalPolynomial(copyOfRange(b, n1, n));
+
+ BigDecimalPolynomial A = (BigDecimalPolynomial)a1.clone();
+ A.add(a2);
+ BigDecimalPolynomial B = (BigDecimalPolynomial)b1.clone();
+ B.add(b2);
+
+ BigDecimalPolynomial c1 = a1.multRecursive(b1);
+ BigDecimalPolynomial c2 = a2.multRecursive(b2);
+ BigDecimalPolynomial c3 = A.multRecursive(B);
+ c3.sub(c1);
+ c3.sub(c2);
+
+ BigDecimalPolynomial c = new BigDecimalPolynomial(2 * n - 1);
+ for (int i = 0; i < c1.coeffs.length; i++)
+ {
+ c.coeffs[i] = c1.coeffs[i];
+ }
+ for (int i = 0; i < c3.coeffs.length; i++)
+ {
+ c.coeffs[n1 + i] = c.coeffs[n1 + i].add(c3.coeffs[i]);
+ }
+ for (int i = 0; i < c2.coeffs.length; i++)
+ {
+ c.coeffs[2 * n1 + i] = c.coeffs[2 * n1 + i].add(c2.coeffs[i]);
+ }
+ return c;
+ }
+ }
+
+ /**
+ * Adds another polynomial which can have a different number of coefficients.
+ *
+ * @param b another polynomial
+ */
+ public void add(BigDecimalPolynomial b)
+ {
+ if (b.coeffs.length > coeffs.length)
+ {
+ int N = coeffs.length;
+ coeffs = copyOf(coeffs, b.coeffs.length);
+ for (int i = N; i < coeffs.length; i++)
+ {
+ coeffs[i] = ZERO;
+ }
+ }
+ for (int i = 0; i < b.coeffs.length; i++)
+ {
+ coeffs[i] = coeffs[i].add(b.coeffs[i]);
+ }
+ }
+
+ /**
+ * Subtracts another polynomial which can have a different number of coefficients.
+ *
+ * @param b
+ */
+ void sub(BigDecimalPolynomial b)
+ {
+ if (b.coeffs.length > coeffs.length)
+ {
+ int N = coeffs.length;
+ coeffs = copyOf(coeffs, b.coeffs.length);
+ for (int i = N; i < coeffs.length; i++)
+ {
+ coeffs[i] = ZERO;
+ }
+ }
+ for (int i = 0; i < b.coeffs.length; i++)
+ {
+ coeffs[i] = coeffs[i].subtract(b.coeffs[i]);
+ }
+ }
+
+ /**
+ * Rounds all coefficients to the nearest integer.
+ *
+ * @return a new polynomial with BigInteger
coefficients
+ */
+ public BigIntPolynomial round()
+ {
+ int N = coeffs.length;
+ BigIntPolynomial p = new BigIntPolynomial(N);
+ for (int i = 0; i < N; i++)
+ {
+ p.coeffs[i] = coeffs[i].setScale(0, BigDecimal.ROUND_HALF_EVEN).toBigInteger();
+ }
+ return p;
+ }
+
+ /**
+ * Makes a copy of the polynomial that is independent of the original.
+ */
+ public Object clone()
+ {
+ return new BigDecimalPolynomial(coeffs.clone());
+ }
+
+ private BigDecimal[] copyOf(BigDecimal[] a, int length)
+ {
+ BigDecimal[] tmp = new BigDecimal[length];
+
+ System.arraycopy(a, 0, tmp, 0, a.length < length ? a.length : length);
+
+ return tmp;
+ }
+
+ private BigDecimal[] copyOfRange(BigDecimal[] a, int from, int to)
+ {
+ int newLength = to - from;
+ BigDecimal[] tmp = new BigDecimal[to - from];
+
+ System.arraycopy(a, from, tmp, 0, (a.length - from) < newLength ? (a.length - from) : newLength);
+
+ return tmp;
+ }
+
+ public BigDecimal[] getCoeffs()
+ {
+ BigDecimal[] tmp = new BigDecimal[coeffs.length];
+
+ System.arraycopy(coeffs, 0, tmp, 0, coeffs.length);
+
+ return tmp;
+ }
+
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ntru/polynomial/BigIntPolynomial.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ntru/polynomial/BigIntPolynomial.java
new file mode 100644
index 0000000..01bc896
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ntru/polynomial/BigIntPolynomial.java
@@ -0,0 +1,394 @@
+package org.bc.math.ntru.polynomial;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.security.SecureRandom;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.bc.util.Arrays;
+
+/**
+ * A polynomial with {@link BigInteger} coefficients.
+ * Some methods (like add
) change the polynomial, others (like mult
) do
+ * not but return the result as a new polynomial.
+ */
+public class BigIntPolynomial
+{
+ private final static double LOG_10_2 = Math.log10(2);
+
+ BigInteger[] coeffs;
+
+ /**
+ * Constructs a new polynomial with N
coefficients initialized to 0.
+ *
+ * @param N the number of coefficients
+ */
+ BigIntPolynomial(int N)
+ {
+ coeffs = new BigInteger[N];
+ for (int i = 0; i < N; i++)
+ {
+ coeffs[i] = Constants.BIGINT_ZERO;
+ }
+ }
+
+ /**
+ * Constructs a new polynomial with a given set of coefficients.
+ *
+ * @param coeffs the coefficients
+ */
+ BigIntPolynomial(BigInteger[] coeffs)
+ {
+ this.coeffs = coeffs;
+ }
+
+ /**
+ * Constructs a BigIntPolynomial
from a IntegerPolynomial
. The two polynomials are
+ * independent of each other.
+ *
+ * @param p the original polynomial
+ */
+ public BigIntPolynomial(IntegerPolynomial p)
+ {
+ coeffs = new BigInteger[p.coeffs.length];
+ for (int i = 0; i < coeffs.length; i++)
+ {
+ coeffs[i] = BigInteger.valueOf(p.coeffs[i]);
+ }
+ }
+
+ /**
+ * Generates a random polynomial with numOnes
coefficients equal to 1,
+ * numNegOnes
coefficients equal to -1, and the rest equal to 0.
+ *
+ * @param N number of coefficients
+ * @param numOnes number of 1's
+ * @param numNegOnes number of -1's
+ * @return
+ */
+ static BigIntPolynomial generateRandomSmall(int N, int numOnes, int numNegOnes)
+ {
+ List coeffs = new ArrayList();
+ for (int i = 0; i < numOnes; i++)
+ {
+ coeffs.add(Constants.BIGINT_ONE);
+ }
+ for (int i = 0; i < numNegOnes; i++)
+ {
+ coeffs.add(BigInteger.valueOf(-1));
+ }
+ while (coeffs.size() < N)
+ {
+ coeffs.add(Constants.BIGINT_ZERO);
+ }
+ Collections.shuffle(coeffs, new SecureRandom());
+
+ BigIntPolynomial poly = new BigIntPolynomial(N);
+ for (int i = 0; i < coeffs.size(); i++)
+ {
+ poly.coeffs[i] = (BigInteger)coeffs.get(i);
+ }
+ return poly;
+ }
+
+ /**
+ * Multiplies the polynomial by another, taking the indices mod N. Does not
+ * change this polynomial but returns the result as a new polynomial.
+ * Both polynomials must have the same number of coefficients.
+ *
+ * @param poly2 the polynomial to multiply by
+ * @return a new polynomial
+ */
+ public BigIntPolynomial mult(BigIntPolynomial poly2)
+ {
+ int N = coeffs.length;
+ if (poly2.coeffs.length != N)
+ {
+ throw new IllegalArgumentException("Number of coefficients must be the same");
+ }
+
+ BigIntPolynomial c = multRecursive(poly2);
+
+ if (c.coeffs.length > N)
+ {
+ for (int k = N; k < c.coeffs.length; k++)
+ {
+ c.coeffs[k - N] = c.coeffs[k - N].add(c.coeffs[k]);
+ }
+ c.coeffs = Arrays.copyOf(c.coeffs, N);
+ }
+ return c;
+ }
+
+ /**
+ * Karazuba multiplication
+ */
+ private BigIntPolynomial multRecursive(BigIntPolynomial poly2)
+ {
+ BigInteger[] a = coeffs;
+ BigInteger[] b = poly2.coeffs;
+
+ int n = poly2.coeffs.length;
+ if (n <= 1)
+ {
+ BigInteger[] c = Arrays.clone(coeffs);
+ for (int i = 0; i < coeffs.length; i++)
+ {
+ c[i] = c[i].multiply(poly2.coeffs[0]);
+ }
+ return new BigIntPolynomial(c);
+ }
+ else
+ {
+ int n1 = n / 2;
+
+ BigIntPolynomial a1 = new BigIntPolynomial(Arrays.copyOf(a, n1));
+ BigIntPolynomial a2 = new BigIntPolynomial(Arrays.copyOfRange(a, n1, n));
+ BigIntPolynomial b1 = new BigIntPolynomial(Arrays.copyOf(b, n1));
+ BigIntPolynomial b2 = new BigIntPolynomial(Arrays.copyOfRange(b, n1, n));
+
+ BigIntPolynomial A = (BigIntPolynomial)a1.clone();
+ A.add(a2);
+ BigIntPolynomial B = (BigIntPolynomial)b1.clone();
+ B.add(b2);
+
+ BigIntPolynomial c1 = a1.multRecursive(b1);
+ BigIntPolynomial c2 = a2.multRecursive(b2);
+ BigIntPolynomial c3 = A.multRecursive(B);
+ c3.sub(c1);
+ c3.sub(c2);
+
+ BigIntPolynomial c = new BigIntPolynomial(2 * n - 1);
+ for (int i = 0; i < c1.coeffs.length; i++)
+ {
+ c.coeffs[i] = c1.coeffs[i];
+ }
+ for (int i = 0; i < c3.coeffs.length; i++)
+ {
+ c.coeffs[n1 + i] = c.coeffs[n1 + i].add(c3.coeffs[i]);
+ }
+ for (int i = 0; i < c2.coeffs.length; i++)
+ {
+ c.coeffs[2 * n1 + i] = c.coeffs[2 * n1 + i].add(c2.coeffs[i]);
+ }
+ return c;
+ }
+ }
+
+ /**
+ * Adds another polynomial which can have a different number of coefficients,
+ * and takes the coefficient values mod modulus
.
+ *
+ * @param b another polynomial
+ */
+ void add(BigIntPolynomial b, BigInteger modulus)
+ {
+ add(b);
+ mod(modulus);
+ }
+
+ /**
+ * Adds another polynomial which can have a different number of coefficients.
+ *
+ * @param b another polynomial
+ */
+ public void add(BigIntPolynomial b)
+ {
+ if (b.coeffs.length > coeffs.length)
+ {
+ int N = coeffs.length;
+ coeffs = Arrays.copyOf(coeffs, b.coeffs.length);
+ for (int i = N; i < coeffs.length; i++)
+ {
+ coeffs[i] = Constants.BIGINT_ZERO;
+ }
+ }
+ for (int i = 0; i < b.coeffs.length; i++)
+ {
+ coeffs[i] = coeffs[i].add(b.coeffs[i]);
+ }
+ }
+
+ /**
+ * Subtracts another polynomial which can have a different number of coefficients.
+ *
+ * @param b another polynomial
+ */
+ public void sub(BigIntPolynomial b)
+ {
+ if (b.coeffs.length > coeffs.length)
+ {
+ int N = coeffs.length;
+ coeffs = Arrays.copyOf(coeffs, b.coeffs.length);
+ for (int i = N; i < coeffs.length; i++)
+ {
+ coeffs[i] = Constants.BIGINT_ZERO;
+ }
+ }
+ for (int i = 0; i < b.coeffs.length; i++)
+ {
+ coeffs[i] = coeffs[i].subtract(b.coeffs[i]);
+ }
+ }
+
+ /**
+ * Multiplies each coefficient by a BigInteger
. Does not return a new polynomial but modifies this polynomial.
+ *
+ * @param factor
+ */
+ public void mult(BigInteger factor)
+ {
+ for (int i = 0; i < coeffs.length; i++)
+ {
+ coeffs[i] = coeffs[i].multiply(factor);
+ }
+ }
+
+ /**
+ * Multiplies each coefficient by a int
. Does not return a new polynomial but modifies this polynomial.
+ *
+ * @param factor
+ */
+ void mult(int factor)
+ {
+ mult(BigInteger.valueOf(factor));
+ }
+
+ /**
+ * Divides each coefficient by a BigInteger
and rounds the result to the nearest whole number.
+ * Does not return a new polynomial but modifies this polynomial.
+ *
+ * @param divisor the number to divide by
+ */
+ public void div(BigInteger divisor)
+ {
+ BigInteger d = divisor.add(Constants.BIGINT_ONE).divide(BigInteger.valueOf(2));
+ for (int i = 0; i < coeffs.length; i++)
+ {
+ coeffs[i] = coeffs[i].compareTo(Constants.BIGINT_ZERO) > 0 ? coeffs[i].add(d) : coeffs[i].add(d.negate());
+ coeffs[i] = coeffs[i].divide(divisor);
+ }
+ }
+
+ /**
+ * Divides each coefficient by a BigDecimal
and rounds the result to decimalPlaces
places.
+ *
+ * @param divisor the number to divide by
+ * @param decimalPlaces the number of fractional digits to round the result to
+ * @return a new BigDecimalPolynomial
+ */
+ public BigDecimalPolynomial div(BigDecimal divisor, int decimalPlaces)
+ {
+ BigInteger max = maxCoeffAbs();
+ int coeffLength = (int)(max.bitLength() * LOG_10_2) + 1;
+ // factor = 1/divisor
+ BigDecimal factor = Constants.BIGDEC_ONE.divide(divisor, coeffLength + decimalPlaces + 1, BigDecimal.ROUND_HALF_EVEN);
+
+ // multiply each coefficient by factor
+ BigDecimalPolynomial p = new BigDecimalPolynomial(coeffs.length);
+ for (int i = 0; i < coeffs.length; i++)
+ // multiply, then truncate after decimalPlaces so subsequent operations aren't slowed down
+ {
+ p.coeffs[i] = new BigDecimal(coeffs[i]).multiply(factor).setScale(decimalPlaces, BigDecimal.ROUND_HALF_EVEN);
+ }
+
+ return p;
+ }
+
+ /**
+ * Returns the base10 length of the largest coefficient.
+ *
+ * @return length of the longest coefficient
+ */
+ public int getMaxCoeffLength()
+ {
+ return (int)(maxCoeffAbs().bitLength() * LOG_10_2) + 1;
+ }
+
+ private BigInteger maxCoeffAbs()
+ {
+ BigInteger max = coeffs[0].abs();
+ for (int i = 1; i < coeffs.length; i++)
+ {
+ BigInteger coeff = coeffs[i].abs();
+ if (coeff.compareTo(max) > 0)
+ {
+ max = coeff;
+ }
+ }
+ return max;
+ }
+
+ /**
+ * Takes each coefficient modulo a number.
+ *
+ * @param modulus
+ */
+ public void mod(BigInteger modulus)
+ {
+ for (int i = 0; i < coeffs.length; i++)
+ {
+ coeffs[i] = coeffs[i].mod(modulus);
+ }
+ }
+
+ /**
+ * Returns the sum of all coefficients, i.e. evaluates the polynomial at 0.
+ *
+ * @return the sum of all coefficients
+ */
+ BigInteger sumCoeffs()
+ {
+ BigInteger sum = Constants.BIGINT_ZERO;
+ for (int i = 0; i < coeffs.length; i++)
+ {
+ sum = sum.add(coeffs[i]);
+ }
+ return sum;
+ }
+
+ /**
+ * Makes a copy of the polynomial that is independent of the original.
+ */
+ public Object clone()
+ {
+ return new BigIntPolynomial(coeffs.clone());
+ }
+
+ public int hashCode()
+ {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + Arrays.hashCode(coeffs);
+ return result;
+ }
+
+ public boolean equals(Object obj)
+ {
+ if (this == obj)
+ {
+ return true;
+ }
+ if (obj == null)
+ {
+ return false;
+ }
+ if (getClass() != obj.getClass())
+ {
+ return false;
+ }
+ BigIntPolynomial other = (BigIntPolynomial)obj;
+ if (!Arrays.areEqual(coeffs, other.coeffs))
+ {
+ return false;
+ }
+ return true;
+ }
+
+ public BigInteger[] getCoeffs()
+ {
+ return Arrays.clone(coeffs);
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ntru/polynomial/Constants.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ntru/polynomial/Constants.java
new file mode 100644
index 0000000..9f0010a
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ntru/polynomial/Constants.java
@@ -0,0 +1,12 @@
+package org.bc.math.ntru.polynomial;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+
+public class Constants
+{
+ static final BigInteger BIGINT_ZERO = BigInteger.valueOf(0);
+ static final BigInteger BIGINT_ONE = BigInteger.valueOf(1);
+
+ static final BigDecimal BIGDEC_ONE = BigDecimal.valueOf(1);
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ntru/polynomial/DenseTernaryPolynomial.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ntru/polynomial/DenseTernaryPolynomial.java
new file mode 100644
index 0000000..cfc4a22
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ntru/polynomial/DenseTernaryPolynomial.java
@@ -0,0 +1,142 @@
+package org.bc.math.ntru.polynomial;
+
+import java.security.SecureRandom;
+
+import org.bc.math.ntru.util.Util;
+import org.bc.util.Arrays;
+
+/**
+ * A TernaryPolynomial
with a "high" number of nonzero coefficients.
+ */
+public class DenseTernaryPolynomial
+ extends IntegerPolynomial
+ implements TernaryPolynomial
+{
+
+ /**
+ * Constructs a new DenseTernaryPolynomial
with N
coefficients.
+ *
+ * @param N the number of coefficients
+ */
+ DenseTernaryPolynomial(int N)
+ {
+ super(N);
+ checkTernarity();
+ }
+
+ /**
+ * Constructs a DenseTernaryPolynomial
from a IntegerPolynomial
. The two polynomials are
+ * independent of each other.
+ *
+ * @param intPoly the original polynomial
+ */
+ public DenseTernaryPolynomial(IntegerPolynomial intPoly)
+ {
+ this(intPoly.coeffs);
+ }
+
+ /**
+ * Constructs a new DenseTernaryPolynomial
with a given set of coefficients.
+ *
+ * @param coeffs the coefficients
+ */
+ public DenseTernaryPolynomial(int[] coeffs)
+ {
+ super(coeffs);
+ checkTernarity();
+ }
+
+ private void checkTernarity()
+ {
+ for (int i = 0; i != coeffs.length; i++)
+ {
+ int c = coeffs[i];
+ if (c < -1 || c > 1)
+ {
+ throw new IllegalStateException("Illegal value: " + c + ", must be one of {-1, 0, 1}");
+ }
+ }
+ }
+
+ /**
+ * Generates a random polynomial with numOnes
coefficients equal to 1,
+ * numNegOnes
coefficients equal to -1, and the rest equal to 0.
+ *
+ * @param N number of coefficients
+ * @param numOnes number of 1's
+ * @param numNegOnes number of -1's
+ */
+ public static DenseTernaryPolynomial generateRandom(int N, int numOnes, int numNegOnes, SecureRandom random)
+ {
+ int[] coeffs = Util.generateRandomTernary(N, numOnes, numNegOnes, random);
+ return new DenseTernaryPolynomial(coeffs);
+ }
+
+ /**
+ * Generates a polynomial with coefficients randomly selected from {-1, 0, 1}
.
+ *
+ * @param N number of coefficients
+ */
+ public static DenseTernaryPolynomial generateRandom(int N, SecureRandom random)
+ {
+ DenseTernaryPolynomial poly = new DenseTernaryPolynomial(N);
+ for (int i = 0; i < N; i++)
+ {
+ poly.coeffs[i] = random.nextInt(3) - 1;
+ }
+ return poly;
+ }
+
+ public IntegerPolynomial mult(IntegerPolynomial poly2, int modulus)
+ {
+ // even on 32-bit systems, LongPolynomial5 multiplies faster than IntegerPolynomial
+ if (modulus == 2048)
+ {
+ IntegerPolynomial poly2Pos = (IntegerPolynomial)poly2.clone();
+ poly2Pos.modPositive(2048);
+ LongPolynomial5 poly5 = new LongPolynomial5(poly2Pos);
+ return poly5.mult(this).toIntegerPolynomial();
+ }
+ else
+ {
+ return super.mult(poly2, modulus);
+ }
+ }
+
+ public int[] getOnes()
+ {
+ int N = coeffs.length;
+ int[] ones = new int[N];
+ int onesIdx = 0;
+ for (int i = 0; i < N; i++)
+ {
+ int c = coeffs[i];
+ if (c == 1)
+ {
+ ones[onesIdx++] = i;
+ }
+ }
+ return Arrays.copyOf(ones, onesIdx);
+ }
+
+ public int[] getNegOnes()
+ {
+ int N = coeffs.length;
+ int[] negOnes = new int[N];
+ int negOnesIdx = 0;
+ for (int i = 0; i < N; i++)
+ {
+ int c = coeffs[i];
+ if (c == -1)
+ {
+ negOnes[negOnesIdx++] = i;
+ }
+ }
+ return Arrays.copyOf(negOnes, negOnesIdx);
+ }
+
+ public int size()
+ {
+ return coeffs.length;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ntru/polynomial/IntegerPolynomial.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ntru/polynomial/IntegerPolynomial.java
new file mode 100644
index 0000000..b76019d
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ntru/polynomial/IntegerPolynomial.java
@@ -0,0 +1,1358 @@
+package org.bc.math.ntru.polynomial;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.LinkedBlockingQueue;
+
+import org.bc.math.ntru.euclid.BigIntEuclidean;
+import org.bc.math.ntru.util.ArrayEncoder;
+import org.bc.math.ntru.util.Util;
+import org.bc.util.Arrays;
+
+/**
+ * A polynomial with int
coefficients.
+ * Some methods (like add
) change the polynomial, others (like mult
) do
+ * not but return the result as a new polynomial.
+ */
+public class IntegerPolynomial
+ implements Polynomial
+{
+ private static final int NUM_EQUAL_RESULTANTS = 3;
+ /**
+ * Prime numbers > 4500 for resultant computation. Starting them below ~4400 causes incorrect results occasionally.
+ * Fortunately, 4500 is about the optimum number for performance.
+ * This array contains enough prime numbers so primes never have to be computed on-line for any standard {@link org.bc.crypto.params.NTRUSigningParameters}.
+ */
+ private static final int[] PRIMES = new int[]{
+ 4507, 4513, 4517, 4519, 4523, 4547, 4549, 4561, 4567, 4583,
+ 4591, 4597, 4603, 4621, 4637, 4639, 4643, 4649, 4651, 4657,
+ 4663, 4673, 4679, 4691, 4703, 4721, 4723, 4729, 4733, 4751,
+ 4759, 4783, 4787, 4789, 4793, 4799, 4801, 4813, 4817, 4831,
+ 4861, 4871, 4877, 4889, 4903, 4909, 4919, 4931, 4933, 4937,
+ 4943, 4951, 4957, 4967, 4969, 4973, 4987, 4993, 4999, 5003,
+ 5009, 5011, 5021, 5023, 5039, 5051, 5059, 5077, 5081, 5087,
+ 5099, 5101, 5107, 5113, 5119, 5147, 5153, 5167, 5171, 5179,
+ 5189, 5197, 5209, 5227, 5231, 5233, 5237, 5261, 5273, 5279,
+ 5281, 5297, 5303, 5309, 5323, 5333, 5347, 5351, 5381, 5387,
+ 5393, 5399, 5407, 5413, 5417, 5419, 5431, 5437, 5441, 5443,
+ 5449, 5471, 5477, 5479, 5483, 5501, 5503, 5507, 5519, 5521,
+ 5527, 5531, 5557, 5563, 5569, 5573, 5581, 5591, 5623, 5639,
+ 5641, 5647, 5651, 5653, 5657, 5659, 5669, 5683, 5689, 5693,
+ 5701, 5711, 5717, 5737, 5741, 5743, 5749, 5779, 5783, 5791,
+ 5801, 5807, 5813, 5821, 5827, 5839, 5843, 5849, 5851, 5857,
+ 5861, 5867, 5869, 5879, 5881, 5897, 5903, 5923, 5927, 5939,
+ 5953, 5981, 5987, 6007, 6011, 6029, 6037, 6043, 6047, 6053,
+ 6067, 6073, 6079, 6089, 6091, 6101, 6113, 6121, 6131, 6133,
+ 6143, 6151, 6163, 6173, 6197, 6199, 6203, 6211, 6217, 6221,
+ 6229, 6247, 6257, 6263, 6269, 6271, 6277, 6287, 6299, 6301,
+ 6311, 6317, 6323, 6329, 6337, 6343, 6353, 6359, 6361, 6367,
+ 6373, 6379, 6389, 6397, 6421, 6427, 6449, 6451, 6469, 6473,
+ 6481, 6491, 6521, 6529, 6547, 6551, 6553, 6563, 6569, 6571,
+ 6577, 6581, 6599, 6607, 6619, 6637, 6653, 6659, 6661, 6673,
+ 6679, 6689, 6691, 6701, 6703, 6709, 6719, 6733, 6737, 6761,
+ 6763, 6779, 6781, 6791, 6793, 6803, 6823, 6827, 6829, 6833,
+ 6841, 6857, 6863, 6869, 6871, 6883, 6899, 6907, 6911, 6917,
+ 6947, 6949, 6959, 6961, 6967, 6971, 6977, 6983, 6991, 6997,
+ 7001, 7013, 7019, 7027, 7039, 7043, 7057, 7069, 7079, 7103,
+ 7109, 7121, 7127, 7129, 7151, 7159, 7177, 7187, 7193, 7207,
+ 7211, 7213, 7219, 7229, 7237, 7243, 7247, 7253, 7283, 7297,
+ 7307, 7309, 7321, 7331, 7333, 7349, 7351, 7369, 7393, 7411,
+ 7417, 7433, 7451, 7457, 7459, 7477, 7481, 7487, 7489, 7499,
+ 7507, 7517, 7523, 7529, 7537, 7541, 7547, 7549, 7559, 7561,
+ 7573, 7577, 7583, 7589, 7591, 7603, 7607, 7621, 7639, 7643,
+ 7649, 7669, 7673, 7681, 7687, 7691, 7699, 7703, 7717, 7723,
+ 7727, 7741, 7753, 7757, 7759, 7789, 7793, 7817, 7823, 7829,
+ 7841, 7853, 7867, 7873, 7877, 7879, 7883, 7901, 7907, 7919,
+ 7927, 7933, 7937, 7949, 7951, 7963, 7993, 8009, 8011, 8017,
+ 8039, 8053, 8059, 8069, 8081, 8087, 8089, 8093, 8101, 8111,
+ 8117, 8123, 8147, 8161, 8167, 8171, 8179, 8191, 8209, 8219,
+ 8221, 8231, 8233, 8237, 8243, 8263, 8269, 8273, 8287, 8291,
+ 8293, 8297, 8311, 8317, 8329, 8353, 8363, 8369, 8377, 8387,
+ 8389, 8419, 8423, 8429, 8431, 8443, 8447, 8461, 8467, 8501,
+ 8513, 8521, 8527, 8537, 8539, 8543, 8563, 8573, 8581, 8597,
+ 8599, 8609, 8623, 8627, 8629, 8641, 8647, 8663, 8669, 8677,
+ 8681, 8689, 8693, 8699, 8707, 8713, 8719, 8731, 8737, 8741,
+ 8747, 8753, 8761, 8779, 8783, 8803, 8807, 8819, 8821, 8831,
+ 8837, 8839, 8849, 8861, 8863, 8867, 8887, 8893, 8923, 8929,
+ 8933, 8941, 8951, 8963, 8969, 8971, 8999, 9001, 9007, 9011,
+ 9013, 9029, 9041, 9043, 9049, 9059, 9067, 9091, 9103, 9109,
+ 9127, 9133, 9137, 9151, 9157, 9161, 9173, 9181, 9187, 9199,
+ 9203, 9209, 9221, 9227, 9239, 9241, 9257, 9277, 9281, 9283,
+ 9293, 9311, 9319, 9323, 9337, 9341, 9343, 9349, 9371, 9377,
+ 9391, 9397, 9403, 9413, 9419, 9421, 9431, 9433, 9437, 9439,
+ 9461, 9463, 9467, 9473, 9479, 9491, 9497, 9511, 9521, 9533,
+ 9539, 9547, 9551, 9587, 9601, 9613, 9619, 9623, 9629, 9631,
+ 9643, 9649, 9661, 9677, 9679, 9689, 9697, 9719, 9721, 9733,
+ 9739, 9743, 9749, 9767, 9769, 9781, 9787, 9791, 9803, 9811,
+ 9817, 9829, 9833, 9839, 9851, 9857, 9859, 9871, 9883, 9887,
+ 9901, 9907, 9923, 9929, 9931, 9941, 9949, 9967, 9973};
+ private static final List BIGINT_PRIMES;
+
+ static
+ {
+ BIGINT_PRIMES = new ArrayList();
+ for (int i = 0; i != PRIMES.length; i++)
+ {
+ BIGINT_PRIMES.add(BigInteger.valueOf(PRIMES[i]));
+ }
+ }
+
+ public int[] coeffs;
+
+ /**
+ * Constructs a new polynomial with N
coefficients initialized to 0.
+ *
+ * @param N the number of coefficients
+ */
+ public IntegerPolynomial(int N)
+ {
+ coeffs = new int[N];
+ }
+
+ /**
+ * Constructs a new polynomial with a given set of coefficients.
+ *
+ * @param coeffs the coefficients
+ */
+ public IntegerPolynomial(int[] coeffs)
+ {
+ this.coeffs = coeffs;
+ }
+
+ /**
+ * Constructs a IntegerPolynomial
from a BigIntPolynomial
. The two polynomials are independent of each other.
+ *
+ * @param p the original polynomial
+ */
+ public IntegerPolynomial(BigIntPolynomial p)
+ {
+ coeffs = new int[p.coeffs.length];
+ for (int i = 0; i < p.coeffs.length; i++)
+ {
+ coeffs[i] = p.coeffs[i].intValue();
+ }
+ }
+
+ /**
+ * Decodes a byte array to a polynomial with N
ternary coefficients
+ * Ignores any excess bytes.
+ *
+ * @param data an encoded ternary polynomial
+ * @param N number of coefficients
+ * @return the decoded polynomial
+ */
+ public static IntegerPolynomial fromBinary3Sves(byte[] data, int N)
+ {
+ return new IntegerPolynomial(ArrayEncoder.decodeMod3Sves(data, N));
+ }
+
+ /**
+ * Converts a byte array produced by {@link #toBinary3Tight()} to a polynomial.
+ *
+ * @param b a byte array
+ * @param N number of coefficients
+ * @return the decoded polynomial
+ */
+ public static IntegerPolynomial fromBinary3Tight(byte[] b, int N)
+ {
+ return new IntegerPolynomial(ArrayEncoder.decodeMod3Tight(b, N));
+ }
+
+ /**
+ * Reads data produced by {@link #toBinary3Tight()} from an input stream and converts it to a polynomial.
+ *
+ * @param is an input stream
+ * @param N number of coefficients
+ * @return the decoded polynomial
+ */
+ public static IntegerPolynomial fromBinary3Tight(InputStream is, int N)
+ throws IOException
+ {
+ return new IntegerPolynomial(ArrayEncoder.decodeMod3Tight(is, N));
+ }
+
+ /**
+ * Returns a polynomial with N coefficients between 0
and q-1
.
+ * q
must be a power of 2.
+ * Ignores any excess bytes.
+ *
+ * @param data an encoded ternary polynomial
+ * @param N number of coefficients
+ * @param q
+ * @return the decoded polynomial
+ */
+ public static IntegerPolynomial fromBinary(byte[] data, int N, int q)
+ {
+ return new IntegerPolynomial(ArrayEncoder.decodeModQ(data, N, q));
+ }
+
+ /**
+ * Returns a polynomial with N coefficients between 0
and q-1
.
+ * q
must be a power of 2.
+ * Ignores any excess bytes.
+ *
+ * @param is an encoded ternary polynomial
+ * @param N number of coefficients
+ * @param q
+ * @return the decoded polynomial
+ */
+ public static IntegerPolynomial fromBinary(InputStream is, int N, int q)
+ throws IOException
+ {
+ return new IntegerPolynomial(ArrayEncoder.decodeModQ(is, N, q));
+ }
+
+ /**
+ * Encodes a polynomial with ternary coefficients to binary.
+ * coeffs[2*i]
and coeffs[2*i+1]
must not both equal -1 for any integer i,
+ * so this method is only safe to use with polynomials produced by
res is set to fromBinary3Sves()
.
+ *
+ * @return the encoded polynomial
+ */
+ public byte[] toBinary3Sves()
+ {
+ return ArrayEncoder.encodeMod3Sves(coeffs);
+ }
+
+ /**
+ * Converts a polynomial with ternary coefficients to binary.
+ *
+ * @return the encoded polynomial
+ */
+ public byte[] toBinary3Tight()
+ {
+ BigInteger sum = Constants.BIGINT_ZERO;
+ for (int i = coeffs.length - 1; i >= 0; i--)
+ {
+ sum = sum.multiply(BigInteger.valueOf(3));
+ sum = sum.add(BigInteger.valueOf(coeffs[i] + 1));
+ }
+
+ int size = (BigInteger.valueOf(3).pow(coeffs.length).bitLength() + 7) / 8;
+ byte[] arr = sum.toByteArray();
+
+ if (arr.length < size)
+ {
+ // pad with leading zeros so arr.length==size
+ byte[] arr2 = new byte[size];
+ System.arraycopy(arr, 0, arr2, size - arr.length, arr.length);
+ return arr2;
+ }
+
+ if (arr.length > size)
+ // drop sign bit
+ {
+ arr = Arrays.copyOfRange(arr, 1, arr.length);
+ }
+ return arr;
+ }
+
+ /**
+ * Encodes a polynomial whose coefficients are between 0 and q, to binary. q must be a power of 2.
+ *
+ * @param q
+ * @return the encoded polynomial
+ */
+ public byte[] toBinary(int q)
+ {
+ return ArrayEncoder.encodeModQ(coeffs, q);
+ }
+
+ /**
+ * Multiplies the polynomial with another, taking the values mod modulus and the indices mod N
+ */
+ public IntegerPolynomial mult(IntegerPolynomial poly2, int modulus)
+ {
+ IntegerPolynomial c = mult(poly2);
+ c.mod(modulus);
+ return c;
+ }
+
+ /**
+ * Multiplies the polynomial with another, taking the indices mod N
+ */
+ public IntegerPolynomial mult(IntegerPolynomial poly2)
+ {
+ int N = coeffs.length;
+ if (poly2.coeffs.length != N)
+ {
+ throw new IllegalArgumentException("Number of coefficients must be the same");
+ }
+
+ IntegerPolynomial c = multRecursive(poly2);
+
+ if (c.coeffs.length > N)
+ {
+ for (int k = N; k < c.coeffs.length; k++)
+ {
+ c.coeffs[k - N] += c.coeffs[k];
+ }
+ c.coeffs = Arrays.copyOf(c.coeffs, N);
+ }
+ return c;
+ }
+
+ public BigIntPolynomial mult(BigIntPolynomial poly2)
+ {
+ return new BigIntPolynomial(this).mult(poly2);
+ }
+
+ /**
+ * Karazuba multiplication
+ */
+ private IntegerPolynomial multRecursive(IntegerPolynomial poly2)
+ {
+ int[] a = coeffs;
+ int[] b = poly2.coeffs;
+
+ int n = poly2.coeffs.length;
+ if (n <= 32)
+ {
+ int cn = 2 * n - 1;
+ IntegerPolynomial c = new IntegerPolynomial(new int[cn]);
+ for (int k = 0; k < cn; k++)
+ {
+ for (int i = Math.max(0, k - n + 1); i <= Math.min(k, n - 1); i++)
+ {
+ c.coeffs[k] += b[i] * a[k - i];
+ }
+ }
+ return c;
+ }
+ else
+ {
+ int n1 = n / 2;
+
+ IntegerPolynomial a1 = new IntegerPolynomial(Arrays.copyOf(a, n1));
+ IntegerPolynomial a2 = new IntegerPolynomial(Arrays.copyOfRange(a, n1, n));
+ IntegerPolynomial b1 = new IntegerPolynomial(Arrays.copyOf(b, n1));
+ IntegerPolynomial b2 = new IntegerPolynomial(Arrays.copyOfRange(b, n1, n));
+
+ IntegerPolynomial A = (IntegerPolynomial)a1.clone();
+ A.add(a2);
+ IntegerPolynomial B = (IntegerPolynomial)b1.clone();
+ B.add(b2);
+
+ IntegerPolynomial c1 = a1.multRecursive(b1);
+ IntegerPolynomial c2 = a2.multRecursive(b2);
+ IntegerPolynomial c3 = A.multRecursive(B);
+ c3.sub(c1);
+ c3.sub(c2);
+
+ IntegerPolynomial c = new IntegerPolynomial(2 * n - 1);
+ for (int i = 0; i < c1.coeffs.length; i++)
+ {
+ c.coeffs[i] = c1.coeffs[i];
+ }
+ for (int i = 0; i < c3.coeffs.length; i++)
+ {
+ c.coeffs[n1 + i] += c3.coeffs[i];
+ }
+ for (int i = 0; i < c2.coeffs.length; i++)
+ {
+ c.coeffs[2 * n1 + i] += c2.coeffs[i];
+ }
+ return c;
+ }
+ }
+
+ /**
+ * Computes the inverse mod q; q
must be a power of 2.
+ * Returns null
if the polynomial is not invertible.
+ *
+ * @param q the modulus
+ * @return a new polynomial
+ */
+ public IntegerPolynomial invertFq(int q)
+ {
+ int N = coeffs.length;
+ int k = 0;
+ IntegerPolynomial b = new IntegerPolynomial(N + 1);
+ b.coeffs[0] = 1;
+ IntegerPolynomial c = new IntegerPolynomial(N + 1);
+ IntegerPolynomial f = new IntegerPolynomial(N + 1);
+ f.coeffs = Arrays.copyOf(coeffs, N + 1);
+ f.modPositive(2);
+ // set g(x) = x^N − 1
+ IntegerPolynomial g = new IntegerPolynomial(N + 1);
+ g.coeffs[0] = 1;
+ g.coeffs[N] = 1;
+ while (true)
+ {
+ while (f.coeffs[0] == 0)
+ {
+ for (int i = 1; i <= N; i++)
+ {
+ f.coeffs[i - 1] = f.coeffs[i]; // f(x) = f(x) / x
+ c.coeffs[N + 1 - i] = c.coeffs[N - i]; // c(x) = c(x) * x
+ }
+ f.coeffs[N] = 0;
+ c.coeffs[0] = 0;
+ k++;
+ if (f.equalsZero())
+ {
+ return null; // not invertible
+ }
+ }
+ if (f.equalsOne())
+ {
+ break;
+ }
+ if (f.degree() < g.degree())
+ {
+ // exchange f and g
+ IntegerPolynomial temp = f;
+ f = g;
+ g = temp;
+ // exchange b and c
+ temp = b;
+ b = c;
+ c = temp;
+ }
+ f.add(g, 2);
+ b.add(c, 2);
+ }
+
+ if (b.coeffs[N] != 0)
+ {
+ return null;
+ }
+ // Fq(x) = x^(N-k) * b(x)
+ IntegerPolynomial Fq = new IntegerPolynomial(N);
+ int j = 0;
+ k %= N;
+ for (int i = N - 1; i >= 0; i--)
+ {
+ j = i - k;
+ if (j < 0)
+ {
+ j += N;
+ }
+ Fq.coeffs[j] = b.coeffs[i];
+ }
+
+ return mod2ToModq(Fq, q);
+ }
+
+ /**
+ * Computes the inverse mod q from the inverse mod 2
+ *
+ * @param Fq
+ * @param q
+ * @return The inverse of this polynomial mod q
+ */
+ private IntegerPolynomial mod2ToModq(IntegerPolynomial Fq, int q)
+ {
+ if (Util.is64BitJVM() && q == 2048)
+ {
+ LongPolynomial2 thisLong = new LongPolynomial2(this);
+ LongPolynomial2 FqLong = new LongPolynomial2(Fq);
+ int v = 2;
+ while (v < q)
+ {
+ v *= 2;
+ LongPolynomial2 temp = (LongPolynomial2)FqLong.clone();
+ temp.mult2And(v - 1);
+ FqLong = thisLong.mult(FqLong).mult(FqLong);
+ temp.subAnd(FqLong, v - 1);
+ FqLong = temp;
+ }
+ return FqLong.toIntegerPolynomial();
+ }
+ else
+ {
+ int v = 2;
+ while (v < q)
+ {
+ v *= 2;
+ IntegerPolynomial temp = new IntegerPolynomial(Arrays.copyOf(Fq.coeffs, Fq.coeffs.length));
+ temp.mult2(v);
+ Fq = mult(Fq, v).mult(Fq, v);
+ temp.sub(Fq, v);
+ Fq = temp;
+ }
+ return Fq;
+ }
+ }
+
+ /**
+ * Computes the inverse mod 3.
+ * Returns null
if the polynomial is not invertible.
+ *
+ * @return a new polynomial
+ */
+ public IntegerPolynomial invertF3()
+ {
+ int N = coeffs.length;
+ int k = 0;
+ IntegerPolynomial b = new IntegerPolynomial(N + 1);
+ b.coeffs[0] = 1;
+ IntegerPolynomial c = new IntegerPolynomial(N + 1);
+ IntegerPolynomial f = new IntegerPolynomial(N + 1);
+ f.coeffs = Arrays.copyOf(coeffs, N + 1);
+ f.modPositive(3);
+ // set g(x) = x^N − 1
+ IntegerPolynomial g = new IntegerPolynomial(N + 1);
+ g.coeffs[0] = -1;
+ g.coeffs[N] = 1;
+ while (true)
+ {
+ while (f.coeffs[0] == 0)
+ {
+ for (int i = 1; i <= N; i++)
+ {
+ f.coeffs[i - 1] = f.coeffs[i]; // f(x) = f(x) / x
+ c.coeffs[N + 1 - i] = c.coeffs[N - i]; // c(x) = c(x) * x
+ }
+ f.coeffs[N] = 0;
+ c.coeffs[0] = 0;
+ k++;
+ if (f.equalsZero())
+ {
+ return null; // not invertible
+ }
+ }
+ if (f.equalsAbsOne())
+ {
+ break;
+ }
+ if (f.degree() < g.degree())
+ {
+ // exchange f and g
+ IntegerPolynomial temp = f;
+ f = g;
+ g = temp;
+ // exchange b and c
+ temp = b;
+ b = c;
+ c = temp;
+ }
+ if (f.coeffs[0] == g.coeffs[0])
+ {
+ f.sub(g, 3);
+ b.sub(c, 3);
+ }
+ else
+ {
+ f.add(g, 3);
+ b.add(c, 3);
+ }
+ }
+
+ if (b.coeffs[N] != 0)
+ {
+ return null;
+ }
+ // Fp(x) = [+-] x^(N-k) * b(x)
+ IntegerPolynomial Fp = new IntegerPolynomial(N);
+ int j = 0;
+ k %= N;
+ for (int i = N - 1; i >= 0; i--)
+ {
+ j = i - k;
+ if (j < 0)
+ {
+ j += N;
+ }
+ Fp.coeffs[j] = f.coeffs[0] * b.coeffs[i];
+ }
+
+ Fp.ensurePositive(3);
+ return Fp;
+ }
+
+ /**
+ * Resultant of this polynomial with x^n-1
using a probabilistic algorithm.
+ *
+ * Unlike EESS, this implementation does not compute all resultants modulo primes
+ * such that their product exceeds the maximum possible resultant, but rather stops
+ * when NUM_EQUAL_RESULTANTS
consecutive modular resultants are equal.
+ * This means the return value may be incorrect. Experiments show this happens in
+ * about 1 out of 100 cases when N=439
and NUM_EQUAL_RESULTANTS=2
,
+ * so the likelyhood of leaving the loop too early is (1/100)^(NUM_EQUAL_RESULTANTS-1)
.
+ *
+ * Because of the above, callers must verify the output and try a different polynomial if necessary.
+ *
+ * @return (rho, res)
satisfying res = rho*this + t*(x^n-1)
for some integer t
.
+ */
+ public Resultant resultant()
+ {
+ int N = coeffs.length;
+
+ // Compute resultants modulo prime numbers. Continue until NUM_EQUAL_RESULTANTS consecutive modular resultants are equal.
+ LinkedList(rho, res)
satisfying res = rho*this + t*(x^n-1)
for some integer t
.
+ */
+ public Resultant resultantMultiThread()
+ {
+ int N = coeffs.length;
+
+ // upper bound for resultant(f, g) = ||f, 2||^deg(g) * ||g, 2||^deg(f) = squaresum(f)^(N/2) * 2^(deg(f)/2) because g(x)=x^N-1
+ // see http://jondalon.mathematik.uni-osnabrueck.de/staff/phpages/brunsw/CompAlg.pdf chapter 3
+ BigInteger max = squareSum().pow((N + 1) / 2);
+ max = max.multiply(BigInteger.valueOf(2).pow((degree() + 1) / 2));
+ BigInteger max2 = max.multiply(BigInteger.valueOf(2));
+
+ // compute resultants modulo prime numbers
+ BigInteger prime = BigInteger.valueOf(10000);
+ BigInteger pProd = Constants.BIGINT_ONE;
+ LinkedBlockingQueuex^n-1 mod p
.
+ *
+ * @return (rho, res)
satisfying res = rho*this + t*(x^n-1) mod p
for some integer t
.
+ */
+ public ModularResultant resultant(int p)
+ {
+ // Add a coefficient as the following operations involve polynomials of degree deg(f)+1
+ int[] fcoeffs = Arrays.copyOf(coeffs, coeffs.length + 1);
+ IntegerPolynomial f = new IntegerPolynomial(fcoeffs);
+ int N = fcoeffs.length;
+
+ IntegerPolynomial a = new IntegerPolynomial(N);
+ a.coeffs[0] = -1;
+ a.coeffs[N - 1] = 1;
+ IntegerPolynomial b = new IntegerPolynomial(f.coeffs);
+ IntegerPolynomial v1 = new IntegerPolynomial(N);
+ IntegerPolynomial v2 = new IntegerPolynomial(N);
+ v2.coeffs[0] = 1;
+ int da = N - 1;
+ int db = b.degree();
+ int ta = da;
+ int c = 0;
+ int r = 1;
+ while (db > 0)
+ {
+ c = Util.invert(b.coeffs[db], p);
+ c = (c * a.coeffs[da]) % p;
+ a.multShiftSub(b, c, da - db, p);
+ v1.multShiftSub(v2, c, da - db, p);
+
+ da = a.degree();
+ if (da < db)
+ {
+ r *= Util.pow(b.coeffs[db], ta - da, p);
+ r %= p;
+ if (ta % 2 == 1 && db % 2 == 1)
+ {
+ r = (-r) % p;
+ }
+ IntegerPolynomial temp = a;
+ a = b;
+ b = temp;
+ int tempdeg = da;
+ da = db;
+ temp = v1;
+ v1 = v2;
+ v2 = temp;
+ ta = db;
+ db = tempdeg;
+ }
+ }
+ r *= Util.pow(b.coeffs[0], da, p);
+ r %= p;
+ c = Util.invert(b.coeffs[0], p);
+ v2.mult(c);
+ v2.mod(p);
+ v2.mult(r);
+ v2.mod(p);
+
+ // drop the highest coefficient so #coeffs matches the original input
+ v2.coeffs = Arrays.copyOf(v2.coeffs, v2.coeffs.length - 1);
+ return new ModularResultant(new BigIntPolynomial(v2), BigInteger.valueOf(r), BigInteger.valueOf(p));
+ }
+
+ /**
+ * Computes this-b*c*(x^k) mod p
and stores the result in this polynomial.
+ * See steps 4a,4b in EESS algorithm 2.2.7.1.
+ *
+ * @param b
+ * @param c
+ * @param k
+ * @param p
+ */
+ private void multShiftSub(IntegerPolynomial b, int c, int k, int p)
+ {
+ int N = coeffs.length;
+ for (int i = k; i < N; i++)
+ {
+ coeffs[i] = (coeffs[i] - b.coeffs[i - k] * c) % p;
+ }
+ }
+
+ /**
+ * Adds the squares of all coefficients.
+ *
+ * @return the sum of squares
+ */
+ private BigInteger squareSum()
+ {
+ BigInteger sum = Constants.BIGINT_ZERO;
+ for (int i = 0; i < coeffs.length; i++)
+ {
+ sum = sum.add(BigInteger.valueOf(coeffs[i] * coeffs[i]));
+ }
+ return sum;
+ }
+
+ /**
+ * Returns the degree of the polynomial
+ *
+ * @return the degree
+ */
+ int degree()
+ {
+ int degree = coeffs.length - 1;
+ while (degree > 0 && coeffs[degree] == 0)
+ {
+ degree--;
+ }
+ return degree;
+ }
+
+ /**
+ * Adds another polynomial which can have a different number of coefficients,
+ * and takes the coefficient values mod modulus
.
+ *
+ * @param b another polynomial
+ */
+ public void add(IntegerPolynomial b, int modulus)
+ {
+ add(b);
+ mod(modulus);
+ }
+
+ /**
+ * Adds another polynomial which can have a different number of coefficients.
+ *
+ * @param b another polynomial
+ */
+ public void add(IntegerPolynomial b)
+ {
+ if (b.coeffs.length > coeffs.length)
+ {
+ coeffs = Arrays.copyOf(coeffs, b.coeffs.length);
+ }
+ for (int i = 0; i < b.coeffs.length; i++)
+ {
+ coeffs[i] += b.coeffs[i];
+ }
+ }
+
+ /**
+ * Subtracts another polynomial which can have a different number of coefficients,
+ * and takes the coefficient values mod modulus
.
+ *
+ * @param b another polynomial
+ */
+ public void sub(IntegerPolynomial b, int modulus)
+ {
+ sub(b);
+ mod(modulus);
+ }
+
+ /**
+ * Subtracts another polynomial which can have a different number of coefficients.
+ *
+ * @param b another polynomial
+ */
+ public void sub(IntegerPolynomial b)
+ {
+ if (b.coeffs.length > coeffs.length)
+ {
+ coeffs = Arrays.copyOf(coeffs, b.coeffs.length);
+ }
+ for (int i = 0; i < b.coeffs.length; i++)
+ {
+ coeffs[i] -= b.coeffs[i];
+ }
+ }
+
+ /**
+ * Subtracts a int
from each coefficient. Does not return a new polynomial but modifies this polynomial.
+ *
+ * @param b
+ */
+ void sub(int b)
+ {
+ for (int i = 0; i < coeffs.length; i++)
+ {
+ coeffs[i] -= b;
+ }
+ }
+
+ /**
+ * Multiplies each coefficient by a int
. Does not return a new polynomial but modifies this polynomial.
+ *
+ * @param factor
+ */
+ public void mult(int factor)
+ {
+ for (int i = 0; i < coeffs.length; i++)
+ {
+ coeffs[i] *= factor;
+ }
+ }
+
+ /**
+ * Multiplies each coefficient by a 2 and applies a modulus. Does not return a new polynomial but modifies this polynomial.
+ *
+ * @param modulus a modulus
+ */
+ private void mult2(int modulus)
+ {
+ for (int i = 0; i < coeffs.length; i++)
+ {
+ coeffs[i] *= 2;
+ coeffs[i] %= modulus;
+ }
+ }
+
+ /**
+ * Multiplies each coefficient by a 2 and applies a modulus. Does not return a new polynomial but modifies this polynomial.
+ *
+ * @param modulus a modulus
+ */
+ public void mult3(int modulus)
+ {
+ for (int i = 0; i < coeffs.length; i++)
+ {
+ coeffs[i] *= 3;
+ coeffs[i] %= modulus;
+ }
+ }
+
+ /**
+ * Divides each coefficient by k
and rounds to the nearest integer. Does not return a new polynomial but modifies this polynomial.
+ *
+ * @param k the divisor
+ */
+ public void div(int k)
+ {
+ int k2 = (k + 1) / 2;
+ for (int i = 0; i < coeffs.length; i++)
+ {
+ coeffs[i] += coeffs[i] > 0 ? k2 : -k2;
+ coeffs[i] /= k;
+ }
+ }
+
+ /**
+ * Takes each coefficient modulo 3 such that all coefficients are ternary.
+ */
+ public void mod3()
+ {
+ for (int i = 0; i < coeffs.length; i++)
+ {
+ coeffs[i] %= 3;
+ if (coeffs[i] > 1)
+ {
+ coeffs[i] -= 3;
+ }
+ if (coeffs[i] < -1)
+ {
+ coeffs[i] += 3;
+ }
+ }
+ }
+
+ /**
+ * Ensures all coefficients are between 0 and modulus-1
+ *
+ * @param modulus a modulus
+ */
+ public void modPositive(int modulus)
+ {
+ mod(modulus);
+ ensurePositive(modulus);
+ }
+
+ /**
+ * Reduces all coefficients to the interval [-modulus/2, modulus/2)
+ */
+ void modCenter(int modulus)
+ {
+ mod(modulus);
+ for (int j = 0; j < coeffs.length; j++)
+ {
+ while (coeffs[j] < modulus / 2)
+ {
+ coeffs[j] += modulus;
+ }
+ while (coeffs[j] >= modulus / 2)
+ {
+ coeffs[j] -= modulus;
+ }
+ }
+ }
+
+ /**
+ * Takes each coefficient modulo modulus
.
+ */
+ public void mod(int modulus)
+ {
+ for (int i = 0; i < coeffs.length; i++)
+ {
+ coeffs[i] %= modulus;
+ }
+ }
+
+ /**
+ * Adds modulus
until all coefficients are above 0.
+ *
+ * @param modulus a modulus
+ */
+ public void ensurePositive(int modulus)
+ {
+ for (int i = 0; i < coeffs.length; i++)
+ {
+ while (coeffs[i] < 0)
+ {
+ coeffs[i] += modulus;
+ }
+ }
+ }
+
+ /**
+ * Computes the centered euclidean norm of the polynomial.
+ *
+ * @param q a modulus
+ * @return the centered norm
+ */
+ public long centeredNormSq(int q)
+ {
+ int N = coeffs.length;
+ IntegerPolynomial p = (IntegerPolynomial)clone();
+ p.shiftGap(q);
+
+ long sum = 0;
+ long sqSum = 0;
+ for (int i = 0; i != p.coeffs.length; i++)
+ {
+ int c = p.coeffs[i];
+ sum += c;
+ sqSum += c * c;
+ }
+
+ long centeredNormSq = sqSum - sum * sum / N;
+ return centeredNormSq;
+ }
+
+ /**
+ * Shifts all coefficients so the largest gap is centered around -q/2
.
+ *
+ * @param q a modulus
+ */
+ void shiftGap(int q)
+ {
+ modCenter(q);
+
+ int[] sorted = Arrays.clone(coeffs);
+
+ sort(sorted);
+
+ int maxrange = 0;
+ int maxrangeStart = 0;
+ for (int i = 0; i < sorted.length - 1; i++)
+ {
+ int range = sorted[i + 1] - sorted[i];
+ if (range > maxrange)
+ {
+ maxrange = range;
+ maxrangeStart = sorted[i];
+ }
+ }
+
+ int pmin = sorted[0];
+ int pmax = sorted[sorted.length - 1];
+
+ int j = q - pmax + pmin;
+ int shift;
+ if (j > maxrange)
+ {
+ shift = (pmax + pmin) / 2;
+ }
+ else
+ {
+ shift = maxrangeStart + maxrange / 2 + q / 2;
+ }
+
+ sub(shift);
+ }
+
+ private void sort(int[] ints)
+ {
+ boolean swap = true;
+
+ while (swap)
+ {
+ swap = false;
+ for (int i = 0; i != ints.length - 1; i++)
+ {
+ if (ints[i] > ints[i+1])
+ {
+ int tmp = ints[i];
+ ints[i] = ints[i+1];
+ ints[i+1] = tmp;
+ swap = true;
+ }
+ }
+ }
+ }
+
+ /**
+ * Shifts the values of all coefficients to the interval [-q/2, q/2]
.
+ *
+ * @param q a modulus
+ */
+ public void center0(int q)
+ {
+ for (int i = 0; i < coeffs.length; i++)
+ {
+ while (coeffs[i] < -q / 2)
+ {
+ coeffs[i] += q;
+ }
+ while (coeffs[i] > q / 2)
+ {
+ coeffs[i] -= q;
+ }
+ }
+ }
+
+ /**
+ * Returns the sum of all coefficients, i.e. evaluates the polynomial at 0.
+ *
+ * @return the sum of all coefficients
+ */
+ public int sumCoeffs()
+ {
+ int sum = 0;
+ for (int i = 0; i < coeffs.length; i++)
+ {
+ sum += coeffs[i];
+ }
+ return sum;
+ }
+
+ /**
+ * Tests if p(x) = 0
.
+ *
+ * @return true iff all coefficients are zeros
+ */
+ private boolean equalsZero()
+ {
+ for (int i = 0; i < coeffs.length; i++)
+ {
+ if (coeffs[i] != 0)
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Tests if p(x) = 1
.
+ *
+ * @return true iff all coefficients are equal to zero, except for the lowest coefficient which must equal 1
+ */
+ public boolean equalsOne()
+ {
+ for (int i = 1; i < coeffs.length; i++)
+ {
+ if (coeffs[i] != 0)
+ {
+ return false;
+ }
+ }
+ return coeffs[0] == 1;
+ }
+
+ /**
+ * Tests if |p(x)| = 1
.
+ *
+ * @return true iff all coefficients are equal to zero, except for the lowest coefficient which must equal 1 or -1
+ */
+ private boolean equalsAbsOne()
+ {
+ for (int i = 1; i < coeffs.length; i++)
+ {
+ if (coeffs[i] != 0)
+ {
+ return false;
+ }
+ }
+ return Math.abs(coeffs[0]) == 1;
+ }
+
+ /**
+ * Counts the number of coefficients equal to an integer
+ *
+ * @param value an integer
+ * @return the number of coefficients equal to value
+ */
+ public int count(int value)
+ {
+ int count = 0;
+ for (int i = 0; i != coeffs.length; i++)
+ {
+ if (coeffs[i] == value)
+ {
+ count++;
+ }
+ }
+ return count;
+ }
+
+ /**
+ * Multiplication by X
in Z[X]/Z[X^n-1]
.
+ */
+ public void rotate1()
+ {
+ int clast = coeffs[coeffs.length - 1];
+ for (int i = coeffs.length - 1; i > 0; i--)
+ {
+ coeffs[i] = coeffs[i - 1];
+ }
+ coeffs[0] = clast;
+ }
+
+ public void clear()
+ {
+ for (int i = 0; i < coeffs.length; i++)
+ {
+ coeffs[i] = 0;
+ }
+ }
+
+ public IntegerPolynomial toIntegerPolynomial()
+ {
+ return (IntegerPolynomial)clone();
+ }
+
+ public Object clone()
+ {
+ return new IntegerPolynomial(coeffs.clone());
+ }
+
+ public boolean equals(Object obj)
+ {
+ if (obj instanceof IntegerPolynomial)
+ {
+ return Arrays.areEqual(coeffs, ((IntegerPolynomial)obj).coeffs);
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ /**
+ * Calls {@link IntegerPolynomial#resultant(int)
+ */
+ private class ModResultantTask
+ implements Callablelong
value for
+ * faster multiplication in 64 bit environments.
+ * Coefficients can be between 0 and 2047 and are stored in pairs in the bits 0..10 and 24..34 of a long
number.
+ */
+public class LongPolynomial2
+{
+ private long[] coeffs; // each representing two coefficients in the original IntegerPolynomial
+ private int numCoeffs;
+
+ /**
+ * Constructs a LongPolynomial2
from a IntegerPolynomial
. The two polynomials are independent of each other.
+ *
+ * @param p the original polynomial. Coefficients must be between 0 and 2047.
+ */
+ public LongPolynomial2(IntegerPolynomial p)
+ {
+ numCoeffs = p.coeffs.length;
+ coeffs = new long[(numCoeffs + 1) / 2];
+ int idx = 0;
+ for (int pIdx = 0; pIdx < numCoeffs; )
+ {
+ int c0 = p.coeffs[pIdx++];
+ while (c0 < 0)
+ {
+ c0 += 2048;
+ }
+ long c1 = pIdx < numCoeffs ? p.coeffs[pIdx++] : 0;
+ while (c1 < 0)
+ {
+ c1 += 2048;
+ }
+ coeffs[idx] = c0 + (c1 << 24);
+ idx++;
+ }
+ }
+
+ private LongPolynomial2(long[] coeffs)
+ {
+ this.coeffs = coeffs;
+ }
+
+ private LongPolynomial2(int N)
+ {
+ coeffs = new long[N];
+ }
+
+ /**
+ * Multiplies the polynomial with another, taking the indices mod N and the values mod 2048.
+ */
+ public LongPolynomial2 mult(LongPolynomial2 poly2)
+ {
+ int N = coeffs.length;
+ if (poly2.coeffs.length != N || numCoeffs != poly2.numCoeffs)
+ {
+ throw new IllegalArgumentException("Number of coefficients must be the same");
+ }
+
+ LongPolynomial2 c = multRecursive(poly2);
+
+ if (c.coeffs.length > N)
+ {
+ if (numCoeffs % 2 == 0)
+ {
+ for (int k = N; k < c.coeffs.length; k++)
+ {
+ c.coeffs[k - N] = (c.coeffs[k - N] + c.coeffs[k]) & 0x7FF0007FFL;
+ }
+ c.coeffs = Arrays.copyOf(c.coeffs, N);
+ }
+ else
+ {
+ for (int k = N; k < c.coeffs.length; k++)
+ {
+ c.coeffs[k - N] = c.coeffs[k - N] + (c.coeffs[k - 1] >> 24);
+ c.coeffs[k - N] = c.coeffs[k - N] + ((c.coeffs[k] & 2047) << 24);
+ c.coeffs[k - N] &= 0x7FF0007FFL;
+ }
+ c.coeffs = Arrays.copyOf(c.coeffs, N);
+ c.coeffs[c.coeffs.length - 1] &= 2047;
+ }
+ }
+
+ c = new LongPolynomial2(c.coeffs);
+ c.numCoeffs = numCoeffs;
+ return c;
+ }
+
+ public IntegerPolynomial toIntegerPolynomial()
+ {
+ int[] intCoeffs = new int[numCoeffs];
+ int uIdx = 0;
+ for (int i = 0; i < coeffs.length; i++)
+ {
+ intCoeffs[uIdx++] = (int)(coeffs[i] & 2047);
+ if (uIdx < numCoeffs)
+ {
+ intCoeffs[uIdx++] = (int)((coeffs[i] >> 24) & 2047);
+ }
+ }
+ return new IntegerPolynomial(intCoeffs);
+ }
+
+ /**
+ * Karazuba multiplication
+ */
+ private LongPolynomial2 multRecursive(LongPolynomial2 poly2)
+ {
+ long[] a = coeffs;
+ long[] b = poly2.coeffs;
+
+ int n = poly2.coeffs.length;
+ if (n <= 32)
+ {
+ int cn = 2 * n;
+ LongPolynomial2 c = new LongPolynomial2(new long[cn]);
+ for (int k = 0; k < cn; k++)
+ {
+ for (int i = Math.max(0, k - n + 1); i <= Math.min(k, n - 1); i++)
+ {
+ long c0 = a[k - i] * b[i];
+ long cu = c0 & 0x7FF000000L + (c0 & 2047);
+ long co = (c0 >>> 48) & 2047;
+
+ c.coeffs[k] = (c.coeffs[k] + cu) & 0x7FF0007FFL;
+ c.coeffs[k + 1] = (c.coeffs[k + 1] + co) & 0x7FF0007FFL;
+ }
+ }
+ return c;
+ }
+ else
+ {
+ int n1 = n / 2;
+
+ LongPolynomial2 a1 = new LongPolynomial2(Arrays.copyOf(a, n1));
+ LongPolynomial2 a2 = new LongPolynomial2(Arrays.copyOfRange(a, n1, n));
+ LongPolynomial2 b1 = new LongPolynomial2(Arrays.copyOf(b, n1));
+ LongPolynomial2 b2 = new LongPolynomial2(Arrays.copyOfRange(b, n1, n));
+
+ LongPolynomial2 A = (LongPolynomial2)a1.clone();
+ A.add(a2);
+ LongPolynomial2 B = (LongPolynomial2)b1.clone();
+ B.add(b2);
+
+ LongPolynomial2 c1 = a1.multRecursive(b1);
+ LongPolynomial2 c2 = a2.multRecursive(b2);
+ LongPolynomial2 c3 = A.multRecursive(B);
+ c3.sub(c1);
+ c3.sub(c2);
+
+ LongPolynomial2 c = new LongPolynomial2(2 * n);
+ for (int i = 0; i < c1.coeffs.length; i++)
+ {
+ c.coeffs[i] = c1.coeffs[i] & 0x7FF0007FFL;
+ }
+ for (int i = 0; i < c3.coeffs.length; i++)
+ {
+ c.coeffs[n1 + i] = (c.coeffs[n1 + i] + c3.coeffs[i]) & 0x7FF0007FFL;
+ }
+ for (int i = 0; i < c2.coeffs.length; i++)
+ {
+ c.coeffs[2 * n1 + i] = (c.coeffs[2 * n1 + i] + c2.coeffs[i]) & 0x7FF0007FFL;
+ }
+ return c;
+ }
+ }
+
+ /**
+ * Adds another polynomial which can have a different number of coefficients.
+ *
+ * @param b another polynomial
+ */
+ private void add(LongPolynomial2 b)
+ {
+ if (b.coeffs.length > coeffs.length)
+ {
+ coeffs = Arrays.copyOf(coeffs, b.coeffs.length);
+ }
+ for (int i = 0; i < b.coeffs.length; i++)
+ {
+ coeffs[i] = (coeffs[i] + b.coeffs[i]) & 0x7FF0007FFL;
+ }
+ }
+
+ /**
+ * Subtracts another polynomial which can have a different number of coefficients.
+ *
+ * @param b another polynomial
+ */
+ private void sub(LongPolynomial2 b)
+ {
+ if (b.coeffs.length > coeffs.length)
+ {
+ coeffs = Arrays.copyOf(coeffs, b.coeffs.length);
+ }
+ for (int i = 0; i < b.coeffs.length; i++)
+ {
+ coeffs[i] = (0x0800000800000L + coeffs[i] - b.coeffs[i]) & 0x7FF0007FFL;
+ }
+ }
+
+ /**
+ * Subtracts another polynomial which must have the same number of coefficients,
+ * and applies an AND mask to the upper and lower halves of each coefficients.
+ *
+ * @param b another polynomial
+ * @param mask a bit mask less than 2048 to apply to each 11-bit coefficient
+ */
+ public void subAnd(LongPolynomial2 b, int mask)
+ {
+ long longMask = (((long)mask) << 24) + mask;
+ for (int i = 0; i < b.coeffs.length; i++)
+ {
+ coeffs[i] = (0x0800000800000L + coeffs[i] - b.coeffs[i]) & longMask;
+ }
+ }
+
+ /**
+ * Multiplies this polynomial by 2 and applies an AND mask to the upper and
+ * lower halves of each coefficients.
+ *
+ * @param mask a bit mask less than 2048 to apply to each 11-bit coefficient
+ */
+ public void mult2And(int mask)
+ {
+ long longMask = (((long)mask) << 24) + mask;
+ for (int i = 0; i < coeffs.length; i++)
+ {
+ coeffs[i] = (coeffs[i] << 1) & longMask;
+ }
+ }
+
+ public Object clone()
+ {
+ LongPolynomial2 p = new LongPolynomial2(coeffs.clone());
+ p.numCoeffs = numCoeffs;
+ return p;
+ }
+
+ public boolean equals(Object obj)
+ {
+ if (obj instanceof LongPolynomial2)
+ {
+ return Arrays.areEqual(coeffs, ((LongPolynomial2)obj).coeffs);
+ }
+ else
+ {
+ return false;
+ }
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ntru/polynomial/LongPolynomial5.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ntru/polynomial/LongPolynomial5.java
new file mode 100644
index 0000000..5e076c2
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ntru/polynomial/LongPolynomial5.java
@@ -0,0 +1,149 @@
+package org.bc.math.ntru.polynomial;
+
+import org.bc.util.Arrays;
+
+/**
+ * A polynomial class that combines five coefficients into one long
value for
+ * faster multiplication by a ternary polynomial.
+ * Coefficients can be between 0 and 2047 and are stored in bits 0..11, 12..23, ..., 48..59 of a long
number.
+ */
+public class LongPolynomial5
+{
+ private long[] coeffs; // groups of 5 coefficients
+ private int numCoeffs;
+
+ /**
+ * Constructs a LongPolynomial5
from a IntegerPolynomial
. The two polynomials are independent of each other.
+ *
+ * @param p the original polynomial. Coefficients must be between 0 and 2047.
+ */
+ public LongPolynomial5(IntegerPolynomial p)
+ {
+ numCoeffs = p.coeffs.length;
+
+ coeffs = new long[(numCoeffs + 4) / 5];
+ int cIdx = 0;
+ int shift = 0;
+ for (int i = 0; i < numCoeffs; i++)
+ {
+ coeffs[cIdx] |= ((long)p.coeffs[i]) << shift;
+ shift += 12;
+ if (shift >= 60)
+ {
+ shift = 0;
+ cIdx++;
+ }
+ }
+ }
+
+ private LongPolynomial5(long[] coeffs, int numCoeffs)
+ {
+ this.coeffs = coeffs;
+ this.numCoeffs = numCoeffs;
+ }
+
+ /**
+ * Multiplies the polynomial with a TernaryPolynomial
, taking the indices mod N and the values mod 2048.
+ */
+ public LongPolynomial5 mult(TernaryPolynomial poly2)
+ {
+ long[][] prod = new long[5][coeffs.length + (poly2.size() + 4) / 5 - 1]; // intermediate results, the subarrays are shifted by 0,...,4 coefficients
+
+ // multiply ones
+ int[] ones = poly2.getOnes();
+ for (int idx = 0; idx != ones.length; idx++)
+ {
+ int pIdx = ones[idx];
+ int cIdx = pIdx / 5;
+ int m = pIdx - cIdx * 5; // m = pIdx % 5
+ for (int i = 0; i < coeffs.length; i++)
+ {
+ prod[m][cIdx] = (prod[m][cIdx] + coeffs[i]) & 0x7FF7FF7FF7FF7FFL;
+ cIdx++;
+ }
+ }
+
+ // multiply negative ones
+ int[] negOnes = poly2.getNegOnes();
+ for (int idx = 0; idx != negOnes.length; idx++)
+ {
+ int pIdx = negOnes[idx];
+ int cIdx = pIdx / 5;
+ int m = pIdx - cIdx * 5; // m = pIdx % 5
+ for (int i = 0; i < coeffs.length; i++)
+ {
+ prod[m][cIdx] = (0x800800800800800L + prod[m][cIdx] - coeffs[i]) & 0x7FF7FF7FF7FF7FFL;
+ cIdx++;
+ }
+ }
+
+ // combine shifted coefficients (5 arrays) into a single array of length prod[*].length+1
+ long[] cCoeffs = Arrays.copyOf(prod[0], prod[0].length + 1);
+ for (int m = 1; m <= 4; m++)
+ {
+ int shift = m * 12;
+ int shift60 = 60 - shift;
+ long mask = (1L << shift60) - 1;
+ int pLen = prod[m].length;
+ for (int i = 0; i < pLen; i++)
+ {
+ long upper, lower;
+ upper = prod[m][i] >> shift60;
+ lower = prod[m][i] & mask;
+
+ cCoeffs[i] = (cCoeffs[i] + (lower << shift)) & 0x7FF7FF7FF7FF7FFL;
+ int nextIdx = i + 1;
+ cCoeffs[nextIdx] = (cCoeffs[nextIdx] + upper) & 0x7FF7FF7FF7FF7FFL;
+ }
+ }
+
+ // reduce indices of cCoeffs modulo numCoeffs
+ int shift = 12 * (numCoeffs % 5);
+ for (int cIdx = coeffs.length - 1; cIdx < cCoeffs.length; cIdx++)
+ {
+ long iCoeff; // coefficient to shift into the [0..numCoeffs-1] range
+ int newIdx;
+ if (cIdx == coeffs.length - 1)
+ {
+ iCoeff = numCoeffs == 5 ? 0 : cCoeffs[cIdx] >> shift;
+ newIdx = 0;
+ }
+ else
+ {
+ iCoeff = cCoeffs[cIdx];
+ newIdx = cIdx * 5 - numCoeffs;
+ }
+
+ int base = newIdx / 5;
+ int m = newIdx - base * 5; // m = newIdx % 5
+ long lower = iCoeff << (12 * m);
+ long upper = iCoeff >> (12 * (5 - m));
+ cCoeffs[base] = (cCoeffs[base] + lower) & 0x7FF7FF7FF7FF7FFL;
+ int base1 = base + 1;
+ if (base1 < coeffs.length)
+ {
+ cCoeffs[base1] = (cCoeffs[base1] + upper) & 0x7FF7FF7FF7FF7FFL;
+ }
+ }
+
+ return new LongPolynomial5(cCoeffs, numCoeffs);
+ }
+
+ public IntegerPolynomial toIntegerPolynomial()
+ {
+ int[] intCoeffs = new int[numCoeffs];
+ int cIdx = 0;
+ int shift = 0;
+ for (int i = 0; i < numCoeffs; i++)
+ {
+ intCoeffs[i] = (int)((coeffs[cIdx] >> shift) & 2047);
+ shift += 12;
+ if (shift >= 60)
+ {
+ shift = 0;
+ cIdx++;
+ }
+ }
+ return new IntegerPolynomial(intCoeffs);
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ntru/polynomial/ModularResultant.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ntru/polynomial/ModularResultant.java
new file mode 100644
index 0000000..94d5a7c
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ntru/polynomial/ModularResultant.java
@@ -0,0 +1,46 @@
+package org.bc.math.ntru.polynomial;
+
+import java.math.BigInteger;
+
+import org.bc.math.ntru.euclid.BigIntEuclidean;
+
+/**
+ * A resultant modulo a BigInteger
+ */
+public class ModularResultant
+ extends Resultant
+{
+ BigInteger modulus;
+
+ ModularResultant(BigIntPolynomial rho, BigInteger res, BigInteger modulus)
+ {
+ super(rho, res);
+ this.modulus = modulus;
+ }
+
+ /**
+ * Calculates a rho
modulo m1*m2
from
+ * two resultants whose rho
s are modulo m1
and m2
.
+ * null
.
+ *
+ * @param modRes1
+ * @param modRes2
+ * @return rho
modulo modRes1.modulus * modRes2.modulus
, and null
for res.
+ */
+ static ModularResultant combineRho(ModularResultant modRes1, ModularResultant modRes2)
+ {
+ BigInteger mod1 = modRes1.modulus;
+ BigInteger mod2 = modRes2.modulus;
+ BigInteger prod = mod1.multiply(mod2);
+ BigIntEuclidean er = BigIntEuclidean.calculate(mod2, mod1);
+
+ BigIntPolynomial rho1 = (BigIntPolynomial)modRes1.rho.clone();
+ rho1.mult(er.x.multiply(mod2));
+ BigIntPolynomial rho2 = (BigIntPolynomial)modRes2.rho.clone();
+ rho2.mult(er.y.multiply(mod1));
+ rho1.add(rho2);
+ rho1.mod(prod);
+
+ return new ModularResultant(rho1, null, prod);
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ntru/polynomial/Polynomial.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ntru/polynomial/Polynomial.java
new file mode 100644
index 0000000..7729a40
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ntru/polynomial/Polynomial.java
@@ -0,0 +1,42 @@
+package org.bc.math.ntru.polynomial;
+
+public interface Polynomial
+{
+
+ /**
+ * Multiplies the polynomial by an IntegerPolynomial
,
+ * taking the indices mod N
.
+ *
+ * @param poly2 a polynomial
+ * @return the product of the two polynomials
+ */
+ IntegerPolynomial mult(IntegerPolynomial poly2);
+
+ /**
+ * Multiplies the polynomial by an IntegerPolynomial
,
+ * taking the coefficient values mod modulus
and the indices mod N
.
+ *
+ * @param poly2 a polynomial
+ * @param modulus a modulus to apply
+ * @return the product of the two polynomials
+ */
+ IntegerPolynomial mult(IntegerPolynomial poly2, int modulus);
+
+ /**
+ * Returns a polynomial that is equal to this polynomial (in the sense that {@link #mult(IntegerPolynomial, int)}
+ * returns equal IntegerPolynomial
s). The new polynomial is guaranteed to be independent of the original.
+ *
+ * @return a new IntegerPolynomial
.
+ */
+ IntegerPolynomial toIntegerPolynomial();
+
+ /**
+ * Multiplies the polynomial by a BigIntPolynomial
, taking the indices mod N. Does not
+ * change this polynomial but returns the result as a new polynomial.
+ * Both polynomials must have the same number of coefficients.
+ *
+ * @param poly2 the polynomial to multiply by
+ * @return a new polynomial
+ */
+ BigIntPolynomial mult(BigIntPolynomial poly2);
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ntru/polynomial/ProductFormPolynomial.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ntru/polynomial/ProductFormPolynomial.java
new file mode 100644
index 0000000..6ab212e
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ntru/polynomial/ProductFormPolynomial.java
@@ -0,0 +1,153 @@
+package org.bc.math.ntru.polynomial;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.SecureRandom;
+
+import org.bc.util.Arrays;
+
+/**
+ * A polynomial of the form f1*f2+f3
, where
+ * f1,f2,f3
are very sparsely populated ternary polynomials.
+ */
+public class ProductFormPolynomial
+ implements Polynomial
+{
+ private SparseTernaryPolynomial f1, f2, f3;
+
+ public ProductFormPolynomial(SparseTernaryPolynomial f1, SparseTernaryPolynomial f2, SparseTernaryPolynomial f3)
+ {
+ this.f1 = f1;
+ this.f2 = f2;
+ this.f3 = f3;
+ }
+
+ public static ProductFormPolynomial generateRandom(int N, int df1, int df2, int df3Ones, int df3NegOnes, SecureRandom random)
+ {
+ SparseTernaryPolynomial f1 = SparseTernaryPolynomial.generateRandom(N, df1, df1, random);
+ SparseTernaryPolynomial f2 = SparseTernaryPolynomial.generateRandom(N, df2, df2, random);
+ SparseTernaryPolynomial f3 = SparseTernaryPolynomial.generateRandom(N, df3Ones, df3NegOnes, random);
+ return new ProductFormPolynomial(f1, f2, f3);
+ }
+
+ public static ProductFormPolynomial fromBinary(byte[] data, int N, int df1, int df2, int df3Ones, int df3NegOnes)
+ throws IOException
+ {
+ return fromBinary(new ByteArrayInputStream(data), N, df1, df2, df3Ones, df3NegOnes);
+ }
+
+ public static ProductFormPolynomial fromBinary(InputStream is, int N, int df1, int df2, int df3Ones, int df3NegOnes)
+ throws IOException
+ {
+ SparseTernaryPolynomial f1;
+
+ f1 = SparseTernaryPolynomial.fromBinary(is, N, df1, df1);
+ SparseTernaryPolynomial f2 = SparseTernaryPolynomial.fromBinary(is, N, df2, df2);
+ SparseTernaryPolynomial f3 = SparseTernaryPolynomial.fromBinary(is, N, df3Ones, df3NegOnes);
+ return new ProductFormPolynomial(f1, f2, f3);
+ }
+
+ public byte[] toBinary()
+ {
+ byte[] f1Bin = f1.toBinary();
+ byte[] f2Bin = f2.toBinary();
+ byte[] f3Bin = f3.toBinary();
+
+ byte[] all = Arrays.copyOf(f1Bin, f1Bin.length + f2Bin.length + f3Bin.length);
+ System.arraycopy(f2Bin, 0, all, f1Bin.length, f2Bin.length);
+ System.arraycopy(f3Bin, 0, all, f1Bin.length + f2Bin.length, f3Bin.length);
+ return all;
+ }
+
+ public IntegerPolynomial mult(IntegerPolynomial b)
+ {
+ IntegerPolynomial c = f1.mult(b);
+ c = f2.mult(c);
+ c.add(f3.mult(b));
+ return c;
+ }
+
+ public BigIntPolynomial mult(BigIntPolynomial b)
+ {
+ BigIntPolynomial c = f1.mult(b);
+ c = f2.mult(c);
+ c.add(f3.mult(b));
+ return c;
+ }
+
+ public IntegerPolynomial toIntegerPolynomial()
+ {
+ IntegerPolynomial i = f1.mult(f2.toIntegerPolynomial());
+ i.add(f3.toIntegerPolynomial());
+ return i;
+ }
+
+ public IntegerPolynomial mult(IntegerPolynomial poly2, int modulus)
+ {
+ IntegerPolynomial c = mult(poly2);
+ c.mod(modulus);
+ return c;
+ }
+
+ public int hashCode()
+ {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((f1 == null) ? 0 : f1.hashCode());
+ result = prime * result + ((f2 == null) ? 0 : f2.hashCode());
+ result = prime * result + ((f3 == null) ? 0 : f3.hashCode());
+ return result;
+ }
+
+ public boolean equals(Object obj)
+ {
+ if (this == obj)
+ {
+ return true;
+ }
+ if (obj == null)
+ {
+ return false;
+ }
+ if (getClass() != obj.getClass())
+ {
+ return false;
+ }
+ ProductFormPolynomial other = (ProductFormPolynomial)obj;
+ if (f1 == null)
+ {
+ if (other.f1 != null)
+ {
+ return false;
+ }
+ }
+ else if (!f1.equals(other.f1))
+ {
+ return false;
+ }
+ if (f2 == null)
+ {
+ if (other.f2 != null)
+ {
+ return false;
+ }
+ }
+ else if (!f2.equals(other.f2))
+ {
+ return false;
+ }
+ if (f3 == null)
+ {
+ if (other.f3 != null)
+ {
+ return false;
+ }
+ }
+ else if (!f3.equals(other.f3))
+ {
+ return false;
+ }
+ return true;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ntru/polynomial/Resultant.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ntru/polynomial/Resultant.java
new file mode 100644
index 0000000..647dc6f
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ntru/polynomial/Resultant.java
@@ -0,0 +1,28 @@
+package org.bc.math.ntru.polynomial;
+
+import java.math.BigInteger;
+
+/**
+ * Contains a resultant and a polynomial rho
such that
+ * res = rho*this + t*(x^n-1) for some integer t
.
+ *
+ * @see IntegerPolynomial#resultant()
+ * @see IntegerPolynomial#resultant(int)
+ */
+public class Resultant
+{
+ /**
+ * A polynomial such that res = rho*this + t*(x^n-1) for some integer t
+ */
+ public BigIntPolynomial rho;
+ /**
+ * Resultant of a polynomial with x^n-1
+ */
+ public BigInteger res;
+
+ Resultant(BigIntPolynomial rho, BigInteger res)
+ {
+ this.rho = rho;
+ this.res = res;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ntru/polynomial/SparseTernaryPolynomial.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ntru/polynomial/SparseTernaryPolynomial.java
new file mode 100644
index 0000000..5b87b89
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ntru/polynomial/SparseTernaryPolynomial.java
@@ -0,0 +1,320 @@
+package org.bc.math.ntru.polynomial;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
+import org.bc.math.ntru.util.ArrayEncoder;
+import org.bc.math.ntru.util.Util;
+import org.bc.util.Arrays;
+
+/**
+ * A TernaryPolynomial
with a "low" number of nonzero coefficients.
+ */
+public class SparseTernaryPolynomial
+ implements TernaryPolynomial
+{
+ /**
+ * Number of bits to use for each coefficient. Determines the upper bound for N
.
+ */
+ private static final int BITS_PER_INDEX = 11;
+
+ private int N;
+ private int[] ones;
+ private int[] negOnes;
+
+ /**
+ * Constructs a new polynomial.
+ *
+ * @param N total number of coefficients including zeros
+ * @param ones indices of coefficients equal to 1
+ * @param negOnes indices of coefficients equal to -1
+ */
+ SparseTernaryPolynomial(int N, int[] ones, int[] negOnes)
+ {
+ this.N = N;
+ this.ones = ones;
+ this.negOnes = negOnes;
+ }
+
+ /**
+ * Constructs a DenseTernaryPolynomial
from a IntegerPolynomial
. The two polynomials are
+ * independent of each other.
+ *
+ * @param intPoly the original polynomial
+ */
+ public SparseTernaryPolynomial(IntegerPolynomial intPoly)
+ {
+ this(intPoly.coeffs);
+ }
+
+ /**
+ * Constructs a new SparseTernaryPolynomial
with a given set of coefficients.
+ *
+ * @param coeffs the coefficients
+ */
+ public SparseTernaryPolynomial(int[] coeffs)
+ {
+ N = coeffs.length;
+ ones = new int[N];
+ negOnes = new int[N];
+ int onesIdx = 0;
+ int negOnesIdx = 0;
+ for (int i = 0; i < N; i++)
+ {
+ int c = coeffs[i];
+ switch (c)
+ {
+ case 1:
+ ones[onesIdx++] = i;
+ break;
+ case -1:
+ negOnes[negOnesIdx++] = i;
+ break;
+ case 0:
+ break;
+ default:
+ throw new IllegalArgumentException("Illegal value: " + c + ", must be one of {-1, 0, 1}");
+ }
+ }
+ ones = Arrays.copyOf(ones, onesIdx);
+ negOnes = Arrays.copyOf(negOnes, negOnesIdx);
+ }
+
+ /**
+ * Decodes a byte array encoded with {@link #toBinary()} to a ploynomial.
+ *
+ * @param is an input stream containing an encoded polynomial
+ * @param N number of coefficients including zeros
+ * @param numOnes number of coefficients equal to 1
+ * @param numNegOnes number of coefficients equal to -1
+ * @return the decoded polynomial
+ * @throws IOException
+ */
+ public static SparseTernaryPolynomial fromBinary(InputStream is, int N, int numOnes, int numNegOnes)
+ throws IOException
+ {
+ int maxIndex = 1 << BITS_PER_INDEX;
+ int bitsPerIndex = 32 - Integer.numberOfLeadingZeros(maxIndex - 1);
+
+ int data1Len = (numOnes * bitsPerIndex + 7) / 8;
+ byte[] data1 = Util.readFullLength(is, data1Len);
+ int[] ones = ArrayEncoder.decodeModQ(data1, numOnes, maxIndex);
+
+ int data2Len = (numNegOnes * bitsPerIndex + 7) / 8;
+ byte[] data2 = Util.readFullLength(is, data2Len);
+ int[] negOnes = ArrayEncoder.decodeModQ(data2, numNegOnes, maxIndex);
+
+ return new SparseTernaryPolynomial(N, ones, negOnes);
+ }
+
+ /**
+ * Generates a random polynomial with numOnes
coefficients equal to 1,
+ * numNegOnes
coefficients equal to -1, and the rest equal to 0.
+ *
+ * @param N number of coefficients
+ * @param numOnes number of 1's
+ * @param numNegOnes number of -1's
+ */
+ public static SparseTernaryPolynomial generateRandom(int N, int numOnes, int numNegOnes, SecureRandom random)
+ {
+ int[] coeffs = Util.generateRandomTernary(N, numOnes, numNegOnes, random);
+ return new SparseTernaryPolynomial(coeffs);
+ }
+
+ public IntegerPolynomial mult(IntegerPolynomial poly2)
+ {
+ int[] b = poly2.coeffs;
+ if (b.length != N)
+ {
+ throw new IllegalArgumentException("Number of coefficients must be the same");
+ }
+
+ int[] c = new int[N];
+ for (int idx = 0; idx != ones.length; idx++)
+ {
+ int i = ones[idx];
+ int j = N - 1 - i;
+ for (int k = N - 1; k >= 0; k--)
+ {
+ c[k] += b[j];
+ j--;
+ if (j < 0)
+ {
+ j = N - 1;
+ }
+ }
+ }
+
+ for (int idx = 0; idx != negOnes.length; idx++)
+ {
+ int i = negOnes[idx];
+ int j = N - 1 - i;
+ for (int k = N - 1; k >= 0; k--)
+ {
+ c[k] -= b[j];
+ j--;
+ if (j < 0)
+ {
+ j = N - 1;
+ }
+ }
+ }
+
+ return new IntegerPolynomial(c);
+ }
+
+ public IntegerPolynomial mult(IntegerPolynomial poly2, int modulus)
+ {
+ IntegerPolynomial c = mult(poly2);
+ c.mod(modulus);
+ return c;
+ }
+
+ public BigIntPolynomial mult(BigIntPolynomial poly2)
+ {
+ BigInteger[] b = poly2.coeffs;
+ if (b.length != N)
+ {
+ throw new IllegalArgumentException("Number of coefficients must be the same");
+ }
+
+ BigInteger[] c = new BigInteger[N];
+ for (int i = 0; i < N; i++)
+ {
+ c[i] = BigInteger.ZERO;
+ }
+
+ for (int idx = 0; idx != ones.length; idx++)
+ {
+ int i = ones[idx];
+ int j = N - 1 - i;
+ for (int k = N - 1; k >= 0; k--)
+ {
+ c[k] = c[k].add(b[j]);
+ j--;
+ if (j < 0)
+ {
+ j = N - 1;
+ }
+ }
+ }
+
+ for (int idx = 0; idx != negOnes.length; idx++)
+ {
+ int i = negOnes[idx];
+ int j = N - 1 - i;
+ for (int k = N - 1; k >= 0; k--)
+ {
+ c[k] = c[k].subtract(b[j]);
+ j--;
+ if (j < 0)
+ {
+ j = N - 1;
+ }
+ }
+ }
+
+ return new BigIntPolynomial(c);
+ }
+
+ public int[] getOnes()
+ {
+ return ones;
+ }
+
+ public int[] getNegOnes()
+ {
+ return negOnes;
+ }
+
+ /**
+ * Encodes the polynomial to a byte array writing BITS_PER_INDEX
bits for each coefficient.
+ *
+ * @return the encoded polynomial
+ */
+ public byte[] toBinary()
+ {
+ int maxIndex = 1 << BITS_PER_INDEX;
+ byte[] bin1 = ArrayEncoder.encodeModQ(ones, maxIndex);
+ byte[] bin2 = ArrayEncoder.encodeModQ(negOnes, maxIndex);
+
+ byte[] bin = Arrays.copyOf(bin1, bin1.length + bin2.length);
+ System.arraycopy(bin2, 0, bin, bin1.length, bin2.length);
+ return bin;
+ }
+
+ public IntegerPolynomial toIntegerPolynomial()
+ {
+ int[] coeffs = new int[N];
+ for (int idx = 0; idx != ones.length; idx++)
+ {
+ int i = ones[idx];
+ coeffs[i] = 1;
+ }
+ for (int idx = 0; idx != negOnes.length; idx++)
+ {
+ int i = negOnes[idx];
+ coeffs[i] = -1;
+ }
+ return new IntegerPolynomial(coeffs);
+ }
+
+ public int size()
+ {
+ return N;
+ }
+
+ public void clear()
+ {
+ for (int i = 0; i < ones.length; i++)
+ {
+ ones[i] = 0;
+ }
+ for (int i = 0; i < negOnes.length; i++)
+ {
+ negOnes[i] = 0;
+ }
+ }
+
+ public int hashCode()
+ {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + N;
+ result = prime * result + Arrays.hashCode(negOnes);
+ result = prime * result + Arrays.hashCode(ones);
+ return result;
+ }
+
+ public boolean equals(Object obj)
+ {
+ if (this == obj)
+ {
+ return true;
+ }
+ if (obj == null)
+ {
+ return false;
+ }
+ if (getClass() != obj.getClass())
+ {
+ return false;
+ }
+ SparseTernaryPolynomial other = (SparseTernaryPolynomial)obj;
+ if (N != other.N)
+ {
+ return false;
+ }
+ if (!Arrays.areEqual(negOnes, other.negOnes))
+ {
+ return false;
+ }
+ if (!Arrays.areEqual(ones, other.ones))
+ {
+ return false;
+ }
+ return true;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ntru/polynomial/TernaryPolynomial.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ntru/polynomial/TernaryPolynomial.java
new file mode 100644
index 0000000..19243ed
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ntru/polynomial/TernaryPolynomial.java
@@ -0,0 +1,25 @@
+package org.bc.math.ntru.polynomial;
+
+/**
+ * A polynomial whose coefficients are all equal to -1, 0, or 1
+ */
+public interface TernaryPolynomial
+ extends Polynomial
+{
+
+ /**
+ * Multiplies the polynomial by an IntegerPolynomial
, taking the indices mod N
+ */
+ IntegerPolynomial mult(IntegerPolynomial poly2);
+
+ int[] getOnes();
+
+ int[] getNegOnes();
+
+ /**
+ * Returns the maximum number of coefficients the polynomial can have
+ */
+ int size();
+
+ void clear();
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ntru/util/ArrayEncoder.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ntru/util/ArrayEncoder.java
new file mode 100644
index 0000000..2436962
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ntru/util/ArrayEncoder.java
@@ -0,0 +1,292 @@
+package org.bc.math.ntru.util;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.math.BigInteger;
+
+import org.bc.util.Arrays;
+
+/**
+ * Converts a coefficient array to a compact byte array and vice versa.
+ */
+public class ArrayEncoder
+{
+ /**
+ * Bit string to coefficient conversion table from P1363.1. Also found at
+ * {@link http://stackoverflow.com/questions/1562548/how-to-make-a-message-into-a-polynomial}
+ *
+ * Convert each three-bit quantity to two ternary coefficients as follows, and concatenate the resulting
+ * ternary quantities to obtain [the output].
+ *
+ *
+ * {0, 0, 0} -> {0, 0}
+ */
+ private static final int[] COEFF1_TABLE = {0, 0, 0, 1, 1, 1, -1, -1};
+ private static final int[] COEFF2_TABLE = {0, 1, -1, 0, 1, -1, 0, 1};
+ /**
+ * Coefficient to bit string conversion table from P1363.1. Also found at
+ * {@link http://stackoverflow.com/questions/1562548/how-to-make-a-message-into-a-polynomial}
+ *
+ * Convert each set of two ternary coefficients to three bits as follows, and concatenate the resulting bit
+ * quantities to obtain [the output]:
+ *
+ *
+ * {0, 0, 1} -> {0, 1}
+ * {0, 1, 0} -> {0, -1}
+ * {0, 1, 1} -> {1, 0}
+ * {1, 0, 0} -> {1, 1}
+ * {1, 0, 1} -> {1, -1}
+ * {1, 1, 0} -> {-1, 0}
+ * {1, 1, 1} -> {-1, 1}
+ *
+ * {-1, -1} -> set "fail" to 1 and set bit string to {1, 1, 1}
+ * {-1, 0} -> {1, 1, 0}
+ */
+ private static final int[] BIT1_TABLE = {1, 1, 1, 0, 0, 0, 1, 0, 1};
+ private static final int[] BIT2_TABLE = {1, 1, 1, 1, 0, 0, 0, 1, 0};
+ private static final int[] BIT3_TABLE = {1, 0, 1, 0, 0, 1, 1, 1, 0};
+
+ /**
+ * Encodes an int array whose elements are between 0 and
+ * {-1, 1} -> {1, 1, 1}
+ * {0, -1} -> {0, 1, 0}
+ * {0, 0} -> {0, 0, 0}
+ * {0, 1} -> {0, 0, 1}
+ * {1, -1} -> {1, 0, 1}
+ * {1, 0} -> {0, 1, 1}
+ * {1, 1} -> {1, 0, 0}
+ * q
,
+ * to a byte array leaving no gaps between bits.
+ * q
must be a power of 2.
+ *
+ * @param a the input array
+ * @param q the modulus
+ * @return the encoded array
+ */
+ public static byte[] encodeModQ(int[] a, int q)
+ {
+ int bitsPerCoeff = 31 - Integer.numberOfLeadingZeros(q);
+ int numBits = a.length * bitsPerCoeff;
+ int numBytes = (numBits + 7) / 8;
+ byte[] data = new byte[numBytes];
+ int bitIndex = 0;
+ int byteIndex = 0;
+ for (int i = 0; i < a.length; i++)
+ {
+ for (int j = 0; j < bitsPerCoeff; j++)
+ {
+ int currentBit = (a[i] >> j) & 1;
+ data[byteIndex] |= currentBit << bitIndex;
+ if (bitIndex == 7)
+ {
+ bitIndex = 0;
+ byteIndex++;
+ }
+ else
+ {
+ bitIndex++;
+ }
+ }
+ }
+ return data;
+ }
+
+ /**
+ * Decodes a byte
array encoded with {@link #encodeModQ(int[], int)} back to an int
array.
+ * N
is the number of coefficients. q
must be a power of 2
.
+ * Ignores any excess bytes.
+ *
+ * @param data an encoded ternary polynomial
+ * @param N number of coefficients
+ * @param q
+ * @return an array containing N
coefficients between 0
and q-1
+ */
+ public static int[] decodeModQ(byte[] data, int N, int q)
+ {
+ int[] coeffs = new int[N];
+ int bitsPerCoeff = 31 - Integer.numberOfLeadingZeros(q);
+ int numBits = N * bitsPerCoeff;
+ int coeffIndex = 0;
+ for (int bitIndex = 0; bitIndex < numBits; bitIndex++)
+ {
+ if (bitIndex > 0 && bitIndex % bitsPerCoeff == 0)
+ {
+ coeffIndex++;
+ }
+ int bit = getBit(data, bitIndex);
+ coeffs[coeffIndex] += bit << (bitIndex % bitsPerCoeff);
+ }
+ return coeffs;
+ }
+
+ /**
+ * Decodes data encoded with {@link #encodeModQ(int[], int)} back to an int
array.
+ * N
is the number of coefficients. q
must be a power of 2
.
+ * Ignores any excess bytes.
+ *
+ * @param is an encoded ternary polynomial
+ * @param N number of coefficients
+ * @param q
+ * @return the decoded polynomial
+ */
+ public static int[] decodeModQ(InputStream is, int N, int q)
+ throws IOException
+ {
+ int qBits = 31 - Integer.numberOfLeadingZeros(q);
+ int size = (N * qBits + 7) / 8;
+ byte[] arr = Util.readFullLength(is, size);
+ return decodeModQ(arr, N, q);
+ }
+
+ /**
+ * Decodes a byte
array encoded with {@link #encodeMod3Sves(int[])} back to an int
array
+ * with N
coefficients between -1
and 1
.
+ * Ignores any excess bytes.
+ * See P1363.1 section 9.2.2.
+ *
+ * @param data an encoded ternary polynomial
+ * @param N number of coefficients
+ * @return the decoded coefficients
+ */
+ public static int[] decodeMod3Sves(byte[] data, int N)
+ {
+ int[] coeffs = new int[N];
+ int coeffIndex = 0;
+ for (int bitIndex = 0; bitIndex < data.length * 8; )
+ {
+ int bit1 = getBit(data, bitIndex++);
+ int bit2 = getBit(data, bitIndex++);
+ int bit3 = getBit(data, bitIndex++);
+ int coeffTableIndex = bit1 * 4 + bit2 * 2 + bit3;
+ coeffs[coeffIndex++] = COEFF1_TABLE[coeffTableIndex];
+ coeffs[coeffIndex++] = COEFF2_TABLE[coeffTableIndex];
+ // ignore bytes that can't fit
+ if (coeffIndex > N - 2)
+ {
+ break;
+ }
+ }
+ return coeffs;
+ }
+
+ /**
+ * Encodes an int
array whose elements are between -1
and 1
, to a byte array.
+ * coeffs[2*i]
and coeffs[2*i+1]
must not both equal -1 for any integer i,
+ * so this method is only safe to use with arrays produced by {@link #decodeMod3Sves(byte[], int)}.
steps of distributed signature
+ * calculaion
+ *
+ * @return true if signature is generated completly, else false
+ */
+ public boolean updateSign()
+ {
+ // steps times do
+
+ for (int s = 0; s < steps; s++)
+ { // do 'step' times
+
+ if (counter < keysize)
+ { // generate the private key or perform
+ // the next hash
+ oneStep();
+ }
+ if (counter == keysize)
+ {// finish
+ return true;
+ }
+ }
+
+ return false; // leaf not finished yet
+ }
+
+ /**
+ * @return The private OTS key
+ */
+ public byte[] getSig()
+ {
+
+ return sign;
+ }
+
+ /**
+ * @return The one-time signature of the message, generated step by step
+ */
+ private void oneStep()
+ {
+ // -------- if (8 % w == 0) ----------
+ if (8 % w == 0)
+ {
+ if (test == 0)
+ {
+ // get current OTSprivateKey
+ this.privateKeyOTS = gmssRandom.nextSeed(seed);
+ // System.arraycopy(privateKeyOTS, 0, hlp, 0, mdsize);
+
+ if (ii < mdsize)
+ { // for main message part
+ test = hash[ii] & k;
+ hash[ii] = (byte)(hash[ii] >>> w);
+ }
+ else
+ { // for checksum part
+ test = checksum & k;
+ checksum >>>= w;
+ }
+ }
+ else if (test > 0)
+ { // hash the private Key 'test' times (on
+ // time each step)
+ messDigestOTS.update(privateKeyOTS, 0, privateKeyOTS.length);
+ privateKeyOTS = new byte[messDigestOTS.getDigestSize()];
+ messDigestOTS.doFinal(privateKeyOTS, 0);
+ test--;
+ }
+ if (test == 0)
+ { // if all hashes done copy result to siganture
+ // array
+ System.arraycopy(privateKeyOTS, 0, sign, counter * mdsize,
+ mdsize);
+ counter++;
+
+ if (counter % (8 / w) == 0)
+ { // raise array index for main
+ // massage part
+ ii++;
+ }
+ }
+
+ }// ----- end if (8 % w == 0) -----
+ // ---------- if ( w < 8 ) ----------------
+ else if (w < 8)
+ {
+
+ if (test == 0)
+ {
+ if (counter % 8 == 0 && ii < mdsize)
+ { // after every 8th "add
+ // to signature"-step
+ big8 = 0;
+ if (counter < ((mdsize / w) << 3))
+ {// main massage
+ // (generate w*8 Bits
+ // every time) part
+ for (int j = 0; j < w; j++)
+ {
+ big8 ^= (hash[ii] & 0xff) << (j << 3);
+ ii++;
+ }
+ }
+ else
+ { // rest of massage part (once)
+ for (int j = 0; j < mdsize % w; j++)
+ {
+ big8 ^= (hash[ii] & 0xff) << (j << 3);
+ ii++;
+ }
+ }
+ }
+ if (counter == messagesize)
+ { // checksum part (once)
+ big8 = checksum;
+ }
+
+ test = (int)(big8 & k);
+ // generate current OTSprivateKey
+ this.privateKeyOTS = gmssRandom.nextSeed(seed);
+ // System.arraycopy(privateKeyOTS, 0, hlp, 0, mdsize);
+
+ }
+ else if (test > 0)
+ { // hash the private Key 'test' times (on
+ // time each step)
+ messDigestOTS.update(privateKeyOTS, 0, privateKeyOTS.length);
+ privateKeyOTS = new byte[messDigestOTS.getDigestSize()];
+ messDigestOTS.doFinal(privateKeyOTS, 0);
+ test--;
+ }
+ if (test == 0)
+ { // if all hashes done copy result to siganture
+ // array
+ System.arraycopy(privateKeyOTS, 0, sign, counter * mdsize,
+ mdsize);
+ big8 >>>= w;
+ counter++;
+ }
+
+ }// ------- end if(w<8)--------------------------------
+ // --------- if w < 57 -----------------------------
+ else if (w < 57)
+ {
+
+ if (test8 == 0)
+ {
+ int s, f, rest;
+ big8 = 0;
+ ii = 0;
+ rest = r % 8;
+ s = r >>> 3;
+ // --- message part---
+ if (s < mdsize)
+ {
+ if (r <= ((mdsize << 3) - w))
+ { // first message part
+ r += w;
+ f = (r + 7) >>> 3;
+ }
+ else
+ { // rest of message part (once)
+ f = mdsize;
+ r += w;
+ }
+ // generate long 'big8' with minimum w next bits of the
+ // message array
+ for (int i = s; i < f; i++)
+ {
+ big8 ^= (hash[i] & 0xff) << (ii << 3);
+ ii++;
+ }
+ // delete bits on the right side, which were used already by
+ // the last loop
+ big8 >>>= rest;
+ test8 = (big8 & k);
+ }
+ // --- checksum part
+ else
+ {
+ test8 = (checksum & k);
+ checksum >>>= w;
+ }
+ // generate current OTSprivateKey
+ this.privateKeyOTS = gmssRandom.nextSeed(seed);
+ // System.arraycopy(privateKeyOTS, 0, hlp, 0, mdsize);
+
+ }
+ else if (test8 > 0)
+ { // hash the private Key 'test' times (on
+ // time each step)
+ messDigestOTS.update(privateKeyOTS, 0, privateKeyOTS.length);
+ privateKeyOTS = new byte[messDigestOTS.getDigestSize()];
+ messDigestOTS.doFinal(privateKeyOTS, 0);
+ test8--;
+ }
+ if (test8 == 0)
+ { // if all hashes done copy result to siganture
+ // array
+ System.arraycopy(privateKeyOTS, 0, sign, counter * mdsize,
+ mdsize);
+ counter++;
+ }
+
+ }
+ }
+
+ /**
+ * This method returns the least integer that is greater or equal to the
+ * logarithm to the base 2 of an integer
+ * See P1363.1 section 9.2.3.
+ *
+ * @param arr
+ * @return the encoded array
+ */
+ public static byte[] encodeMod3Sves(int[] arr)
+ {
+ int numBits = (arr.length * 3 + 1) / 2;
+ int numBytes = (numBits + 7) / 8;
+ byte[] data = new byte[numBytes];
+ int bitIndex = 0;
+ int byteIndex = 0;
+ for (int i = 0; i < arr.length / 2 * 2; )
+ { // if length is an odd number, throw away the highest coeff
+ int coeff1 = arr[i++] + 1;
+ int coeff2 = arr[i++] + 1;
+ if (coeff1 == 0 && coeff2 == 0)
+ {
+ throw new IllegalStateException("Illegal encoding!");
+ }
+ int bitTableIndex = coeff1 * 3 + coeff2;
+ int[] bits = new int[]{BIT1_TABLE[bitTableIndex], BIT2_TABLE[bitTableIndex], BIT3_TABLE[bitTableIndex]};
+ for (int j = 0; j < 3; j++)
+ {
+ data[byteIndex] |= bits[j] << bitIndex;
+ if (bitIndex == 7)
+ {
+ bitIndex = 0;
+ byteIndex++;
+ }
+ else
+ {
+ bitIndex++;
+ }
+ }
+ }
+ return data;
+ }
+
+ /**
+ * Encodes an int
array whose elements are between -1
and 1
, to a byte array.
+ *
+ * @return the encoded array
+ */
+ public static byte[] encodeMod3Tight(int[] intArray)
+ {
+ BigInteger sum = BigInteger.ZERO;
+ for (int i = intArray.length - 1; i >= 0; i--)
+ {
+ sum = sum.multiply(BigInteger.valueOf(3));
+ sum = sum.add(BigInteger.valueOf(intArray[i] + 1));
+ }
+
+ int size = (BigInteger.valueOf(3).pow(intArray.length).bitLength() + 7) / 8;
+ byte[] arr = sum.toByteArray();
+
+ if (arr.length < size)
+ {
+ // pad with leading zeros so arr.length==size
+ byte[] arr2 = new byte[size];
+ System.arraycopy(arr, 0, arr2, size - arr.length, arr.length);
+ return arr2;
+ }
+
+ if (arr.length > size)
+ // drop sign bit
+ {
+ arr = Arrays.copyOfRange(arr, 1, arr.length);
+ }
+ return arr;
+ }
+
+ /**
+ * Converts a byte array produced by {@link #encodeMod3Tight(int[])} back to an int
array.
+ *
+ * @param b a byte array
+ * @param N number of coefficients
+ * @return the decoded array
+ */
+ public static int[] decodeMod3Tight(byte[] b, int N)
+ {
+ BigInteger sum = new BigInteger(1, b);
+ int[] coeffs = new int[N];
+ for (int i = 0; i < N; i++)
+ {
+ coeffs[i] = sum.mod(BigInteger.valueOf(3)).intValue() - 1;
+ if (coeffs[i] > 1)
+ {
+ coeffs[i] -= 3;
+ }
+ sum = sum.divide(BigInteger.valueOf(3));
+ }
+ return coeffs;
+ }
+
+ /**
+ * Converts data produced by {@link #encodeMod3Tight(int[])} back to an int
array.
+ *
+ * @param is an input stream containing the data to decode
+ * @param N number of coefficients
+ * @return the decoded array
+ */
+ public static int[] decodeMod3Tight(InputStream is, int N)
+ throws IOException
+ {
+ int size = (int)Math.ceil(N * Math.log(3) / Math.log(2) / 8);
+ byte[] arr = Util.readFullLength(is, size);
+ return decodeMod3Tight(arr, N);
+ }
+
+ private static int getBit(byte[] arr, int bitIndex)
+ {
+ int byteIndex = bitIndex / 8;
+ int arrElem = arr[byteIndex] & 0xFF;
+ return (arrElem >> (bitIndex % 8)) & 1;
+ }
+}
\ No newline at end of file
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ntru/util/Util.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ntru/util/Util.java
new file mode 100644
index 0000000..a254bf4
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/math/ntru/util/Util.java
@@ -0,0 +1,158 @@
+package org.bc.math.ntru.util;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.SecureRandom;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.bc.math.ntru.euclid.IntEuclidean;
+import org.bc.math.ntru.polynomial.DenseTernaryPolynomial;
+import org.bc.math.ntru.polynomial.SparseTernaryPolynomial;
+import org.bc.math.ntru.polynomial.TernaryPolynomial;
+import org.bc.util.Integers;
+
+public class Util
+{
+ private static volatile boolean IS_64_BITNESS_KNOWN;
+ private static volatile boolean IS_64_BIT_JVM;
+
+ /**
+ * Calculates the inverse of n mod modulus
+ */
+ public static int invert(int n, int modulus)
+ {
+ n %= modulus;
+ if (n < 0)
+ {
+ n += modulus;
+ }
+ return IntEuclidean.calculate(n, modulus).x;
+ }
+
+ /**
+ * Calculates a^b mod modulus
+ */
+ public static int pow(int a, int b, int modulus)
+ {
+ int p = 1;
+ for (int i = 0; i < b; i++)
+ {
+ p = (p * a) % modulus;
+ }
+ return p;
+ }
+
+ /**
+ * Calculates a^b mod modulus
+ */
+ public static long pow(long a, int b, long modulus)
+ {
+ long p = 1;
+ for (int i = 0; i < b; i++)
+ {
+ p = (p * a) % modulus;
+ }
+ return p;
+ }
+
+ /**
+ * Generates a "sparse" or "dense" polynomial containing numOnes ints equal to 1,
+ * numNegOnes int equal to -1, and the rest equal to 0.
+ *
+ * @param N
+ * @param numOnes
+ * @param numNegOnes
+ * @param sparse whether to create a {@link SparseTernaryPolynomial} or {@link DenseTernaryPolynomial}
+ * @return a ternary polynomial
+ */
+ public static TernaryPolynomial generateRandomTernary(int N, int numOnes, int numNegOnes, boolean sparse, SecureRandom random)
+ {
+ if (sparse)
+ {
+ return SparseTernaryPolynomial.generateRandom(N, numOnes, numNegOnes, random);
+ }
+ else
+ {
+ return DenseTernaryPolynomial.generateRandom(N, numOnes, numNegOnes, random);
+ }
+ }
+
+ /**
+ * Generates an array containing numOnes ints equal to 1,
+ * numNegOnes int equal to -1, and the rest equal to 0.
+ *
+ * @param N
+ * @param numOnes
+ * @param numNegOnes
+ * @return an array of integers
+ */
+ public static int[] generateRandomTernary(int N, int numOnes, int numNegOnes, SecureRandom random)
+ {
+ Integer one = Integers.valueOf(1);
+ Integer minusOne = Integers.valueOf(-1);
+ Integer zero = Integers.valueOf(0);
+
+ List list = new ArrayList();
+ for (int i = 0; i < numOnes; i++)
+ {
+ list.add(one);
+ }
+ for (int i = 0; i < numNegOnes; i++)
+ {
+ list.add(minusOne);
+ }
+ while (list.size() < N)
+ {
+ list.add(zero);
+ }
+
+ Collections.shuffle(list, random);
+
+ int[] arr = new int[N];
+ for (int i = 0; i < N; i++)
+ {
+ arr[i] = ((Integer)list.get(i)).intValue();
+ }
+ return arr;
+ }
+
+ /**
+ * Takes an educated guess as to whether 64 bits are supported by the JVM.
+ *
+ * @return true
if 64-bit support detected, false
otherwise
+ */
+ public static boolean is64BitJVM()
+ {
+ if (!IS_64_BITNESS_KNOWN)
+ {
+ String arch = System.getProperty("os.arch");
+ String sunModel = System.getProperty("sun.arch.data.model");
+ IS_64_BIT_JVM = "amd64".equals(arch) || "x86_64".equals(arch) || "ppc64".equals(arch) || "64".equals(sunModel);
+ IS_64_BITNESS_KNOWN = true;
+ }
+ return IS_64_BIT_JVM;
+ }
+
+ /**
+ * Reads a given number of bytes from an InputStream
.
+ * If there are not enough bytes in the stream, an IOException
+ * is thrown.
+ *
+ * @param is
+ * @param length
+ * @return an array of length length
+ * @throws IOException
+ */
+ public static byte[] readFullLength(InputStream is, int length)
+ throws IOException
+ {
+ byte[] arr = new byte[length];
+ if (is.read(arr) != arr.length)
+ {
+ throw new IOException("Not enough bytes to read.");
+ }
+ return arr;
+ }
+}
\ No newline at end of file
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/asn1/GMSSPrivateKey.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/asn1/GMSSPrivateKey.java
new file mode 100644
index 0000000..5b420bd
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/asn1/GMSSPrivateKey.java
@@ -0,0 +1,1314 @@
+package org.bc.pqc.asn1;
+
+import java.math.BigInteger;
+import java.util.Vector;
+
+import org.bc.asn1.ASN1Encodable;
+import org.bc.asn1.ASN1EncodableVector;
+import org.bc.asn1.ASN1Integer;
+import org.bc.asn1.ASN1Object;
+import org.bc.asn1.ASN1Primitive;
+import org.bc.asn1.ASN1Sequence;
+import org.bc.asn1.DERIA5String;
+import org.bc.asn1.DEROctetString;
+import org.bc.asn1.DERSequence;
+import org.bc.asn1.x509.AlgorithmIdentifier;
+import org.bc.crypto.Digest;
+import org.bc.pqc.crypto.gmss.GMSSLeaf;
+import org.bc.pqc.crypto.gmss.GMSSParameters;
+import org.bc.pqc.crypto.gmss.GMSSRootCalc;
+import org.bc.pqc.crypto.gmss.GMSSRootSig;
+import org.bc.pqc.crypto.gmss.Treehash;
+
+public class GMSSPrivateKey
+ extends ASN1Object
+{
+ private ASN1Primitive primitive;
+
+ private GMSSPrivateKey(ASN1Sequence mtsPrivateKey)
+ {
+ // --- Decode
+ * GMSSPublicKey ::= SEQUENCE{
+ * version INTEGER
+ * publicKey OCTET STRING
+ * }
+ *
+ */
+public class GMSSPublicKey
+ extends ASN1Object
+{
+ private ASN1Integer version;
+ private byte[] publicKey;
+
+ private GMSSPublicKey(ASN1Sequence seq)
+ {
+ if (seq.size() != 2)
+ {
+ throw new IllegalArgumentException("size of seq = " + seq.size());
+ }
+
+ this.version = ASN1Integer.getInstance(seq.getObjectAt(0));
+ this.publicKey = ASN1OctetString.getInstance(seq.getObjectAt(1)).getOctets();
+ }
+
+ public GMSSPublicKey(byte[] publicKeyBytes)
+ {
+ this.version = new ASN1Integer(0);
+ this.publicKey = publicKeyBytes;
+ }
+
+ public static GMSSPublicKey getInstance(Object o)
+ {
+ if (o instanceof GMSSPublicKey)
+ {
+ return (GMSSPublicKey)o;
+ }
+ else if (o != null)
+ {
+ return new GMSSPublicKey(ASN1Sequence.getInstance(o));
+ }
+
+ return null;
+ }
+
+ public byte[] getPublicKey()
+ {
+ return Arrays.clone(publicKey);
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(version);
+ v.add(new DEROctetString(publicKey));
+
+ return new DERSequence(v);
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/asn1/McElieceCCA2PrivateKey.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/asn1/McElieceCCA2PrivateKey.java
new file mode 100644
index 0000000..83e1dda
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/asn1/McElieceCCA2PrivateKey.java
@@ -0,0 +1,173 @@
+package org.bc.pqc.asn1;
+
+import java.math.BigInteger;
+
+import org.bc.asn1.ASN1EncodableVector;
+import org.bc.asn1.ASN1Integer;
+import org.bc.asn1.ASN1Object;
+import org.bc.asn1.ASN1ObjectIdentifier;
+import org.bc.asn1.ASN1OctetString;
+import org.bc.asn1.ASN1Primitive;
+import org.bc.asn1.ASN1Sequence;
+import org.bc.asn1.DEROctetString;
+import org.bc.asn1.DERSequence;
+import org.bc.pqc.math.linearalgebra.GF2Matrix;
+import org.bc.pqc.math.linearalgebra.GF2mField;
+import org.bc.pqc.math.linearalgebra.Permutation;
+import org.bc.pqc.math.linearalgebra.PolynomialGF2mSmallM;
+
+
+public class McElieceCCA2PrivateKey
+ extends ASN1Object
+{
+ private ASN1ObjectIdentifier oid;
+ private int n;
+ private int k;
+ private byte[] encField;
+ private byte[] encGp;
+ private byte[] encP;
+ private byte[] encH;
+ private byte[][] encqInv;
+
+
+ public McElieceCCA2PrivateKey(ASN1ObjectIdentifier oid, int n, int k, GF2mField field, PolynomialGF2mSmallM goppaPoly, Permutation p, GF2Matrix h, PolynomialGF2mSmallM[] qInv)
+ {
+ this.oid = oid;
+ this.n = n;
+ this.k = k;
+ this.encField = field.getEncoded();
+ this.encGp = goppaPoly.getEncoded();
+ this.encP = p.getEncoded();
+ this.encH = h.getEncoded();
+ this.encqInv = new byte[qInv.length][];
+
+ for (int i = 0; i != qInv.length; i++)
+ {
+ encqInv[i] = qInv[i].getEncoded();
+ }
+ }
+
+ private McElieceCCA2PrivateKey(ASN1Sequence seq)
+ {
+ oid = ((ASN1ObjectIdentifier)seq.getObjectAt(0));
+
+ BigInteger bigN = ((ASN1Integer)seq.getObjectAt(1)).getValue();
+ n = bigN.intValue();
+
+ BigInteger bigK = ((ASN1Integer)seq.getObjectAt(2)).getValue();
+ k = bigK.intValue();
+
+ encField = ((ASN1OctetString)seq.getObjectAt(3)).getOctets();
+
+ encGp = ((ASN1OctetString)seq.getObjectAt(4)).getOctets();
+
+ encP = ((ASN1OctetString)seq.getObjectAt(5)).getOctets();
+
+ encH = ((ASN1OctetString)seq.getObjectAt(6)).getOctets();
+
+ ASN1Sequence asnQInv = (ASN1Sequence)seq.getObjectAt(7);
+ encqInv = new byte[asnQInv.size()][];
+ for (int i = 0; i < asnQInv.size(); i++)
+ {
+ encqInv[i] = ((ASN1OctetString)asnQInv.getObjectAt(i)).getOctets();
+ }
+ }
+
+ public ASN1ObjectIdentifier getOID()
+ {
+ return oid;
+ }
+
+ public int getN()
+ {
+ return n;
+ }
+
+ public int getK()
+ {
+ return k;
+ }
+
+ public GF2mField getField()
+ {
+ return new GF2mField(encField);
+ }
+
+ public PolynomialGF2mSmallM getGoppaPoly()
+ {
+ return new PolynomialGF2mSmallM(this.getField(), encGp);
+ }
+
+ public Permutation getP()
+ {
+ return new Permutation(encP);
+ }
+
+ public GF2Matrix getH()
+ {
+ return new GF2Matrix(encH);
+ }
+
+ public PolynomialGF2mSmallM[] getQInv()
+ {
+ PolynomialGF2mSmallM[] qInv = new PolynomialGF2mSmallM[encqInv.length];
+ GF2mField field = this.getField();
+
+ for (int i = 0; i < encqInv.length; i++)
+ {
+ qInv[i] = new PolynomialGF2mSmallM(field, encqInv[i]);
+ }
+
+ return qInv;
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+
+ ASN1EncodableVector v = new ASN1EncodableVector();
+ // encode
+ ASN1EncodableVector asnQInv = new ASN1EncodableVector();
+ for (int i = 0; i < encqInv.length; i++)
+ {
+ asnQInv.add(new DEROctetString(encqInv[i]));
+ }
+
+ v.add(new DERSequence(asnQInv));
+
+ return new DERSequence(v);
+ }
+
+ public static McElieceCCA2PrivateKey getInstance(Object o)
+ {
+ if (o instanceof McElieceCCA2PrivateKey)
+ {
+ return (McElieceCCA2PrivateKey)o;
+ }
+ else if (o != null)
+ {
+ return new McElieceCCA2PrivateKey(ASN1Sequence.getInstance(o));
+ }
+
+ return null;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/asn1/McElieceCCA2PublicKey.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/asn1/McElieceCCA2PublicKey.java
new file mode 100644
index 0000000..982d7a0
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/asn1/McElieceCCA2PublicKey.java
@@ -0,0 +1,96 @@
+package org.bc.pqc.asn1;
+
+import java.math.BigInteger;
+
+import org.bc.asn1.ASN1EncodableVector;
+import org.bc.asn1.ASN1Integer;
+import org.bc.asn1.ASN1Object;
+import org.bc.asn1.ASN1ObjectIdentifier;
+import org.bc.asn1.ASN1OctetString;
+import org.bc.asn1.ASN1Primitive;
+import org.bc.asn1.ASN1Sequence;
+import org.bc.asn1.DEROctetString;
+import org.bc.asn1.DERSequence;
+import org.bc.pqc.math.linearalgebra.GF2Matrix;
+
+public class McElieceCCA2PublicKey
+ extends ASN1Object
+{
+ private ASN1ObjectIdentifier oid;
+ private int n;
+ private int t;
+
+ private byte[] matrixG;
+
+ public McElieceCCA2PublicKey(ASN1ObjectIdentifier oid, int n, int t, GF2Matrix g)
+ {
+ this.oid = oid;
+ this.n = n;
+ this.t = t;
+ this.matrixG = g.getEncoded();
+ }
+
+ private McElieceCCA2PublicKey(ASN1Sequence seq)
+ {
+ oid = ((ASN1ObjectIdentifier)seq.getObjectAt(0));
+ BigInteger bigN = ((ASN1Integer)seq.getObjectAt(1)).getValue();
+ n = bigN.intValue();
+
+ BigInteger bigT = ((ASN1Integer)seq.getObjectAt(2)).getValue();
+ t = bigT.intValue();
+
+ matrixG = ((ASN1OctetString)seq.getObjectAt(3)).getOctets();
+ }
+
+ public ASN1ObjectIdentifier getOID()
+ {
+ return oid;
+ }
+
+ public int getN()
+ {
+ return n;
+ }
+
+ public int getT()
+ {
+ return t;
+ }
+
+ public GF2Matrix getG()
+ {
+ return new GF2Matrix(matrixG);
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+ // encode
+ ASN1EncodableVector asnQInv = new ASN1EncodableVector();
+ for (int i = 0; i < encqInv.length; i++)
+ {
+ asnQInv.add(new DEROctetString(encqInv[i]));
+ }
+
+ v.add(new DERSequence(asnQInv));
+
+ return new DERSequence(v);
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/asn1/McEliecePublicKey.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/asn1/McEliecePublicKey.java
new file mode 100644
index 0000000..b9cdfdd
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/asn1/McEliecePublicKey.java
@@ -0,0 +1,97 @@
+package org.bc.pqc.asn1;
+
+import java.math.BigInteger;
+
+import org.bc.asn1.ASN1EncodableVector;
+import org.bc.asn1.ASN1Integer;
+import org.bc.asn1.ASN1Object;
+import org.bc.asn1.ASN1ObjectIdentifier;
+import org.bc.asn1.ASN1OctetString;
+import org.bc.asn1.ASN1Primitive;
+import org.bc.asn1.ASN1Sequence;
+import org.bc.asn1.DEROctetString;
+import org.bc.asn1.DERSequence;
+import org.bc.pqc.math.linearalgebra.GF2Matrix;
+
+public class McEliecePublicKey
+ extends ASN1Object
+{
+
+ private ASN1ObjectIdentifier oid;
+ private int n;
+ private int t;
+
+ private byte[] matrixG;
+
+ public McEliecePublicKey(ASN1ObjectIdentifier oid, int n, int t, GF2Matrix g)
+ {
+ this.oid = oid;
+ this.n = n;
+ this.t = t;
+ this.matrixG = g.getEncoded();
+ }
+
+ private McEliecePublicKey(ASN1Sequence seq)
+ {
+ oid = ((ASN1ObjectIdentifier)seq.getObjectAt(0));
+ BigInteger bigN = ((ASN1Integer)seq.getObjectAt(1)).getValue();
+ n = bigN.intValue();
+
+ BigInteger bigT = ((ASN1Integer)seq.getObjectAt(2)).getValue();
+ t = bigT.intValue();
+
+ matrixG = ((ASN1OctetString)seq.getObjectAt(3)).getOctets();
+ }
+
+ public ASN1ObjectIdentifier getOID()
+ {
+ return oid;
+ }
+
+ public int getN()
+ {
+ return n;
+ }
+
+ public int getT()
+ {
+ return t;
+ }
+
+ public GF2Matrix getG()
+ {
+ return new GF2Matrix(matrixG);
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+ // encode
+ * ParSet ::= SEQUENCE {
+ * T INTEGER
+ * h SEQUENCE OF INTEGER
+ * w SEQUENCE OF INTEGER
+ * K SEQUENCE OF INTEGER
+ * }
+ *
+ */
+public class ParSet
+ extends ASN1Object
+{
+ private static final BigInteger ZERO = BigInteger.valueOf(0);
+
+ private int t;
+ private int[] h;
+ private int[] w;
+ private int[] k;
+
+ private static int checkBigIntegerInIntRangeAndPositive(BigInteger b)
+ {
+ if ((b.compareTo(BigInteger.valueOf(Integer.MAX_VALUE)) > 0) ||
+ (b.compareTo(ZERO) <= 0))
+ {
+ throw new IllegalArgumentException("BigInteger not in Range: " + b.toString());
+ }
+ return b.intValue();
+ }
+
+ private ParSet(ASN1Sequence seq)
+ {
+ if (seq.size() != 4)
+ {
+ throw new IllegalArgumentException("sie of seqOfParams = " + seq.size());
+ }
+ BigInteger asn1int = ((ASN1Integer)seq.getObjectAt(0)).getValue();
+
+ t = checkBigIntegerInIntRangeAndPositive(asn1int);
+
+ ASN1Sequence seqOfPSh = (ASN1Sequence)seq.getObjectAt(1);
+ ASN1Sequence seqOfPSw = (ASN1Sequence)seq.getObjectAt(2);
+ ASN1Sequence seqOfPSK = (ASN1Sequence)seq.getObjectAt(3);
+
+ if ((seqOfPSh.size() != t) ||
+ (seqOfPSw.size() != t) ||
+ (seqOfPSK.size() != t))
+ {
+ throw new IllegalArgumentException("invalid size of sequences");
+ }
+
+ h = new int[seqOfPSh.size()];
+ w = new int[seqOfPSw.size()];
+ k = new int[seqOfPSK.size()];
+
+ for (int i = 0; i < t; i++)
+ {
+ h[i] = checkBigIntegerInIntRangeAndPositive((((ASN1Integer)seqOfPSh.getObjectAt(i))).getValue());
+ w[i] = checkBigIntegerInIntRangeAndPositive((((ASN1Integer)seqOfPSw.getObjectAt(i))).getValue());
+ k[i] = checkBigIntegerInIntRangeAndPositive((((ASN1Integer)seqOfPSK.getObjectAt(i))).getValue());
+ }
+ }
+
+ public ParSet(int t, int[] h, int[] w, int[] k)
+ {
+ this.t = t;
+ this.h = h;
+ this.w = w;
+ this.k = k;
+ }
+
+ public static ParSet getInstance(Object o)
+ {
+ if (o instanceof ParSet)
+ {
+ return (ParSet)o;
+ }
+ else if (o != null)
+ {
+ return new ParSet(ASN1Sequence.getInstance(o));
+ }
+
+ return null;
+ }
+
+ public int getT()
+ {
+ return t;
+ }
+
+ public int[] getH()
+ {
+ return Arrays.clone(h);
+ }
+
+ public int[] getW()
+ {
+ return Arrays.clone(w);
+ }
+
+ public int[] getK()
+ {
+ return Arrays.clone(k);
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector seqOfPSh = new ASN1EncodableVector();
+ ASN1EncodableVector seqOfPSw = new ASN1EncodableVector();
+ ASN1EncodableVector seqOfPSK = new ASN1EncodableVector();
+
+ for (int i = 0; i < h.length; i++)
+ {
+ seqOfPSh.add(new ASN1Integer(h[i]));
+ seqOfPSw.add(new ASN1Integer(w[i]));
+ seqOfPSK.add(new ASN1Integer(k[i]));
+ }
+
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(new ASN1Integer(t));
+ v.add(new DERSequence(seqOfPSh));
+ v.add(new DERSequence(seqOfPSw));
+ v.add(new DERSequence(seqOfPSK));
+
+ return new DERSequence(v);
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/asn1/RainbowPrivateKey.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/asn1/RainbowPrivateKey.java
new file mode 100644
index 0000000..5dd1958
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/asn1/RainbowPrivateKey.java
@@ -0,0 +1,350 @@
+package org.bc.pqc.asn1;
+
+import org.bc.asn1.ASN1EncodableVector;
+import org.bc.asn1.ASN1Integer;
+import org.bc.asn1.ASN1Object;
+import org.bc.asn1.ASN1ObjectIdentifier;
+import org.bc.asn1.ASN1OctetString;
+import org.bc.asn1.ASN1Primitive;
+import org.bc.asn1.ASN1Sequence;
+import org.bc.asn1.DEROctetString;
+import org.bc.asn1.DERSequence;
+import org.bc.pqc.crypto.rainbow.Layer;
+import org.bc.pqc.crypto.rainbow.util.RainbowUtil;
+
+/**
+ * Return the key data to encode in the PrivateKeyInfo structure.
+ *
+ * The ASN.1 definition of the key structure is
+ *
+ *
+ * RainbowPrivateKey ::= SEQUENCE {
+ * CHOICE
+ * {
+ * oid OBJECT IDENTIFIER -- OID identifying the algorithm
+ * version INTEGER -- 0
+ * }
+ * A1inv SEQUENCE OF OCTET STRING -- inversed matrix of L1
+ * b1 OCTET STRING -- translation vector of L1
+ * A2inv SEQUENCE OF OCTET STRING -- inversed matrix of L2
+ * b2 OCTET STRING -- translation vector of L2
+ * vi OCTET STRING -- num of elmts in each Set S
+ * layers SEQUENCE OF Layer -- layers of F
+ * }
+ *
+ * Layer ::= SEQUENCE OF Poly
+ *
+ * Poly ::= SEQUENCE {
+ * alpha SEQUENCE OF OCTET STRING
+ * beta SEQUENCE OF OCTET STRING
+ * gamma OCTET STRING
+ * eta INTEGER
+ * }
+ *
+ */
+public class RainbowPrivateKey
+ extends ASN1Object
+{
+ private ASN1Integer version;
+ private ASN1ObjectIdentifier oid;
+
+ private byte[][] invA1;
+ private byte[] b1;
+ private byte[][] invA2;
+ private byte[] b2;
+ private byte[] vi;
+ private Layer[] layers;
+
+ private RainbowPrivateKey(ASN1Sequence seq)
+ {
+ //
+ * RainbowPublicKey ::= SEQUENCE {
+ * CHOICE
+ * {
+ * oid OBJECT IDENTIFIER -- OID identifying the algorithm
+ * version INTEGER -- 0
+ * }
+ * docLength Integer -- length of the code
+ * coeffquadratic SEQUENCE OF OCTET STRING -- quadratic (mixed) coefficients
+ * coeffsingular SEQUENCE OF OCTET STRING -- singular coefficients
+ * coeffscalar SEQUENCE OF OCTET STRING -- scalar coefficients
+ * }
+ *
+ */
+public class RainbowPublicKey
+ extends ASN1Object
+{
+ private ASN1Integer version;
+ private ASN1ObjectIdentifier oid;
+ private ASN1Integer docLength;
+ private byte[][] coeffQuadratic;
+ private byte[][] coeffSingular;
+ private byte[] coeffScalar;
+
+ private RainbowPublicKey(ASN1Sequence seq)
+ {
+ // keySize
as input. It provides a simple use of the GMSS for
+ * testing demands.
+ *
+ * A given keysize
of less than 10 creates an amount 2^10
+ * signatures. A keySize between 10 and 20 creates 2^20 signatures. Given an
+ * integer greater than 20 the key pair generator creates 2^40 signatures.
+ *
+ * @param keySize Assigns the parameters used for the GMSS signatures. There are
+ * 3 choices:
+ * 1. keysize <= 10: creates 2^10 signatures using the
+ * parameterset
+ * P = (2, (5, 5), (3, 3), (3, 3))
+ * 2. keysize > 10 and <= 20: creates 2^20 signatures using the
+ * parameterset
+ * P = (2, (10, 10), (5, 4), (2, 2))
+ * 3. keysize > 20: creates 2^40 signatures using the
+ * parameterset
+ * P = (2, (10, 10, 10, 10), (9, 9, 9, 3), (2, 2, 2, 2))
+ * @param secureRandom not used by GMSS, the SHA1PRNG of the SUN Provider is always
+ * used
+ */
+ public void initialize(int keySize, SecureRandom secureRandom)
+ {
+
+ KeyGenerationParameters kgp;
+ if (keySize <= 10)
+ { // create 2^10 keys
+ int[] defh = {10};
+ int[] defw = {3};
+ int[] defk = {2};
+ // XXX sec random neede?
+ kgp = new GMSSKeyGenerationParameters(secureRandom, new GMSSParameters(defh.length, defh, defw, defk));
+ }
+ else if (keySize <= 20)
+ { // create 2^20 keys
+ int[] defh = {10, 10};
+ int[] defw = {5, 4};
+ int[] defk = {2, 2};
+ kgp = new GMSSKeyGenerationParameters(secureRandom, new GMSSParameters(defh.length, defh, defw, defk));
+ }
+ else
+ { // create 2^40 keys, keygen lasts around 80 seconds
+ int[] defh = {10, 10, 10, 10};
+ int[] defw = {9, 9, 9, 3};
+ int[] defk = {2, 2, 2, 2};
+ kgp = new GMSSKeyGenerationParameters(secureRandom, new GMSSParameters(defh.length, defh, defw, defk));
+ }
+
+ // call the initializer with the chosen parameters
+ this.initialize(kgp);
+
+ }
+
+
+ /**
+ * Initalizes the key pair generator using a parameter set as input
+ */
+ public void initialize(KeyGenerationParameters param)
+ {
+
+ this.gmssParams = (GMSSKeyGenerationParameters)param;
+
+ // generate GMSSParameterset
+ this.gmssPS = new GMSSParameters(gmssParams.getParameters().getNumOfLayers(), gmssParams.getParameters().getHeightOfTrees(),
+ gmssParams.getParameters().getWinternitzParameter(), gmssParams.getParameters().getK());
+
+ this.numLayer = gmssPS.getNumOfLayers();
+ this.heightOfTrees = gmssPS.getHeightOfTrees();
+ this.otsIndex = gmssPS.getWinternitzParameter();
+ this.K = gmssPS.getK();
+
+ // seeds
+ this.currentSeeds = new byte[numLayer][mdLength];
+ this.nextNextSeeds = new byte[numLayer - 1][mdLength];
+
+ // construct SecureRandom for initial seed generation
+ SecureRandom secRan = new SecureRandom();
+
+ // generation of initial seeds
+ for (int i = 0; i < numLayer; i++)
+ {
+ secRan.nextBytes(currentSeeds[i]);
+ gmssRandom.nextSeed(currentSeeds[i]);
+ }
+
+ this.initialized = true;
+ }
+
+ /**
+ * This method is called by generateKeyPair() in case that no other
+ * initialization method has been called by the user
+ */
+ private void initializeDefault()
+ {
+ int[] defh = {10, 10, 10, 10};
+ int[] defw = {3, 3, 3, 3};
+ int[] defk = {2, 2, 2, 2};
+
+ KeyGenerationParameters kgp = new GMSSKeyGenerationParameters(new SecureRandom(), new GMSSParameters(defh.length, defh, defw, defk));
+ this.initialize(kgp);
+
+ }
+
+ public void init(KeyGenerationParameters param)
+ {
+ this.initialize(param);
+
+ }
+
+ public AsymmetricCipherKeyPair generateKeyPair()
+ {
+ return genKeyPair();
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/gmss/GMSSKeyParameters.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/gmss/GMSSKeyParameters.java
new file mode 100644
index 0000000..3af78cb
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/gmss/GMSSKeyParameters.java
@@ -0,0 +1,22 @@
+package org.bc.pqc.crypto.gmss;
+
+import org.bc.crypto.params.AsymmetricKeyParameter;
+
+public class GMSSKeyParameters
+ extends AsymmetricKeyParameter
+{
+ private GMSSParameters params;
+
+ public GMSSKeyParameters(
+ boolean isPrivate,
+ GMSSParameters params)
+ {
+ super(isPrivate);
+ this.params = params;
+ }
+
+ public GMSSParameters getParameters()
+ {
+ return params;
+ }
+}
\ No newline at end of file
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/gmss/GMSSLeaf.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/gmss/GMSSLeaf.java
new file mode 100644
index 0000000..626bac5
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/gmss/GMSSLeaf.java
@@ -0,0 +1,315 @@
+package org.bc.pqc.crypto.gmss;
+
+import org.bc.crypto.Digest;
+import org.bc.pqc.crypto.gmss.util.GMSSRandom;
+import org.bc.util.Arrays;
+import org.bc.util.encoders.Hex;
+
+
+/**
+ * This class implements the distributed computation of the public key of the
+ * Winternitz one-time signature scheme (OTSS). The class is used by the GMSS
+ * classes for calculation of upcoming leafs.
+ */
+public class GMSSLeaf
+{
+
+ /**
+ * The hash function used by the OTS and the PRNG
+ */
+ private Digest messDigestOTS;
+
+ /**
+ * The length of the message digest and private key
+ */
+ private int mdsize, keysize;
+
+ /**
+ * The source of randomness for OTS private key generation
+ */
+ private GMSSRandom gmssRandom;
+
+ /**
+ * Byte array for distributed coputation of the upcoming leaf
+ */
+ private byte[] leaf;
+
+ /**
+ * Byte array for storing the concatenated hashes of private key parts
+ */
+ private byte[] concHashs;
+
+ /**
+ * indices for distributed computation
+ */
+ private int i, j;
+
+ /**
+ * storing 2^w
+ */
+ private int two_power_w;
+
+ /**
+ * Winternitz parameter w
+ */
+ private int w;
+
+ /**
+ * the amount of distributed computation steps when updateLeaf is called
+ */
+ private int steps;
+
+ /**
+ * the internal seed
+ */
+ private byte[] seed;
+
+ /**
+ * the OTS privateKey parts
+ */
+ byte[] privateKeyOTS;
+
+ /**
+ * This constructor regenerates a prior GMSSLeaf object
+ *
+ * @param digest an array of strings, containing the name of the used hash
+ * function and PRNG and the name of the corresponding
+ * provider
+ * @param otsIndex status bytes
+ * @param numLeafs status ints
+ */
+ public GMSSLeaf(Digest digest, byte[][] otsIndex, int[] numLeafs)
+ {
+ this.i = numLeafs[0];
+ this.j = numLeafs[1];
+ this.steps = numLeafs[2];
+ this.w = numLeafs[3];
+
+ messDigestOTS = digest;
+
+ gmssRandom = new GMSSRandom(messDigestOTS);
+
+ // calulate keysize for private key and the help array
+ mdsize = messDigestOTS.getDigestSize();
+ int mdsizeBit = mdsize << 3;
+ int messagesize = (int)Math.ceil((double)(mdsizeBit) / (double)w);
+ int checksumsize = getLog((messagesize << w) + 1);
+ this.keysize = messagesize
+ + (int)Math.ceil((double)checksumsize / (double)w);
+ this.two_power_w = 1 << w;
+
+ // calculate steps
+ // ((2^w)-1)*keysize + keysize + 1 / (2^h -1)
+
+ // initialize arrays
+ this.privateKeyOTS = otsIndex[0];
+ this.seed = otsIndex[1];
+ this.concHashs = otsIndex[2];
+ this.leaf = otsIndex[3];
+ }
+
+ /**
+ * The constructor precomputes some needed variables for distributed leaf
+ * calculation
+ *
+ * @param digest an array of strings, containing the digest of the used hash
+ * function and PRNG and the digest of the corresponding
+ * provider
+ * @param w the winterniz parameter of that tree the leaf is computed
+ * for
+ * @param numLeafs the number of leafs of the tree from where the distributed
+ * computation is called
+ */
+ public GMSSLeaf(Digest digest, int w, int numLeafs)
+ {
+ this.w = w;
+
+ messDigestOTS = digest;
+
+ gmssRandom = new GMSSRandom(messDigestOTS);
+
+ // calulate keysize for private key and the help array
+ mdsize = messDigestOTS.getDigestSize();
+ int mdsizeBit = mdsize << 3;
+ int messagesize = (int)Math.ceil((double)(mdsizeBit) / (double)w);
+ int checksumsize = getLog((messagesize << w) + 1);
+ this.keysize = messagesize
+ + (int)Math.ceil((double)checksumsize / (double)w);
+ this.two_power_w = 1 << w;
+
+ // calculate steps
+ // ((2^w)-1)*keysize + keysize + 1 / (2^h -1)
+ this.steps = (int)Math
+ .ceil((double)(((1 << w) - 1) * keysize + 1 + keysize)
+ / (double)(numLeafs));
+
+ // initialize arrays
+ this.seed = new byte[mdsize];
+ this.leaf = new byte[mdsize];
+ this.privateKeyOTS = new byte[mdsize];
+ this.concHashs = new byte[mdsize * keysize];
+ }
+
+ /**
+ * initialize the distributed leaf calculation reset i,j and compute OTSseed
+ * with seed0
+ *
+ * @param seed0 the starting seed
+ */
+ public void initLeafCalc(byte[] seed0)
+ {
+ this.i = 0;
+ this.j = 0;
+ byte[] dummy = new byte[mdsize];
+ System.arraycopy(seed0, 0, dummy, 0, seed.length);
+ this.seed = gmssRandom.nextSeed(dummy);
+ }
+
+ /**
+ * Processes steps
steps of distributed leaf calculation
+ *
+ * @return true if leaf is completed, else false
+ */
+ public boolean updateLeafCalc()
+ {
+ // steps times do
+ for (int s = 0; s < steps; s++)
+ {
+
+ if (i == keysize && j == two_power_w - 1)
+ { // [3] at last hash the
+ // concatenation
+ messDigestOTS.update(concHashs, 0, concHashs.length);
+ leaf = new byte[messDigestOTS.getDigestSize()];
+ messDigestOTS.doFinal(leaf, 0);
+ return true; // leaf fineshed
+ }
+ else if (i == 0 || j == two_power_w - 1)
+ { // [1] at the
+ // beginning and
+ // when [2] is
+ // finished: get the
+ // next private key
+ // part
+ i++;
+ j = 0;
+ // get next privKey part
+ this.privateKeyOTS = gmssRandom.nextSeed(seed);
+ }
+ else
+ { // [2] hash the privKey part
+ messDigestOTS.update(privateKeyOTS, 0, privateKeyOTS.length);
+ privateKeyOTS = new byte[messDigestOTS.getDigestSize()];
+ messDigestOTS.doFinal(privateKeyOTS, 0);
+ j++;
+ if (j == two_power_w - 1)
+ { // after w hashes add to the
+ // concatenated array
+ System.arraycopy(privateKeyOTS, 0, concHashs, mdsize
+ * (i - 1), mdsize);
+ }
+ }
+ }
+
+ return false; // leaf not finished yet
+ }
+
+ /**
+ * Returns the leaf value.
+ *
+ * @return the leaf value
+ */
+ public byte[] getLeaf()
+ {
+ return Arrays.clone(leaf);
+ }
+
+ /**
+ * This method returns the least integer that is greater or equal to the
+ * logarithm to the base 2 of an integer intValue
.
+ *
+ * @param intValue an integer
+ * @return The least integer greater or equal to the logarithm to the base 2
+ * of intValue
+ */
+ private int getLog(int intValue)
+ {
+ int log = 1;
+ int i = 2;
+ while (i < intValue)
+ {
+ i <<= 1;
+ log++;
+ }
+ return log;
+ }
+
+ /**
+ * Returns the status byte array used by the GMSSPrivateKeyASN.1 class
+ *
+ * @return The status bytes
+ */
+ public byte[][] getStatByte()
+ {
+
+ byte[][] statByte = new byte[4][];
+ statByte[0] = new byte[mdsize];
+ statByte[1] = new byte[mdsize];
+ statByte[2] = new byte[mdsize * keysize];
+ statByte[3] = new byte[mdsize];
+ statByte[0] = privateKeyOTS;
+ statByte[1] = seed;
+ statByte[2] = concHashs;
+ statByte[3] = leaf;
+
+ return statByte;
+ }
+
+ /**
+ * Returns the status int array used by the GMSSPrivateKeyASN.1 class
+ *
+ * @return The status ints
+ */
+ public int[] getStatInt()
+ {
+
+ int[] statInt = new int[4];
+ statInt[0] = i;
+ statInt[1] = j;
+ statInt[2] = steps;
+ statInt[3] = w;
+ return statInt;
+ }
+
+ /**
+ * Returns a String representation of the main part of this element
+ *
+ * @return a String representation of the main part of this element
+ */
+ public String toString()
+ {
+ String out = "";
+
+ for (int i = 0; i < 4; i++)
+ {
+ out = out + this.getStatInt()[i] + " ";
+ }
+ out = out + " " + this.mdsize + " " + this.keysize + " "
+ + this.two_power_w + " ";
+
+ byte[][] temp = this.getStatByte();
+ for (int i = 0; i < 4; i++)
+ {
+ if (temp[i] != null)
+ {
+ out = out + new String(Hex.encode(temp[i])) + " ";
+ }
+ else
+ {
+ out = out + "null ";
+ }
+ }
+ return out;
+ }
+
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/gmss/GMSSParameters.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/gmss/GMSSParameters.java
new file mode 100644
index 0000000..001e275
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/gmss/GMSSParameters.java
@@ -0,0 +1,156 @@
+package org.bc.pqc.crypto.gmss;
+
+import org.bc.util.Arrays;
+
+/**
+ * This class provides a specification for the GMSS parameters that are used by
+ * the GMSSKeyPairGenerator and GMSSSignature classes.
+ *
+ * @see org.bc.pqc.crypto.gmss.GMSSKeyPairGenerator
+ */
+public class GMSSParameters
+{
+ /**
+ * The number of authentication tree layers.
+ */
+ private int numOfLayers;
+
+ /**
+ * The height of the authentication trees of each layer.
+ */
+ private int[] heightOfTrees;
+
+ /**
+ * The Winternitz Parameter 'w' of each layer.
+ */
+ private int[] winternitzParameter;
+
+ /**
+ * The parameter K needed for the authentication path computation
+ */
+ private int[] K;
+
+ /**
+ * The constructor for the parameters of the GMSSKeyPairGenerator.
+ *
+ *
+ * @param layers the number of authentication tree layers
+ * @param heightOfTrees the height of the authentication trees
+ * @param winternitzParameter the Winternitz Parameter 'w' of each layer
+ * @param K parameter for authpath computation
+ */
+ public GMSSParameters(int layers, int[] heightOfTrees, int[] winternitzParameter, int[] K)
+ throws IllegalArgumentException
+ {
+ init(layers, heightOfTrees, winternitzParameter, K);
+ }
+
+ private void init(int layers, int[] heightOfTrees,
+ int[] winternitzParameter, int[] K)
+ throws IllegalArgumentException
+ {
+ boolean valid = true;
+ String errMsg = "";
+ this.numOfLayers = layers;
+ if ((numOfLayers != winternitzParameter.length)
+ || (numOfLayers != heightOfTrees.length)
+ || (numOfLayers != K.length))
+ {
+ valid = false;
+ errMsg = "Unexpected parameterset format";
+ }
+ for (int i = 0; i < numOfLayers; i++)
+ {
+ if ((K[i] < 2) || ((heightOfTrees[i] - K[i]) % 2 != 0))
+ {
+ valid = false;
+ errMsg = "Wrong parameter K (K >= 2 and H-K even required)!";
+ }
+
+ if ((heightOfTrees[i] < 4) || (winternitzParameter[i] < 2))
+ {
+ valid = false;
+ errMsg = "Wrong parameter H or w (H > 3 and w > 1 required)!";
+ }
+ }
+
+ if (valid)
+ {
+ this.heightOfTrees = Arrays.clone(heightOfTrees);
+ this.winternitzParameter = Arrays.clone(winternitzParameter);
+ this.K = Arrays.clone(K);
+ }
+ else
+ {
+ throw new IllegalArgumentException(errMsg);
+ }
+ }
+
+ public GMSSParameters(int keySize)
+ throws IllegalArgumentException
+ {
+ if (keySize <= 10)
+ { // create 2^10 keys
+ int[] defh = {10};
+ int[] defw = {3};
+ int[] defk = {2};
+ this.init(defh.length, defh, defw, defk);
+ }
+ else if (keySize <= 20)
+ { // create 2^20 keys
+ int[] defh = {10, 10};
+ int[] defw = {5, 4};
+ int[] defk = {2, 2};
+ this.init(defh.length, defh, defw, defk);
+ }
+ else
+ { // create 2^40 keys, keygen lasts around 80 seconds
+ int[] defh = {10, 10, 10, 10};
+ int[] defw = {9, 9, 9, 3};
+ int[] defk = {2, 2, 2, 2};
+ this.init(defh.length, defh, defw, defk);
+ }
+ }
+
+ /**
+ * Returns the number of levels of the authentication trees.
+ *
+ * @return The number of levels of the authentication trees.
+ */
+ public int getNumOfLayers()
+ {
+ return numOfLayers;
+ }
+
+ /**
+ * Returns the array of height (for each layer) of the authentication trees
+ *
+ * @return The array of height (for each layer) of the authentication trees
+ */
+ public int[] getHeightOfTrees()
+ {
+ return Arrays.clone(heightOfTrees);
+ }
+
+ /**
+ * Returns the array of WinternitzParameter (for each layer) of the
+ * authentication trees
+ *
+ * @return The array of WinternitzParameter (for each layer) of the
+ * authentication trees
+ */
+ public int[] getWinternitzParameter()
+ {
+ return Arrays.clone(winternitzParameter);
+ }
+
+ /**
+ * Returns the parameter K needed for authentication path computation
+ *
+ * @return The parameter K needed for authentication path computation
+ */
+ public int[] getK()
+ {
+ return Arrays.clone(K);
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/gmss/GMSSPrivateKeyParameters.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/gmss/GMSSPrivateKeyParameters.java
new file mode 100644
index 0000000..f4a802e
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/gmss/GMSSPrivateKeyParameters.java
@@ -0,0 +1,1092 @@
+package org.bc.pqc.crypto.gmss;
+
+import java.util.Vector;
+
+import org.bc.crypto.Digest;
+import org.bc.pqc.crypto.gmss.util.GMSSRandom;
+import org.bc.pqc.crypto.gmss.util.WinternitzOTSignature;
+
+
+/**
+ * This class provides a specification for a GMSS private key.
+ */
+public class GMSSPrivateKeyParameters
+ extends GMSSKeyParameters
+{
+
+ private int[] index;
+
+ private byte[][] currentSeeds;
+ private byte[][] nextNextSeeds;
+
+ private byte[][][] currentAuthPaths;
+ private byte[][][] nextAuthPaths;
+
+ private Treehash[][] currentTreehash;
+ private Treehash[][] nextTreehash;
+
+ private Vector[] currentStack;
+ private Vector[] nextStack;
+
+ private Vector[][] currentRetain;
+ private Vector[][] nextRetain;
+
+ private byte[][][] keep;
+
+ private GMSSLeaf[] nextNextLeaf;
+ private GMSSLeaf[] upperLeaf;
+ private GMSSLeaf[] upperTreehashLeaf;
+
+ private int[] minTreehash;
+
+ private GMSSParameters gmssPS;
+
+ private byte[][] nextRoot;
+ private GMSSRootCalc[] nextNextRoot;
+
+ private byte[][] currentRootSig;
+ private GMSSRootSig[] nextRootSig;
+
+ private GMSSDigestProvider digestProvider;
+
+
+ /**
+ * An array of the heights of the authentication trees of each layer
+ */
+ private int[] heightOfTrees;
+
+ /**
+ * An array of the Winternitz parameter 'w' of each layer
+ */
+ private int[] otsIndex;
+
+ /**
+ * The parameter K needed for the authentication path computation
+ */
+ private int[] K;
+
+ /**
+ * the number of Layers
+ */
+ private int numLayer;
+
+ /**
+ * The hash function used to construct the authentication trees
+ */
+ private Digest messDigestTrees;
+
+ /**
+ * The message digest length
+ */
+ private int mdLength;
+
+ /**
+ * The PRNG used for private key generation
+ */
+ private GMSSRandom gmssRandom;
+
+
+ /**
+ * The number of leafs of one tree of each layer
+ */
+ private int[] numLeafs;
+
+
+ /**
+ * Generates a new GMSS private key
+ *
+ * @param currentSeed seed for the generation of private OTS keys for the
+ * current subtrees
+ * @param nextNextSeed seed for the generation of private OTS keys for the next
+ * subtrees
+ * @param currentAuthPath array of current authentication paths
+ * @param nextAuthPath array of next authentication paths
+ * @param currentTreehash array of current treehash instances
+ * @param nextTreehash array of next treehash instances
+ * @param currentStack array of current shared stacks
+ * @param nextStack array of next shared stacks
+ * @param currentRetain array of current retain stacks
+ * @param nextRetain array of next retain stacks
+ * @param nextRoot the roots of the next subtree
+ * @param currentRootSig array of signatures of the roots of the current subtrees
+ * @param gmssParameterset the GMSS Parameterset
+ * @param digest An array of strings, containing the name of the used hash
+ * function and the name of the corresponding provider
+ * @see org.bc.pqc.crypto.gmss.GMSSKeyPairGenerator
+ */
+
+ public GMSSPrivateKeyParameters(byte[][] currentSeed, byte[][] nextNextSeed,
+ byte[][][] currentAuthPath, byte[][][] nextAuthPath,
+ Treehash[][] currentTreehash, Treehash[][] nextTreehash,
+ Vector[] currentStack, Vector[] nextStack,
+ Vector[][] currentRetain, Vector[][] nextRetain, byte[][] nextRoot,
+ byte[][] currentRootSig, GMSSParameters gmssParameterset,
+ GMSSDigestProvider digestProvider)
+ {
+ this(null, currentSeed, nextNextSeed, currentAuthPath, nextAuthPath,
+ null, currentTreehash, nextTreehash, currentStack, nextStack,
+ currentRetain, nextRetain, null, null, null, null, nextRoot,
+ null, currentRootSig, null, gmssParameterset, digestProvider);
+ }
+
+ /**
+ * /**
+ *
+ * @param index tree indices
+ * @param currentSeed seed for the generation of private OTS keys for the
+ * current subtrees (TREE)
+ * @param nextNextSeed seed for the generation of private OTS keys for the
+ * subtrees after next (TREE++)
+ * @param currentAuthPath array of current authentication paths (AUTHPATH)
+ * @param nextAuthPath array of next authentication paths (AUTHPATH+)
+ * @param keep keep array for the authPath algorithm
+ * @param currentTreehash treehash for authPath algorithm of current tree
+ * @param nextTreehash treehash for authPath algorithm of next tree (TREE+)
+ * @param currentStack shared stack for authPath algorithm of current tree
+ * @param nextStack shared stack for authPath algorithm of next tree (TREE+)
+ * @param currentRetain retain stack for authPath algorithm of current tree
+ * @param nextRetain retain stack for authPath algorithm of next tree (TREE+)
+ * @param nextNextLeaf array of upcoming leafs of the tree after next (LEAF++) of
+ * each layer
+ * @param upperLeaf needed for precomputation of upper nodes
+ * @param upperTreehashLeaf needed for precomputation of upper treehash nodes
+ * @param minTreehash index of next treehash instance to receive an update
+ * @param nextRoot the roots of the next trees (ROOT+)
+ * @param nextNextRoot the roots of the tree after next (ROOT++)
+ * @param currentRootSig array of signatures of the roots of the current subtrees
+ * (SIG)
+ * @param nextRootSig array of signatures of the roots of the next subtree
+ * (SIG+)
+ * @param gmssParameterset the GMSS Parameterset
+ * @param digestClass An array of strings, containing the name of the used hash
+ * function and the name of the corresponding provider
+ */
+ public GMSSPrivateKeyParameters(int[] index, byte[][] currentSeeds,
+ byte[][] nextNextSeeds, byte[][][] currentAuthPaths,
+ byte[][][] nextAuthPaths, byte[][][] keep,
+ Treehash[][] currentTreehash, Treehash[][] nextTreehash,
+ Vector[] currentStack, Vector[] nextStack,
+ Vector[][] currentRetain, Vector[][] nextRetain,
+ GMSSLeaf[] nextNextLeaf, GMSSLeaf[] upperLeaf,
+ GMSSLeaf[] upperTreehashLeaf, int[] minTreehash, byte[][] nextRoot,
+ GMSSRootCalc[] nextNextRoot, byte[][] currentRootSig,
+ GMSSRootSig[] nextRootSig, GMSSParameters gmssParameterset,
+ GMSSDigestProvider digestProvider)
+ {
+
+ super(true, gmssParameterset);
+
+ // construct message digest
+
+ this.messDigestTrees = digestProvider.get();
+ this.mdLength = messDigestTrees.getDigestSize();
+
+
+ // Parameter
+ this.gmssPS = gmssParameterset;
+ this.otsIndex = gmssParameterset.getWinternitzParameter();
+ this.K = gmssParameterset.getK();
+ this.heightOfTrees = gmssParameterset.getHeightOfTrees();
+ // initialize numLayer
+ this.numLayer = gmssPS.getNumOfLayers();
+
+ // initialize index if null
+ if (index == null)
+ {
+ this.index = new int[numLayer];
+ for (int i = 0; i < numLayer; i++)
+ {
+ this.index[i] = 0;
+ }
+ }
+ else
+ {
+ this.index = index;
+ }
+
+ this.currentSeeds = currentSeeds;
+ this.nextNextSeeds = nextNextSeeds;
+
+ this.currentAuthPaths = currentAuthPaths;
+ this.nextAuthPaths = nextAuthPaths;
+
+ // initialize keep if null
+ if (keep == null)
+ {
+ this.keep = new byte[numLayer][][];
+ for (int i = 0; i < numLayer; i++)
+ {
+ this.keep[i] = new byte[(int)Math.floor(heightOfTrees[i] / 2)][mdLength];
+ }
+ }
+ else
+ {
+ this.keep = keep;
+ }
+
+ // initialize stack if null
+ if (currentStack == null)
+ {
+ this.currentStack = new Vector[numLayer];
+ for (int i = 0; i < numLayer; i++)
+ {
+ this.currentStack[i] = new Vector();
+ }
+ }
+ else
+ {
+ this.currentStack = currentStack;
+ }
+
+ // initialize nextStack if null
+ if (nextStack == null)
+ {
+ this.nextStack = new Vector[numLayer - 1];
+ for (int i = 0; i < numLayer - 1; i++)
+ {
+ this.nextStack[i] = new Vector();
+ }
+ }
+ else
+ {
+ this.nextStack = nextStack;
+ }
+
+ this.currentTreehash = currentTreehash;
+ this.nextTreehash = nextTreehash;
+
+ this.currentRetain = currentRetain;
+ this.nextRetain = nextRetain;
+
+ this.nextRoot = nextRoot;
+
+ this.digestProvider = digestProvider;
+
+ if (nextNextRoot == null)
+ {
+ this.nextNextRoot = new GMSSRootCalc[numLayer - 1];
+ for (int i = 0; i < numLayer - 1; i++)
+ {
+ this.nextNextRoot[i] = new GMSSRootCalc(
+ this.heightOfTrees[i + 1], this.K[i + 1], this.digestProvider);
+ }
+ }
+ else
+ {
+ this.nextNextRoot = nextNextRoot;
+ }
+ this.currentRootSig = currentRootSig;
+
+ // calculate numLeafs
+ numLeafs = new int[numLayer];
+ for (int i = 0; i < numLayer; i++)
+ {
+ numLeafs[i] = 1 << heightOfTrees[i];
+ }
+ // construct PRNG
+ this.gmssRandom = new GMSSRandom(messDigestTrees);
+
+ if (numLayer > 1)
+ {
+ // construct the nextNextLeaf (LEAFs++) array for upcoming leafs in
+ // tree after next (TREE++)
+ if (nextNextLeaf == null)
+ {
+ this.nextNextLeaf = new GMSSLeaf[numLayer - 2];
+ for (int i = 0; i < numLayer - 2; i++)
+ {
+ this.nextNextLeaf[i] = new GMSSLeaf(digestProvider.get(), otsIndex[i + 1], numLeafs[i + 2]);
+ this.nextNextLeaf[i].initLeafCalc(this.nextNextSeeds[i]);
+ }
+ }
+ else
+ {
+ this.nextNextLeaf = nextNextLeaf;
+ }
+ }
+ else
+ {
+ this.nextNextLeaf = new GMSSLeaf[0];
+ }
+
+ // construct the upperLeaf array for upcoming leafs in tree over the
+ // actual
+ if (upperLeaf == null)
+ {
+ this.upperLeaf = new GMSSLeaf[numLayer - 1];
+ for (int i = 0; i < numLayer - 1; i++)
+ {
+ this.upperLeaf[i] = new GMSSLeaf(digestProvider.get(), otsIndex[i],
+ numLeafs[i + 1]);
+ this.upperLeaf[i].initLeafCalc(this.currentSeeds[i]);
+ }
+ }
+ else
+ {
+ this.upperLeaf = upperLeaf;
+ }
+
+ // construct the leafs for upcoming leafs in treehashs in tree over the
+ // actual
+ if (upperTreehashLeaf == null)
+ {
+ this.upperTreehashLeaf = new GMSSLeaf[numLayer - 1];
+ for (int i = 0; i < numLayer - 1; i++)
+ {
+ this.upperTreehashLeaf[i] = new GMSSLeaf(digestProvider.get(), otsIndex[i],
+ numLeafs[i + 1]);
+ }
+ }
+ else
+ {
+ this.upperTreehashLeaf = upperTreehashLeaf;
+ }
+
+ if (minTreehash == null)
+ {
+ this.minTreehash = new int[numLayer - 1];
+ for (int i = 0; i < numLayer - 1; i++)
+ {
+ this.minTreehash[i] = -1;
+ }
+ }
+ else
+ {
+ this.minTreehash = minTreehash;
+ }
+
+ // construct the nextRootSig (RootSig++)
+ byte[] dummy = new byte[mdLength];
+ byte[] OTSseed = new byte[mdLength];
+ if (nextRootSig == null)
+ {
+ this.nextRootSig = new GMSSRootSig[numLayer - 1];
+ for (int i = 0; i < numLayer - 1; i++)
+ {
+ System.arraycopy(currentSeeds[i], 0, dummy, 0, mdLength);
+ gmssRandom.nextSeed(dummy);
+ OTSseed = gmssRandom.nextSeed(dummy);
+ this.nextRootSig[i] = new GMSSRootSig(digestProvider.get(), otsIndex[i],
+ heightOfTrees[i + 1]);
+ this.nextRootSig[i].initSign(OTSseed, nextRoot[i]);
+ }
+ }
+ else
+ {
+ this.nextRootSig = nextRootSig;
+ }
+ }
+
+ /**
+ * This method updates the GMSS private key for the next signature
+ *
+ * @param layer the layer where the next key is processed
+ */
+ public void nextKey(int layer)
+ {
+ // only for lowest layer ( other layers indices are raised in nextTree()
+ // method )
+ if (layer == numLayer - 1)
+ {
+ index[layer]++;
+ } // else System.out.println(" --- nextKey on layer " + layer + "
+ // index is now : " + index[layer]);
+
+ // if tree of this layer is depleted
+ if (index[layer] == numLeafs[layer])
+ {
+ if (numLayer != 1)
+ {
+ nextTree(layer);
+ index[layer] = 0;
+ }
+ }
+ else
+ {
+ updateKey(layer);
+ }
+ }
+
+ /**
+ * Switch to next subtree if the current one is depleted
+ *
+ * @param layer the layer where the next tree is processed
+ */
+ private void nextTree(int layer)
+ {
+ // System.out.println("NextTree method called on layer " + layer);
+ // dont create next tree for the top layer
+ if (layer > 0)
+ {
+ // raise index for upper layer
+ index[layer - 1]++;
+
+ // test if it is already the last tree
+ boolean lastTree = true;
+ int z = layer;
+ do
+ {
+ z--;
+ if (index[z] < numLeafs[z])
+ {
+ lastTree = false;
+ }
+ }
+ while (lastTree && (z > 0));
+
+ // only construct next subtree if last one is not already in use
+ if (!lastTree)
+ {
+ gmssRandom.nextSeed(currentSeeds[layer]);
+
+ // last step of distributed signature calculation
+ nextRootSig[layer - 1].updateSign();
+
+ // last step of distributed leaf calculation for nextNextLeaf
+ if (layer > 1)
+ {
+ nextNextLeaf[layer - 1 - 1].updateLeafCalc();
+ }
+
+ // last step of distributed leaf calculation for upper leaf
+ upperLeaf[layer - 1].updateLeafCalc();
+
+ // last step of distributed leaf calculation for all treehashs
+
+ if (minTreehash[layer - 1] >= 0)
+ {
+ this.upperTreehashLeaf[layer - 1].updateLeafCalc();
+ byte[] leaf = this.upperTreehashLeaf[layer - 1].getLeaf();
+ // if update is required use the precomputed leaf to update
+ // treehash
+ try
+ {
+ currentTreehash[layer - 1][minTreehash[layer - 1]]
+ .update(this.gmssRandom, leaf);
+ // System.out.println("UUUpdated TH " +
+ // minTreehash[layer - 1]);
+ if (currentTreehash[layer - 1][minTreehash[layer - 1]]
+ .wasFinished())
+ {
+ // System.out.println("FFFinished TH " +
+ // minTreehash[layer - 1]);
+ }
+ }
+ catch (Exception e)
+ {
+ System.out.println(e);
+ }
+ }
+
+ // last step of nextNextAuthRoot calculation
+ this.updateNextNextAuthRoot(layer);
+
+ // ******************************************************** /
+
+ // NOW: advance to next tree on layer 'layer'
+
+ // NextRootSig --> currentRootSigs
+ this.currentRootSig[layer - 1] = nextRootSig[layer - 1]
+ .getSig();
+
+ // -----------------------
+
+ // nextTreehash --> currentTreehash
+ // nextNextTreehash --> nextTreehash
+ for (int i = 0; i < heightOfTrees[layer] - K[layer]; i++)
+ {
+ this.currentTreehash[layer][i] = this.nextTreehash[layer - 1][i];
+ this.nextTreehash[layer - 1][i] = this.nextNextRoot[layer - 1]
+ .getTreehash()[i];
+ }
+
+ // NextAuthPath --> currentAuthPath
+ // nextNextAuthPath --> nextAuthPath
+ for (int i = 0; i < heightOfTrees[layer]; i++)
+ {
+ System.arraycopy(nextAuthPaths[layer - 1][i], 0,
+ currentAuthPaths[layer][i], 0, mdLength);
+ System.arraycopy(nextNextRoot[layer - 1].getAuthPath()[i],
+ 0, nextAuthPaths[layer - 1][i], 0, mdLength);
+ }
+
+ // nextRetain --> currentRetain
+ // nextNextRetain --> nextRetain
+ for (int i = 0; i < K[layer] - 1; i++)
+ {
+ this.currentRetain[layer][i] = this.nextRetain[layer - 1][i];
+ this.nextRetain[layer - 1][i] = this.nextNextRoot[layer - 1]
+ .getRetain()[i];
+ }
+
+ // nextStack --> currentStack
+ this.currentStack[layer] = this.nextStack[layer - 1];
+ // nextNextStack --> nextStack
+ this.nextStack[layer - 1] = this.nextNextRoot[layer - 1]
+ .getStack();
+
+ // nextNextRoot --> nextRoot
+ this.nextRoot[layer - 1] = this.nextNextRoot[layer - 1]
+ .getRoot();
+ // -----------------------
+
+ // -----------------
+ byte[] OTSseed = new byte[mdLength];
+ byte[] dummy = new byte[mdLength];
+ // gmssRandom.setSeed(currentSeeds[layer]);
+ System
+ .arraycopy(currentSeeds[layer - 1], 0, dummy, 0,
+ mdLength);
+ OTSseed = gmssRandom.nextSeed(dummy); // only need OTSSeed
+ OTSseed = gmssRandom.nextSeed(dummy);
+ OTSseed = gmssRandom.nextSeed(dummy);
+ // nextWinSig[layer-1]=new
+ // GMSSWinSig(OTSseed,algNames,otsIndex[layer-1],heightOfTrees[layer],nextRoot[layer-1]);
+ nextRootSig[layer - 1].initSign(OTSseed, nextRoot[layer - 1]);
+
+ // nextKey for upper layer
+ nextKey(layer - 1);
+ }
+ }
+ }
+
+ /**
+ * This method computes the authpath (AUTH) for the current tree,
+ * Additionally the root signature for the next tree (SIG+), the authpath
+ * (AUTH++) and root (ROOT++) for the tree after next in layer
+ * layer
, and the LEAF++^1 for the next next tree in the
+ * layer above are updated This method is used by nextKey()
+ *
+ * @param layer
+ */
+ private void updateKey(int layer)
+ {
+ // ----------current tree processing of actual layer---------
+ // compute upcoming authpath for current Tree (AUTH)
+ computeAuthPaths(layer);
+
+ // -----------distributed calculations part------------
+ // not for highest tree layer
+ if (layer > 0)
+ {
+
+ // compute (partial) next leaf on TREE++ (not on layer 1 and 0)
+ if (layer > 1)
+ {
+ nextNextLeaf[layer - 1 - 1].updateLeafCalc();
+ }
+
+ // compute (partial) next leaf on tree above (not on layer 0)
+ upperLeaf[layer - 1].updateLeafCalc();
+
+ // compute (partial) next leaf for all treehashs on tree above (not
+ // on layer 0)
+
+ int t = (int)Math
+ .floor((double)(this.getNumLeafs(layer) * 2)
+ / (double)(this.heightOfTrees[layer - 1] - this.K[layer - 1]));
+
+ if (index[layer] % t == 1)
+ {
+ // System.out.println(" layer: " + layer + " index: " +
+ // index[layer] + " t : " + t);
+
+ // take precomputed node for treehash update
+ // ------------------------------------------------
+ if (index[layer] > 1 && minTreehash[layer - 1] >= 0)
+ {
+ byte[] leaf = this.upperTreehashLeaf[layer - 1].getLeaf();
+ // if update is required use the precomputed leaf to update
+ // treehash
+ try
+ {
+ currentTreehash[layer - 1][minTreehash[layer - 1]]
+ .update(this.gmssRandom, leaf);
+ // System.out.println("Updated TH " + minTreehash[layer
+ // - 1]);
+ if (currentTreehash[layer - 1][minTreehash[layer - 1]]
+ .wasFinished())
+ {
+ // System.out.println("Finished TH " +
+ // minTreehash[layer - 1]);
+ }
+ }
+ catch (Exception e)
+ {
+ System.out.println(e);
+ }
+ // ------------------------------------------------
+ }
+
+ // initialize next leaf precomputation
+ // ------------------------------------------------
+
+ // get lowest index of treehashs
+ this.minTreehash[layer - 1] = getMinTreehashIndex(layer - 1);
+
+ if (this.minTreehash[layer - 1] >= 0)
+ {
+ // initialize leaf
+ byte[] seed = this.currentTreehash[layer - 1][this.minTreehash[layer - 1]]
+ .getSeedActive();
+ this.upperTreehashLeaf[layer - 1] = new GMSSLeaf(
+ this.digestProvider.get(), this.otsIndex[layer - 1], t);
+ this.upperTreehashLeaf[layer - 1].initLeafCalc(seed);
+ this.upperTreehashLeaf[layer - 1].updateLeafCalc();
+ // System.out.println("restarted treehashleaf (" + (layer -
+ // 1) + "," + this.minTreehash[layer - 1] + ")");
+ }
+ // ------------------------------------------------
+
+ }
+ else
+ {
+ // update the upper leaf for the treehash one step
+ if (this.minTreehash[layer - 1] >= 0)
+ {
+ this.upperTreehashLeaf[layer - 1].updateLeafCalc();
+ // if (minTreehash[layer - 1] > 3)
+ // System.out.print("#");
+ }
+ }
+
+ // compute (partial) the signature of ROOT+ (RootSig+) (not on top
+ // layer)
+ nextRootSig[layer - 1].updateSign();
+
+ // compute (partial) AUTHPATH++ & ROOT++ (not on top layer)
+ if (index[layer] == 1)
+ {
+ // init root and authpath calculation for tree after next
+ // (AUTH++, ROOT++)
+ this.nextNextRoot[layer - 1].initialize(new Vector());
+ }
+
+ // update root and authpath calculation for tree after next (AUTH++,
+ // ROOT++)
+ this.updateNextNextAuthRoot(layer);
+ }
+ // ----------- end distributed calculations part-----------------
+ }
+
+ /**
+ * This method returns the index of the next Treehash instance that should
+ * receive an update
+ *
+ * @param layer the layer of the GMSS tree
+ * @return index of the treehash instance that should get the update
+ */
+ private int getMinTreehashIndex(int layer)
+ {
+ int minTreehash = -1;
+ for (int h = 0; h < heightOfTrees[layer] - K[layer]; h++)
+ {
+ if (currentTreehash[layer][h].wasInitialized()
+ && !currentTreehash[layer][h].wasFinished())
+ {
+ if (minTreehash == -1)
+ {
+ minTreehash = h;
+ }
+ else if (currentTreehash[layer][h].getLowestNodeHeight() < currentTreehash[layer][minTreehash]
+ .getLowestNodeHeight())
+ {
+ minTreehash = h;
+ }
+ }
+ }
+ return minTreehash;
+ }
+
+ /**
+ * Computes the upcoming currentAuthpath of layer layer
using
+ * the revisited authentication path computation of Dahmen/Schneider 2008
+ *
+ * @param layer the actual layer
+ */
+ private void computeAuthPaths(int layer)
+ {
+
+ int Phi = index[layer];
+ int H = heightOfTrees[layer];
+ int K = this.K[layer];
+
+ // update all nextSeeds for seed scheduling
+ for (int i = 0; i < H - K; i++)
+ {
+ currentTreehash[layer][i].updateNextSeed(gmssRandom);
+ }
+
+ // STEP 1 of Algorithm
+ int Tau = heightOfPhi(Phi);
+
+ byte[] OTSseed = new byte[mdLength];
+ OTSseed = gmssRandom.nextSeed(currentSeeds[layer]);
+
+ // STEP 2 of Algorithm
+ // if phi's parent on height tau + 1 if left node, store auth_tau
+ // in keep_tau.
+ // TODO check it, formerly was
+ // int L = Phi / (int) Math.floor(Math.pow(2, Tau + 1));
+ // L %= 2;
+ int L = (Phi >>> (Tau + 1)) & 1;
+
+ byte[] tempKeep = new byte[mdLength];
+ // store the keep node not in keep[layer][tau/2] because it might be in
+ // use
+ // wait until the space is freed in step 4a
+ if (Tau < H - 1 && L == 0)
+ {
+ System.arraycopy(currentAuthPaths[layer][Tau], 0, tempKeep, 0,
+ mdLength);
+ }
+
+ byte[] help = new byte[mdLength];
+ // STEP 3 of Algorithm
+ // if phi is left child, compute and store leaf for next currentAuthPath
+ // path,
+ // (obtained by veriying current signature)
+ if (Tau == 0)
+ {
+ // LEAFCALC !!!
+ if (layer == numLayer - 1)
+ { // lowest layer computes the
+ // necessary leaf completely at this
+ // time
+ WinternitzOTSignature ots = new WinternitzOTSignature(OTSseed,
+ digestProvider.get(), otsIndex[layer]);
+ help = ots.getPublicKey();
+ }
+ else
+ { // other layers use the precomputed leafs in
+ // nextNextLeaf
+ byte[] dummy = new byte[mdLength];
+ System.arraycopy(currentSeeds[layer], 0, dummy, 0, mdLength);
+ gmssRandom.nextSeed(dummy);
+ help = upperLeaf[layer].getLeaf();
+ this.upperLeaf[layer].initLeafCalc(dummy);
+
+ // WinternitzOTSVerify otsver = new
+ // WinternitzOTSVerify(algNames, otsIndex[layer]);
+ // byte[] help2 = otsver.Verify(currentRoot[layer],
+ // currentRootSig[layer]);
+ // System.out.println(" --- " + layer + " " +
+ // ByteUtils.toHexString(help) + " " +
+ // ByteUtils.toHexString(help2));
+ }
+ System.arraycopy(help, 0, currentAuthPaths[layer][0], 0, mdLength);
+ }
+ else
+ {
+ // STEP 4a of Algorithm
+ // get new left currentAuthPath node on height tau
+ byte[] toBeHashed = new byte[mdLength << 1];
+ System.arraycopy(currentAuthPaths[layer][Tau - 1], 0, toBeHashed,
+ 0, mdLength);
+ // free the shared keep[layer][tau/2]
+ System.arraycopy(keep[layer][(int)Math.floor((Tau - 1) / 2)], 0,
+ toBeHashed, mdLength, mdLength);
+ messDigestTrees.update(toBeHashed, 0, toBeHashed.length);
+ currentAuthPaths[layer][Tau] = new byte[messDigestTrees.getDigestSize()];
+ messDigestTrees.doFinal(currentAuthPaths[layer][Tau], 0);
+
+ // STEP 4b and 4c of Algorithm
+ // copy right nodes to currentAuthPath on height 0..Tau-1
+ for (int i = 0; i < Tau; i++)
+ {
+
+ // STEP 4b of Algorithm
+ // 1st: copy from treehashs
+ if (i < H - K)
+ {
+ if (currentTreehash[layer][i].wasFinished())
+ {
+ System.arraycopy(currentTreehash[layer][i]
+ .getFirstNode(), 0, currentAuthPaths[layer][i],
+ 0, mdLength);
+ currentTreehash[layer][i].destroy();
+ }
+ else
+ {
+ System.err
+ .println("Treehash ("
+ + layer
+ + ","
+ + i
+ + ") not finished when needed in AuthPathComputation");
+ }
+ }
+
+ // 2nd: copy precomputed values from Retain
+ if (i < H - 1 && i >= H - K)
+ {
+ if (currentRetain[layer][i - (H - K)].size() > 0)
+ {
+ // pop element from retain
+ System.arraycopy(currentRetain[layer][i - (H - K)]
+ .lastElement(), 0, currentAuthPaths[layer][i],
+ 0, mdLength);
+ currentRetain[layer][i - (H - K)]
+ .removeElementAt(currentRetain[layer][i
+ - (H - K)].size() - 1);
+ }
+ }
+
+ // STEP 4c of Algorithm
+ // initialize new stack at heights 0..Tau-1
+ if (i < H - K)
+ {
+ // create stacks anew
+ int startPoint = Phi + 3 * (1 << i);
+ if (startPoint < numLeafs[layer])
+ {
+ // if (layer < 2) {
+ // System.out.println("initialized TH " + i + " on layer
+ // " + layer);
+ // }
+ currentTreehash[layer][i].initialize();
+ }
+ }
+ }
+ }
+
+ // now keep space is free to use
+ if (Tau < H - 1 && L == 0)
+ {
+ System.arraycopy(tempKeep, 0,
+ keep[layer][(int)Math.floor(Tau / 2)], 0, mdLength);
+ }
+
+ // only update empty stack at height h if all other stacks have
+ // tailnodes with height >h
+ // finds active stack with lowest node height, choses lower index in
+ // case of tie
+
+ // on the lowest layer leafs must be computed at once, no precomputation
+ // is possible. So all treehash updates are done at once here
+ if (layer == numLayer - 1)
+ {
+ for (int tmp = 1; tmp <= (H - K) / 2; tmp++)
+ {
+ // index of the treehash instance that receives the next update
+ int minTreehash = getMinTreehashIndex(layer);
+
+ // if active treehash is found update with a leaf
+ if (minTreehash >= 0)
+ {
+ try
+ {
+ byte[] seed = new byte[mdLength];
+ System.arraycopy(
+ this.currentTreehash[layer][minTreehash]
+ .getSeedActive(), 0, seed, 0, mdLength);
+ byte[] seed2 = gmssRandom.nextSeed(seed);
+ WinternitzOTSignature ots = new WinternitzOTSignature(
+ seed2, this.digestProvider.get(), this.otsIndex[layer]);
+ byte[] leaf = ots.getPublicKey();
+ currentTreehash[layer][minTreehash].update(
+ this.gmssRandom, leaf);
+ }
+ catch (Exception e)
+ {
+ System.out.println(e);
+ }
+ }
+ }
+ }
+ else
+ { // on higher layers the updates are done later
+ this.minTreehash[layer] = getMinTreehashIndex(layer);
+ }
+ }
+
+ /**
+ * Returns the largest h such that 2^h | Phi
+ *
+ * @param Phi the leaf index
+ * @return The largest h
with 2^h | Phi
if
+ * Phi!=0
else return -1
+ */
+ private int heightOfPhi(int Phi)
+ {
+ if (Phi == 0)
+ {
+ return -1;
+ }
+ int Tau = 0;
+ int modul = 1;
+ while (Phi % modul == 0)
+ {
+ modul *= 2;
+ Tau += 1;
+ }
+ return Tau - 1;
+ }
+
+ /**
+ * Updates the authentication path and root calculation for the tree after
+ * next (AUTH++, ROOT++) in layer layer
+ *
+ * @param layer
+ */
+ private void updateNextNextAuthRoot(int layer)
+ {
+
+ byte[] OTSseed = new byte[mdLength];
+ OTSseed = gmssRandom.nextSeed(nextNextSeeds[layer - 1]);
+
+ // get the necessary leaf
+ if (layer == numLayer - 1)
+ { // lowest layer computes the necessary
+ // leaf completely at this time
+ WinternitzOTSignature ots = new WinternitzOTSignature(OTSseed,
+ digestProvider.get(), otsIndex[layer]);
+ this.nextNextRoot[layer - 1].update(nextNextSeeds[layer - 1], ots
+ .getPublicKey());
+ }
+ else
+ { // other layers use the precomputed leafs in nextNextLeaf
+ this.nextNextRoot[layer - 1].update(nextNextSeeds[layer - 1],
+ nextNextLeaf[layer - 1].getLeaf());
+ this.nextNextLeaf[layer - 1].initLeafCalc(nextNextSeeds[layer - 1]);
+ }
+ }
+
+ public int[] getIndex()
+ {
+ return index;
+ }
+
+ /**
+ * @return The current index of layer i
+ */
+ public int getIndex(int i)
+ {
+ return index[i];
+ }
+
+ public byte[][] getCurrentSeeds()
+ {
+ return currentSeeds;
+ }
+
+ public byte[][] getNextNextSeeds()
+ {
+ return nextNextSeeds;
+ }
+
+ public byte[][][] getCurrentAuthPaths()
+ {
+ return currentAuthPaths;
+ }
+
+ public byte[][][] getNextAuthPaths()
+ {
+ return nextAuthPaths;
+ }
+
+ public Treehash[][] getCurrentTreehash()
+ {
+ return currentTreehash;
+ }
+
+ public Treehash[][] getNextTreehash()
+ {
+ return nextTreehash;
+ }
+
+ public byte[][][] getKeep()
+ {
+ return keep;
+ }
+
+ public Vector[] getCurrentStack()
+ {
+ return currentStack;
+ }
+
+ public Vector[] getNextStack()
+ {
+ return nextStack;
+ }
+
+ public Vector[][] getCurrentRetain()
+ {
+ return currentRetain;
+ }
+
+ public Vector[][] getNextRetain()
+ {
+ return nextRetain;
+ }
+
+ public GMSSLeaf[] getNextNextLeaf()
+ {
+ return nextNextLeaf;
+ }
+
+ public GMSSLeaf[] getUpperLeaf()
+ {
+ return upperLeaf;
+ }
+
+ public GMSSLeaf[] getUpperTreehashLeaf()
+ {
+ return upperTreehashLeaf;
+ }
+
+ public int[] getMinTreehash()
+ {
+ return minTreehash;
+ }
+
+ public GMSSRootSig[] getNextRootSig()
+ {
+ return nextRootSig;
+ }
+
+ public byte[][] getNextRoot()
+ {
+ return nextRoot;
+ }
+
+ public GMSSRootCalc[] getNextNextRoot()
+ {
+ return nextNextRoot;
+ }
+
+ public byte[][] getCurrentRootSig()
+ {
+ return currentRootSig;
+ }
+
+ /**
+ * @return The one-time signature of the root of the current subtree
+ */
+ public byte[] getSubtreeRootSig(int i)
+ {
+ return currentRootSig[i];
+ }
+
+
+ public GMSSDigestProvider getName()
+ {
+ return digestProvider;
+ }
+
+ /**
+ * @return The number of leafs of each tree of layer i
+ */
+ public int getNumLeafs(int i)
+ {
+ return numLeafs[i];
+ }
+
+ /**
+ * @return The array of number of leafs of a tree of each layer
+ */
+ public int[] getNumLeafs()
+ {
+ return numLeafs;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/gmss/GMSSPublicKeyParameters.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/gmss/GMSSPublicKeyParameters.java
new file mode 100644
index 0000000..9f7e0f4
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/gmss/GMSSPublicKeyParameters.java
@@ -0,0 +1,33 @@
+package org.bc.pqc.crypto.gmss;
+
+
+public class GMSSPublicKeyParameters
+ extends GMSSKeyParameters
+{
+ /**
+ * The GMSS public key
+ */
+ private byte[] gmssPublicKey;
+
+ /**
+ * The constructor.
+ *
+ * @param key a raw GMSS public key
+ * @param gmssParameterSet an instance of GMSSParameterset
+ */
+ public GMSSPublicKeyParameters(byte[] key, GMSSParameters gmssParameterSet)
+ {
+ super(false, gmssParameterSet);
+ this.gmssPublicKey = key;
+ }
+
+ /**
+ * Returns the GMSS public key
+ *
+ * @return The GMSS public key
+ */
+ public byte[] getPublicKey()
+ {
+ return gmssPublicKey;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/gmss/GMSSRootCalc.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/gmss/GMSSRootCalc.java
new file mode 100644
index 0000000..192e414
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/gmss/GMSSRootCalc.java
@@ -0,0 +1,596 @@
+package org.bc.pqc.crypto.gmss;
+
+import java.util.Enumeration;
+import java.util.Vector;
+
+import org.bc.crypto.Digest;
+import org.bc.util.Arrays;
+import org.bc.util.Integers;
+import org.bc.util.encoders.Hex;
+
+
+/**
+ * This class computes a whole Merkle tree and saves the needed values for
+ * AuthPath computation. It is used for precomputation of the root of a
+ * following tree. After initialization, 2^H updates are required to complete
+ * the root. Every update requires one leaf value as parameter. While computing
+ * the root all initial values for the authentication path algorithm (treehash,
+ * auth, retain) are stored for later use.
+ */
+public class GMSSRootCalc
+{
+
+ /**
+ * max height of the tree
+ */
+ private int heightOfTree;
+
+ /**
+ * length of the messageDigest
+ */
+ private int mdLength;
+
+ /**
+ * the treehash instances of the tree
+ */
+ private Treehash[] treehash;
+
+ /**
+ * stores the retain nodes for authPath computation
+ */
+ private Vector[] retain;
+
+ /**
+ * finally stores the root of the tree when finished
+ */
+ private byte[] root;
+
+ /**
+ * stores the authentication path y_1(i), i = 0..H-1
+ */
+ private byte[][] AuthPath;
+
+ /**
+ * the value K for the authentication path computation
+ */
+ private int K;
+
+ /**
+ * Vector element that stores the nodes on the stack
+ */
+ private Vector tailStack;
+
+ /**
+ * stores the height of all nodes laying on the tailStack
+ */
+ private Vector heightOfNodes;
+ /**
+ * The hash function used for the construction of the authentication trees
+ */
+ private Digest messDigestTree;
+
+ /**
+ * An array of strings containing the name of the hash function used to
+ * construct the authentication trees and used by the OTS.
+ */
+ private GMSSDigestProvider digestProvider;
+
+ /**
+ * stores the index of the current node on each height of the tree
+ */
+ private int[] index;
+
+ /**
+ * true if instance was already initialized, false otherwise
+ */
+ private boolean isInitialized;
+
+ /**
+ * true it instance was finished
+ */
+ private boolean isFinished;
+
+ /**
+ * Integer that stores the index of the next seed that has to be omitted to
+ * the treehashs
+ */
+ private int indexForNextSeed;
+
+ /**
+ * temporary integer that stores the height of the next treehash instance
+ * that gets initialized with a seed
+ */
+ private int heightOfNextSeed;
+
+ /**
+ * This constructor regenerates a prior treehash object
+ *
+ * @param digest an array of strings, containing the digest of the used hash
+ * function and PRNG and the digest of the corresponding
+ * provider
+ * @param statByte status bytes
+ * @param statInt status ints
+ */
+ public GMSSRootCalc(Digest digest, byte[][] statByte, int[] statInt,
+ Treehash[] treeH, Vector[] ret)
+ {
+ this.messDigestTree = digestProvider.get();
+ this.digestProvider = digestProvider;
+ // decode statInt
+ this.heightOfTree = statInt[0];
+ this.mdLength = statInt[1];
+ this.K = statInt[2];
+ this.indexForNextSeed = statInt[3];
+ this.heightOfNextSeed = statInt[4];
+ if (statInt[5] == 1)
+ {
+ this.isFinished = true;
+ }
+ else
+ {
+ this.isFinished = false;
+ }
+ if (statInt[6] == 1)
+ {
+ this.isInitialized = true;
+ }
+ else
+ {
+ this.isInitialized = false;
+ }
+
+ int tailLength = statInt[7];
+
+ this.index = new int[heightOfTree];
+ for (int i = 0; i < heightOfTree; i++)
+ {
+ this.index[i] = statInt[8 + i];
+ }
+
+ this.heightOfNodes = new Vector();
+ for (int i = 0; i < tailLength; i++)
+ {
+ this.heightOfNodes.addElement(Integers.valueOf(statInt[8 + heightOfTree
+ + i]));
+ }
+
+ // decode statByte
+ this.root = statByte[0];
+
+ this.AuthPath = new byte[heightOfTree][mdLength];
+ for (int i = 0; i < heightOfTree; i++)
+ {
+ this.AuthPath[i] = statByte[1 + i];
+ }
+
+ this.tailStack = new Vector();
+ for (int i = 0; i < tailLength; i++)
+ {
+ this.tailStack.addElement(statByte[1 + heightOfTree + i]);
+ }
+
+ // decode treeH
+ this.treehash = GMSSUtils.clone(treeH);
+
+ // decode ret
+ this.retain = GMSSUtils.clone(ret);
+ }
+
+ /**
+ * Constructor
+ *
+ * @param heightOfTree maximal height of the tree
+ * @param digestProvider an array of strings, containing the name of the used hash
+ * function and PRNG and the name of the corresponding
+ * provider
+ */
+ public GMSSRootCalc(int heightOfTree, int K, GMSSDigestProvider digestProvider)
+ {
+ this.heightOfTree = heightOfTree;
+ this.digestProvider = digestProvider;
+ this.messDigestTree = digestProvider.get();
+ this.mdLength = messDigestTree.getDigestSize();
+ this.K = K;
+ this.index = new int[heightOfTree];
+ this.AuthPath = new byte[heightOfTree][mdLength];
+ this.root = new byte[mdLength];
+ // this.treehash = new Treehash[this.heightOfTree - this.K];
+ this.retain = new Vector[this.K - 1];
+ for (int i = 0; i < K - 1; i++)
+ {
+ this.retain[i] = new Vector();
+ }
+
+ }
+
+ /**
+ * Initializes the calculation of a new root
+ *
+ * @param sharedStack the stack shared by all treehash instances of this tree
+ */
+ public void initialize(Vector sharedStack)
+ {
+ this.treehash = new Treehash[this.heightOfTree - this.K];
+ for (int i = 0; i < this.heightOfTree - this.K; i++)
+ {
+ this.treehash[i] = new Treehash(sharedStack, i, this.digestProvider.get());
+ }
+
+ this.index = new int[heightOfTree];
+ this.AuthPath = new byte[heightOfTree][mdLength];
+ this.root = new byte[mdLength];
+
+ this.tailStack = new Vector();
+ this.heightOfNodes = new Vector();
+ this.isInitialized = true;
+ this.isFinished = false;
+
+ for (int i = 0; i < heightOfTree; i++)
+ {
+ this.index[i] = -1;
+ }
+
+ this.retain = new Vector[this.K - 1];
+ for (int i = 0; i < K - 1; i++)
+ {
+ this.retain[i] = new Vector();
+ }
+
+ this.indexForNextSeed = 3;
+ this.heightOfNextSeed = 0;
+ }
+
+ /**
+ * updates the root with one leaf and stores needed values in retain,
+ * treehash or authpath. Additionally counts the seeds used. This method is
+ * used when performing the updates for TREE++.
+ *
+ * @param seed the initial seed for treehash: seedNext
+ * @param leaf the height of the treehash
+ */
+ public void update(byte[] seed, byte[] leaf)
+ {
+ if (this.heightOfNextSeed < (this.heightOfTree - this.K)
+ && this.indexForNextSeed - 2 == index[0])
+ {
+ this.initializeTreehashSeed(seed, this.heightOfNextSeed);
+ this.heightOfNextSeed++;
+ this.indexForNextSeed *= 2;
+ }
+ // now call the simple update
+ this.update(leaf);
+ }
+
+ /**
+ * Updates the root with one leaf and stores the needed values in retain,
+ * treehash or authpath
+ */
+ public void update(byte[] leaf)
+ {
+
+ if (isFinished)
+ {
+ System.out.print("Too much updates for Tree!!");
+ return;
+ }
+ if (!isInitialized)
+ {
+ System.err.println("GMSSRootCalc not initialized!");
+ return;
+ }
+
+ // a new leaf was omitted, so raise index on lowest layer
+ index[0]++;
+
+ // store the nodes on the lowest layer in treehash or authpath
+ if (index[0] == 1)
+ {
+ System.arraycopy(leaf, 0, AuthPath[0], 0, mdLength);
+ }
+ else if (index[0] == 3)
+ {
+ // store in treehash only if K < H
+ if (heightOfTree > K)
+ {
+ treehash[0].setFirstNode(leaf);
+ }
+ }
+
+ if ((index[0] - 3) % 2 == 0 && index[0] >= 3)
+ {
+ // store in retain if K = H
+ if (heightOfTree == K)
+ // TODO: check it
+ {
+ retain[0].insertElementAt(leaf, 0);
+ }
+ }
+
+ // if first update to this tree is made
+ if (index[0] == 0)
+ {
+ tailStack.addElement(leaf);
+ heightOfNodes.addElement(Integers.valueOf(0));
+ }
+ else
+ {
+
+ byte[] help = new byte[mdLength];
+ byte[] toBeHashed = new byte[mdLength << 1];
+
+ // store the new leaf in help
+ System.arraycopy(leaf, 0, help, 0, mdLength);
+ int helpHeight = 0;
+ // while top to nodes have same height
+ while (tailStack.size() > 0
+ && helpHeight == ((Integer)heightOfNodes.lastElement())
+ .intValue())
+ {
+
+ // help <-- hash(stack top element || help)
+ System.arraycopy(tailStack.lastElement(), 0, toBeHashed, 0,
+ mdLength);
+ tailStack.removeElementAt(tailStack.size() - 1);
+ heightOfNodes.removeElementAt(heightOfNodes.size() - 1);
+ System.arraycopy(help, 0, toBeHashed, mdLength, mdLength);
+
+ messDigestTree.update(toBeHashed, 0, toBeHashed.length);
+ help = new byte[messDigestTree.getDigestSize()];
+ messDigestTree.doFinal(help, 0);
+
+ // the new help node is one step higher
+ helpHeight++;
+ if (helpHeight < heightOfTree)
+ {
+ index[helpHeight]++;
+
+ // add index 1 element to initial authpath
+ if (index[helpHeight] == 1)
+ {
+ System.arraycopy(help, 0, AuthPath[helpHeight], 0,
+ mdLength);
+ }
+
+ if (helpHeight >= heightOfTree - K)
+ {
+ if (helpHeight == 0)
+ {
+ System.out.println("M���P");
+ }
+ // add help element to retain stack if it is a right
+ // node
+ // and not stored in treehash
+ if ((index[helpHeight] - 3) % 2 == 0
+ && index[helpHeight] >= 3)
+ // TODO: check it
+ {
+ retain[helpHeight - (heightOfTree - K)]
+ .insertElementAt(help, 0);
+ }
+ }
+ else
+ {
+ // if element is third in his line add it to treehash
+ if (index[helpHeight] == 3)
+ {
+ treehash[helpHeight].setFirstNode(help);
+ }
+ }
+ }
+ }
+ // push help element to the stack
+ tailStack.addElement(help);
+ heightOfNodes.addElement(Integers.valueOf(helpHeight));
+
+ // is the root calculation finished?
+ if (helpHeight == heightOfTree)
+ {
+ isFinished = true;
+ isInitialized = false;
+ root = (byte[])tailStack.lastElement();
+ }
+ }
+
+ }
+
+ /**
+ * initializes the seeds for the treehashs of the tree precomputed by this
+ * class
+ *
+ * @param seed the initial seed for treehash: seedNext
+ * @param index the height of the treehash
+ */
+ public void initializeTreehashSeed(byte[] seed, int index)
+ {
+ treehash[index].initializeSeed(seed);
+ }
+
+ /**
+ * Method to check whether the instance has been initialized or not
+ *
+ * @return true if treehash was already initialized
+ */
+ public boolean wasInitialized()
+ {
+ return isInitialized;
+ }
+
+ /**
+ * Method to check whether the instance has been finished or not
+ *
+ * @return true if tree has reached its maximum height
+ */
+ public boolean wasFinished()
+ {
+ return isFinished;
+ }
+
+ /**
+ * returns the authentication path of the first leaf of the tree
+ *
+ * @return the authentication path of the first leaf of the tree
+ */
+ public byte[][] getAuthPath()
+ {
+ return GMSSUtils.clone(AuthPath);
+ }
+
+ /**
+ * returns the initial treehash instances, storing value y_3(i)
+ *
+ * @return the initial treehash instances, storing value y_3(i)
+ */
+ public Treehash[] getTreehash()
+ {
+ return GMSSUtils.clone(treehash);
+ }
+
+ /**
+ * returns the retain stacks storing all right nodes near to the root
+ *
+ * @return the retain stacks storing all right nodes near to the root
+ */
+ public Vector[] getRetain()
+ {
+ return GMSSUtils.clone(retain);
+ }
+
+ /**
+ * returns the finished root value
+ *
+ * @return the finished root value
+ */
+ public byte[] getRoot()
+ {
+ return Arrays.clone(root);
+ }
+
+ /**
+ * returns the shared stack
+ *
+ * @return the shared stack
+ */
+ public Vector getStack()
+ {
+ Vector copy = new Vector();
+ for (Enumeration en = tailStack.elements(); en.hasMoreElements();)
+ {
+ copy.addElement(en.nextElement());
+ }
+ return copy;
+ }
+
+ /**
+ * Returns the status byte array used by the GMSSPrivateKeyASN.1 class
+ *
+ * @return The status bytes
+ */
+ public byte[][] getStatByte()
+ {
+
+ int tailLength;
+ if (tailStack == null)
+ {
+ tailLength = 0;
+ }
+ else
+ {
+ tailLength = tailStack.size();
+ }
+ byte[][] statByte = new byte[1 + heightOfTree + tailLength][64]; //FIXME: messDigestTree.getByteLength()
+ statByte[0] = root;
+
+ for (int i = 0; i < heightOfTree; i++)
+ {
+ statByte[1 + i] = AuthPath[i];
+ }
+ for (int i = 0; i < tailLength; i++)
+ {
+ statByte[1 + heightOfTree + i] = (byte[])tailStack.elementAt(i);
+ }
+
+ return statByte;
+ }
+
+ /**
+ * Returns the status int array used by the GMSSPrivateKeyASN.1 class
+ *
+ * @return The status ints
+ */
+ public int[] getStatInt()
+ {
+
+ int tailLength;
+ if (tailStack == null)
+ {
+ tailLength = 0;
+ }
+ else
+ {
+ tailLength = tailStack.size();
+ }
+ int[] statInt = new int[8 + heightOfTree + tailLength];
+ statInt[0] = heightOfTree;
+ statInt[1] = mdLength;
+ statInt[2] = K;
+ statInt[3] = indexForNextSeed;
+ statInt[4] = heightOfNextSeed;
+ if (isFinished)
+ {
+ statInt[5] = 1;
+ }
+ else
+ {
+ statInt[5] = 0;
+ }
+ if (isInitialized)
+ {
+ statInt[6] = 1;
+ }
+ else
+ {
+ statInt[6] = 0;
+ }
+ statInt[7] = tailLength;
+
+ for (int i = 0; i < heightOfTree; i++)
+ {
+ statInt[8 + i] = index[i];
+ }
+ for (int i = 0; i < tailLength; i++)
+ {
+ statInt[8 + heightOfTree + i] = ((Integer)heightOfNodes
+ .elementAt(i)).intValue();
+ }
+
+ return statInt;
+ }
+
+ /**
+ * @return a human readable version of the structure
+ */
+ public String toString()
+ {
+ String out = "";
+ int tailLength;
+ if (tailStack == null)
+ {
+ tailLength = 0;
+ }
+ else
+ {
+ tailLength = tailStack.size();
+ }
+
+ for (int i = 0; i < 8 + heightOfTree + tailLength; i++)
+ {
+ out = out + getStatInt()[i] + " ";
+ }
+ for (int i = 0; i < 1 + heightOfTree + tailLength; i++)
+ {
+ out = out + new String(Hex.encode(getStatByte()[i])) + " ";
+ }
+ out = out + " " + digestProvider.get().getDigestSize();
+ return out;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/gmss/GMSSRootSig.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/gmss/GMSSRootSig.java
new file mode 100644
index 0000000..a0d502c
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/gmss/GMSSRootSig.java
@@ -0,0 +1,666 @@
+package org.bc.pqc.crypto.gmss;
+
+import org.bc.crypto.Digest;
+import org.bc.pqc.crypto.gmss.util.GMSSRandom;
+import org.bc.util.encoders.Hex;
+
+
+/**
+ * This class implements the distributed signature generation of the Winternitz
+ * one-time signature scheme (OTSS), described in C.Dods, N.P. Smart, and M.
+ * Stam, "Hash Based Digital Signature Schemes", LNCS 3796, pages 96–115,
+ * 2005. The class is used by the GMSS classes.
+ */
+public class GMSSRootSig
+{
+
+ /**
+ * The hash function used by the OTS
+ */
+ private Digest messDigestOTS;
+
+ /**
+ * The length of the message digest and private key
+ */
+ private int mdsize, keysize;
+
+ /**
+ * The private key
+ */
+ private byte[] privateKeyOTS;
+
+ /**
+ * The message bytes
+ */
+ private byte[] hash;
+
+ /**
+ * The signature bytes
+ */
+ private byte[] sign;
+
+ /**
+ * The Winternitz parameter
+ */
+ private int w;
+
+ /**
+ * The source of randomness for OTS private key generation
+ */
+ private GMSSRandom gmssRandom;
+
+ /**
+ * Sizes of the message
+ */
+ private int messagesize;
+
+ /**
+ * Some precalculated values
+ */
+ private int k;
+
+ /**
+ * Some variables for storing the actual status of distributed signing
+ */
+ private int r, test, counter, ii;
+
+ /**
+ * variables for storing big numbers for the actual status of distributed
+ * signing
+ */
+ private long test8, big8;
+
+ /**
+ * The necessary steps of each updateSign() call
+ */
+ private int steps;
+
+ /**
+ * The checksum part
+ */
+ private int checksum;
+
+ /**
+ * The height of the tree
+ */
+ private int height;
+
+ /**
+ * The current intern OTSseed
+ */
+ private byte[] seed;
+
+ /**
+ * This constructor regenerates a prior GMSSRootSig object used by the
+ * GMSSPrivateKeyASN.1 class
+ *
+ * @param digest an array of strings, containing the digest of the used hash
+ * function, the digest of the PRGN and the names of the
+ * corresponding providers
+ * @param statByte status byte array
+ * @param statInt status int array
+ */
+ public GMSSRootSig(Digest digest, byte[][] statByte, int[] statInt)
+ {
+ messDigestOTS = digest;
+ gmssRandom = new GMSSRandom(messDigestOTS);
+
+ this.counter = statInt[0];
+ this.test = statInt[1];
+ this.ii = statInt[2];
+ this.r = statInt[3];
+ this.steps = statInt[4];
+ this.keysize = statInt[5];
+ this.height = statInt[6];
+ this.w = statInt[7];
+ this.checksum = statInt[8];
+
+ this.mdsize = messDigestOTS.getDigestSize();
+
+ this.k = (1 << w) - 1;
+
+ int mdsizeBit = mdsize << 3;
+ this.messagesize = (int)Math.ceil((double)(mdsizeBit) / (double)w);
+
+ this.privateKeyOTS = statByte[0];
+ this.seed = statByte[1];
+ this.hash = statByte[2];
+
+ this.sign = statByte[3];
+
+ this.test8 = ((statByte[4][0] & 0xff))
+ | ((long)(statByte[4][1] & 0xff) << 8)
+ | ((long)(statByte[4][2] & 0xff) << 16)
+ | ((long)(statByte[4][3] & 0xff)) << 24
+ | ((long)(statByte[4][4] & 0xff)) << 32
+ | ((long)(statByte[4][5] & 0xff)) << 40
+ | ((long)(statByte[4][6] & 0xff)) << 48
+ | ((long)(statByte[4][7] & 0xff)) << 56;
+
+ this.big8 = ((statByte[4][8] & 0xff))
+ | ((long)(statByte[4][9] & 0xff) << 8)
+ | ((long)(statByte[4][10] & 0xff) << 16)
+ | ((long)(statByte[4][11] & 0xff)) << 24
+ | ((long)(statByte[4][12] & 0xff)) << 32
+ | ((long)(statByte[4][13] & 0xff)) << 40
+ | ((long)(statByte[4][14] & 0xff)) << 48
+ | ((long)(statByte[4][15] & 0xff)) << 56;
+ }
+
+ /**
+ * The constructor generates the PRNG and initializes some variables
+ *
+ * @param digest an array of strings, containing the digest of the used hash
+ * function, the digest of the PRGN and the names of the
+ * corresponding providers
+ * @param w the winternitz parameter
+ * @param height the heigth of the tree
+ */
+ public GMSSRootSig(Digest digest, int w, int height)
+ {
+ messDigestOTS = digest;
+ gmssRandom = new GMSSRandom(messDigestOTS);
+
+ this.mdsize = messDigestOTS.getDigestSize();
+ this.w = w;
+ this.height = height;
+
+ this.k = (1 << w) - 1;
+
+ int mdsizeBit = mdsize << 3;
+ this.messagesize = (int)Math.ceil((double)(mdsizeBit) / (double)w);
+ }
+
+ /**
+ * This method initializes the distributed sigature calculation. Variables
+ * are reseted and necessary steps are calculated
+ *
+ * @param seed0 the initial OTSseed
+ * @param message the massage which will be signed
+ */
+ public void initSign(byte[] seed0, byte[] message)
+ {
+
+ // create hash of message m
+ this.hash = new byte[mdsize];
+ messDigestOTS.update(message, 0, message.length);
+ this.hash = new byte[messDigestOTS.getDigestSize()];
+ messDigestOTS.doFinal(this.hash, 0);
+
+ // variables for calculation of steps
+ byte[] messPart = new byte[mdsize];
+ System.arraycopy(hash, 0, messPart, 0, mdsize);
+ int checkPart = 0;
+ int sumH = 0;
+ int checksumsize = getLog((messagesize << w) + 1);
+
+ // ------- calculation of necessary steps ------
+ if (8 % w == 0)
+ {
+ int dt = 8 / w;
+ // message part
+ for (int a = 0; a < mdsize; a++)
+ {
+ // count necessary hashs in 'sumH'
+ for (int b = 0; b < dt; b++)
+ {
+ sumH += messPart[a] & k;
+ messPart[a] = (byte)(messPart[a] >>> w);
+ }
+ }
+ // checksum part
+ this.checksum = (messagesize << w) - sumH;
+ checkPart = checksum;
+ // count necessary hashs in 'sumH'
+ for (int b = 0; b < checksumsize; b += w)
+ {
+ sumH += checkPart & k;
+ checkPart >>>= w;
+ }
+ } // end if ( 8 % w == 0 )
+ else if (w < 8)
+ {
+ long big8;
+ int ii = 0;
+ int dt = mdsize / w;
+
+ // first d*w bytes of hash (main message part)
+ for (int i = 0; i < dt; i++)
+ {
+ big8 = 0;
+ for (int j = 0; j < w; j++)
+ {
+ big8 ^= (messPart[ii] & 0xff) << (j << 3);
+ ii++;
+ }
+ // count necessary hashs in 'sumH'
+ for (int j = 0; j < 8; j++)
+ {
+ sumH += (int)(big8 & k);
+ big8 >>>= w;
+ }
+ }
+ // rest of message part
+ dt = mdsize % w;
+ big8 = 0;
+ for (int j = 0; j < dt; j++)
+ {
+ big8 ^= (messPart[ii] & 0xff) << (j << 3);
+ ii++;
+ }
+ dt <<= 3;
+ // count necessary hashs in 'sumH'
+ for (int j = 0; j < dt; j += w)
+ {
+ sumH += (int)(big8 & k);
+ big8 >>>= w;
+ }
+ // checksum part
+ this.checksum = (messagesize << w) - sumH;
+ checkPart = checksum;
+ // count necessary hashs in 'sumH'
+ for (int i = 0; i < checksumsize; i += w)
+ {
+ sumH += checkPart & k;
+ checkPart >>>= w;
+ }
+ }// end if(w<8)
+ else if (w < 57)
+ {
+ long big8;
+ int r = 0;
+ int s, f, rest, ii;
+
+ // first a*w bits of hash where a*w <= 8*mdsize < (a+1)*w (main
+ // message part)
+ while (r <= ((mdsize << 3) - w))
+ {
+ s = r >>> 3;
+ rest = r % 8;
+ r += w;
+ f = (r + 7) >>> 3;
+ big8 = 0;
+ ii = 0;
+ for (int j = s; j < f; j++)
+ {
+ big8 ^= (messPart[j] & 0xff) << (ii << 3);
+ ii++;
+ }
+ big8 >>>= rest;
+ // count necessary hashs in 'sumH'
+ sumH += (big8 & k);
+
+ }
+ // rest of message part
+ s = r >>> 3;
+ if (s < mdsize)
+ {
+ rest = r % 8;
+ big8 = 0;
+ ii = 0;
+ for (int j = s; j < mdsize; j++)
+ {
+ big8 ^= (messPart[j] & 0xff) << (ii << 3);
+ ii++;
+ }
+
+ big8 >>>= rest;
+ // count necessary hashs in 'sumH'
+ sumH += (big8 & k);
+ }
+ // checksum part
+ this.checksum = (messagesize << w) - sumH;
+ checkPart = checksum;
+ // count necessary hashs in 'sumH'
+ for (int i = 0; i < checksumsize; i += w)
+ {
+ sumH += (checkPart & k);
+ checkPart >>>= w;
+ }
+ }// end if(w<57)
+
+ // calculate keysize
+ this.keysize = messagesize
+ + (int)Math.ceil((double)checksumsize / (double)w);
+
+ // calculate steps: 'keysize' times PRNG, 'sumH' times hashing,
+ // (1<intValue
.
+ *
+ * @param intValue an integer
+ * @return The least integer greater or equal to the logarithm to the base 2
+ * of intValue
+ */
+ public int getLog(int intValue)
+ {
+ int log = 1;
+ int i = 2;
+ while (i < intValue)
+ {
+ i <<= 1;
+ log++;
+ }
+ return log;
+ }
+
+ /**
+ * This method returns the status byte array
+ *
+ * @return statBytes
+ */
+ public byte[][] getStatByte()
+ {
+
+ byte[][] statByte = new byte[5][mdsize];
+ statByte[0] = privateKeyOTS;
+ statByte[1] = seed;
+ statByte[2] = hash;
+ statByte[3] = sign;
+ statByte[4] = this.getStatLong();
+
+ return statByte;
+ }
+
+ /**
+ * This method returns the status int array
+ *
+ * @return statInt
+ */
+ public int[] getStatInt()
+ {
+ int[] statInt = new int[9];
+ statInt[0] = counter;
+ statInt[1] = test;
+ statInt[2] = ii;
+ statInt[3] = r;
+ statInt[4] = steps;
+ statInt[5] = keysize;
+ statInt[6] = height;
+ statInt[7] = w;
+ statInt[8] = checksum;
+ return statInt;
+ }
+
+ /**
+ * Converts the long parameters into byte arrays to store it in
+ * statByte-Array
+ */
+ public byte[] getStatLong()
+ {
+ byte[] bytes = new byte[16];
+
+ bytes[0] = (byte)((test8) & 0xff);
+ bytes[1] = (byte)((test8 >> 8) & 0xff);
+ bytes[2] = (byte)((test8 >> 16) & 0xff);
+ bytes[3] = (byte)((test8 >> 24) & 0xff);
+ bytes[4] = (byte)((test8) >> 32 & 0xff);
+ bytes[5] = (byte)((test8 >> 40) & 0xff);
+ bytes[6] = (byte)((test8 >> 48) & 0xff);
+ bytes[7] = (byte)((test8 >> 56) & 0xff);
+
+ bytes[8] = (byte)((big8) & 0xff);
+ bytes[9] = (byte)((big8 >> 8) & 0xff);
+ bytes[10] = (byte)((big8 >> 16) & 0xff);
+ bytes[11] = (byte)((big8 >> 24) & 0xff);
+ bytes[12] = (byte)((big8) >> 32 & 0xff);
+ bytes[13] = (byte)((big8 >> 40) & 0xff);
+ bytes[14] = (byte)((big8 >> 48) & 0xff);
+ bytes[15] = (byte)((big8 >> 56) & 0xff);
+
+ return bytes;
+ }
+
+ /**
+ * returns a string representation of the instance
+ *
+ * @return a string representation of the instance
+ */
+ public String toString()
+ {
+ String out = "" + this.big8 + " ";
+ int[] statInt = new int[9];
+ statInt = this.getStatInt();
+ byte[][] statByte = new byte[5][mdsize];
+ statByte = this.getStatByte();
+ for (int i = 0; i < 9; i++)
+ {
+ out = out + statInt[i] + " ";
+ }
+ for (int i = 0; i < 5; i++)
+ {
+ out = out + new String(Hex.encode(statByte[i])) + " ";
+ }
+
+ return out;
+ }
+
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/gmss/GMSSSigner.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/gmss/GMSSSigner.java
new file mode 100644
index 0000000..51ec2f2
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/gmss/GMSSSigner.java
@@ -0,0 +1,403 @@
+package org.bc.pqc.crypto.gmss;
+
+import java.security.SecureRandom;
+
+import org.bc.crypto.CipherParameters;
+import org.bc.crypto.Digest;
+import org.bc.crypto.params.ParametersWithRandom;
+import org.bc.pqc.crypto.MessageSigner;
+import org.bc.pqc.crypto.gmss.util.GMSSRandom;
+import org.bc.pqc.crypto.gmss.util.GMSSUtil;
+import org.bc.pqc.crypto.gmss.util.WinternitzOTSVerify;
+import org.bc.pqc.crypto.gmss.util.WinternitzOTSignature;
+import org.bc.util.Arrays;
+
+/**
+ * This class implements the GMSS signature scheme.
+ */
+public class GMSSSigner
+ implements MessageSigner
+{
+
+ /**
+ * Instance of GMSSParameterSpec
+ */
+ //private GMSSParameterSpec gmssParameterSpec;
+
+ /**
+ * Instance of GMSSUtilities
+ */
+ private GMSSUtil gmssUtil = new GMSSUtil();
+
+
+ /**
+ * The raw GMSS public key
+ */
+ private byte[] pubKeyBytes;
+
+ /**
+ * Hash function for the construction of the authentication trees
+ */
+ private Digest messDigestTrees;
+
+ /**
+ * The length of the hash function output
+ */
+ private int mdLength;
+
+ /**
+ * The number of tree layers
+ */
+ private int numLayer;
+
+ /**
+ * The hash function used by the OTS
+ */
+ private Digest messDigestOTS;
+
+ /**
+ * An instance of the Winternitz one-time signature
+ */
+ private WinternitzOTSignature ots;
+
+ /**
+ * Array of strings containing the name of the hash function used by the OTS
+ * and the corresponding provider name
+ */
+ private GMSSDigestProvider digestProvider;
+
+ /**
+ * The current main tree and subtree indices
+ */
+ private int[] index;
+
+ /**
+ * Array of the authentication paths for the current trees of all layers
+ */
+ private byte[][][] currentAuthPaths;
+
+ /**
+ * The one-time signature of the roots of the current subtrees
+ */
+ private byte[][] subtreeRootSig;
+
+
+ /**
+ * The GMSSParameterset
+ */
+ private GMSSParameters gmssPS;
+
+ /**
+ * The PRNG
+ */
+ private GMSSRandom gmssRandom;
+
+ GMSSKeyParameters key;
+
+ // XXX needed? Source of randomness
+ private SecureRandom random;
+
+
+ /**
+ * The standard constructor tries to generate the MerkleTree Algorithm
+ * identifier with the corresponding OID.
+ *
+ * @param digest the digest to use
+ */
+ // TODO
+ public GMSSSigner(GMSSDigestProvider digest)
+ {
+ digestProvider = digest;
+ messDigestTrees = digest.get();
+ messDigestOTS = messDigestTrees;
+ mdLength = messDigestTrees.getDigestSize();
+ gmssRandom = new GMSSRandom(messDigestTrees);
+ }
+
+ public void init(boolean forSigning,
+ CipherParameters param)
+ {
+
+ if (forSigning)
+ {
+ if (param instanceof ParametersWithRandom)
+ {
+ ParametersWithRandom rParam = (ParametersWithRandom)param;
+
+ // XXX random needed?
+ this.random = rParam.getRandom();
+ this.key = (GMSSPrivateKeyParameters)rParam.getParameters();
+ initSign();
+
+ }
+ else
+ {
+
+ this.random = new SecureRandom();
+ this.key = (GMSSPrivateKeyParameters)param;
+ initSign();
+ }
+ }
+ else
+ {
+ this.key = (GMSSPublicKeyParameters)param;
+ initVerify();
+
+ }
+
+ }
+
+
+ /**
+ * Initializes the signature algorithm for signing a message.
+ */
+ private void initSign()
+ {
+
+ messDigestTrees.reset();
+ // set private key and take from it ots key, auth, tree and key
+ // counter, rootSign
+ GMSSPrivateKeyParameters gmssPrivateKey = (GMSSPrivateKeyParameters)key;
+
+ // check if last signature has been generated
+ if (gmssPrivateKey.getIndex(0) >= gmssPrivateKey.getNumLeafs(0))
+ {
+ throw new RuntimeException("No more signatures can be generated");
+ }
+
+ // get Parameterset
+ this.gmssPS = gmssPrivateKey.getParameters();
+ // get numLayer
+ this.numLayer = gmssPS.getNumOfLayers();
+
+ // get OTS Instance of lowest layer
+ byte[] seed = gmssPrivateKey.getCurrentSeeds()[numLayer - 1];
+ byte[] OTSSeed = new byte[mdLength];
+ byte[] dummy = new byte[mdLength];
+ System.arraycopy(seed, 0, dummy, 0, mdLength);
+ OTSSeed = gmssRandom.nextSeed(dummy); // secureRandom.nextBytes(currentSeeds[currentSeeds.length-1]);secureRandom.nextBytes(OTSseed);
+ this.ots = new WinternitzOTSignature(OTSSeed, digestProvider.get(), gmssPS.getWinternitzParameter()[numLayer - 1]);
+
+ byte[][][] helpCurrentAuthPaths = gmssPrivateKey.getCurrentAuthPaths();
+ currentAuthPaths = new byte[numLayer][][];
+
+ // copy the main tree authentication path
+ for (int j = 0; j < numLayer; j++)
+ {
+ currentAuthPaths[j] = new byte[helpCurrentAuthPaths[j].length][mdLength];
+ for (int i = 0; i < helpCurrentAuthPaths[j].length; i++)
+ {
+ System.arraycopy(helpCurrentAuthPaths[j][i], 0, currentAuthPaths[j][i], 0, mdLength);
+ }
+ }
+
+ // copy index
+ index = new int[numLayer];
+ System.arraycopy(gmssPrivateKey.getIndex(), 0, index, 0, numLayer);
+
+ // copy subtreeRootSig
+ byte[] helpSubtreeRootSig;
+ subtreeRootSig = new byte[numLayer - 1][];
+ for (int i = 0; i < numLayer - 1; i++)
+ {
+ helpSubtreeRootSig = gmssPrivateKey.getSubtreeRootSig(i);
+ subtreeRootSig[i] = new byte[helpSubtreeRootSig.length];
+ System.arraycopy(helpSubtreeRootSig, 0, subtreeRootSig[i], 0, helpSubtreeRootSig.length);
+ }
+
+ // change private key for next signature
+ gmssPrivateKey.nextKey(numLayer - 1);
+
+
+ }
+
+ /**
+ * Signs a message.
+ *
+ *
+ * @return the signature.
+ */
+ public byte[] generateSignature(byte[] message)
+ {
+
+ byte[] otsSig = new byte[mdLength];
+ byte[] authPathBytes;
+ byte[] indexBytes;
+
+ otsSig = ots.getSignature(message);
+
+ // get concatenated lowest layer tree authentication path
+ authPathBytes = gmssUtil.concatenateArray(currentAuthPaths[numLayer - 1]);
+
+ // put lowest layer index into a byte array
+ indexBytes = gmssUtil.intToBytesLittleEndian(index[numLayer - 1]);
+
+ // create first part of GMSS signature
+ byte[] gmssSigFirstPart = new byte[indexBytes.length + otsSig.length + authPathBytes.length];
+ System.arraycopy(indexBytes, 0, gmssSigFirstPart, 0, indexBytes.length);
+ System.arraycopy(otsSig, 0, gmssSigFirstPart, indexBytes.length, otsSig.length);
+ System.arraycopy(authPathBytes, 0, gmssSigFirstPart, (indexBytes.length + otsSig.length), authPathBytes.length);
+ // --- end first part
+
+ // --- next parts of the signature
+ // create initial array with length 0 for iteration
+ byte[] gmssSigNextPart = new byte[0];
+
+ for (int i = numLayer - 1 - 1; i >= 0; i--)
+ {
+
+ // get concatenated next tree authentication path
+ authPathBytes = gmssUtil.concatenateArray(currentAuthPaths[i]);
+
+ // put next tree index into a byte array
+ indexBytes = gmssUtil.intToBytesLittleEndian(index[i]);
+
+ // create next part of GMSS signature
+
+ // create help array and copy actual gmssSig into it
+ byte[] helpGmssSig = new byte[gmssSigNextPart.length];
+ System.arraycopy(gmssSigNextPart, 0, helpGmssSig, 0, gmssSigNextPart.length);
+ // adjust length of gmssSigNextPart for adding next part
+ gmssSigNextPart = new byte[helpGmssSig.length + indexBytes.length + subtreeRootSig[i].length + authPathBytes.length];
+
+ // copy old data (help array) and new data in gmssSigNextPart
+ System.arraycopy(helpGmssSig, 0, gmssSigNextPart, 0, helpGmssSig.length);
+ System.arraycopy(indexBytes, 0, gmssSigNextPart, helpGmssSig.length, indexBytes.length);
+ System.arraycopy(subtreeRootSig[i], 0, gmssSigNextPart, (helpGmssSig.length + indexBytes.length), subtreeRootSig[i].length);
+ System.arraycopy(authPathBytes, 0, gmssSigNextPart, (helpGmssSig.length + indexBytes.length + subtreeRootSig[i].length), authPathBytes.length);
+
+ }
+ // --- end next parts
+
+ // concatenate the two parts of the GMSS signature
+ byte[] gmssSig = new byte[gmssSigFirstPart.length + gmssSigNextPart.length];
+ System.arraycopy(gmssSigFirstPart, 0, gmssSig, 0, gmssSigFirstPart.length);
+ System.arraycopy(gmssSigNextPart, 0, gmssSig, gmssSigFirstPart.length, gmssSigNextPart.length);
+
+ // return the GMSS signature
+ return gmssSig;
+ }
+
+ /**
+ * Initializes the signature algorithm for verifying a signature.
+ */
+ private void initVerify()
+ {
+ messDigestTrees.reset();
+
+ GMSSPublicKeyParameters gmssPublicKey = (GMSSPublicKeyParameters)key;
+ pubKeyBytes = gmssPublicKey.getPublicKey();
+ gmssPS = gmssPublicKey.getParameters();
+ // get numLayer
+ this.numLayer = gmssPS.getNumOfLayers();
+
+
+ }
+
+ /**
+ * This function verifies the signature of the message that has been
+ * updated, with the aid of the public key.
+ *
+ * @param message the message
+ * @param signature the signature associated with the message
+ * @return true if the signature has been verified, false otherwise.
+ */
+ public boolean verifySignature(byte[] message, byte[] signature)
+ {
+
+ boolean success = false;
+ // int halfSigLength = signature.length >>> 1;
+ messDigestOTS.reset();
+ WinternitzOTSVerify otsVerify;
+ int otsSigLength;
+
+ byte[] help = message;
+
+ byte[] otsSig;
+ byte[] otsPublicKey;
+ byte[][] authPath;
+ byte[] dest;
+ int nextEntry = 0;
+ int index;
+ // Verify signature
+
+ // --- begin with message = 'message that was signed'
+ // and then in each step message = subtree root
+ for (int j = numLayer - 1; j >= 0; j--)
+ {
+ otsVerify = new WinternitzOTSVerify(digestProvider.get(), gmssPS.getWinternitzParameter()[j]);
+ otsSigLength = otsVerify.getSignatureLength();
+
+ message = help;
+ // get the subtree index
+ index = gmssUtil.bytesToIntLittleEndian(signature, nextEntry);
+
+ // 4 is the number of bytes in integer
+ nextEntry += 4;
+
+ // get one-time signature
+ otsSig = new byte[otsSigLength];
+ System.arraycopy(signature, nextEntry, otsSig, 0, otsSigLength);
+ nextEntry += otsSigLength;
+
+ // compute public OTS key from the one-time signature
+ otsPublicKey = otsVerify.Verify(message, otsSig);
+
+ // test if OTSsignature is correct
+ if (otsPublicKey == null)
+ {
+ System.err.println("OTS Public Key is null in GMSSSignature.verify");
+ return false;
+ }
+
+ // get authentication path from the signature
+ authPath = new byte[gmssPS.getHeightOfTrees()[j]][mdLength];
+ for (int i = 0; i < authPath.length; i++)
+ {
+ System.arraycopy(signature, nextEntry, authPath[i], 0, mdLength);
+ nextEntry = nextEntry + mdLength;
+ }
+
+ // compute the root of the subtree from the authentication path
+ help = new byte[mdLength];
+
+ help = otsPublicKey;
+
+ int count = 1 << authPath.length;
+ count = count + index;
+
+ for (int i = 0; i < authPath.length; i++)
+ {
+ dest = new byte[mdLength << 1];
+
+ if ((count % 2) == 0)
+ {
+ System.arraycopy(help, 0, dest, 0, mdLength);
+ System.arraycopy(authPath[i], 0, dest, mdLength, mdLength);
+ count = count / 2;
+ }
+ else
+ {
+ System.arraycopy(authPath[i], 0, dest, 0, mdLength);
+ System.arraycopy(help, 0, dest, mdLength, help.length);
+ count = (count - 1) / 2;
+ }
+ messDigestTrees.update(dest, 0, dest.length);
+ help = new byte[messDigestTrees.getDigestSize()];
+ messDigestTrees.doFinal(help, 0);
+ }
+ }
+
+ // now help contains the root of the maintree
+
+ // test if help is equal to the GMSS public key
+ if (Arrays.areEqual(pubKeyBytes, help))
+ {
+ success = true;
+ }
+
+ return success;
+ }
+
+
+}
\ No newline at end of file
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/gmss/GMSSUtils.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/gmss/GMSSUtils.java
new file mode 100644
index 0000000..444715d
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/gmss/GMSSUtils.java
@@ -0,0 +1,145 @@
+package org.bc.pqc.crypto.gmss;
+
+import java.util.Enumeration;
+import java.util.Vector;
+
+import org.bc.util.Arrays;
+
+class GMSSUtils
+{
+ static GMSSLeaf[] clone(GMSSLeaf[] data)
+ {
+ if (data == null)
+ {
+ return null;
+ }
+ GMSSLeaf[] copy = new GMSSLeaf[data.length];
+
+ System.arraycopy(data, 0, copy, 0, data.length);
+
+ return copy;
+ }
+
+ static GMSSRootCalc[] clone(GMSSRootCalc[] data)
+ {
+ if (data == null)
+ {
+ return null;
+ }
+ GMSSRootCalc[] copy = new GMSSRootCalc[data.length];
+
+ System.arraycopy(data, 0, copy, 0, data.length);
+
+ return copy;
+ }
+
+ static GMSSRootSig[] clone(GMSSRootSig[] data)
+ {
+ if (data == null)
+ {
+ return null;
+ }
+ GMSSRootSig[] copy = new GMSSRootSig[data.length];
+
+ System.arraycopy(data, 0, copy, 0, data.length);
+
+ return copy;
+ }
+
+ static byte[][] clone(byte[][] data)
+ {
+ if (data == null)
+ {
+ return null;
+ }
+ byte[][] copy = new byte[data.length][];
+
+ for (int i = 0; i != data.length; i++)
+ {
+ copy[i] = Arrays.clone(data[i]);
+ }
+
+ return copy;
+ }
+
+ static byte[][][] clone(byte[][][] data)
+ {
+ if (data == null)
+ {
+ return null;
+ }
+ byte[][][] copy = new byte[data.length][][];
+
+ for (int i = 0; i != data.length; i++)
+ {
+ copy[i] = clone(data[i]);
+ }
+
+ return copy;
+ }
+
+ static Treehash[] clone(Treehash[] data)
+ {
+ if (data == null)
+ {
+ return null;
+ }
+ Treehash[] copy = new Treehash[data.length];
+
+ System.arraycopy(data, 0, copy, 0, data.length);
+
+ return copy;
+ }
+
+ static Treehash[][] clone(Treehash[][] data)
+ {
+ if (data == null)
+ {
+ return null;
+ }
+ Treehash[][] copy = new Treehash[data.length][];
+
+ for (int i = 0; i != data.length; i++)
+ {
+ copy[i] = clone(data[i]);
+ }
+
+ return copy;
+ }
+
+ static Vector[] clone(Vector[] data)
+ {
+ if (data == null)
+ {
+ return null;
+ }
+ Vector[] copy = new Vector[data.length];
+
+ for (int i = 0; i != data.length; i++)
+ {
+ copy[i] = new Vector();
+ for (Enumeration en = data[i].elements(); en.hasMoreElements();)
+ {
+ copy[i].addElement(en.nextElement());
+ }
+ }
+
+ return copy;
+ }
+
+ static Vector[][] clone(Vector[][] data)
+ {
+ if (data == null)
+ {
+ return null;
+ }
+ Vector[][] copy = new Vector[data.length][];
+
+ for (int i = 0; i != data.length; i++)
+ {
+ copy[i] = clone(data[i]);
+ }
+
+ return copy;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/gmss/Treehash.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/gmss/Treehash.java
new file mode 100644
index 0000000..e1a483d
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/gmss/Treehash.java
@@ -0,0 +1,525 @@
+package org.bc.pqc.crypto.gmss;
+
+import java.util.Vector;
+
+import org.bc.crypto.Digest;
+import org.bc.pqc.crypto.gmss.util.GMSSRandom;
+import org.bc.util.Integers;
+import org.bc.util.encoders.Hex;
+
+
+/**
+ * This class implements a treehash instance for the Merkle tree traversal
+ * algorithm. The first node of the stack is stored in this instance itself,
+ * additional tail nodes are stored on a tailstack.
+ */
+public class Treehash
+{
+
+ /**
+ * max height of current treehash instance.
+ */
+ private int maxHeight;
+
+ /**
+ * Vector element that stores the nodes on the stack
+ */
+ private Vector tailStack;
+
+ /**
+ * Vector element that stores the height of the nodes on the stack
+ */
+ private Vector heightOfNodes;
+
+ /**
+ * the first node is stored in the treehash instance itself, not on stack
+ */
+ private byte[] firstNode;
+
+ /**
+ * seedActive needed for the actual node
+ */
+ private byte[] seedActive;
+
+ /**
+ * the seed needed for the next re-initialization of the treehash instance
+ */
+ private byte[] seedNext;
+
+ /**
+ * number of nodes stored on the stack and belonging to this treehash
+ * instance
+ */
+ private int tailLength;
+
+ /**
+ * the height in the tree of the first node stored in treehash
+ */
+ private int firstNodeHeight;
+
+ /**
+ * true if treehash instance was already initialized, false otherwise
+ */
+ private boolean isInitialized;
+
+ /**
+ * true if the first node's height equals the maxHeight of the treehash
+ */
+ private boolean isFinished;
+
+ /**
+ * true if the nextSeed has been initialized with index 3*2^h needed for the
+ * seed scheduling
+ */
+ private boolean seedInitialized;
+
+ /**
+ * denotes the Message Digest used by the tree to create nodes
+ */
+ private Digest messDigestTree;
+
+ /**
+ * This constructor regenerates a prior treehash object
+ *
+ * @param name an array of strings, containing the name of the used hash
+ * function and PRNG and the name of the corresponding provider
+ * @param statByte status bytes
+ * @param statInt status ints
+ */
+ public Treehash(Digest name, byte[][] statByte, int[] statInt)
+ {
+ this.messDigestTree = name;
+
+ // decode statInt
+ this.maxHeight = statInt[0];
+ this.tailLength = statInt[1];
+ this.firstNodeHeight = statInt[2];
+
+ if (statInt[3] == 1)
+ {
+ this.isFinished = true;
+ }
+ else
+ {
+ this.isFinished = false;
+ }
+ if (statInt[4] == 1)
+ {
+ this.isInitialized = true;
+ }
+ else
+ {
+ this.isInitialized = false;
+ }
+ if (statInt[5] == 1)
+ {
+ this.seedInitialized = true;
+ }
+ else
+ {
+ this.seedInitialized = false;
+ }
+
+ this.heightOfNodes = new Vector();
+ for (int i = 0; i < tailLength; i++)
+ {
+ this.heightOfNodes.addElement(Integers.valueOf(statInt[6 + i]));
+ }
+
+ // decode statByte
+ this.firstNode = statByte[0];
+ this.seedActive = statByte[1];
+ this.seedNext = statByte[2];
+
+ this.tailStack = new Vector();
+ for (int i = 0; i < tailLength; i++)
+ {
+ this.tailStack.addElement(statByte[3 + i]);
+ }
+ }
+
+ /**
+ * Constructor
+ *
+ * @param tailStack a vector element where the stack nodes are stored
+ * @param maxHeight maximal height of the treehash instance
+ * @param digest an array of strings, containing the name of the used hash
+ * function and PRNG and the name of the corresponding provider
+ */
+ public Treehash(Vector tailStack, int maxHeight, Digest digest)
+ {
+ this.tailStack = tailStack;
+ this.maxHeight = maxHeight;
+ this.firstNode = null;
+ this.isInitialized = false;
+ this.isFinished = false;
+ this.seedInitialized = false;
+ this.messDigestTree = digest;
+
+ this.seedNext = new byte[messDigestTree.getDigestSize()];
+ this.seedActive = new byte[messDigestTree.getDigestSize()];
+ }
+
+ /**
+ * Method to initialize the seeds needed for the precomputation of right
+ * nodes. Should be initialized with index 3*2^i for treehash_i
+ *
+ * @param seedIn
+ */
+ public void initializeSeed(byte[] seedIn)
+ {
+ System.arraycopy(seedIn, 0, this.seedNext, 0, this.messDigestTree
+ .getDigestSize());
+ this.seedInitialized = true;
+ }
+
+ /**
+ * initializes the treehash instance. The seeds must already have been
+ * initialized to work correctly.
+ */
+ public void initialize()
+ {
+ if (!this.seedInitialized)
+ {
+ System.err.println("Seed " + this.maxHeight + " not initialized");
+ return;
+ }
+
+ this.heightOfNodes = new Vector();
+ this.tailLength = 0;
+ this.firstNode = null;
+ this.firstNodeHeight = -1;
+ this.isInitialized = true;
+ System.arraycopy(this.seedNext, 0, this.seedActive, 0, messDigestTree
+ .getDigestSize());
+ }
+
+ /**
+ * Calculates one update of the treehash instance, i.e. creates a new leaf
+ * and hashes if possible
+ *
+ * @param gmssRandom an instance of the PRNG
+ * @param leaf The byte value of the leaf needed for the update
+ */
+ public void update(GMSSRandom gmssRandom, byte[] leaf)
+ {
+
+ if (this.isFinished)
+ {
+ System.err
+ .println("No more update possible for treehash instance!");
+ return;
+ }
+ if (!this.isInitialized)
+ {
+ System.err
+ .println("Treehash instance not initialized before update");
+ return;
+ }
+
+ byte[] help = new byte[this.messDigestTree.getDigestSize()];
+ int helpHeight = -1;
+
+ gmssRandom.nextSeed(this.seedActive);
+
+ // if treehash gets first update
+ if (this.firstNode == null)
+ {
+ this.firstNode = leaf;
+ this.firstNodeHeight = 0;
+ }
+ else
+ {
+ // store the new node in help array, do not push it on the stack
+ help = leaf;
+ helpHeight = 0;
+
+ // hash the nodes on the stack if possible
+ while (this.tailLength > 0
+ && helpHeight == ((Integer)heightOfNodes.lastElement())
+ .intValue())
+ {
+ // put top element of the stack and help node in array
+ // 'tobehashed'
+ // and hash them together, put result again in help array
+ byte[] toBeHashed = new byte[this.messDigestTree
+ .getDigestSize() << 1];
+
+ // pop element from stack
+ System.arraycopy(this.tailStack.lastElement(), 0, toBeHashed,
+ 0, this.messDigestTree.getDigestSize());
+ this.tailStack.removeElementAt(this.tailStack.size() - 1);
+ this.heightOfNodes
+ .removeElementAt(this.heightOfNodes.size() - 1);
+
+ System.arraycopy(help, 0, toBeHashed, this.messDigestTree
+ .getDigestSize(), this.messDigestTree
+ .getDigestSize());
+ messDigestTree.update(toBeHashed, 0, toBeHashed.length);
+ help = new byte[messDigestTree.getDigestSize()];
+ messDigestTree.doFinal(help, 0);
+
+ // increase help height, stack was reduced by one element
+ helpHeight++;
+ this.tailLength--;
+ }
+
+ // push the new node on the stack
+ this.tailStack.addElement(help);
+ this.heightOfNodes.addElement(Integers.valueOf(helpHeight));
+ this.tailLength++;
+
+ // finally check whether the top node on stack and the first node
+ // in treehash have same height. If so hash them together
+ // and store them in treehash
+ if (((Integer)heightOfNodes.lastElement()).intValue() == this.firstNodeHeight)
+ {
+ byte[] toBeHashed = new byte[this.messDigestTree
+ .getDigestSize() << 1];
+ System.arraycopy(this.firstNode, 0, toBeHashed, 0,
+ this.messDigestTree.getDigestSize());
+
+ // pop element from tailStack and copy it into help2 array
+ System.arraycopy(this.tailStack.lastElement(), 0, toBeHashed,
+ this.messDigestTree.getDigestSize(),
+ this.messDigestTree.getDigestSize());
+ this.tailStack.removeElementAt(this.tailStack.size() - 1);
+ this.heightOfNodes
+ .removeElementAt(this.heightOfNodes.size() - 1);
+
+ // store new element in firstNode, stack is then empty
+ messDigestTree.update(toBeHashed, 0, toBeHashed.length);
+ this.firstNode = new byte[messDigestTree.getDigestSize()];
+ messDigestTree.doFinal(this.firstNode, 0);
+ this.firstNodeHeight++;
+
+ // empty the stack
+ this.tailLength = 0;
+ }
+ }
+
+ // check if treehash instance is completed
+ if (this.firstNodeHeight == this.maxHeight)
+ {
+ this.isFinished = true;
+ }
+ }
+
+ /**
+ * Destroys a treehash instance after the top node was taken for
+ * authentication path.
+ */
+ public void destroy()
+ {
+ this.isInitialized = false;
+ this.isFinished = false;
+ this.firstNode = null;
+ this.tailLength = 0;
+ this.firstNodeHeight = -1;
+ }
+
+ /**
+ * Returns the height of the lowest node stored either in treehash or on the
+ * stack. It must not be set to infinity (as mentioned in the paper) because
+ * this cases are considered in the computeAuthPaths method of
+ * JDKGMSSPrivateKey
+ *
+ * @return Height of the lowest node
+ */
+ public int getLowestNodeHeight()
+ {
+ if (this.firstNode == null)
+ {
+ return this.maxHeight;
+ }
+ else if (this.tailLength == 0)
+ {
+ return this.firstNodeHeight;
+ }
+ else
+ {
+ return Math.min(this.firstNodeHeight, ((Integer)heightOfNodes
+ .lastElement()).intValue());
+ }
+ }
+
+ /**
+ * Returns the top node height
+ *
+ * @return Height of the first node, the top node
+ */
+ public int getFirstNodeHeight()
+ {
+ if (firstNode == null)
+ {
+ return maxHeight;
+ }
+ return firstNodeHeight;
+ }
+
+ /**
+ * Method to check whether the instance has been initialized or not
+ *
+ * @return true if treehash was already initialized
+ */
+ public boolean wasInitialized()
+ {
+ return this.isInitialized;
+ }
+
+ /**
+ * Method to check whether the instance has been finished or not
+ *
+ * @return true if treehash has reached its maximum height
+ */
+ public boolean wasFinished()
+ {
+ return this.isFinished;
+ }
+
+ /**
+ * returns the first node stored in treehash instance itself
+ *
+ * @return the first node stored in treehash instance itself
+ */
+ public byte[] getFirstNode()
+ {
+ return this.firstNode;
+ }
+
+ /**
+ * returns the active seed
+ *
+ * @return the active seed
+ */
+ public byte[] getSeedActive()
+ {
+ return this.seedActive;
+ }
+
+ /**
+ * This method sets the first node stored in the treehash instance itself
+ *
+ * @param hash
+ */
+ public void setFirstNode(byte[] hash)
+ {
+ if (!this.isInitialized)
+ {
+ this.initialize();
+ }
+ this.firstNode = hash;
+ this.firstNodeHeight = this.maxHeight;
+ this.isFinished = true;
+ }
+
+ /**
+ * updates the nextSeed of this treehash instance one step needed for the
+ * schedulng of the seeds
+ *
+ * @param gmssRandom the prng used for the seeds
+ */
+ public void updateNextSeed(GMSSRandom gmssRandom)
+ {
+ gmssRandom.nextSeed(seedNext);
+ }
+
+ /**
+ * Returns the tailstack
+ *
+ * @return the tailstack
+ */
+ public Vector getTailStack()
+ {
+ return this.tailStack;
+ }
+
+ /**
+ * Returns the status byte array used by the GMSSPrivateKeyASN.1 class
+ *
+ * @return The status bytes
+ */
+ public byte[][] getStatByte()
+ {
+
+ byte[][] statByte = new byte[3 + tailLength][this.messDigestTree
+ .getDigestSize()];
+ statByte[0] = firstNode;
+ statByte[1] = seedActive;
+ statByte[2] = seedNext;
+ for (int i = 0; i < tailLength; i++)
+ {
+ statByte[3 + i] = (byte[])tailStack.elementAt(i);
+ }
+ return statByte;
+ }
+
+ /**
+ * Returns the status int array used by the GMSSPrivateKeyASN.1 class
+ *
+ * @return The status ints
+ */
+ public int[] getStatInt()
+ {
+
+ int[] statInt = new int[6 + tailLength];
+ statInt[0] = maxHeight;
+ statInt[1] = tailLength;
+ statInt[2] = firstNodeHeight;
+ if (this.isFinished)
+ {
+ statInt[3] = 1;
+ }
+ else
+ {
+ statInt[3] = 0;
+ }
+ if (this.isInitialized)
+ {
+ statInt[4] = 1;
+ }
+ else
+ {
+ statInt[4] = 0;
+ }
+ if (this.seedInitialized)
+ {
+ statInt[5] = 1;
+ }
+ else
+ {
+ statInt[5] = 0;
+ }
+ for (int i = 0; i < tailLength; i++)
+ {
+ statInt[6 + i] = ((Integer)heightOfNodes.elementAt(i)).intValue();
+ }
+ return statInt;
+ }
+
+ /**
+ * returns a String representation of the treehash instance
+ */
+ public String toString()
+ {
+ String out = "Treehash : ";
+ for (int i = 0; i < 6 + tailLength; i++)
+ {
+ out = out + this.getStatInt()[i] + " ";
+ }
+ for (int i = 0; i < 3 + tailLength; i++)
+ {
+ if (this.getStatByte()[i] != null)
+ {
+ out = out + new String(Hex.encode((this.getStatByte()[i]))) + " ";
+ }
+ else
+ {
+ out = out + "null ";
+ }
+ }
+ out = out + " " + this.messDigestTree.getDigestSize();
+ return out;
+ }
+
+}
\ No newline at end of file
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/gmss/util/GMSSRandom.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/gmss/util/GMSSRandom.java
new file mode 100644
index 0000000..b6db5c9
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/gmss/util/GMSSRandom.java
@@ -0,0 +1,78 @@
+package org.bc.pqc.crypto.gmss.util;
+
+import org.bc.crypto.Digest;
+
+/**
+ * This class provides a PRNG for GMSS
+ */
+public class GMSSRandom
+{
+ /**
+ * Hash function for the construction of the authentication trees
+ */
+ private Digest messDigestTree;
+
+ /**
+ * Constructor
+ *
+ * @param messDigestTree2
+ */
+ public GMSSRandom(Digest messDigestTree2)
+ {
+
+ this.messDigestTree = messDigestTree2;
+ }
+
+ /**
+ * computes the next seed value, returns a random byte array and sets
+ * outseed to the next value
+ *
+ * @param outseed byte array in which ((1 + SEEDin +RAND) mod 2^n) will be
+ * stored
+ * @return byte array of H(SEEDin)
+ */
+ public byte[] nextSeed(byte[] outseed)
+ {
+ // RAND <-- H(SEEDin)
+ byte[] rand = new byte[outseed.length];
+ messDigestTree.update(outseed, 0, outseed.length);
+ rand = new byte[messDigestTree.getDigestSize()];
+ messDigestTree.doFinal(rand, 0);
+
+ // SEEDout <-- (1 + SEEDin +RAND) mod 2^n
+ addByteArrays(outseed, rand);
+ addOne(outseed);
+
+ // System.arraycopy(outseed, 0, outseed, 0, outseed.length);
+
+ return rand;
+ }
+
+ private void addByteArrays(byte[] a, byte[] b)
+ {
+
+ byte overflow = 0;
+ int temp;
+
+ for (int i = 0; i < a.length; i++)
+ {
+ temp = (0xFF & a[i]) + (0xFF & b[i]) + overflow;
+ a[i] = (byte)temp;
+ overflow = (byte)(temp >> 8);
+ }
+ }
+
+ private void addOne(byte[] a)
+ {
+
+ byte overflow = 1;
+ int temp;
+
+ for (int i = 0; i < a.length; i++)
+ {
+ temp = (0xFF & a[i]) + overflow;
+ a[i] = (byte)temp;
+ overflow = (byte)(temp >> 8);
+ }
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/gmss/util/GMSSUtil.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/gmss/util/GMSSUtil.java
new file mode 100644
index 0000000..cc63ca9
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/gmss/util/GMSSUtil.java
@@ -0,0 +1,151 @@
+package org.bc.pqc.crypto.gmss.util;
+
+/**
+ * This class provides several methods that are required by the GMSS classes.
+ */
+public class GMSSUtil
+{
+ /**
+ * Converts a 32 bit integer into a byte array beginning at
+ * offset
(little-endian representation)
+ *
+ * @param value the integer to convert
+ */
+ public byte[] intToBytesLittleEndian(int value)
+ {
+ byte[] bytes = new byte[4];
+
+ bytes[0] = (byte)((value) & 0xff);
+ bytes[1] = (byte)((value >> 8) & 0xff);
+ bytes[2] = (byte)((value >> 16) & 0xff);
+ bytes[3] = (byte)((value >> 24) & 0xff);
+ return bytes;
+ }
+
+ /**
+ * Converts a byte array beginning at offset
into a 32 bit
+ * integer (little-endian representation)
+ *
+ * @param bytes the byte array
+ * @return The resulting integer
+ */
+ public int bytesToIntLittleEndian(byte[] bytes)
+ {
+
+ return ((bytes[0] & 0xff)) | ((bytes[1] & 0xff) << 8)
+ | ((bytes[2] & 0xff) << 16) | ((bytes[3] & 0xff)) << 24;
+ }
+
+ /**
+ * Converts a byte array beginning at offset
into a 32 bit
+ * integer (little-endian representation)
+ *
+ * @param bytes the byte array
+ * @param offset the integer offset into the byte array
+ * @return The resulting integer
+ */
+ public int bytesToIntLittleEndian(byte[] bytes, int offset)
+ {
+ return ((bytes[offset++] & 0xff)) | ((bytes[offset++] & 0xff) << 8)
+ | ((bytes[offset++] & 0xff) << 16)
+ | ((bytes[offset] & 0xff)) << 24;
+ }
+
+ /**
+ * This method concatenates a 2-dimensional byte array into a 1-dimensional
+ * byte array
+ *
+ * @param arraycp a 2-dimensional byte array.
+ * @return 1-dimensional byte array with concatenated input array
+ */
+ public byte[] concatenateArray(byte[][] arraycp)
+ {
+ byte[] dest = new byte[arraycp.length * arraycp[0].length];
+ int indx = 0;
+ for (int i = 0; i < arraycp.length; i++)
+ {
+ System.arraycopy(arraycp[i], 0, dest, indx, arraycp[i].length);
+ indx = indx + arraycp[i].length;
+ }
+ return dest;
+ }
+
+ /**
+ * This method prints the values of a 2-dimensional byte array
+ *
+ * @param text a String
+ * @param array a 2-dimensional byte array
+ */
+ public void printArray(String text, byte[][] array)
+ {
+ System.out.println(text);
+ int counter = 0;
+ for (int i = 0; i < array.length; i++)
+ {
+ for (int j = 0; j < array[0].length; j++)
+ {
+ System.out.println(counter + "; " + array[i][j]);
+ counter++;
+ }
+ }
+ }
+
+ /**
+ * This method prints the values of a 1-dimensional byte array
+ *
+ * @param text a String
+ * @param array a 1-dimensional byte array.
+ */
+ public void printArray(String text, byte[] array)
+ {
+ System.out.println(text);
+ int counter = 0;
+ for (int i = 0; i < array.length; i++)
+ {
+ System.out.println(counter + "; " + array[i]);
+ counter++;
+ }
+ }
+
+ /**
+ * This method tests if an integer is a power of 2.
+ *
+ * @param testValue an integer
+ * @return TRUE
if testValue
is a power of 2,
+ * FALSE
otherwise
+ */
+ public boolean testPowerOfTwo(int testValue)
+ {
+ int a = 1;
+ while (a < testValue)
+ {
+ a <<= 1;
+ }
+ if (testValue == a)
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * This method returns the least integer that is greater or equal to the
+ * logarithm to the base 2 of an integer intValue
.
+ *
+ * @param intValue an integer
+ * @return The least integer greater or equal to the logarithm to the base 2
+ * of intValue
+ */
+ public int getLog(int intValue)
+ {
+ int log = 1;
+ int i = 2;
+ while (i < intValue)
+ {
+ i <<= 1;
+ log++;
+ }
+ return log;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/gmss/util/WinternitzOTSVerify.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/gmss/util/WinternitzOTSVerify.java
new file mode 100644
index 0000000..8175670
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/gmss/util/WinternitzOTSVerify.java
@@ -0,0 +1,345 @@
+package org.bc.pqc.crypto.gmss.util;
+
+import org.bc.crypto.Digest;
+
+/**
+ * This class implements signature verification of the Winternitz one-time
+ * signature scheme (OTSS), described in C.Dods, N.P. Smart, and M. Stam, "Hash
+ * Based Digital Signature Schemes", LNCS 3796, pages 96–115, 2005. The
+ * class is used by the GMSS classes.
+ */
+public class WinternitzOTSVerify
+{
+
+ private Digest messDigestOTS;
+
+ /**
+ * The Winternitz parameter
+ */
+ private int w;
+
+ /**
+ * The constructor
+ *
+ *
+ * @param digest the name of the hash function used by the OTS and the provider
+ * name of the hash function
+ * @param w the Winternitz parameter
+ */
+ public WinternitzOTSVerify(Digest digest, int w)
+ {
+ this.w = w;
+
+ messDigestOTS = digest;
+ }
+
+ /**
+ * @return The length of the one-time signature
+ */
+ public int getSignatureLength()
+ {
+ int mdsize = messDigestOTS.getDigestSize();
+ int size = ((mdsize << 3) + (w - 1)) / w;
+ int logs = getLog((size << w) + 1);
+ size += (logs + w - 1) / w;
+
+ return mdsize * size;
+ }
+
+ /**
+ * This method computes the public OTS key from the one-time signature of a
+ * message. This is *NOT* a complete OTS signature verification, but it
+ * suffices for usage with CMSS.
+ *
+ * @param message the message
+ * @param signature the one-time signature
+ * @return The public OTS key
+ */
+ public byte[] Verify(byte[] message, byte[] signature)
+ {
+
+ int mdsize = messDigestOTS.getDigestSize();
+ byte[] hash = new byte[mdsize]; // hash of message m
+
+ // create hash of message m
+ messDigestOTS.update(message, 0, message.length);
+ hash = new byte[messDigestOTS.getDigestSize()];
+ messDigestOTS.doFinal(hash, 0);
+
+ int size = ((mdsize << 3) + (w - 1)) / w;
+ int logs = getLog((size << w) + 1);
+ int keysize = size + (logs + w - 1) / w;
+
+ int testKeySize = mdsize * keysize;
+
+ if (testKeySize != signature.length)
+ {
+ return null;
+ }
+
+ byte[] testKey = new byte[testKeySize];
+
+ int c = 0;
+ int counter = 0;
+ int test;
+
+ if (8 % w == 0)
+ {
+ int d = 8 / w;
+ int k = (1 << w) - 1;
+ byte[] hlp = new byte[mdsize];
+
+ // verify signature
+ for (int i = 0; i < hash.length; i++)
+ {
+ for (int j = 0; j < d; j++)
+ {
+ test = hash[i] & k;
+ c += test;
+
+ System.arraycopy(signature, counter * mdsize, hlp, 0, mdsize);
+
+ while (test < k)
+ {
+ messDigestOTS.update(hlp, 0, hlp.length);
+ hlp = new byte[messDigestOTS.getDigestSize()];
+ messDigestOTS.doFinal(hlp, 0);
+ test++;
+ }
+
+ System.arraycopy(hlp, 0, testKey, counter * mdsize, mdsize);
+ hash[i] = (byte)(hash[i] >>> w);
+ counter++;
+ }
+ }
+
+ c = (size << w) - c;
+ for (int i = 0; i < logs; i += w)
+ {
+ test = c & k;
+
+ System.arraycopy(signature, counter * mdsize, hlp, 0, mdsize);
+
+ while (test < k)
+ {
+ messDigestOTS.update(hlp, 0, hlp.length);
+ hlp = new byte[messDigestOTS.getDigestSize()];
+ messDigestOTS.doFinal(hlp, 0);
+ test++;
+ }
+ System.arraycopy(hlp, 0, testKey, counter * mdsize, mdsize);
+ c >>>= w;
+ counter++;
+ }
+ }
+ else if (w < 8)
+ {
+ int d = mdsize / w;
+ int k = (1 << w) - 1;
+ byte[] hlp = new byte[mdsize];
+ long big8;
+ int ii = 0;
+ // create signature
+ // first d*w bytes of hash
+ for (int i = 0; i < d; i++)
+ {
+ big8 = 0;
+ for (int j = 0; j < w; j++)
+ {
+ big8 ^= (hash[ii] & 0xff) << (j << 3);
+ ii++;
+ }
+ for (int j = 0; j < 8; j++)
+ {
+ test = (int)(big8 & k);
+ c += test;
+
+ System.arraycopy(signature, counter * mdsize, hlp, 0, mdsize);
+
+ while (test < k)
+ {
+ messDigestOTS.update(hlp, 0, hlp.length);
+ hlp = new byte[messDigestOTS.getDigestSize()];
+ messDigestOTS.doFinal(hlp, 0);
+ test++;
+ }
+
+ System.arraycopy(hlp, 0, testKey, counter * mdsize, mdsize);
+ big8 >>>= w;
+ counter++;
+ }
+ }
+ // rest of hash
+ d = mdsize % w;
+ big8 = 0;
+ for (int j = 0; j < d; j++)
+ {
+ big8 ^= (hash[ii] & 0xff) << (j << 3);
+ ii++;
+ }
+ d <<= 3;
+ for (int j = 0; j < d; j += w)
+ {
+ test = (int)(big8 & k);
+ c += test;
+
+ System.arraycopy(signature, counter * mdsize, hlp, 0, mdsize);
+
+ while (test < k)
+ {
+ messDigestOTS.update(hlp, 0, hlp.length);
+ hlp = new byte[messDigestOTS.getDigestSize()];
+ messDigestOTS.doFinal(hlp, 0);
+ test++;
+ }
+
+ System.arraycopy(hlp, 0, testKey, counter * mdsize, mdsize);
+ big8 >>>= w;
+ counter++;
+ }
+
+ // check bytes
+ c = (size << w) - c;
+ for (int i = 0; i < logs; i += w)
+ {
+ test = c & k;
+
+ System.arraycopy(signature, counter * mdsize, hlp, 0, mdsize);
+
+ while (test < k)
+ {
+ messDigestOTS.update(hlp, 0, hlp.length);
+ hlp = new byte[messDigestOTS.getDigestSize()];
+ messDigestOTS.doFinal(hlp, 0);
+ test++;
+ }
+
+ System.arraycopy(hlp, 0, testKey, counter * mdsize, mdsize);
+ c >>>= w;
+ counter++;
+ }
+ }// end if(w<8)
+ else if (w < 57)
+ {
+ int d = (mdsize << 3) - w;
+ int k = (1 << w) - 1;
+ byte[] hlp = new byte[mdsize];
+ long big8, test8;
+ int r = 0;
+ int s, f, rest, ii;
+ // create signature
+ // first a*w bits of hash where a*w <= 8*mdsize < (a+1)*w
+ while (r <= d)
+ {
+ s = r >>> 3;
+ rest = r % 8;
+ r += w;
+ f = (r + 7) >>> 3;
+ big8 = 0;
+ ii = 0;
+ for (int j = s; j < f; j++)
+ {
+ big8 ^= (hash[j] & 0xff) << (ii << 3);
+ ii++;
+ }
+
+ big8 >>>= rest;
+ test8 = (big8 & k);
+ c += test8;
+
+ System.arraycopy(signature, counter * mdsize, hlp, 0, mdsize);
+
+ while (test8 < k)
+ {
+ messDigestOTS.update(hlp, 0, hlp.length);
+ hlp = new byte[messDigestOTS.getDigestSize()];
+ messDigestOTS.doFinal(hlp, 0);
+ test8++;
+ }
+
+ System.arraycopy(hlp, 0, testKey, counter * mdsize, mdsize);
+ counter++;
+
+ }
+ // rest of hash
+ s = r >>> 3;
+ if (s < mdsize)
+ {
+ rest = r % 8;
+ big8 = 0;
+ ii = 0;
+ for (int j = s; j < mdsize; j++)
+ {
+ big8 ^= (hash[j] & 0xff) << (ii << 3);
+ ii++;
+ }
+
+ big8 >>>= rest;
+ test8 = (big8 & k);
+ c += test8;
+
+ System.arraycopy(signature, counter * mdsize, hlp, 0, mdsize);
+
+ while (test8 < k)
+ {
+ messDigestOTS.update(hlp, 0, hlp.length);
+ hlp = new byte[messDigestOTS.getDigestSize()];
+ messDigestOTS.doFinal(hlp, 0);
+ test8++;
+ }
+
+ System.arraycopy(hlp, 0, testKey, counter * mdsize, mdsize);
+ counter++;
+ }
+ // check bytes
+ c = (size << w) - c;
+ for (int i = 0; i < logs; i += w)
+ {
+ test8 = (c & k);
+
+ System.arraycopy(signature, counter * mdsize, hlp, 0, mdsize);
+
+ while (test8 < k)
+ {
+ messDigestOTS.update(hlp, 0, hlp.length);
+ hlp = new byte[messDigestOTS.getDigestSize()];
+ messDigestOTS.doFinal(hlp, 0);
+ test8++;
+ }
+
+ System.arraycopy(hlp, 0, testKey, counter * mdsize, mdsize);
+ c >>>= w;
+ counter++;
+ }
+ }// end if(w<57)
+
+ byte[] TKey = new byte[mdsize];
+ messDigestOTS.update(testKey, 0, testKey.length);
+ TKey = new byte[messDigestOTS.getDigestSize()];
+ messDigestOTS.doFinal(TKey, 0);
+
+ return TKey;
+
+ }
+
+ /**
+ * This method returns the least integer that is greater or equal to the
+ * logarithm to the base 2 of an integer intValue
.
+ *
+ * @param intValue an integer
+ * @return The least integer greater or equal to the logarithm to the base
+ * 256 of intValue
+ */
+ public int getLog(int intValue)
+ {
+ int log = 1;
+ int i = 2;
+ while (i < intValue)
+ {
+ i <<= 1;
+ log++;
+ }
+ return log;
+ }
+
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/gmss/util/WinternitzOTSignature.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/gmss/util/WinternitzOTSignature.java
new file mode 100644
index 0000000..b0a9f58
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/gmss/util/WinternitzOTSignature.java
@@ -0,0 +1,405 @@
+package org.bc.pqc.crypto.gmss.util;
+
+import org.bc.crypto.Digest;
+
+/**
+ * This class implements key pair generation and signature generation of the
+ * Winternitz one-time signature scheme (OTSS), described in C.Dods, N.P. Smart,
+ * and M. Stam, "Hash Based Digital Signature Schemes", LNCS 3796, pages
+ * 96–115, 2005. The class is used by the GMSS classes.
+ */
+
+public class WinternitzOTSignature
+{
+
+ /**
+ * The hash function used by the OTS
+ */
+ private Digest messDigestOTS;
+
+ /**
+ * The length of the message digest and private key
+ */
+ private int mdsize, keysize;
+
+ /**
+ * An array of strings, containing the name of the used hash function, the
+ * name of the PRGN and the names of the corresponding providers
+ */
+ // private String[] name = new String[2];
+ /**
+ * The private key
+ */
+ private byte[][] privateKeyOTS;
+
+ /**
+ * The Winternitz parameter
+ */
+ private int w;
+
+ /**
+ * The source of randomness for OTS private key generation
+ */
+ private GMSSRandom gmssRandom;
+
+ /**
+ * Sizes of the message and the checksum, both
+ */
+ private int messagesize, checksumsize;
+
+ /**
+ * The constructor generates an OTS key pair, using seed0
and
+ * the PRNG
+ *
+ *
+ * @param seed0 the seed for the PRGN
+ * @param digest an array of strings, containing the name of the used hash
+ * function, the name of the PRGN and the names of the
+ * corresponding providers
+ * @param w the Winternitz parameter
+ */
+ public WinternitzOTSignature(byte[] seed0, Digest digest, int w)
+ {
+ // this.name = name;
+ this.w = w;
+
+ messDigestOTS = digest;
+
+ gmssRandom = new GMSSRandom(messDigestOTS);
+
+ // calulate keysize for private and public key and also the help
+ // array
+
+ mdsize = messDigestOTS.getDigestSize();
+ int mdsizeBit = mdsize << 3;
+ messagesize = (int)Math.ceil((double)(mdsizeBit) / (double)w);
+
+ checksumsize = getLog((messagesize << w) + 1);
+
+ keysize = messagesize
+ + (int)Math.ceil((double)checksumsize / (double)w);
+
+ /*
+ * mdsize = messDigestOTS.getDigestLength(); messagesize =
+ * ((mdsize<<3)+(w-1))/w;
+ *
+ * checksumsize = getlog((messagesize<intValue
.
+ *
+ * @param intValue an integer
+ * @return The least integer greater or equal to the logarithm to the base 2
+ * of intValue
+ */
+ public int getLog(int intValue)
+ {
+ int log = 1;
+ int i = 2;
+ while (i < intValue)
+ {
+ i <<= 1;
+ log++;
+ }
+ return log;
+ }
+
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/mceliece/Conversions.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/mceliece/Conversions.java
new file mode 100644
index 0000000..fd5a468
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/mceliece/Conversions.java
@@ -0,0 +1,236 @@
+package org.bc.pqc.crypto.mceliece;
+
+import java.math.BigInteger;
+
+import org.bc.pqc.math.linearalgebra.BigIntUtils;
+import org.bc.pqc.math.linearalgebra.GF2Vector;
+import org.bc.pqc.math.linearalgebra.IntegerFunctions;
+
+
+/**
+ * Provides methods for CCA2-Secure Conversions of McEliece PKCS
+ */
+final class Conversions
+{
+ private static final BigInteger ZERO = BigInteger.valueOf(0);
+ private static final BigInteger ONE = BigInteger.valueOf(1);
+
+ /**
+ * Default constructor (private).
+ */
+ private Conversions()
+ {
+ }
+
+ /**
+ * Encode a number between 0 and (n|t) (binomial coefficient) into a binary
+ * vector of length n with weight t. The number is given as a byte array.
+ * Only the first s bits are used, where s = floor[log(n|t)].
+ *
+ * @param n integer
+ * @param t integer
+ * @param m the message as a byte array
+ * @return the encoded message as {@link GF2Vector}
+ */
+ public static GF2Vector encode(final int n, final int t, final byte[] m)
+ {
+ if (n < t)
+ {
+ throw new IllegalArgumentException("n < t");
+ }
+
+ // compute the binomial c = (n|t)
+ BigInteger c = IntegerFunctions.binomial(n, t);
+ // get the number encoded in m
+ BigInteger i = new BigInteger(1, m);
+ // compare
+ if (i.compareTo(c) >= 0)
+ {
+ throw new IllegalArgumentException("Encoded number too large.");
+ }
+
+ GF2Vector result = new GF2Vector(n);
+
+ int nn = n;
+ int tt = t;
+ for (int j = 0; j < n; j++)
+ {
+ c = c.multiply(BigInteger.valueOf(nn - tt)).divide(
+ BigInteger.valueOf(nn));
+ nn--;
+ if (c.compareTo(i) <= 0)
+ {
+ result.setBit(j);
+ i = i.subtract(c);
+ tt--;
+ if (nn == tt)
+ {
+ c = ONE;
+ }
+ else
+ {
+ c = (c.multiply(BigInteger.valueOf(tt + 1)))
+ .divide(BigInteger.valueOf(nn - tt));
+ }
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Decode a binary vector of length n and weight t into a number between 0
+ * and (n|t) (binomial coefficient). The result is given as a byte array of
+ * length floor[(s+7)/8], where s = floor[log(n|t)].
+ *
+ * @param n integer
+ * @param t integer
+ * @param vec the binary vector
+ * @return the decoded vector as a byte array
+ */
+ public static byte[] decode(int n, int t, GF2Vector vec)
+ {
+ if ((vec.getLength() != n) || (vec.getHammingWeight() != t))
+ {
+ throw new IllegalArgumentException(
+ "vector has wrong length or hamming weight");
+ }
+ int[] vecArray = vec.getVecArray();
+
+ BigInteger bc = IntegerFunctions.binomial(n, t);
+ BigInteger d = ZERO;
+ int nn = n;
+ int tt = t;
+ for (int i = 0; i < n; i++)
+ {
+ bc = bc.multiply(BigInteger.valueOf(nn - tt)).divide(
+ BigInteger.valueOf(nn));
+ nn--;
+
+ int q = i >> 5;
+ int e = vecArray[q] & (1 << (i & 0x1f));
+ if (e != 0)
+ {
+ d = d.add(bc);
+ tt--;
+ if (nn == tt)
+ {
+ bc = ONE;
+ }
+ else
+ {
+ bc = bc.multiply(BigInteger.valueOf(tt + 1)).divide(
+ BigInteger.valueOf(nn - tt));
+ }
+
+ }
+ }
+
+ return BigIntUtils.toMinimalByteArray(d);
+ }
+
+ /**
+ * Compute a message representative of a message given as a vector of length
+ * n bit and of hamming weight t. The result is a
+ * byte array of length (s+7)/8, where
+ * s = floor[log(n|t)].
+ *
+ * @param n integer
+ * @param t integer
+ * @param m the message vector as a byte array
+ * @return a message representative for m
+ */
+ public static byte[] signConversion(int n, int t, byte[] m)
+ {
+ if (n < t)
+ {
+ throw new IllegalArgumentException("n < t");
+ }
+
+ BigInteger bc = IntegerFunctions.binomial(n, t);
+ // finds s = floor[log(binomial(n,t))]
+ int s = bc.bitLength() - 1;
+ // s = sq*8 + sr;
+ int sq = s >> 3;
+ int sr = s & 7;
+ if (sr == 0)
+ {
+ sq--;
+ sr = 8;
+ }
+
+ // n = nq*8+nr;
+ int nq = n >> 3;
+ int nr = n & 7;
+ if (nr == 0)
+ {
+ nq--;
+ nr = 8;
+ }
+ // take s bit from m
+ byte[] data = new byte[nq + 1];
+ if (m.length < data.length)
+ {
+ System.arraycopy(m, 0, data, 0, m.length);
+ for (int i = m.length; i < data.length; i++)
+ {
+ data[i] = 0;
+ }
+ }
+ else
+ {
+ System.arraycopy(m, 0, data, 0, nq);
+ int h = (1 << nr) - 1;
+ data[nq] = (byte)(h & m[nq]);
+ }
+
+ BigInteger d = ZERO;
+ int nn = n;
+ int tt = t;
+ for (int i = 0; i < n; i++)
+ {
+ bc = (bc.multiply(new BigInteger(Integer.toString(nn - tt))))
+ .divide(new BigInteger(Integer.toString(nn)));
+ nn--;
+
+ int q = i >>> 3;
+ int r = i & 7;
+ r = 1 << r;
+ byte e = (byte)(r & data[q]);
+ if (e != 0)
+ {
+ d = d.add(bc);
+ tt--;
+ if (nn == tt)
+ {
+ bc = ONE;
+ }
+ else
+ {
+ bc = (bc
+ .multiply(new BigInteger(Integer.toString(tt + 1))))
+ .divide(new BigInteger(Integer.toString(nn - tt)));
+ }
+ }
+ }
+
+ byte[] result = new byte[sq + 1];
+ byte[] help = d.toByteArray();
+ if (help.length < result.length)
+ {
+ System.arraycopy(help, 0, result, 0, help.length);
+ for (int i = help.length; i < result.length; i++)
+ {
+ result[i] = 0;
+ }
+ }
+ else
+ {
+ System.arraycopy(help, 0, result, 0, sq);
+ result[sq] = (byte)(((1 << sr) - 1) & help[sq]);
+ }
+
+ return result;
+ }
+
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/mceliece/McElieceCCA2KeyGenerationParameters.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/mceliece/McElieceCCA2KeyGenerationParameters.java
new file mode 100644
index 0000000..3778317
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/mceliece/McElieceCCA2KeyGenerationParameters.java
@@ -0,0 +1,25 @@
+package org.bc.pqc.crypto.mceliece;
+
+import java.security.SecureRandom;
+
+import org.bc.crypto.KeyGenerationParameters;
+
+public class McElieceCCA2KeyGenerationParameters
+ extends KeyGenerationParameters
+{
+ private McElieceCCA2Parameters params;
+
+ public McElieceCCA2KeyGenerationParameters(
+ SecureRandom random,
+ McElieceCCA2Parameters params)
+ {
+ // XXX key size?
+ super(random, 128);
+ this.params = params;
+ }
+
+ public McElieceCCA2Parameters getParameters()
+ {
+ return params;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/mceliece/McElieceCCA2KeyPairGenerator.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/mceliece/McElieceCCA2KeyPairGenerator.java
new file mode 100644
index 0000000..b24f57f
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/mceliece/McElieceCCA2KeyPairGenerator.java
@@ -0,0 +1,119 @@
+package org.bc.pqc.crypto.mceliece;
+
+
+import java.security.SecureRandom;
+
+import org.bc.crypto.AsymmetricCipherKeyPair;
+import org.bc.crypto.AsymmetricCipherKeyPairGenerator;
+import org.bc.crypto.KeyGenerationParameters;
+import org.bc.pqc.math.linearalgebra.GF2Matrix;
+import org.bc.pqc.math.linearalgebra.GF2mField;
+import org.bc.pqc.math.linearalgebra.GoppaCode;
+import org.bc.pqc.math.linearalgebra.Permutation;
+import org.bc.pqc.math.linearalgebra.PolynomialGF2mSmallM;
+import org.bc.pqc.math.linearalgebra.PolynomialRingGF2m;
+import org.bc.pqc.math.linearalgebra.GoppaCode.MaMaPe;
+
+
+/**
+ * This class implements key pair generation of the McEliece Public Key
+ * Cryptosystem (McEliecePKC).
+ */
+public class McElieceCCA2KeyPairGenerator
+ implements AsymmetricCipherKeyPairGenerator
+{
+
+
+ /**
+ * The OID of the algorithm.
+ */
+ public static final String OID = "1.3.6.1.4.1.8301.3.1.3.4.2";
+
+ private McElieceCCA2KeyGenerationParameters mcElieceCCA2Params;
+
+ // the extension degree of the finite field GF(2^m)
+ private int m;
+
+ // the length of the code
+ private int n;
+
+ // the error correction capability
+ private int t;
+
+ // the field polynomial
+ private int fieldPoly;
+
+ // the source of randomness
+ private SecureRandom random;
+
+ // flag indicating whether the key pair generator has been initialized
+ private boolean initialized = false;
+
+ /**
+ * Default initialization of the key pair generator.
+ */
+ private void initializeDefault()
+ {
+ McElieceCCA2KeyGenerationParameters mcCCA2Params = new McElieceCCA2KeyGenerationParameters(new SecureRandom(), new McElieceCCA2Parameters());
+ init(mcCCA2Params);
+ }
+
+ // TODO
+ public void init(
+ KeyGenerationParameters param)
+ {
+ this.mcElieceCCA2Params = (McElieceCCA2KeyGenerationParameters)param;
+
+ // set source of randomness
+ this.random = new SecureRandom();
+
+ this.m = this.mcElieceCCA2Params.getParameters().getM();
+ this.n = this.mcElieceCCA2Params.getParameters().getN();
+ this.t = this.mcElieceCCA2Params.getParameters().getT();
+ this.fieldPoly = this.mcElieceCCA2Params.getParameters().getFieldPoly();
+ this.initialized = true;
+ }
+
+
+ public AsymmetricCipherKeyPair generateKeyPair()
+ {
+
+ if (!initialized)
+ {
+ initializeDefault();
+ }
+
+ // finite field GF(2^m)
+ GF2mField field = new GF2mField(m, fieldPoly);
+
+ // irreducible Goppa polynomial
+ PolynomialGF2mSmallM gp = new PolynomialGF2mSmallM(field, t,
+ PolynomialGF2mSmallM.RANDOM_IRREDUCIBLE_POLYNOMIAL, random);
+ PolynomialRingGF2m ring = new PolynomialRingGF2m(field, gp);
+
+ // matrix for computing square roots in (GF(2^m))^t
+ PolynomialGF2mSmallM[] qInv = ring.getSquareRootMatrix();
+
+ // generate canonical check matrix
+ GF2Matrix h = GoppaCode.createCanonicalCheckMatrix(field, gp);
+
+ // compute short systematic form of check matrix
+ MaMaPe mmp = GoppaCode.computeSystematicForm(h, random);
+ GF2Matrix shortH = mmp.getSecondMatrix();
+ Permutation p = mmp.getPermutation();
+
+ // compute short systematic form of generator matrix
+ GF2Matrix shortG = (GF2Matrix)shortH.computeTranspose();
+
+ // obtain number of rows of G (= dimension of the code)
+ int k = shortG.getNumRows();
+
+ // generate keys
+ McElieceCCA2PublicKeyParameters pubKey = new McElieceCCA2PublicKeyParameters(OID, n, t, shortG, mcElieceCCA2Params.getParameters());
+ McElieceCCA2PrivateKeyParameters privKey = new McElieceCCA2PrivateKeyParameters(OID, n, k,
+ field, gp, p, h, qInv, mcElieceCCA2Params.getParameters());
+
+ // return key pair
+ return new AsymmetricCipherKeyPair(pubKey, privKey);
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/mceliece/McElieceCCA2KeyParameters.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/mceliece/McElieceCCA2KeyParameters.java
new file mode 100644
index 0000000..3a157f2
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/mceliece/McElieceCCA2KeyParameters.java
@@ -0,0 +1,25 @@
+package org.bc.pqc.crypto.mceliece;
+
+import org.bc.crypto.params.AsymmetricKeyParameter;
+
+
+public class McElieceCCA2KeyParameters
+ extends AsymmetricKeyParameter
+{
+ private McElieceCCA2Parameters params;
+
+ public McElieceCCA2KeyParameters(
+ boolean isPrivate,
+ McElieceCCA2Parameters params)
+ {
+ super(isPrivate);
+ this.params = params;
+ }
+
+
+ public McElieceCCA2Parameters getParameters()
+ {
+ return params;
+ }
+
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/mceliece/McElieceCCA2Parameters.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/mceliece/McElieceCCA2Parameters.java
new file mode 100644
index 0000000..c21d987
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/mceliece/McElieceCCA2Parameters.java
@@ -0,0 +1,51 @@
+package org.bc.pqc.crypto.mceliece;
+
+
+import org.bc.crypto.Digest;
+import org.bc.crypto.digests.SHA256Digest;
+
+/**
+ * This class provides a specification for the parameters of the CCA2-secure
+ * variants of the McEliece PKCS that are used with
+ * {@link McElieceFujisakiCipher}, {@link McElieceKobaraImaiCipher}, and
+ * {@link McEliecePointchevalCipher}.
+ *
+ * @see McElieceFujisakiCipher
+ * @see McElieceKobaraImaiCipher
+ * @see McEliecePointchevalCipher
+ */
+public class McElieceCCA2Parameters
+ extends McElieceParameters
+{
+
+
+ public Digest digest;
+
+
+ /**
+ * Construct the default parameters.
+ * The default message digest is SHA256.
+ */
+ public McElieceCCA2Parameters()
+ {
+ this.digest = new SHA256Digest();
+ }
+
+ public McElieceCCA2Parameters(int m, int t)
+ {
+ super(m, t);
+ this.digest = new SHA256Digest();
+ }
+
+ public McElieceCCA2Parameters(Digest digest)
+ {
+ this.digest = digest;
+ }
+
+ public Digest getDigest()
+ {
+ return this.digest;
+ }
+
+
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/mceliece/McElieceCCA2Primitives.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/mceliece/McElieceCCA2Primitives.java
new file mode 100644
index 0000000..ae309b5
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/mceliece/McElieceCCA2Primitives.java
@@ -0,0 +1,86 @@
+package org.bc.pqc.crypto.mceliece;
+
+import org.bc.pqc.math.linearalgebra.GF2Matrix;
+import org.bc.pqc.math.linearalgebra.GF2Vector;
+import org.bc.pqc.math.linearalgebra.GF2mField;
+import org.bc.pqc.math.linearalgebra.GoppaCode;
+import org.bc.pqc.math.linearalgebra.Permutation;
+import org.bc.pqc.math.linearalgebra.PolynomialGF2mSmallM;
+import org.bc.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 m*G + 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 c = m*G + z
+ * @return the message vector m and the error vector z
+ */
+ 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/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/mceliece/McElieceCCA2PrivateKeyParameters.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/mceliece/McElieceCCA2PrivateKeyParameters.java
new file mode 100644
index 0000000..6db5bef
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/mceliece/McElieceCCA2PrivateKeyParameters.java
@@ -0,0 +1,172 @@
+package org.bc.pqc.crypto.mceliece;
+
+
+import org.bc.pqc.math.linearalgebra.GF2Matrix;
+import org.bc.pqc.math.linearalgebra.GF2mField;
+import org.bc.pqc.math.linearalgebra.Permutation;
+import org.bc.pqc.math.linearalgebra.PolynomialGF2mSmallM;
+
+/**
+ *
+ *
+ *
+ */
+public class McElieceCCA2PrivateKeyParameters
+ extends McElieceCCA2KeyParameters
+{
+
+ // the OID of the algorithm
+ private String oid;
+
+ // the length of the code
+ private int n;
+
+ // the dimension of the code
+ 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;
+
+ /**
+ * Constructor.
+ *
+ * @param n the length of the code
+ * @param k the dimension of the code
+ * @param field the finite field GF(2m)
+ * @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
+ * (GF(2^m))^t
+ * @param params McElieceCCA2Parameters
+ */
+ public McElieceCCA2PrivateKeyParameters(String oid, int n, int k, GF2mField field,
+ PolynomialGF2mSmallM gp, Permutation p, GF2Matrix h,
+ PolynomialGF2mSmallM[] qInv, McElieceCCA2Parameters params)
+ {
+ super(true, params);
+ 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 McElieceKeyFactory}.
+ *
+ * @param n the length of the code
+ * @param k the dimension of the code
+ * @param encFieldPoly the encoded field polynomial defining the finite field
+ * GF(2m)
+ * @param encGoppaPoly the encoded irreducible Goppa polynomial
+ * @param encP the encoded permutation
+ * @param encH the encoded canonical check matrix
+ * @param encQInv the encoded matrix used to compute square roots in
+ * (GF(2^m))^t
+ * @param params McElieceCCA2Parameters
+ */
+ public McElieceCCA2PrivateKeyParameters(String oid, int n, int k, byte[] encFieldPoly,
+ byte[] encGoppaPoly, byte[] encP, byte[] encH, byte[][] encQInv, McElieceCCA2Parameters params)
+ {
+ super(true, params);
+ this.oid = oid;
+ this.n = n;
+ this.k = k;
+ field = new GF2mField(encFieldPoly);
+ goppaPoly = new PolynomialGF2mSmallM(field, encGoppaPoly);
+ p = new Permutation(encP);
+ h = new GF2Matrix(encH);
+ qInv = new PolynomialGF2mSmallM[encQInv.length];
+ for (int i = 0; i < encQInv.length; i++)
+ {
+ qInv[i] = new PolynomialGF2mSmallM(field, encQInv[i]);
+ }
+ }
+
+ /**
+ * @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 P
+ */
+ public Permutation getP()
+ {
+ return p;
+ }
+
+ /**
+ * @return the canonical check matrix H
+ */
+ public GF2Matrix getH()
+ {
+ return h;
+ }
+
+ /**
+ * @return the matrix used to compute square roots in (GF(2^m))^t
+ */
+ public PolynomialGF2mSmallM[] getQInv()
+ {
+ return qInv;
+ }
+
+ public String getOIDString()
+ {
+ return oid;
+
+ }
+
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/mceliece/McElieceCCA2PublicKeyParameters.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/mceliece/McElieceCCA2PublicKeyParameters.java
new file mode 100644
index 0000000..6803907
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/mceliece/McElieceCCA2PublicKeyParameters.java
@@ -0,0 +1,97 @@
+package org.bc.pqc.crypto.mceliece;
+
+import org.bc.pqc.math.linearalgebra.GF2Matrix;
+
+/**
+ *
+ *
+ *
+ */
+public class McElieceCCA2PublicKeyParameters
+ extends McElieceCCA2KeyParameters
+{
+
+ // 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 matrixG;
+
+ /**
+ * Constructor.
+ *
+ * @param n length of the code
+ * @param t error correction capability
+ * @param matrix generator matrix
+ * @param params McElieceCCA2Parameters
+ */
+ public McElieceCCA2PublicKeyParameters(String oid, int n, int t, GF2Matrix matrix, McElieceCCA2Parameters params)
+ {
+ super(false, params);
+ this.oid = oid;
+ this.n = n;
+ this.t = t;
+ this.matrixG = new GF2Matrix(matrix);
+ }
+
+ /**
+ * Constructor (used by {@link McElieceKeyFactory}).
+ *
+ * @param n length of the code
+ * @param t error correction capability of the code
+ * @param encMatrix encoded generator matrix
+ * @param params McElieceCCA2Parameters
+ */
+ public McElieceCCA2PublicKeyParameters(String oid, int n, int t, byte[] encMatrix, McElieceCCA2Parameters params)
+ {
+ super(false, params);
+ this.oid = oid;
+ this.n = n;
+ this.t = t;
+ this.matrixG = new GF2Matrix(encMatrix);
+ }
+
+ /**
+ * @return the length of the code
+ */
+ public int getN()
+ {
+ return n;
+ }
+
+ /**
+ * @return the error correction capability of the code
+ */
+ public int getT()
+ {
+ return t;
+ }
+
+ /**
+ * @return the generator matrix
+ */
+ public GF2Matrix getMatrixG()
+ {
+ return matrixG;
+ }
+
+ /**
+ * @return the dimension of the code
+ */
+ public int getK()
+ {
+ return matrixG.getNumRows();
+ }
+
+ public String getOIDString()
+ {
+ return oid;
+
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/mceliece/McElieceFujisakiCipher.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/mceliece/McElieceFujisakiCipher.java
new file mode 100644
index 0000000..2d78230
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/mceliece/McElieceFujisakiCipher.java
@@ -0,0 +1,218 @@
+package org.bc.pqc.crypto.mceliece;
+
+import java.security.SecureRandom;
+
+import org.bc.crypto.CipherParameters;
+import org.bc.crypto.Digest;
+import org.bc.crypto.digests.SHA1Digest;
+import org.bc.crypto.params.ParametersWithRandom;
+import org.bc.crypto.prng.DigestRandomGenerator;
+import org.bc.pqc.crypto.MessageEncryptor;
+import org.bc.pqc.math.linearalgebra.ByteUtils;
+import org.bc.pqc.math.linearalgebra.GF2Vector;
+
+/**
+ * This class implements the Fujisaki/Okamoto conversion of the McEliecePKCS.
+ * Fujisaki and Okamoto propose hybrid encryption that merges a symmetric
+ * encryption scheme which is secure in the find-guess model with an asymmetric
+ * one-way encryption scheme which is sufficiently probabilistic to obtain a
+ * public key cryptosystem which is CCA2-secure. For details, see D. Engelbert,
+ * R. Overbeck, A. Schmidt, "A summary of the development of the McEliece
+ * Cryptosystem", technical report.
+ */
+public class McElieceFujisakiCipher
+ implements MessageEncryptor
+{
+
+
+ /**
+ * The OID of the algorithm.
+ */
+ public static final String OID = "1.3.6.1.4.1.8301.3.1.3.4.2.1";
+
+ private static final String DEFAULT_PRNG_NAME = "SHA1PRNG";
+
+ private Digest messDigest;
+
+ private SecureRandom sr;
+
+ /**
+ * The McEliece main parameters
+ */
+ private int n, k, t;
+
+ McElieceCCA2KeyParameters key;
+
+
+ public void init(boolean forSigning,
+ CipherParameters param)
+ {
+
+ if (forSigning)
+ {
+ if (param instanceof ParametersWithRandom)
+ {
+ ParametersWithRandom rParam = (ParametersWithRandom)param;
+
+ this.sr = rParam.getRandom();
+ this.key = (McElieceCCA2PublicKeyParameters)rParam.getParameters();
+ this.initCipherEncrypt((McElieceCCA2PublicKeyParameters)key);
+
+ }
+ else
+ {
+ this.sr = new SecureRandom();
+ this.key = (McElieceCCA2PublicKeyParameters)param;
+ this.initCipherEncrypt((McElieceCCA2PublicKeyParameters)key);
+ }
+ }
+ else
+ {
+ this.key = (McElieceCCA2PrivateKeyParameters)param;
+ this.initCipherDecrypt((McElieceCCA2PrivateKeyParameters)key);
+ }
+
+ }
+
+
+ public int getKeySize(McElieceCCA2KeyParameters key)
+ throws IllegalArgumentException
+ {
+
+ if (key instanceof McElieceCCA2PublicKeyParameters)
+ {
+ return ((McElieceCCA2PublicKeyParameters)key).getN();
+
+ }
+ if (key instanceof McElieceCCA2PrivateKeyParameters)
+ {
+ return ((McElieceCCA2PrivateKeyParameters)key).getN();
+ }
+ throw new IllegalArgumentException("unsupported type");
+
+ }
+
+
+ private void initCipherEncrypt(McElieceCCA2PublicKeyParameters pubKey)
+ {
+ this.sr = sr != null ? sr : new SecureRandom();
+ this.messDigest = pubKey.getParameters().getDigest();
+ n = pubKey.getN();
+ k = pubKey.getK();
+ t = pubKey.getT();
+ }
+
+
+ public void initCipherDecrypt(McElieceCCA2PrivateKeyParameters privKey)
+ {
+ this.messDigest = privKey.getParameters().getDigest();
+ n = privKey.getN();
+ t = privKey.getT();
+ }
+
+
+ public byte[] messageEncrypt(byte[] input)
+ throws Exception
+ {
+
+ // generate random vector r of length k bits
+ GF2Vector r = new GF2Vector(k, sr);
+
+ // convert r to byte array
+ byte[] rBytes = r.getEncoded();
+
+ // compute (r||input)
+ byte[] rm = ByteUtils.concatenate(rBytes, input);
+
+ // compute H(r||input)
+ messDigest.update(rm, 0, rm.length);
+ byte[] hrm = new byte[messDigest.getDigestSize()];
+ messDigest.doFinal(hrm, 0);
+
+ // convert H(r||input) to error vector z
+ GF2Vector z = Conversions.encode(n, t, hrm);
+
+ // compute c1 = E(r, z)
+ byte[] c1 = McElieceCCA2Primitives.encryptionPrimitive((McElieceCCA2PublicKeyParameters)key, r, z)
+ .getEncoded();
+
+ // get PRNG object
+ DigestRandomGenerator sr0 = new DigestRandomGenerator(new SHA1Digest());
+
+ // seed PRNG with r'
+ sr0.addSeedMaterial(rBytes);
+
+ // generate random c2
+ byte[] c2 = new byte[input.length];
+ sr0.nextBytes(c2);
+
+ // XOR with input
+ for (int i = 0; i < input.length; i++)
+ {
+ c2[i] ^= input[i];
+ }
+
+ // return (c1||c2)
+ return ByteUtils.concatenate(c1, c2);
+ }
+
+ public byte[] messageDecrypt(byte[] input)
+ throws Exception
+ {
+
+ int c1Len = (n + 7) >> 3;
+ int c2Len = input.length - c1Len;
+
+ // split ciphertext (c1||c2)
+ byte[][] c1c2 = ByteUtils.split(input, c1Len);
+ byte[] c1 = c1c2[0];
+ byte[] c2 = c1c2[1];
+
+ // decrypt c1 ...
+ GF2Vector hrmVec = GF2Vector.OS2VP(n, c1);
+ GF2Vector[] decC1 = McElieceCCA2Primitives.decryptionPrimitive((McElieceCCA2PrivateKeyParameters)key,
+ hrmVec);
+ byte[] rBytes = decC1[0].getEncoded();
+ // ... and obtain error vector z
+ GF2Vector z = decC1[1];
+
+ // get PRNG object
+ DigestRandomGenerator sr0 = new DigestRandomGenerator(new SHA1Digest());
+
+ // seed PRNG with r'
+ sr0.addSeedMaterial(rBytes);
+
+ // generate random sequence
+ byte[] mBytes = new byte[c2Len];
+ sr0.nextBytes(mBytes);
+
+ // XOR with c2 to obtain m
+ for (int i = 0; i < c2Len; i++)
+ {
+ mBytes[i] ^= c2[i];
+ }
+
+ // compute H(r||m)
+ byte[] rmBytes = ByteUtils.concatenate(rBytes, mBytes);
+ byte[] hrm = new byte[messDigest.getDigestSize()];
+ messDigest.update(rmBytes, 0, rmBytes.length);
+ messDigest.doFinal(hrm, 0);
+
+
+ // compute Conv(H(r||m))
+ hrmVec = Conversions.encode(n, t, hrm);
+
+ // check that Conv(H(m||r)) = z
+ if (!hrmVec.equals(z))
+ {
+
+ throw new Exception("Bad Padding: invalid ciphertext");
+
+ }
+
+ // return plaintext m
+ return mBytes;
+ }
+
+
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/mceliece/McElieceFujisakiDigestCipher.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/mceliece/McElieceFujisakiDigestCipher.java
new file mode 100644
index 0000000..70fbc8f
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/mceliece/McElieceFujisakiDigestCipher.java
@@ -0,0 +1,128 @@
+package org.bc.pqc.crypto.mceliece;
+
+
+import org.bc.crypto.CipherParameters;
+import org.bc.crypto.Digest;
+import org.bc.crypto.params.AsymmetricKeyParameter;
+import org.bc.crypto.params.ParametersWithRandom;
+import org.bc.pqc.crypto.MessageEncryptor;
+
+// TODO should implement some interface?
+public class McElieceFujisakiDigestCipher
+{
+
+ private final Digest messDigest;
+
+ private final MessageEncryptor mcElieceCCA2Cipher;
+
+ private boolean forEncrypting;
+
+
+ public McElieceFujisakiDigestCipher(MessageEncryptor mcElieceCCA2Cipher, Digest messDigest)
+ {
+ this.mcElieceCCA2Cipher = mcElieceCCA2Cipher;
+ this.messDigest = messDigest;
+ }
+
+
+ public void init(boolean forEncrypting,
+ CipherParameters param)
+ {
+
+ this.forEncrypting = forEncrypting;
+ AsymmetricKeyParameter k;
+
+ if (param instanceof ParametersWithRandom)
+ {
+ k = (AsymmetricKeyParameter)((ParametersWithRandom)param).getParameters();
+ }
+ else
+ {
+ k = (AsymmetricKeyParameter)param;
+ }
+
+ if (forEncrypting && k.isPrivate())
+ {
+ throw new IllegalArgumentException("Encrypting Requires Public Key.");
+ }
+
+ if (!forEncrypting && !k.isPrivate())
+ {
+ throw new IllegalArgumentException("Decrypting Requires Private Key.");
+ }
+
+ reset();
+
+ mcElieceCCA2Cipher.init(forEncrypting, param);
+ }
+
+
+ public byte[] messageEncrypt()
+ {
+ if (!forEncrypting)
+ {
+ throw new IllegalStateException("McElieceFujisakiDigestCipher not initialised for encrypting.");
+ }
+
+ byte[] hash = new byte[messDigest.getDigestSize()];
+ messDigest.doFinal(hash, 0);
+ byte[] enc = null;
+
+ try
+ {
+ enc = mcElieceCCA2Cipher.messageEncrypt(hash);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+
+
+ return enc;
+ }
+
+
+ public byte[] messageDecrypt(byte[] ciphertext)
+ {
+ byte[] output = null;
+ if (forEncrypting)
+ {
+ throw new IllegalStateException("McElieceFujisakiDigestCipher not initialised for decrypting.");
+ }
+
+
+ try
+ {
+ output = mcElieceCCA2Cipher.messageDecrypt(ciphertext);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+
+
+ return output;
+ }
+
+
+ public void update(byte b)
+ {
+ messDigest.update(b);
+
+ }
+
+ public void update(byte[] in, int off, int len)
+ {
+ messDigest.update(in, off, len);
+
+ }
+
+
+ public void reset()
+ {
+ messDigest.reset();
+
+ }
+
+
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/mceliece/McElieceKeyGenerationParameters.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/mceliece/McElieceKeyGenerationParameters.java
new file mode 100644
index 0000000..a762e10
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/mceliece/McElieceKeyGenerationParameters.java
@@ -0,0 +1,25 @@
+package org.bc.pqc.crypto.mceliece;
+
+import java.security.SecureRandom;
+
+import org.bc.crypto.KeyGenerationParameters;
+
+public class McElieceKeyGenerationParameters
+ extends KeyGenerationParameters
+{
+ private McElieceParameters params;
+
+ public McElieceKeyGenerationParameters(
+ SecureRandom random,
+ McElieceParameters params)
+ {
+ // XXX key size?
+ super(random, 256);
+ this.params = params;
+ }
+
+ public McElieceParameters getParameters()
+ {
+ return params;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/mceliece/McElieceKeyPairGenerator.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/mceliece/McElieceKeyPairGenerator.java
new file mode 100644
index 0000000..94aa017
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/mceliece/McElieceKeyPairGenerator.java
@@ -0,0 +1,151 @@
+package org.bc.pqc.crypto.mceliece;
+
+import java.security.SecureRandom;
+
+import org.bc.crypto.AsymmetricCipherKeyPair;
+import org.bc.crypto.AsymmetricCipherKeyPairGenerator;
+import org.bc.crypto.KeyGenerationParameters;
+import org.bc.pqc.math.linearalgebra.GF2Matrix;
+import org.bc.pqc.math.linearalgebra.GF2mField;
+import org.bc.pqc.math.linearalgebra.GoppaCode;
+import org.bc.pqc.math.linearalgebra.Permutation;
+import org.bc.pqc.math.linearalgebra.PolynomialGF2mSmallM;
+import org.bc.pqc.math.linearalgebra.PolynomialRingGF2m;
+import org.bc.pqc.math.linearalgebra.GoppaCode.MaMaPe;
+
+
+/**
+ * This class implements key pair generation of the McEliece Public Key
+ * Cryptosystem (McEliecePKC).
+ */
+public class McElieceKeyPairGenerator
+ implements AsymmetricCipherKeyPairGenerator
+{
+
+
+ public McElieceKeyPairGenerator()
+ {
+
+ }
+
+
+ /**
+ * The OID of the algorithm.
+ */
+ private static final String OID = "1.3.6.1.4.1.8301.3.1.3.4.1";
+
+ private McElieceKeyGenerationParameters mcElieceParams;
+
+ // the extension degree of the finite field GF(2^m)
+ private int m;
+
+ // the length of the code
+ private int n;
+
+ // the error correction capability
+ private int t;
+
+ // the field polynomial
+ private int fieldPoly;
+
+ // the source of randomness
+ private SecureRandom random;
+
+ // flag indicating whether the key pair generator has been initialized
+ private boolean initialized = false;
+
+
+ /**
+ * Default initialization of the key pair generator.
+ */
+ private void initializeDefault()
+ {
+ McElieceKeyGenerationParameters mcParams = new McElieceKeyGenerationParameters(new SecureRandom(), new McElieceParameters());
+ initialize(mcParams);
+ }
+
+ private void initialize(
+ KeyGenerationParameters param)
+ {
+ this.mcElieceParams = (McElieceKeyGenerationParameters)param;
+
+ // set source of randomness
+ this.random = new SecureRandom();
+
+ this.m = this.mcElieceParams.getParameters().getM();
+ this.n = this.mcElieceParams.getParameters().getN();
+ this.t = this.mcElieceParams.getParameters().getT();
+ this.fieldPoly = this.mcElieceParams.getParameters().getFieldPoly();
+ this.initialized = true;
+ }
+
+
+ private AsymmetricCipherKeyPair genKeyPair()
+ {
+
+ if (!initialized)
+ {
+ initializeDefault();
+ }
+
+ // finite field GF(2^m)
+ GF2mField field = new GF2mField(m, fieldPoly);
+
+ // irreducible Goppa polynomial
+ PolynomialGF2mSmallM gp = new PolynomialGF2mSmallM(field, t,
+ PolynomialGF2mSmallM.RANDOM_IRREDUCIBLE_POLYNOMIAL, random);
+ PolynomialRingGF2m ring = new PolynomialRingGF2m(field, gp);
+
+ // matrix used to compute square roots in (GF(2^m))^t
+ PolynomialGF2mSmallM[] sqRootMatrix = ring.getSquareRootMatrix();
+
+ // generate canonical check matrix
+ GF2Matrix h = GoppaCode.createCanonicalCheckMatrix(field, gp);
+
+ // compute short systematic form of check matrix
+ MaMaPe mmp = GoppaCode.computeSystematicForm(h, random);
+ GF2Matrix shortH = mmp.getSecondMatrix();
+ Permutation p1 = mmp.getPermutation();
+
+ // compute short systematic form of generator matrix
+ GF2Matrix shortG = (GF2Matrix)shortH.computeTranspose();
+
+ // extend to full systematic form
+ GF2Matrix gPrime = shortG.extendLeftCompactForm();
+
+ // obtain number of rows of G (= dimension of the code)
+ int k = shortG.getNumRows();
+
+ // generate random invertible (k x k)-matrix S and its inverse S^-1
+ GF2Matrix[] matrixSandInverse = GF2Matrix
+ .createRandomRegularMatrixAndItsInverse(k, random);
+
+ // generate random permutation P2
+ Permutation p2 = new Permutation(n, random);
+
+ // compute public matrix G=S*G'*P2
+ GF2Matrix g = (GF2Matrix)matrixSandInverse[0].rightMultiply(gPrime);
+ g = (GF2Matrix)g.rightMultiply(p2);
+
+
+ // generate keys
+ McEliecePublicKeyParameters pubKey = new McEliecePublicKeyParameters(OID, n, t, g, mcElieceParams.getParameters());
+ McEliecePrivateKeyParameters privKey = new McEliecePrivateKeyParameters(OID, n, k,
+ field, gp, matrixSandInverse[1], p1, p2, h, sqRootMatrix, mcElieceParams.getParameters());
+
+ // return key pair
+ return new AsymmetricCipherKeyPair(pubKey, privKey);
+ }
+
+ public void init(KeyGenerationParameters param)
+ {
+ this.initialize(param);
+
+ }
+
+ public AsymmetricCipherKeyPair generateKeyPair()
+ {
+ return genKeyPair();
+ }
+
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/mceliece/McElieceKeyParameters.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/mceliece/McElieceKeyParameters.java
new file mode 100644
index 0000000..4c2826d
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/mceliece/McElieceKeyParameters.java
@@ -0,0 +1,25 @@
+package org.bc.pqc.crypto.mceliece;
+
+import org.bc.crypto.params.AsymmetricKeyParameter;
+
+
+public class McElieceKeyParameters
+ extends AsymmetricKeyParameter
+{
+ private McElieceParameters params;
+
+ public McElieceKeyParameters(
+ boolean isPrivate,
+ McElieceParameters params)
+ {
+ super(isPrivate);
+ this.params = params;
+ }
+
+
+ public McElieceParameters getParameters()
+ {
+ return params;
+ }
+
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/mceliece/McElieceKobaraImaiCipher.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/mceliece/McElieceKobaraImaiCipher.java
new file mode 100644
index 0000000..eceae65
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/mceliece/McElieceKobaraImaiCipher.java
@@ -0,0 +1,319 @@
+package org.bc.pqc.crypto.mceliece;
+
+import java.security.SecureRandom;
+
+import org.bc.crypto.CipherParameters;
+import org.bc.crypto.Digest;
+import org.bc.crypto.digests.SHA1Digest;
+import org.bc.crypto.params.ParametersWithRandom;
+import org.bc.crypto.prng.DigestRandomGenerator;
+import org.bc.pqc.crypto.MessageEncryptor;
+import org.bc.pqc.math.linearalgebra.ByteUtils;
+import org.bc.pqc.math.linearalgebra.GF2Vector;
+import org.bc.pqc.math.linearalgebra.IntegerFunctions;
+
+/**
+ * This class implements the Kobara/Imai conversion of the McEliecePKCS. This is
+ * a conversion of the McEliecePKCS which is CCA2-secure. For details, see D.
+ * Engelbert, R. Overbeck, A. Schmidt, "A summary of the development of the
+ * McEliece Cryptosystem", technical report.
+ */
+public class McElieceKobaraImaiCipher
+ implements MessageEncryptor
+{
+
+ /**
+ * The OID of the algorithm.
+ */
+ public static final String OID = "1.3.6.1.4.1.8301.3.1.3.4.2.3";
+
+ private static final String DEFAULT_PRNG_NAME = "SHA1PRNG";
+
+ /**
+ * A predetermined public constant.
+ */
+ public static final byte[] PUBLIC_CONSTANT = "a predetermined public constant"
+ .getBytes();
+
+
+ private Digest messDigest;
+
+ private SecureRandom sr;
+
+ McElieceCCA2KeyParameters key;
+
+ /**
+ * The McEliece main parameters
+ */
+ private int n, k, t;
+
+
+ public void init(boolean forSigning,
+ CipherParameters param)
+ {
+
+ if (forSigning)
+ {
+ if (param instanceof ParametersWithRandom)
+ {
+ ParametersWithRandom rParam = (ParametersWithRandom)param;
+
+ this.sr = rParam.getRandom();
+ this.key = (McElieceCCA2PublicKeyParameters)rParam.getParameters();
+ this.initCipherEncrypt((McElieceCCA2PublicKeyParameters)key);
+
+ }
+ else
+ {
+ this.sr = new SecureRandom();
+ this.key = (McElieceCCA2PublicKeyParameters)param;
+ this.initCipherEncrypt((McElieceCCA2PublicKeyParameters)key);
+ }
+ }
+ else
+ {
+ this.key = (McElieceCCA2PrivateKeyParameters)param;
+ this.initCipherDecrypt((McElieceCCA2PrivateKeyParameters)key);
+ }
+
+ }
+
+ /**
+ * Return the key size of the given key object.
+ *
+ * @param key the McElieceCCA2KeyParameters object
+ * @return the key size of the given key object
+ */
+ public int getKeySize(McElieceCCA2KeyParameters key)
+ {
+ if (key instanceof McElieceCCA2PublicKeyParameters)
+ {
+ return ((McElieceCCA2PublicKeyParameters)key).getN();
+
+ }
+ if (key instanceof McElieceCCA2PrivateKeyParameters)
+ {
+ return ((McElieceCCA2PrivateKeyParameters)key).getN();
+ }
+ throw new IllegalArgumentException("unsupported type");
+ }
+
+ private void initCipherEncrypt(McElieceCCA2PublicKeyParameters pubKey)
+ {
+ this.messDigest = pubKey.getParameters().getDigest();
+ n = pubKey.getN();
+ k = pubKey.getK();
+ t = pubKey.getT();
+
+ }
+
+ public void initCipherDecrypt(McElieceCCA2PrivateKeyParameters privKey)
+ {
+ this.messDigest = privKey.getParameters().getDigest();
+ n = privKey.getN();
+ k = privKey.getK();
+ t = privKey.getT();
+ }
+
+ public byte[] messageEncrypt(byte[] input)
+ throws Exception
+ {
+
+ int c2Len = messDigest.getDigestSize();
+ int c4Len = k >> 3;
+ int c5Len = (IntegerFunctions.binomial(n, t).bitLength() - 1) >> 3;
+
+
+ int mLen = c4Len + c5Len - c2Len - PUBLIC_CONSTANT.length;
+ if (input.length > mLen)
+ {
+ mLen = input.length;
+ }
+
+ int c1Len = mLen + PUBLIC_CONSTANT.length;
+ int c6Len = c1Len + c2Len - c4Len - c5Len;
+
+ // compute (m||const)
+ byte[] mConst = new byte[c1Len];
+ System.arraycopy(input, 0, mConst, 0, input.length);
+ System.arraycopy(PUBLIC_CONSTANT, 0, mConst, mLen,
+ PUBLIC_CONSTANT.length);
+
+ // generate random r of length c2Len bytes
+ byte[] r = new byte[c2Len];
+ sr.nextBytes(r);
+
+ // get PRNG object
+ // get PRNG object
+ DigestRandomGenerator sr0 = new DigestRandomGenerator(new SHA1Digest());
+
+ // seed PRNG with r'
+ sr0.addSeedMaterial(r);
+
+ // generate random sequence ...
+ byte[] c1 = new byte[c1Len];
+ sr0.nextBytes(c1);
+
+ // ... and XOR with (m||const) to obtain c1
+ for (int i = c1Len - 1; i >= 0; i--)
+ {
+ c1[i] ^= mConst[i];
+ }
+
+ // compute H(c1) ...
+ byte[] c2 = new byte[messDigest.getDigestSize()];
+ messDigest.update(c1, 0, c1.length);
+ messDigest.doFinal(c2, 0);
+
+ // ... and XOR with r
+ for (int i = c2Len - 1; i >= 0; i--)
+ {
+ c2[i] ^= r[i];
+ }
+
+ // compute (c2||c1)
+ byte[] c2c1 = ByteUtils.concatenate(c2, c1);
+
+ // split (c2||c1) into (c6||c5||c4), where c4Len is k/8 bytes, c5Len is
+ // floor[log(n|t)]/8 bytes, and c6Len is c1Len+c2Len-c4Len-c5Len (may be
+ // 0).
+ byte[] c6 = new byte[0];
+ if (c6Len > 0)
+ {
+ c6 = new byte[c6Len];
+ System.arraycopy(c2c1, 0, c6, 0, c6Len);
+ }
+
+ byte[] c5 = new byte[c5Len];
+ System.arraycopy(c2c1, c6Len, c5, 0, c5Len);
+
+ byte[] c4 = new byte[c4Len];
+ System.arraycopy(c2c1, c6Len + c5Len, c4, 0, c4Len);
+
+ // convert c4 to vector over GF(2)
+ GF2Vector c4Vec = GF2Vector.OS2VP(k, c4);
+
+ // convert c5 to error vector z
+ GF2Vector z = Conversions.encode(n, t, c5);
+
+ // compute encC4 = E(c4, z)
+ byte[] encC4 = McElieceCCA2Primitives.encryptionPrimitive((McElieceCCA2PublicKeyParameters)key,
+ c4Vec, z).getEncoded();
+
+ // if c6Len > 0
+ if (c6Len > 0)
+ {
+ // return (c6||encC4)
+ return ByteUtils.concatenate(c6, encC4);
+ }
+ // else, return encC4
+ return encC4;
+ }
+
+
+ public byte[] messageDecrypt(byte[] input)
+ throws Exception
+ {
+
+ int nDiv8 = n >> 3;
+
+ if (input.length < nDiv8)
+ {
+ throw new Exception("Bad Padding: Ciphertext too short.");
+ }
+
+ int c2Len = messDigest.getDigestSize();
+ int c4Len = k >> 3;
+ int c6Len = input.length - nDiv8;
+
+ // split cipher text (c6||encC4), where c6 may be empty
+ byte[] c6, encC4;
+ if (c6Len > 0)
+ {
+ byte[][] c6EncC4 = ByteUtils.split(input, c6Len);
+ c6 = c6EncC4[0];
+ encC4 = c6EncC4[1];
+ }
+ else
+ {
+ c6 = new byte[0];
+ encC4 = input;
+ }
+
+ // convert encC4 into vector over GF(2)
+ GF2Vector encC4Vec = GF2Vector.OS2VP(n, encC4);
+
+ // decrypt encC4Vec to obtain c4 and error vector z
+ GF2Vector[] c4z = McElieceCCA2Primitives.decryptionPrimitive((McElieceCCA2PrivateKeyParameters)key,
+ encC4Vec);
+ byte[] c4 = c4z[0].getEncoded();
+ GF2Vector z = c4z[1];
+
+ // if length of c4 is greater than c4Len (because of padding) ...
+ if (c4.length > c4Len)
+ {
+ // ... truncate the padding bytes
+ c4 = ByteUtils.subArray(c4, 0, c4Len);
+ }
+
+ // compute c5 = Conv^-1(z)
+ byte[] c5 = Conversions.decode(n, t, z);
+
+ // compute (c6||c5||c4)
+ byte[] c6c5c4 = ByteUtils.concatenate(c6, c5);
+ c6c5c4 = ByteUtils.concatenate(c6c5c4, c4);
+
+ // split (c6||c5||c4) into (c2||c1), where c2Len = mdLen and c1Len =
+ // input.length-c2Len bytes.
+ int c1Len = c6c5c4.length - c2Len;
+ byte[][] c2c1 = ByteUtils.split(c6c5c4, c2Len);
+ byte[] c2 = c2c1[0];
+ byte[] c1 = c2c1[1];
+
+ // compute H(c1) ...
+ byte[] rPrime = new byte[messDigest.getDigestSize()];
+ messDigest.update(c1, 0, c1.length);
+ messDigest.doFinal(rPrime, 0);
+
+ // ... and XOR with c2 to obtain r'
+ for (int i = c2Len - 1; i >= 0; i--)
+ {
+ rPrime[i] ^= c2[i];
+ }
+
+ // get PRNG object
+ DigestRandomGenerator sr0 = new DigestRandomGenerator(new SHA1Digest());
+
+ // seed PRNG with r'
+ sr0.addSeedMaterial(rPrime);
+
+ // generate random sequence R(r') ...
+ byte[] mConstPrime = new byte[c1Len];
+ sr0.nextBytes(mConstPrime);
+
+ // ... and XOR with c1 to obtain (m||const')
+ for (int i = c1Len - 1; i >= 0; i--)
+ {
+ mConstPrime[i] ^= c1[i];
+ }
+
+ if (mConstPrime.length < c1Len)
+ {
+ throw new Exception("Bad Padding: invalid ciphertext");
+ }
+
+ byte[][] temp = ByteUtils.split(mConstPrime, c1Len
+ - PUBLIC_CONSTANT.length);
+ byte[] mr = temp[0];
+ byte[] constPrime = temp[1];
+
+ if (!ByteUtils.equals(constPrime, PUBLIC_CONSTANT))
+ {
+ throw new Exception("Bad Padding: invalid ciphertext");
+ }
+
+ return mr;
+ }
+
+
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/mceliece/McElieceKobaraImaiDigestCipher.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/mceliece/McElieceKobaraImaiDigestCipher.java
new file mode 100644
index 0000000..0c72588
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/mceliece/McElieceKobaraImaiDigestCipher.java
@@ -0,0 +1,128 @@
+package org.bc.pqc.crypto.mceliece;
+
+
+import org.bc.crypto.CipherParameters;
+import org.bc.crypto.Digest;
+import org.bc.crypto.params.AsymmetricKeyParameter;
+import org.bc.crypto.params.ParametersWithRandom;
+import org.bc.pqc.crypto.MessageEncryptor;
+
+// TODO should implement some interface?
+public class McElieceKobaraImaiDigestCipher
+{
+
+ private final Digest messDigest;
+
+ private final MessageEncryptor mcElieceCCA2Cipher;
+
+ private boolean forEncrypting;
+
+
+ public McElieceKobaraImaiDigestCipher(MessageEncryptor mcElieceCCA2Cipher, Digest messDigest)
+ {
+ this.mcElieceCCA2Cipher = mcElieceCCA2Cipher;
+ this.messDigest = messDigest;
+ }
+
+
+ public void init(boolean forEncrypting,
+ CipherParameters param)
+ {
+
+ this.forEncrypting = forEncrypting;
+ AsymmetricKeyParameter k;
+
+ if (param instanceof ParametersWithRandom)
+ {
+ k = (AsymmetricKeyParameter)((ParametersWithRandom)param).getParameters();
+ }
+ else
+ {
+ k = (AsymmetricKeyParameter)param;
+ }
+
+ if (forEncrypting && k.isPrivate())
+ {
+ throw new IllegalArgumentException("Encrypting Requires Public Key.");
+ }
+
+ if (!forEncrypting && !k.isPrivate())
+ {
+ throw new IllegalArgumentException("Decrypting Requires Private Key.");
+ }
+
+ reset();
+
+ mcElieceCCA2Cipher.init(forEncrypting, param);
+ }
+
+
+ public byte[] messageEncrypt()
+ {
+ if (!forEncrypting)
+ {
+ throw new IllegalStateException("McElieceKobaraImaiDigestCipher not initialised for encrypting.");
+ }
+
+ byte[] hash = new byte[messDigest.getDigestSize()];
+ messDigest.doFinal(hash, 0);
+ byte[] enc = null;
+
+ try
+ {
+ enc = mcElieceCCA2Cipher.messageEncrypt(hash);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+
+
+ return enc;
+ }
+
+
+ public byte[] messageDecrypt(byte[] ciphertext)
+ {
+ byte[] output = null;
+ if (forEncrypting)
+ {
+ throw new IllegalStateException("McElieceKobaraImaiDigestCipher not initialised for decrypting.");
+ }
+
+
+ try
+ {
+ output = mcElieceCCA2Cipher.messageDecrypt(ciphertext);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+
+
+ return output;
+ }
+
+
+ public void update(byte b)
+ {
+ messDigest.update(b);
+
+ }
+
+ public void update(byte[] in, int off, int len)
+ {
+ messDigest.update(in, off, len);
+
+ }
+
+
+ public void reset()
+ {
+ messDigest.reset();
+
+ }
+
+
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/mceliece/McEliecePKCSCipher.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/mceliece/McEliecePKCSCipher.java
new file mode 100644
index 0000000..f08c304
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/mceliece/McEliecePKCSCipher.java
@@ -0,0 +1,224 @@
+package org.bc.pqc.crypto.mceliece;
+
+import java.security.SecureRandom;
+
+import org.bc.crypto.CipherParameters;
+import org.bc.crypto.params.ParametersWithRandom;
+import org.bc.pqc.crypto.MessageEncryptor;
+import org.bc.pqc.math.linearalgebra.GF2Matrix;
+import org.bc.pqc.math.linearalgebra.GF2Vector;
+import org.bc.pqc.math.linearalgebra.GF2mField;
+import org.bc.pqc.math.linearalgebra.GoppaCode;
+import org.bc.pqc.math.linearalgebra.Permutation;
+import org.bc.pqc.math.linearalgebra.PolynomialGF2mSmallM;
+import org.bc.pqc.math.linearalgebra.Vector;
+
+/**
+ * This class implements the McEliece Public Key cryptosystem (McEliecePKCS). It
+ * was first described in R.J. McEliece, "A public key cryptosystem based on
+ * algebraic coding theory", DSN progress report, 42-44:114-116, 1978. The
+ * McEliecePKCS is the first cryptosystem which is based on error correcting
+ * codes. The trapdoor for the McEliece cryptosystem using Goppa codes is the
+ * knowledge of the Goppa polynomial used to generate the code.
+ */
+public class McEliecePKCSCipher
+ implements MessageEncryptor
+{
+
+ /**
+ * The OID of the algorithm.
+ */
+ public static final String OID = "1.3.6.1.4.1.8301.3.1.3.4.1";
+
+
+ // the source of randomness
+ private SecureRandom sr;
+
+ // the McEliece main parameters
+ private int n, k, t;
+
+ // The maximum number of bytes the cipher can decrypt
+ public int maxPlainTextSize;
+
+ // The maximum number of bytes the cipher can encrypt
+ public int cipherTextSize;
+
+ McElieceKeyParameters key;
+
+
+ public void init(boolean forSigning,
+ CipherParameters param)
+ {
+
+ if (forSigning)
+ {
+ if (param instanceof ParametersWithRandom)
+ {
+ ParametersWithRandom rParam = (ParametersWithRandom)param;
+
+ this.sr = rParam.getRandom();
+ this.key = (McEliecePublicKeyParameters)rParam.getParameters();
+ this.initCipherEncrypt((McEliecePublicKeyParameters)key);
+
+ }
+ else
+ {
+ this.sr = new SecureRandom();
+ this.key = (McEliecePublicKeyParameters)param;
+ this.initCipherEncrypt((McEliecePublicKeyParameters)key);
+ }
+ }
+ else
+ {
+ this.key = (McEliecePrivateKeyParameters)param;
+ this.initCipherDecrypt((McEliecePrivateKeyParameters)key);
+ }
+
+ }
+
+
+ /**
+ * Return the key size of the given key object.
+ *
+ * @param key the McElieceKeyParameters object
+ * @return the keysize of the given key object
+ */
+
+ public int getKeySize(McElieceKeyParameters key)
+ {
+
+ if (key instanceof McEliecePublicKeyParameters)
+ {
+ return ((McEliecePublicKeyParameters)key).getN();
+
+ }
+ if (key instanceof McEliecePrivateKeyParameters)
+ {
+ return ((McEliecePrivateKeyParameters)key).getN();
+ }
+ throw new IllegalArgumentException("unsupported type");
+
+ }
+
+
+ public void initCipherEncrypt(McEliecePublicKeyParameters pubKey)
+ {
+ this.sr = sr != null ? sr : new SecureRandom();
+ n = pubKey.getN();
+ k = pubKey.getK();
+ t = pubKey.getT();
+ cipherTextSize = n >> 3;
+ maxPlainTextSize = (k >> 3);
+ }
+
+
+ public void initCipherDecrypt(McEliecePrivateKeyParameters privKey)
+ {
+ n = privKey.getN();
+ k = privKey.getK();
+
+ maxPlainTextSize = (k >> 3);
+ cipherTextSize = n >> 3;
+ }
+
+ /**
+ * Encrypt a plain text.
+ *
+ * @param input the plain text
+ * @return the cipher text
+ */
+ public byte[] messageEncrypt(byte[] input)
+ {
+ GF2Vector m = computeMessageRepresentative(input);
+ GF2Vector z = new GF2Vector(n, t, sr);
+
+ GF2Matrix g = ((McEliecePublicKeyParameters)key).getG();
+ Vector mG = g.leftMultiply(m);
+ GF2Vector mGZ = (GF2Vector)mG.add(z);
+
+ return mGZ.getEncoded();
+ }
+
+ private GF2Vector computeMessageRepresentative(byte[] input)
+ {
+ byte[] data = new byte[maxPlainTextSize + ((k & 0x07) != 0 ? 1 : 0)];
+ System.arraycopy(input, 0, data, 0, input.length);
+ data[input.length] = 0x01;
+ return GF2Vector.OS2VP(k, data);
+ }
+
+ /**
+ * Decrypt a cipher text.
+ *
+ * @param input the cipher text
+ * @return the plain text
+ * @throws Exception if the cipher text is invalid.
+ */
+ public byte[] messageDecrypt(byte[] input)
+ throws Exception
+ {
+ GF2Vector vec = GF2Vector.OS2VP(n, input);
+ McEliecePrivateKeyParameters privKey = (McEliecePrivateKeyParameters)key;
+ GF2mField field = privKey.getField();
+ PolynomialGF2mSmallM gp = privKey.getGoppaPoly();
+ GF2Matrix sInv = privKey.getSInv();
+ Permutation p1 = privKey.getP1();
+ Permutation p2 = privKey.getP2();
+ GF2Matrix h = privKey.getH();
+ PolynomialGF2mSmallM[] qInv = privKey.getQInv();
+
+ // compute permutation P = P1 * P2
+ Permutation p = p1.rightMultiply(p2);
+
+ // compute P^-1
+ Permutation pInv = p.computeInverse();
+
+ // compute c P^-1
+ GF2Vector cPInv = (GF2Vector)vec.multiply(pInv);
+
+ // compute syndrome of c P^-1
+ GF2Vector syndrome = (GF2Vector)h.rightMultiply(cPInv);
+
+ // decode syndrome
+ GF2Vector z = GoppaCode.syndromeDecode(syndrome, field, gp, qInv);
+ GF2Vector mSG = (GF2Vector)cPInv.add(z);
+
+ // multiply codeword with P1 and error vector with P
+ mSG = (GF2Vector)mSG.multiply(p1);
+ z = (GF2Vector)z.multiply(p);
+
+ // extract mS (last k columns of mSG)
+ GF2Vector mS = mSG.extractRightVector(k);
+
+ // compute plaintext vector
+ GF2Vector mVec = (GF2Vector)sInv.leftMultiply(mS);
+
+ // compute and return plaintext
+ return computeMessage(mVec);
+ }
+
+ private byte[] computeMessage(GF2Vector mr)
+ throws Exception
+ {
+ byte[] mrBytes = mr.getEncoded();
+ // find first non-zero byte
+ int index;
+ for (index = mrBytes.length - 1; index >= 0 && mrBytes[index] == 0; index--)
+ {
+ ;
+ }
+
+ // check if padding byte is valid
+ if (mrBytes[index] != 0x01)
+ {
+ throw new Exception("Bad Padding: invalid ciphertext");
+ }
+
+ // extract and return message
+ byte[] mBytes = new byte[index];
+ System.arraycopy(mrBytes, 0, mBytes, 0, index);
+ return mBytes;
+ }
+
+
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/mceliece/McEliecePKCSDigestCipher.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/mceliece/McEliecePKCSDigestCipher.java
new file mode 100644
index 0000000..1c02b10
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/mceliece/McEliecePKCSDigestCipher.java
@@ -0,0 +1,128 @@
+package org.bc.pqc.crypto.mceliece;
+
+
+import org.bc.crypto.CipherParameters;
+import org.bc.crypto.Digest;
+import org.bc.crypto.params.AsymmetricKeyParameter;
+import org.bc.crypto.params.ParametersWithRandom;
+import org.bc.pqc.crypto.MessageEncryptor;
+
+// TODO should implement some interface?
+public class McEliecePKCSDigestCipher
+{
+
+ private final Digest messDigest;
+
+ private final MessageEncryptor mcElieceCipher;
+
+ private boolean forEncrypting;
+
+
+ public McEliecePKCSDigestCipher(MessageEncryptor mcElieceCipher, Digest messDigest)
+ {
+ this.mcElieceCipher = mcElieceCipher;
+ this.messDigest = messDigest;
+ }
+
+
+ public void init(boolean forEncrypting,
+ CipherParameters param)
+ {
+
+ this.forEncrypting = forEncrypting;
+ AsymmetricKeyParameter k;
+
+ if (param instanceof ParametersWithRandom)
+ {
+ k = (AsymmetricKeyParameter)((ParametersWithRandom)param).getParameters();
+ }
+ else
+ {
+ k = (AsymmetricKeyParameter)param;
+ }
+
+ if (forEncrypting && k.isPrivate())
+ {
+ throw new IllegalArgumentException("Encrypting Requires Public Key.");
+ }
+
+ if (!forEncrypting && !k.isPrivate())
+ {
+ throw new IllegalArgumentException("Decrypting Requires Private Key.");
+ }
+
+ reset();
+
+ mcElieceCipher.init(forEncrypting, param);
+ }
+
+
+ public byte[] messageEncrypt()
+ {
+ if (!forEncrypting)
+ {
+ throw new IllegalStateException("McEliecePKCSDigestCipher not initialised for encrypting.");
+ }
+
+ byte[] hash = new byte[messDigest.getDigestSize()];
+ messDigest.doFinal(hash, 0);
+ byte[] enc = null;
+
+ try
+ {
+ enc = mcElieceCipher.messageEncrypt(hash);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+
+
+ return enc;
+ }
+
+
+ public byte[] messageDecrypt(byte[] ciphertext)
+ {
+ byte[] output = null;
+ if (forEncrypting)
+ {
+ throw new IllegalStateException("McEliecePKCSDigestCipher not initialised for decrypting.");
+ }
+
+
+ try
+ {
+ output = mcElieceCipher.messageDecrypt(ciphertext);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+
+
+ return output;
+ }
+
+
+ public void update(byte b)
+ {
+ messDigest.update(b);
+
+ }
+
+ public void update(byte[] in, int off, int len)
+ {
+ messDigest.update(in, off, len);
+
+ }
+
+
+ public void reset()
+ {
+ messDigest.reset();
+
+ }
+
+
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/mceliece/McElieceParameters.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/mceliece/McElieceParameters.java
new file mode 100644
index 0000000..797d213
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/mceliece/McElieceParameters.java
@@ -0,0 +1,181 @@
+package org.bc.pqc.crypto.mceliece;
+
+import org.bc.crypto.CipherParameters;
+import org.bc.pqc.math.linearalgebra.PolynomialRingGF2;
+
+public class McElieceParameters
+ implements CipherParameters
+{
+
+ /**
+ * The default extension degree
+ */
+ public static final int DEFAULT_M = 11;
+
+ /**
+ * The default error correcting capability.
+ */
+ public static final int DEFAULT_T = 50;
+
+ /**
+ * extension degree of the finite field GF(2^m)
+ */
+ private int m;
+
+ /**
+ * error correction capability of the code
+ */
+ private int t;
+
+ /**
+ * length of the code
+ */
+ private int n;
+
+ /**
+ * the field polynomial
+ */
+ private int fieldPoly;
+
+ /**
+ * Constructor. Set the default parameters: extension degree.
+ */
+ public McElieceParameters()
+ {
+ this(DEFAULT_M, DEFAULT_T);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param keysize the length of a Goppa code
+ * @throws IllegalArgumentException if keysize < 1.
+ */
+ public McElieceParameters(int keysize)
+ throws IllegalArgumentException
+ {
+ if (keysize < 1)
+ {
+ throw new IllegalArgumentException("key size must be positive");
+ }
+ m = 0;
+ n = 1;
+ while (n < keysize)
+ {
+ n <<= 1;
+ m++;
+ }
+ t = n >>> 1;
+ t /= m;
+ fieldPoly = PolynomialRingGF2.getIrreduciblePolynomial(m);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param m degree of the finite field GF(2^m)
+ * @param t error correction capability of the code
+ * @throws IllegalArgumentException if m < 1 or m > 32 or
+ * t < 0 or t > n.
+ */
+ public McElieceParameters(int m, int t)
+ throws IllegalArgumentException
+ {
+ if (m < 1)
+ {
+ throw new IllegalArgumentException("m must be positive");
+ }
+ if (m > 32)
+ {
+ throw new IllegalArgumentException("m is too large");
+ }
+ this.m = m;
+ n = 1 << m;
+ if (t < 0)
+ {
+ throw new IllegalArgumentException("t must be positive");
+ }
+ if (t > n)
+ {
+ throw new IllegalArgumentException("t must be less than n = 2^m");
+ }
+ this.t = t;
+ fieldPoly = PolynomialRingGF2.getIrreduciblePolynomial(m);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param m degree of the finite field GF(2^m)
+ * @param t error correction capability of the code
+ * @param poly the field polynomial
+ * @throws IllegalArgumentException if m < 1 or m > 32 or
+ * t < 0 or t > n or
+ * poly is not an irreducible field polynomial.
+ */
+ public McElieceParameters(int m, int t, int poly)
+ throws IllegalArgumentException
+ {
+ this.m = m;
+ if (m < 1)
+ {
+ throw new IllegalArgumentException("m must be positive");
+ }
+ if (m > 32)
+ {
+ throw new IllegalArgumentException(" m is too large");
+ }
+ this.n = 1 << m;
+ this.t = t;
+ if (t < 0)
+ {
+ throw new IllegalArgumentException("t must be positive");
+ }
+ if (t > n)
+ {
+ throw new IllegalArgumentException("t must be less than n = 2^m");
+ }
+ if ((PolynomialRingGF2.degree(poly) == m)
+ && (PolynomialRingGF2.isIrreducible(poly)))
+ {
+ this.fieldPoly = poly;
+ }
+ else
+ {
+ throw new IllegalArgumentException(
+ "polynomial is not a field polynomial for GF(2^m)");
+ }
+ }
+
+ /**
+ * @return the extension degree of the finite field GF(2^m)
+ */
+ public int getM()
+ {
+ return m;
+ }
+
+ /**
+ * @return the length of the code
+ */
+ public int getN()
+ {
+ return n;
+ }
+
+ /**
+ * @return the error correction capability of the code
+ */
+ public int getT()
+ {
+ return t;
+ }
+
+ /**
+ * @return the field polynomial
+ */
+ public int getFieldPoly()
+ {
+ return fieldPoly;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/mceliece/McEliecePointchevalCipher.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/mceliece/McEliecePointchevalCipher.java
new file mode 100644
index 0000000..d039b04
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/mceliece/McEliecePointchevalCipher.java
@@ -0,0 +1,241 @@
+package org.bc.pqc.crypto.mceliece;
+
+import java.security.SecureRandom;
+
+import org.bc.crypto.CipherParameters;
+import org.bc.crypto.Digest;
+import org.bc.crypto.digests.SHA1Digest;
+import org.bc.crypto.params.ParametersWithRandom;
+import org.bc.crypto.prng.DigestRandomGenerator;
+import org.bc.pqc.crypto.MessageEncryptor;
+import org.bc.pqc.math.linearalgebra.ByteUtils;
+import org.bc.pqc.math.linearalgebra.GF2Vector;
+
+/**
+ * This class implements the Pointcheval conversion of the McEliecePKCS.
+ * Pointcheval presents a generic technique to make a CCA2-secure cryptosystem
+ * from any partially trapdoor one-way function in the random oracle model. For
+ * details, see D. Engelbert, R. Overbeck, A. Schmidt, "A summary of the
+ * development of the McEliece Cryptosystem", technical report.
+ */
+public class McEliecePointchevalCipher
+ implements MessageEncryptor
+{
+
+
+ /**
+ * The OID of the algorithm.
+ */
+ public static final String OID = "1.3.6.1.4.1.8301.3.1.3.4.2.2";
+
+ private Digest messDigest;
+
+ private SecureRandom sr;
+
+ /**
+ * The McEliece main parameters
+ */
+ private int n, k, t;
+
+ McElieceCCA2KeyParameters key;
+
+ public void init(boolean forSigning,
+ CipherParameters param)
+ {
+
+ if (forSigning)
+ {
+ if (param instanceof ParametersWithRandom)
+ {
+ ParametersWithRandom rParam = (ParametersWithRandom)param;
+
+ this.sr = rParam.getRandom();
+ this.key = (McElieceCCA2PublicKeyParameters)rParam.getParameters();
+ this.initCipherEncrypt((McElieceCCA2PublicKeyParameters)key);
+
+ }
+ else
+ {
+ this.sr = new SecureRandom();
+ this.key = (McElieceCCA2PublicKeyParameters)param;
+ this.initCipherEncrypt((McElieceCCA2PublicKeyParameters)key);
+ }
+ }
+ else
+ {
+ this.key = (McElieceCCA2PrivateKeyParameters)param;
+ this.initCipherDecrypt((McElieceCCA2PrivateKeyParameters)key);
+ }
+
+ }
+
+ /**
+ * Return the key size of the given key object.
+ *
+ * @param key the McElieceCCA2KeyParameters object
+ * @return the key size of the given key object
+ * @throws IllegalArgumentException if the key is invalid
+ */
+ public int getKeySize(McElieceCCA2KeyParameters key)
+ throws IllegalArgumentException
+ {
+
+ if (key instanceof McElieceCCA2PublicKeyParameters)
+ {
+ return ((McElieceCCA2PublicKeyParameters)key).getN();
+
+ }
+ if (key instanceof McElieceCCA2PrivateKeyParameters)
+ {
+ return ((McElieceCCA2PrivateKeyParameters)key).getN();
+ }
+ throw new IllegalArgumentException("unsupported type");
+
+ }
+
+
+ protected int decryptOutputSize(int inLen)
+ {
+ return 0;
+ }
+
+ protected int encryptOutputSize(int inLen)
+ {
+ return 0;
+ }
+
+
+ public void initCipherEncrypt(McElieceCCA2PublicKeyParameters pubKey)
+ {
+ this.sr = sr != null ? sr : new SecureRandom();
+ this.messDigest = pubKey.getParameters().getDigest();
+ n = pubKey.getN();
+ k = pubKey.getK();
+ t = pubKey.getT();
+ }
+
+ public void initCipherDecrypt(McElieceCCA2PrivateKeyParameters privKey)
+ {
+ this.messDigest = privKey.getParameters().getDigest();
+ n = privKey.getN();
+ k = privKey.getK();
+ t = privKey.getT();
+ }
+
+ public byte[] messageEncrypt(byte[] input)
+ throws Exception
+ {
+
+ int kDiv8 = k >> 3;
+
+ // generate random r of length k div 8 bytes
+ byte[] r = new byte[kDiv8];
+ sr.nextBytes(r);
+
+ // generate random vector r' of length k bits
+ GF2Vector rPrime = new GF2Vector(k, sr);
+
+ // convert r' to byte array
+ byte[] rPrimeBytes = rPrime.getEncoded();
+
+ // compute (input||r)
+ byte[] mr = ByteUtils.concatenate(input, r);
+
+ // compute H(input||r)
+ messDigest.update(mr, 0, mr.length);
+ byte[] hmr = new byte[messDigest.getDigestSize()];
+ messDigest.doFinal(hmr, 0);
+
+
+ // convert H(input||r) to error vector z
+ GF2Vector z = Conversions.encode(n, t, hmr);
+
+ // compute c1 = E(rPrime, z)
+ byte[] c1 = McElieceCCA2Primitives.encryptionPrimitive((McElieceCCA2PublicKeyParameters)key, rPrime,
+ z).getEncoded();
+
+ // get PRNG object
+ DigestRandomGenerator sr0 = new DigestRandomGenerator(new SHA1Digest());
+
+ // seed PRNG with r'
+ sr0.addSeedMaterial(rPrimeBytes);
+
+ // generate random c2
+ byte[] c2 = new byte[input.length + kDiv8];
+ sr0.nextBytes(c2);
+
+ // XOR with input
+ for (int i = 0; i < input.length; i++)
+ {
+ c2[i] ^= input[i];
+ }
+ // XOR with r
+ for (int i = 0; i < kDiv8; i++)
+ {
+ c2[input.length + i] ^= r[i];
+ }
+
+ // return (c1||c2)
+ return ByteUtils.concatenate(c1, c2);
+ }
+
+ public byte[] messageDecrypt(byte[] input)
+ throws Exception
+ {
+
+ int c1Len = (n + 7) >> 3;
+ int c2Len = input.length - c1Len;
+
+ // split cipher text (c1||c2)
+ byte[][] c1c2 = ByteUtils.split(input, c1Len);
+ byte[] c1 = c1c2[0];
+ byte[] c2 = c1c2[1];
+
+ // decrypt c1 ...
+ GF2Vector c1Vec = GF2Vector.OS2VP(n, c1);
+ GF2Vector[] c1Dec = McElieceCCA2Primitives.decryptionPrimitive((McElieceCCA2PrivateKeyParameters)key,
+ c1Vec);
+ byte[] rPrimeBytes = c1Dec[0].getEncoded();
+ // ... and obtain error vector z
+ GF2Vector z = c1Dec[1];
+
+ // get PRNG object
+ DigestRandomGenerator sr0 = new DigestRandomGenerator(new SHA1Digest());
+
+ // seed PRNG with r'
+ sr0.addSeedMaterial(rPrimeBytes);
+
+ // generate random sequence
+ byte[] mrBytes = new byte[c2Len];
+ sr0.nextBytes(mrBytes);
+
+ // XOR with c2 to obtain (m||r)
+ for (int i = 0; i < c2Len; i++)
+ {
+ mrBytes[i] ^= c2[i];
+ }
+
+ // compute H(m||r)
+ messDigest.update(mrBytes, 0, mrBytes.length);
+ byte[] hmr = new byte[messDigest.getDigestSize()];
+ messDigest.doFinal(hmr, 0);
+
+ // compute Conv(H(m||r))
+ c1Vec = Conversions.encode(n, t, hmr);
+
+ // check that Conv(H(m||r)) = z
+ if (!c1Vec.equals(z))
+ {
+ throw new Exception("Bad Padding: Invalid ciphertext.");
+ }
+
+ // split (m||r) to obtain m
+ int kDiv8 = k >> 3;
+ byte[][] mr = ByteUtils.split(mrBytes, c2Len - kDiv8);
+
+ // return plain text m
+ return mr[0];
+ }
+
+
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/mceliece/McEliecePointchevalDigestCipher.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/mceliece/McEliecePointchevalDigestCipher.java
new file mode 100644
index 0000000..5205266
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/mceliece/McEliecePointchevalDigestCipher.java
@@ -0,0 +1,128 @@
+package org.bc.pqc.crypto.mceliece;
+
+
+import org.bc.crypto.CipherParameters;
+import org.bc.crypto.Digest;
+import org.bc.crypto.params.AsymmetricKeyParameter;
+import org.bc.crypto.params.ParametersWithRandom;
+import org.bc.pqc.crypto.MessageEncryptor;
+
+// TODO should implement some interface?
+public class McEliecePointchevalDigestCipher
+{
+
+ private final Digest messDigest;
+
+ private final MessageEncryptor mcElieceCCA2Cipher;
+
+ private boolean forEncrypting;
+
+
+ public McEliecePointchevalDigestCipher(MessageEncryptor mcElieceCCA2Cipher, Digest messDigest)
+ {
+ this.mcElieceCCA2Cipher = mcElieceCCA2Cipher;
+ this.messDigest = messDigest;
+ }
+
+
+ public void init(boolean forEncrypting,
+ CipherParameters param)
+ {
+
+ this.forEncrypting = forEncrypting;
+ AsymmetricKeyParameter k;
+
+ if (param instanceof ParametersWithRandom)
+ {
+ k = (AsymmetricKeyParameter)((ParametersWithRandom)param).getParameters();
+ }
+ else
+ {
+ k = (AsymmetricKeyParameter)param;
+ }
+
+ if (forEncrypting && k.isPrivate())
+ {
+ throw new IllegalArgumentException("Encrypting Requires Public Key.");
+ }
+
+ if (!forEncrypting && !k.isPrivate())
+ {
+ throw new IllegalArgumentException("Decrypting Requires Private Key.");
+ }
+
+ reset();
+
+ mcElieceCCA2Cipher.init(forEncrypting, param);
+ }
+
+
+ public byte[] messageEncrypt()
+ {
+ if (!forEncrypting)
+ {
+ throw new IllegalStateException("McEliecePointchevalDigestCipher not initialised for encrypting.");
+ }
+
+ byte[] hash = new byte[messDigest.getDigestSize()];
+ messDigest.doFinal(hash, 0);
+ byte[] enc = null;
+
+ try
+ {
+ enc = mcElieceCCA2Cipher.messageEncrypt(hash);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+
+
+ return enc;
+ }
+
+
+ public byte[] messageDecrypt(byte[] ciphertext)
+ {
+ byte[] output = null;
+ if (forEncrypting)
+ {
+ throw new IllegalStateException("McEliecePointchevalDigestCipher not initialised for decrypting.");
+ }
+
+
+ try
+ {
+ output = mcElieceCCA2Cipher.messageDecrypt(ciphertext);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+
+
+ return output;
+ }
+
+
+ public void update(byte b)
+ {
+ messDigest.update(b);
+
+ }
+
+ public void update(byte[] in, int off, int len)
+ {
+ messDigest.update(in, off, len);
+
+ }
+
+
+ public void reset()
+ {
+ messDigest.reset();
+
+ }
+
+
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/mceliece/McEliecePrivateKeyParameters.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/mceliece/McEliecePrivateKeyParameters.java
new file mode 100644
index 0000000..fec426e
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/mceliece/McEliecePrivateKeyParameters.java
@@ -0,0 +1,197 @@
+package org.bc.pqc.crypto.mceliece;
+
+import org.bc.pqc.math.linearalgebra.GF2Matrix;
+import org.bc.pqc.math.linearalgebra.GF2mField;
+import org.bc.pqc.math.linearalgebra.Permutation;
+import org.bc.pqc.math.linearalgebra.PolynomialGF2mSmallM;
+
+
+public class McEliecePrivateKeyParameters
+ extends McElieceKeyParameters
+{
+
+ // the OID of the algorithm
+ private String oid;
+
+ // the length of the code
+ private int n;
+
+ // the dimension of the code, where k >= n - mt
+ private int k;
+
+ // the underlying finite field
+ private GF2mField field;
+
+ // the irreducible Goppa polynomial
+ private PolynomialGF2mSmallM goppaPoly;
+
+ // a k x k random binary non-singular matrix
+ private GF2Matrix sInv;
+
+ // the permutation used to generate the systematic check matrix
+ private Permutation p1;
+
+ // the permutation 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 (GF(2^m))^t
+ private PolynomialGF2mSmallM[] qInv;
+
+ /**
+ * Constructor.
+ *
+ * @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
+ * GF(2m)
+ * @param goppaPoly the irreducible Goppa polynomial
+ * @param sInv the matrix S-1
+ * @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
+ * (GF(2m))t
+ * @param params McElieceParameters
+ */
+ public McEliecePrivateKeyParameters(String oid, int n, int k, GF2mField field,
+ PolynomialGF2mSmallM goppaPoly, GF2Matrix sInv, Permutation p1,
+ Permutation p2, GF2Matrix h, PolynomialGF2mSmallM[] qInv, McElieceParameters params)
+ {
+ super(true, params);
+ this.oid = oid;
+ this.k = k;
+ this.n = n;
+ 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 McElieceKeyFactory}).
+ *
+ * @param oid
+ * @param n the length of the code
+ * @param k the dimension of the code
+ * @param encField the encoded field polynomial defining the finite field
+ * GF(2m)
+ * @param encGoppaPoly the encoded irreducible Goppa polynomial
+ * @param encSInv the encoded matrix S-1
+ * @param encP1 the encoded permutation used to generate the systematic
+ * check matrix
+ * @param encP2 the encoded permutation used to compute the public
+ * generator matrix
+ * @param encH the encoded canonical check matrix
+ * @param encQInv the encoded matrix used to compute square roots in
+ * (GF(2m))t
+ * @param params McElieceParameters
+ */
+ public McEliecePrivateKeyParameters(String oid, int n, int k, byte[] encField,
+ byte[] encGoppaPoly, byte[] encSInv, byte[] encP1, byte[] encP2,
+ byte[] encH, byte[][] encQInv, McElieceParameters params)
+ {
+ super(true, params);
+ this.oid = oid;
+ this.n = n;
+ this.k = k;
+ field = new GF2mField(encField);
+ goppaPoly = new PolynomialGF2mSmallM(field, encGoppaPoly);
+ sInv = new GF2Matrix(encSInv);
+ p1 = new Permutation(encP1);
+ p2 = new Permutation(encP2);
+ h = new GF2Matrix(encH);
+ qInv = new PolynomialGF2mSmallM[encQInv.length];
+ for (int i = 0; i < encQInv.length; i++)
+ {
+ qInv[i] = new PolynomialGF2mSmallM(field, encQInv[i]);
+ }
+ }
+
+ /**
+ * @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 GF(2m)
+ */
+ 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^-1
+ */
+ 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 H
+ */
+ public GF2Matrix getH()
+ {
+ return h;
+ }
+
+ /**
+ * @return the matrix used to compute square roots in
+ * (GF(2m))t
+ */
+ public PolynomialGF2mSmallM[] getQInv()
+ {
+ return qInv;
+ }
+
+ public String getOIDString()
+ {
+ return oid;
+ }
+
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/mceliece/McEliecePublicKeyParameters.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/mceliece/McEliecePublicKeyParameters.java
new file mode 100644
index 0000000..5b862e4
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/mceliece/McEliecePublicKeyParameters.java
@@ -0,0 +1,96 @@
+package org.bc.pqc.crypto.mceliece;
+
+import org.bc.pqc.math.linearalgebra.GF2Matrix;
+
+
+public class McEliecePublicKeyParameters
+ extends McElieceKeyParameters
+{
+
+ // 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;
+
+ /**
+ * Constructor (used by {@link McElieceKeyFactory}).
+ *
+ * @param oid
+ * @param n the length of the code
+ * @param t the error correction capability of the code
+ * @param g the generator matrix
+ * @param params McElieceParameters
+ */
+ public McEliecePublicKeyParameters(String oid, int n, int t, GF2Matrix g, McElieceParameters params)
+ {
+ super(false, params);
+ this.oid = oid;
+ this.n = n;
+ this.t = t;
+ this.g = new GF2Matrix(g);
+ }
+
+ /**
+ * Constructor (used by {@link McElieceKeyFactory}).
+ *
+ * @param oid
+ * @param n the length of the code
+ * @param t the error correction capability of the code
+ * @param encG the encoded generator matrix
+ * @param params McElieceParameters
+ */
+ public McEliecePublicKeyParameters(String oid, int t, int n, byte[] encG, McElieceParameters params)
+ {
+ super(false, params);
+ this.oid = oid;
+ this.n = n;
+ this.t = t;
+ this.g = new GF2Matrix(encG);
+ }
+
+ /**
+ * @return the length of the code
+ */
+ public int getN()
+ {
+ return n;
+ }
+
+ /**
+ * @return the error correction capability of the code
+ */
+ public int getT()
+ {
+ return t;
+ }
+
+ /**
+ * @return the generator matrix
+ */
+ public GF2Matrix getG()
+ {
+ return g;
+ }
+
+ public String getOIDString()
+ {
+ return oid;
+
+ }
+
+ /**
+ * @return the dimension of the code
+ */
+ public int getK()
+ {
+ return g.getNumRows();
+ }
+
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/rainbow/Layer.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/rainbow/Layer.java
new file mode 100644
index 0000000..b869b86
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/rainbow/Layer.java
@@ -0,0 +1,322 @@
+package org.bc.pqc.crypto.rainbow;
+
+import java.security.SecureRandom;
+
+import org.bc.pqc.crypto.rainbow.util.GF2Field;
+import org.bc.pqc.crypto.rainbow.util.RainbowUtil;
+import org.bc.util.Arrays;
+
+
+/**
+ * This class represents a layer of the Rainbow Oil- and Vinegar Map. Each Layer
+ * consists of oi polynomials with their coefficients, generated at random.
+ *
+ * To sign a document, we solve a LES (linear equation system) for each layer in
+ * order to find the oil variables of that layer and to be able to use the
+ * variables to compute the signature. This functionality is implemented in the
+ * RainbowSignature-class, by the aid of the private key.
+ *
+ * Each layer is a part of the private key.
+ *
+ * More information about the layer can be found in the paper of Jintai Ding,
+ * Dieter Schmidt: Rainbow, a New Multivariable Polynomial Signature Scheme.
+ * ACNS 2005: 164-175 (http://dx.doi.org/10.1007/11496137_12)
+ */
+public class Layer
+{
+ private int vi; // number of vinegars in this layer
+ private int viNext; // number of vinegars in next layer
+ private int oi; // number of oils in this layer
+
+ /*
+ * k : index of polynomial
+ *
+ * i,j : indices of oil and vinegar variables
+ */
+ private short[/* k */][/* i */][/* j */] coeff_alpha;
+ private short[/* k */][/* i */][/* j */] coeff_beta;
+ private short[/* k */][/* i */] coeff_gamma;
+ private short[/* k */] coeff_eta;
+
+ /**
+ * Constructor
+ *
+ * @param vi number of vinegar variables of this layer
+ * @param viNext number of vinegar variables of next layer. It's the same as
+ * (num of oils) + (num of vinegars) of this layer.
+ * @param coeffAlpha alpha-coefficients in the polynomials of this layer
+ * @param coeffBeta beta-coefficients in the polynomials of this layer
+ * @param coeffGamma gamma-coefficients in the polynomials of this layer
+ * @param coeffEta eta-coefficients in the polynomials of this layer
+ */
+ public Layer(byte vi, byte viNext, short[][][] coeffAlpha,
+ short[][][] coeffBeta, short[][] coeffGamma, short[] coeffEta)
+ {
+ this.vi = vi & 0xff;
+ this.viNext = viNext & 0xff;
+ this.oi = this.viNext - this.vi;
+
+ // the secret coefficients of all polynomials in this layer
+ this.coeff_alpha = coeffAlpha;
+ this.coeff_beta = coeffBeta;
+ this.coeff_gamma = coeffGamma;
+ this.coeff_eta = coeffEta;
+ }
+
+ /**
+ * This function generates the coefficients of all polynomials in this layer
+ * at random using random generator.
+ *
+ * @param sr the random generator which is to be used
+ */
+ public Layer(int vi, int viNext, SecureRandom sr)
+ {
+ this.vi = vi;
+ this.viNext = viNext;
+ this.oi = viNext - vi;
+
+ // the coefficients of all polynomials in this layer
+ this.coeff_alpha = new short[this.oi][this.oi][this.vi];
+ this.coeff_beta = new short[this.oi][this.vi][this.vi];
+ this.coeff_gamma = new short[this.oi][this.viNext];
+ this.coeff_eta = new short[this.oi];
+
+ int numOfPoly = this.oi; // number of polynomials per layer
+
+ // Alpha coeffs
+ for (int k = 0; k < numOfPoly; k++)
+ {
+ for (int i = 0; i < this.oi; i++)
+ {
+ for (int j = 0; j < this.vi; j++)
+ {
+ coeff_alpha[k][i][j] = (short)(sr.nextInt() & GF2Field.MASK);
+ }
+ }
+ }
+ // Beta coeffs
+ for (int k = 0; k < numOfPoly; k++)
+ {
+ for (int i = 0; i < this.vi; i++)
+ {
+ for (int j = 0; j < this.vi; j++)
+ {
+ coeff_beta[k][i][j] = (short)(sr.nextInt() & GF2Field.MASK);
+ }
+ }
+ }
+ // Gamma coeffs
+ for (int k = 0; k < numOfPoly; k++)
+ {
+ for (int i = 0; i < this.viNext; i++)
+ {
+ coeff_gamma[k][i] = (short)(sr.nextInt() & GF2Field.MASK);
+ }
+ }
+ // Eta
+ for (int k = 0; k < numOfPoly; k++)
+ {
+ coeff_eta[k] = (short)(sr.nextInt() & GF2Field.MASK);
+ }
+ }
+
+ /**
+ * This method plugs in the vinegar variables into the polynomials of this
+ * layer and computes the coefficients of the Oil-variables as well as the
+ * free coefficient in each polynomial.
+ *
+ * It is needed for computing the Oil variables while signing.
+ *
+ * @param x vinegar variables of this layer that should be plugged into
+ * the polynomials.
+ * @return coeff the coefficients of Oil variables and the free coeff in the
+ * polynomials of this layer.
+ */
+ public short[][] plugInVinegars(short[] x)
+ {
+ // temporary variable needed for the multiplication
+ short tmpMult = 0;
+ // coeff: 1st index = which polynomial, 2nd index=which variable
+ short[][] coeff = new short[oi][oi + 1]; // gets returned
+ // free coefficient per polynomial
+ short[] sum = new short[oi];
+
+ /*
+ * evaluate the beta-part of the polynomials (it contains no oil
+ * variables)
+ */
+ for (int k = 0; k < oi; k++)
+ {
+ for (int i = 0; i < vi; i++)
+ {
+ for (int j = 0; j < vi; j++)
+ {
+ // tmp = beta * xi (plug in)
+ tmpMult = GF2Field.multElem(coeff_beta[k][i][j], x[i]);
+ // tmp = tmp * xj
+ tmpMult = GF2Field.multElem(tmpMult, x[j]);
+ // accumulate into the array for the free coefficients.
+ sum[k] = GF2Field.addElem(sum[k], tmpMult);
+ }
+ }
+ }
+
+ /* evaluate the alpha-part (it contains oils) */
+ for (int k = 0; k < oi; k++)
+ {
+ for (int i = 0; i < oi; i++)
+ {
+ for (int j = 0; j < vi; j++)
+ {
+ // alpha * xj (plug in)
+ tmpMult = GF2Field.multElem(coeff_alpha[k][i][j], x[j]);
+ // accumulate
+ coeff[k][i] = GF2Field.addElem(coeff[k][i], tmpMult);
+ }
+ }
+ }
+ /* evaluate the gama-part of the polynomial (containing no oils) */
+ for (int k = 0; k < oi; k++)
+ {
+ for (int i = 0; i < vi; i++)
+ {
+ // gamma * xi (plug in)
+ tmpMult = GF2Field.multElem(coeff_gamma[k][i], x[i]);
+ // accumulate in the array for the free coefficients (per
+ // polynomial).
+ sum[k] = GF2Field.addElem(sum[k], tmpMult);
+ }
+ }
+ /* evaluate the gama-part of the polynomial (but containing oils) */
+ for (int k = 0; k < oi; k++)
+ {
+ for (int i = vi; i < viNext; i++)
+ { // oils
+ // accumulate the coefficients of the oil variables (per
+ // polynomial).
+ coeff[k][i - vi] = GF2Field.addElem(coeff_gamma[k][i],
+ coeff[k][i - vi]);
+ }
+ }
+ /* evaluate the eta-part of the polynomial */
+ for (int k = 0; k < oi; k++)
+ {
+ // accumulate in the array for the free coefficients per polynomial.
+ sum[k] = GF2Field.addElem(sum[k], coeff_eta[k]);
+ }
+
+ /* put the free coefficients (sum) into the coeff-array as last column */
+ for (int k = 0; k < oi; k++)
+ {
+ coeff[k][oi] = sum[k];
+ }
+ return coeff;
+ }
+
+ /**
+ * Getter for the number of vinegar variables of this layer.
+ *
+ * @return the number of vinegar variables of this layer.
+ */
+ public int getVi()
+ {
+ return vi;
+ }
+
+ /**
+ * Getter for the number of vinegar variables of the next layer.
+ *
+ * @return the number of vinegar variables of the next layer.
+ */
+ public int getViNext()
+ {
+ return viNext;
+ }
+
+ /**
+ * Getter for the number of Oil variables of this layer.
+ *
+ * @return the number of oil variables of this layer.
+ */
+ public int getOi()
+ {
+ return oi;
+ }
+
+ /**
+ * Getter for the alpha-coefficients of the polynomials in this layer.
+ *
+ * @return the coefficients of alpha-terms of this layer.
+ */
+ public short[][][] getCoeffAlpha()
+ {
+ return coeff_alpha;
+ }
+
+ /**
+ * Getter for the beta-coefficients of the polynomials in this layer.
+ *
+ * @return the coefficients of beta-terms of this layer.
+ */
+
+ public short[][][] getCoeffBeta()
+ {
+ return coeff_beta;
+ }
+
+ /**
+ * Getter for the gamma-coefficients of the polynomials in this layer.
+ *
+ * @return the coefficients of gamma-terms of this layer
+ */
+ public short[][] getCoeffGamma()
+ {
+ return coeff_gamma;
+ }
+
+ /**
+ * Getter for the eta-coefficients of the polynomials in this layer.
+ *
+ * @return the coefficients eta of this layer
+ */
+ public short[] getCoeffEta()
+ {
+ return coeff_eta;
+ }
+
+ /**
+ * This function compares this Layer with another object.
+ *
+ * @param other the other object
+ * @return the result of the comparison
+ */
+ public boolean equals(Object other)
+ {
+ if (other == null || !(other instanceof Layer))
+ {
+ return false;
+ }
+ Layer otherLayer = (Layer)other;
+
+ return vi == otherLayer.getVi()
+ && viNext == otherLayer.getViNext()
+ && oi == otherLayer.getOi()
+ && RainbowUtil.equals(coeff_alpha, otherLayer.getCoeffAlpha())
+ && RainbowUtil.equals(coeff_beta, otherLayer.getCoeffBeta())
+ && RainbowUtil.equals(coeff_gamma, otherLayer.getCoeffGamma())
+ && RainbowUtil.equals(coeff_eta, otherLayer.getCoeffEta());
+ }
+
+ public int hashCode()
+ {
+ int hash = vi;
+ hash = hash * 37 + viNext;
+ hash = hash * 37 + oi;
+ hash = hash * 37 + Arrays.hashCode(coeff_alpha);
+ hash = hash * 37 + Arrays.hashCode(coeff_beta);
+ hash = hash * 37 + Arrays.hashCode(coeff_gamma);
+ hash = hash * 37 + Arrays.hashCode(coeff_eta);
+
+ return hash;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/rainbow/RainbowKeyGenerationParameters.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/rainbow/RainbowKeyGenerationParameters.java
new file mode 100644
index 0000000..838a55c
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/rainbow/RainbowKeyGenerationParameters.java
@@ -0,0 +1,26 @@
+package org.bc.pqc.crypto.rainbow;
+
+import java.security.SecureRandom;
+
+import org.bc.crypto.KeyGenerationParameters;
+
+public class RainbowKeyGenerationParameters
+ extends KeyGenerationParameters
+{
+ private RainbowParameters params;
+
+ public RainbowKeyGenerationParameters(
+ SecureRandom random,
+ RainbowParameters params)
+ {
+ // TODO: key size?
+ super(random, params.getVi()[params.getVi().length - 1] - params.getVi()[0]);
+ this.params = params;
+ }
+
+ public RainbowParameters getParameters()
+ {
+ return params;
+ }
+}
+
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/rainbow/RainbowKeyPairGenerator.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/rainbow/RainbowKeyPairGenerator.java
new file mode 100644
index 0000000..4f457c7
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/rainbow/RainbowKeyPairGenerator.java
@@ -0,0 +1,414 @@
+package org.bc.pqc.crypto.rainbow;
+
+import java.security.SecureRandom;
+
+import org.bc.crypto.AsymmetricCipherKeyPair;
+import org.bc.crypto.AsymmetricCipherKeyPairGenerator;
+import org.bc.crypto.KeyGenerationParameters;
+import org.bc.pqc.crypto.rainbow.util.ComputeInField;
+import org.bc.pqc.crypto.rainbow.util.GF2Field;
+
+/**
+ * This class implements AsymmetricCipherKeyPairGenerator. It is used
+ * as a generator for the private and public key of the Rainbow Signature
+ * Scheme.
+ *
+ * Detailed information about the key generation is to be found in the paper of
+ * Jintai Ding, Dieter Schmidt: Rainbow, a New Multivariable Polynomial
+ * Signature Scheme. ACNS 2005: 164-175 (http://dx.doi.org/10.1007/11496137_12)
+ */
+public class RainbowKeyPairGenerator
+ implements AsymmetricCipherKeyPairGenerator
+{
+ private boolean initialized = false;
+ private SecureRandom sr;
+ private RainbowKeyGenerationParameters rainbowParams;
+
+ /* linear affine map L1: */
+ private short[][] A1; // matrix of the lin. affine map L1(n-v1 x n-v1 matrix)
+ private short[][] A1inv; // inverted A1
+ private short[] b1; // translation element of the lin.affine map L1
+
+ /* linear affine map L2: */
+ private short[][] A2; // matrix of the lin. affine map (n x n matrix)
+ private short[][] A2inv; // inverted A2
+ private short[] b2; // translation elemt of the lin.affine map L2
+
+ /* components of F: */
+ private int numOfLayers; // u (number of sets S)
+ private Layer layers[]; // layers of polynomials of F
+ private int[] vi; // set of vinegar vars per layer.
+
+ /* components of Public Key */
+ private short[][] pub_quadratic; // quadratic(mixed) coefficients
+ private short[][] pub_singular; // singular coefficients
+ private short[] pub_scalar; // scalars
+
+ // TODO
+
+ /**
+ * The standard constructor tries to generate the Rainbow algorithm identifier
+ * with the corresponding OID.
+ *
+ */
+ public RainbowKeyPairGenerator()
+ {
+ }
+
+
+ /**
+ * This function generates a Rainbow key pair.
+ *
+ * @return the generated key pair
+ */
+ public AsymmetricCipherKeyPair genKeyPair()
+ {
+ RainbowPrivateKeyParameters privKey;
+ RainbowPublicKeyParameters pubKey;
+
+ if (!initialized)
+ {
+ initializeDefault();
+ }
+
+ /* choose all coefficients at random */
+ keygen();
+
+ /* now marshall them to PrivateKey */
+ privKey = new RainbowPrivateKeyParameters(A1inv, b1, A2inv, b2, vi, layers);
+
+
+ /* marshall to PublicKey */
+ pubKey = new RainbowPublicKeyParameters(vi[vi.length - 1] - vi[0], pub_quadratic, pub_singular, pub_scalar);
+
+ return new AsymmetricCipherKeyPair(pubKey, privKey);
+ }
+
+ // TODO
+ public void initialize(
+ KeyGenerationParameters param)
+ {
+ this.rainbowParams = (RainbowKeyGenerationParameters)param;
+
+ // set source of randomness
+ this.sr = new SecureRandom();
+
+ // unmarshalling:
+ this.vi = this.rainbowParams.getParameters().getVi();
+ this.numOfLayers = this.rainbowParams.getParameters().getNumOfLayers();
+
+ this.initialized = true;
+ }
+
+ private void initializeDefault()
+ {
+ RainbowKeyGenerationParameters rbKGParams = new RainbowKeyGenerationParameters(new SecureRandom(), new RainbowParameters());
+ initialize(rbKGParams);
+ }
+
+ /**
+ * This function calls the functions for the random generation of the coefficients
+ * and the matrices needed for the private key and the method for computing the public key.
+ */
+ private void keygen()
+ {
+ generateL1();
+ generateL2();
+ generateF();
+ computePublicKey();
+ }
+
+ /**
+ * This function generates the invertible affine linear map L1 = A1*x + b1
+ *
+ * The translation part b1, is stored in a separate array. The inverse of
+ * the matrix-part of L1 A1inv is also computed here.
+ *
+ * This linear map hides the output of the map F. It is on k^(n-v1).
+ */
+ private void generateL1()
+ {
+
+ // dimension = n-v1 = vi[last] - vi[first]
+ int dim = vi[vi.length - 1] - vi[0];
+ this.A1 = new short[dim][dim];
+ this.A1inv = null;
+ ComputeInField c = new ComputeInField();
+
+ /* generation of A1 at random */
+ while (A1inv == null)
+ {
+ for (int i = 0; i < dim; i++)
+ {
+ for (int j = 0; j < dim; j++)
+ {
+ A1[i][j] = (short)(sr.nextInt() & GF2Field.MASK);
+ }
+ }
+ A1inv = c.inverse(A1);
+ }
+
+ /* generation of the translation vector at random */
+ b1 = new short[dim];
+ for (int i = 0; i < dim; i++)
+ {
+ b1[i] = (short)(sr.nextInt() & GF2Field.MASK);
+ }
+ }
+
+ /**
+ * This function generates the invertible affine linear map L2 = A2*x + b2
+ *
+ * The translation part b2, is stored in a separate array. The inverse of
+ * the matrix-part of L2 A2inv is also computed here.
+ *
+ * This linear map hides the output of the map F. It is on k^(n).
+ */
+ private void generateL2()
+ {
+
+ // dimension = n = vi[last]
+ int dim = vi[vi.length - 1];
+ this.A2 = new short[dim][dim];
+ this.A2inv = null;
+ ComputeInField c = new ComputeInField();
+
+ /* generation of A2 at random */
+ while (this.A2inv == null)
+ {
+ for (int i = 0; i < dim; i++)
+ {
+ for (int j = 0; j < dim; j++)
+ { // one col extra for b
+ A2[i][j] = (short)(sr.nextInt() & GF2Field.MASK);
+ }
+ }
+ this.A2inv = c.inverse(A2);
+ }
+ /* generation of the translation vector at random */
+ b2 = new short[dim];
+ for (int i = 0; i < dim; i++)
+ {
+ b2[i] = (short)(sr.nextInt() & GF2Field.MASK);
+ }
+
+ }
+
+ /**
+ * This function generates the private map F, which consists of u-1 layers.
+ * Each layer consists of oi polynomials where oi = vi[i+1]-vi[i].
+ *
+ * The methods for the generation of the coefficients of these polynomials
+ * are called here.
+ */
+ private void generateF()
+ {
+
+ this.layers = new Layer[this.numOfLayers];
+ for (int i = 0; i < this.numOfLayers; i++)
+ {
+ layers[i] = new Layer(this.vi[i], this.vi[i + 1], sr);
+ }
+ }
+
+ /**
+ * This function computes the public key from the private key.
+ *
+ * The composition of F with L2 is computed, followed by applying L1 to the
+ * composition's result. The singular and scalar values constitute to the
+ * public key as is, the quadratic terms are compacted in
+ * compactPublicKey()
+ */
+ private void computePublicKey()
+ {
+
+ ComputeInField c = new ComputeInField();
+ int rows = this.vi[this.vi.length - 1] - this.vi[0];
+ int vars = this.vi[this.vi.length - 1];
+ // Fpub
+ short[][][] coeff_quadratic_3dim = new short[rows][vars][vars];
+ this.pub_singular = new short[rows][vars];
+ this.pub_scalar = new short[rows];
+
+ // Coefficients of layers of Private Key F
+ short[][][] coeff_alpha;
+ short[][][] coeff_beta;
+ short[][] coeff_gamma;
+ short[] coeff_eta;
+
+ // Needed for counters;
+ int oils = 0;
+ int vins = 0;
+ int crnt_row = 0; // current row (polynomial)
+
+ short vect_tmp[] = new short[vars]; // vector tmp;
+ short sclr_tmp = 0;
+
+ // Composition of F and L2: Insert L2 = A2*x+b2 in F
+ for (int l = 0; l < this.layers.length; l++)
+ {
+ // get coefficients of current layer
+ coeff_alpha = this.layers[l].getCoeffAlpha();
+ coeff_beta = this.layers[l].getCoeffBeta();
+ coeff_gamma = this.layers[l].getCoeffGamma();
+ coeff_eta = this.layers[l].getCoeffEta();
+ oils = coeff_alpha[0].length;// this.layers[l].getOi();
+ vins = coeff_beta[0].length;// this.layers[l].getVi();
+ // compute polynomials of layer
+ for (int p = 0; p < oils; p++)
+ {
+ // multiply alphas
+ for (int x1 = 0; x1 < oils; x1++)
+ {
+ for (int x2 = 0; x2 < vins; x2++)
+ {
+ // multiply polynomial1 with polynomial2
+ vect_tmp = c.multVect(coeff_alpha[p][x1][x2],
+ this.A2[x1 + vins]);
+ coeff_quadratic_3dim[crnt_row + p] = c.addSquareMatrix(
+ coeff_quadratic_3dim[crnt_row + p], c
+ .multVects(vect_tmp, this.A2[x2]));
+ // mul poly1 with scalar2
+ vect_tmp = c.multVect(this.b2[x2], vect_tmp);
+ this.pub_singular[crnt_row + p] = c.addVect(vect_tmp,
+ this.pub_singular[crnt_row + p]);
+ // mul scalar1 with poly2
+ vect_tmp = c.multVect(coeff_alpha[p][x1][x2],
+ this.A2[x2]);
+ vect_tmp = c.multVect(b2[x1 + vins], vect_tmp);
+ this.pub_singular[crnt_row + p] = c.addVect(vect_tmp,
+ this.pub_singular[crnt_row + p]);
+ // mul scalar1 with scalar2
+ sclr_tmp = GF2Field.multElem(coeff_alpha[p][x1][x2],
+ this.b2[x1 + vins]);
+ this.pub_scalar[crnt_row + p] = GF2Field.addElem(
+ this.pub_scalar[crnt_row + p], GF2Field
+ .multElem(sclr_tmp, this.b2[x2]));
+ }
+ }
+ // multiply betas
+ for (int x1 = 0; x1 < vins; x1++)
+ {
+ for (int x2 = 0; x2 < vins; x2++)
+ {
+ // multiply polynomial1 with polynomial2
+ vect_tmp = c.multVect(coeff_beta[p][x1][x2],
+ this.A2[x1]);
+ coeff_quadratic_3dim[crnt_row + p] = c.addSquareMatrix(
+ coeff_quadratic_3dim[crnt_row + p], c
+ .multVects(vect_tmp, this.A2[x2]));
+ // mul poly1 with scalar2
+ vect_tmp = c.multVect(this.b2[x2], vect_tmp);
+ this.pub_singular[crnt_row + p] = c.addVect(vect_tmp,
+ this.pub_singular[crnt_row + p]);
+ // mul scalar1 with poly2
+ vect_tmp = c.multVect(coeff_beta[p][x1][x2],
+ this.A2[x2]);
+ vect_tmp = c.multVect(this.b2[x1], vect_tmp);
+ this.pub_singular[crnt_row + p] = c.addVect(vect_tmp,
+ this.pub_singular[crnt_row + p]);
+ // mul scalar1 with scalar2
+ sclr_tmp = GF2Field.multElem(coeff_beta[p][x1][x2],
+ this.b2[x1]);
+ this.pub_scalar[crnt_row + p] = GF2Field.addElem(
+ this.pub_scalar[crnt_row + p], GF2Field
+ .multElem(sclr_tmp, this.b2[x2]));
+ }
+ }
+ // multiply gammas
+ for (int n = 0; n < vins + oils; n++)
+ {
+ // mul poly with scalar
+ vect_tmp = c.multVect(coeff_gamma[p][n], this.A2[n]);
+ this.pub_singular[crnt_row + p] = c.addVect(vect_tmp,
+ this.pub_singular[crnt_row + p]);
+ // mul scalar with scalar
+ this.pub_scalar[crnt_row + p] = GF2Field.addElem(
+ this.pub_scalar[crnt_row + p], GF2Field.multElem(
+ coeff_gamma[p][n], this.b2[n]));
+ }
+ // add eta
+ this.pub_scalar[crnt_row + p] = GF2Field.addElem(
+ this.pub_scalar[crnt_row + p], coeff_eta[p]);
+ }
+ crnt_row = crnt_row + oils;
+ }
+
+ // Apply L1 = A1*x+b1 to composition of F and L2
+ {
+ // temporary coefficient arrays
+ short[][][] tmp_c_quad = new short[rows][vars][vars];
+ short[][] tmp_c_sing = new short[rows][vars];
+ short[] tmp_c_scal = new short[rows];
+ for (int r = 0; r < rows; r++)
+ {
+ for (int q = 0; q < A1.length; q++)
+ {
+ tmp_c_quad[r] = c.addSquareMatrix(tmp_c_quad[r], c
+ .multMatrix(A1[r][q], coeff_quadratic_3dim[q]));
+ tmp_c_sing[r] = c.addVect(tmp_c_sing[r], c.multVect(
+ A1[r][q], this.pub_singular[q]));
+ tmp_c_scal[r] = GF2Field.addElem(tmp_c_scal[r], GF2Field
+ .multElem(A1[r][q], this.pub_scalar[q]));
+ }
+ tmp_c_scal[r] = GF2Field.addElem(tmp_c_scal[r], b1[r]);
+ }
+ // set public key
+ coeff_quadratic_3dim = tmp_c_quad;
+ this.pub_singular = tmp_c_sing;
+ this.pub_scalar = tmp_c_scal;
+ }
+ compactPublicKey(coeff_quadratic_3dim);
+ }
+
+ /**
+ * The quadratic (or mixed) terms of the public key are compacted from a n x
+ * n matrix per polynomial to an upper diagonal matrix stored in one integer
+ * array of n (n + 1) / 2 elements per polynomial. The ordering of elements
+ * is lexicographic and the result is updating this.pub_quadratic,
+ * which stores the quadratic elements of the public key.
+ *
+ * @param coeff_quadratic_to_compact 3-dimensional array containing a n x n Matrix for each of the
+ * n - v1 polynomials
+ */
+ private void compactPublicKey(short[][][] coeff_quadratic_to_compact)
+ {
+ int polynomials = coeff_quadratic_to_compact.length;
+ int n = coeff_quadratic_to_compact[0].length;
+ int entries = n * (n + 1) / 2;// the small gauss
+ this.pub_quadratic = new short[polynomials][entries];
+ int offset = 0;
+
+ for (int p = 0; p < polynomials; p++)
+ {
+ offset = 0;
+ for (int x = 0; x < n; x++)
+ {
+ for (int y = x; y < n; y++)
+ {
+ if (y == x)
+ {
+ this.pub_quadratic[p][offset] = coeff_quadratic_to_compact[p][x][y];
+ }
+ else
+ {
+ this.pub_quadratic[p][offset] = GF2Field.addElem(
+ coeff_quadratic_to_compact[p][x][y],
+ coeff_quadratic_to_compact[p][y][x]);
+ }
+ offset++;
+ }
+ }
+ }
+ }
+
+ public void init(KeyGenerationParameters param)
+ {
+ this.initialize(param);
+ }
+
+ public AsymmetricCipherKeyPair generateKeyPair()
+ {
+ return genKeyPair();
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/rainbow/RainbowKeyParameters.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/rainbow/RainbowKeyParameters.java
new file mode 100644
index 0000000..0a8caa8
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/rainbow/RainbowKeyParameters.java
@@ -0,0 +1,25 @@
+package org.bc.pqc.crypto.rainbow;
+
+import org.bc.crypto.params.AsymmetricKeyParameter;
+
+public class RainbowKeyParameters
+ extends AsymmetricKeyParameter
+{
+ private int docLength;
+
+ public RainbowKeyParameters(
+ boolean isPrivate,
+ int docLength)
+ {
+ super(isPrivate);
+ this.docLength = docLength;
+ }
+
+ /**
+ * @return the docLength
+ */
+ public int getDocLength()
+ {
+ return this.docLength;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/rainbow/RainbowParameters.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/rainbow/RainbowParameters.java
new file mode 100644
index 0000000..c80a040
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/rainbow/RainbowParameters.java
@@ -0,0 +1,111 @@
+package org.bc.pqc.crypto.rainbow;
+
+import org.bc.crypto.CipherParameters;
+
+public class RainbowParameters
+ implements CipherParameters
+{
+
+ /**
+ * DEFAULT PARAMS
+ */
+ /*
+ * Vi = vinegars per layer whereas n is vu (vu = 33 = n) such that
+ *
+ * v1 = 6; o1 = 12-6 = 6
+ *
+ * v2 = 12; o2 = 17-12 = 5
+ *
+ * v3 = 17; o3 = 22-17 = 5
+ *
+ * v4 = 22; o4 = 33-22 = 11
+ *
+ * v5 = 33; (o5 = 0)
+ */
+ private final int[] DEFAULT_VI = {6, 12, 17, 22, 33};
+
+ private int[] vi;// set of vinegar vars per layer.
+
+ /**
+ * Default Constructor The elements of the array containing the number of
+ * Vinegar variables in each layer are set to the default values here.
+ */
+ public RainbowParameters()
+ {
+ this.vi = this.DEFAULT_VI;
+ }
+
+ /**
+ * Constructor with parameters
+ *
+ * @param vi The elements of the array containing the number of Vinegar
+ * variables per layer are set to the values of the input array.
+ */
+ public RainbowParameters(int[] vi)
+ {
+ this.vi = vi;
+ try
+ {
+ checkParams();
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ private void checkParams()
+ throws Exception
+ {
+ if (vi == null)
+ {
+ throw new Exception("no layers defined.");
+ }
+ if (vi.length > 1)
+ {
+ for (int i = 0; i < vi.length - 1; i++)
+ {
+ if (vi[i] >= vi[i + 1])
+ {
+ throw new Exception(
+ "v[i] has to be smaller than v[i+1]");
+ }
+ }
+ }
+ else
+ {
+ throw new Exception(
+ "Rainbow needs at least 1 layer, such that v1 < v2.");
+ }
+ }
+
+ /**
+ * Getter for the number of layers
+ *
+ * @return the number of layers
+ */
+ public int getNumOfLayers()
+ {
+ return this.vi.length - 1;
+ }
+
+ /**
+ * Getter for the number of all the polynomials in Rainbow
+ *
+ * @return the number of the polynomials
+ */
+ public int getDocLength()
+ {
+ return vi[vi.length - 1] - vi[0];
+ }
+
+ /**
+ * Getter for the array containing the number of Vinegar-variables per layer
+ *
+ * @return the numbers of vinegars per layer
+ */
+ public int[] getVi()
+ {
+ return this.vi;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/rainbow/RainbowPrivateKeyParameters.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/rainbow/RainbowPrivateKeyParameters.java
new file mode 100644
index 0000000..36207ab
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/rainbow/RainbowPrivateKeyParameters.java
@@ -0,0 +1,117 @@
+package org.bc.pqc.crypto.rainbow;
+
+public class RainbowPrivateKeyParameters
+ extends RainbowKeyParameters
+{
+ /**
+ * Constructor
+ *
+ * @param A1inv the inverse of A1(the matrix part of the affine linear map L1)
+ * (n-v1 x n-v1 matrix)
+ * @param b1 translation vector, part of the linear affine map L1
+ * @param A2inv the inverse of A2(the matrix part of the affine linear map L2)
+ * (n x n matrix)
+ * @param b2 translation vector, part of the linear affine map L2
+ * @param vi the number of Vinegar-variables per layer
+ * @param layers the polynomials with their coefficients of private map F
+ */
+ public RainbowPrivateKeyParameters(short[][] A1inv, short[] b1,
+ short[][] A2inv, short[] b2, int[] vi, Layer[] layers)
+ {
+ super(true, vi[vi.length - 1] - vi[0]);
+
+ this.A1inv = A1inv;
+ this.b1 = b1;
+ this.A2inv = A2inv;
+ this.b2 = b2;
+ this.vi = vi;
+ this.layers = layers;
+ }
+
+ /*
+ * invertible affine linear map L1
+ */
+ // the inverse of A1, (n-v1 x n-v1 matrix)
+ private short[][] A1inv;
+
+ // translation vector of L1
+ private short[] b1;
+
+ /*
+ * invertible affine linear map L2
+ */
+ // the inverse of A2, (n x n matrix)
+ private short[][] A2inv;
+
+ // translation vector of L2
+ private short[] b2;
+
+ /*
+ * components of F
+ */
+ // the number of Vinegar-variables per layer.
+ private int[] vi;
+
+ // contains the polynomials with their coefficients of private map F
+ private Layer[] layers;
+
+ /**
+ * Getter for the translation part of the private quadratic map L1.
+ *
+ * @return b1 the translation part of L1
+ */
+ public short[] getB1()
+ {
+ return this.b1;
+ }
+
+ /**
+ * Getter for the inverse matrix of A1.
+ *
+ * @return the A1inv inverse
+ */
+ public short[][] getInvA1()
+ {
+ return this.A1inv;
+ }
+
+ /**
+ * Getter for the translation part of the private quadratic map L2.
+ *
+ * @return b2 the translation part of L2
+ */
+ public short[] getB2()
+ {
+ return this.b2;
+ }
+
+ /**
+ * Getter for the inverse matrix of A2
+ *
+ * @return the A2inv
+ */
+ public short[][] getInvA2()
+ {
+ return this.A2inv;
+ }
+
+ /**
+ * Returns the layers contained in the private key
+ *
+ * @return layers
+ */
+ public Layer[] getLayers()
+ {
+ return this.layers;
+ }
+
+ /**
+ * /** Returns the array of vi-s
+ *
+ * @return the vi
+ */
+ public int[] getVi()
+ {
+ return vi;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/rainbow/RainbowPublicKeyParameters.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/rainbow/RainbowPublicKeyParameters.java
new file mode 100644
index 0000000..dd131a0
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/rainbow/RainbowPublicKeyParameters.java
@@ -0,0 +1,53 @@
+package org.bc.pqc.crypto.rainbow;
+
+public class RainbowPublicKeyParameters
+ extends RainbowKeyParameters
+{
+ private short[][] coeffquadratic;
+ private short[][] coeffsingular;
+ private short[] coeffscalar;
+
+ /**
+ * Constructor
+ *
+ * @param docLength
+ * @param coeffQuadratic
+ * @param coeffSingular
+ * @param coeffScalar
+ */
+ public RainbowPublicKeyParameters(int docLength,
+ short[][] coeffQuadratic, short[][] coeffSingular,
+ short[] coeffScalar)
+ {
+ super(false, docLength);
+
+ this.coeffquadratic = coeffQuadratic;
+ this.coeffsingular = coeffSingular;
+ this.coeffscalar = coeffScalar;
+
+ }
+
+ /**
+ * @return the coeffquadratic
+ */
+ public short[][] getCoeffQuadratic()
+ {
+ return coeffquadratic;
+ }
+
+ /**
+ * @return the coeffsingular
+ */
+ public short[][] getCoeffSingular()
+ {
+ return coeffsingular;
+ }
+
+ /**
+ * @return the coeffscalar
+ */
+ public short[] getCoeffScalar()
+ {
+ return coeffscalar;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/rainbow/RainbowSigner.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/rainbow/RainbowSigner.java
new file mode 100644
index 0000000..6b34f3a
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/rainbow/RainbowSigner.java
@@ -0,0 +1,301 @@
+package org.bc.pqc.crypto.rainbow;
+
+import java.security.SecureRandom;
+
+import org.bc.crypto.CipherParameters;
+import org.bc.crypto.params.ParametersWithRandom;
+import org.bc.pqc.crypto.MessageSigner;
+import org.bc.pqc.crypto.rainbow.util.ComputeInField;
+import org.bc.pqc.crypto.rainbow.util.GF2Field;
+
+/**
+ * It implements the sign and verify functions for the Rainbow Signature Scheme.
+ * Here the message, which has to be signed, is updated. The use of
+ * different hash functions is possible.
+ *
+ * Detailed information about the signature and the verify-method is to be found
+ * in the paper of Jintai Ding, Dieter Schmidt: Rainbow, a New Multivariable
+ * Polynomial Signature Scheme. ACNS 2005: 164-175
+ * (http://dx.doi.org/10.1007/11496137_12)
+ */
+public class RainbowSigner
+ implements MessageSigner
+{
+ // Source of randomness
+ private SecureRandom random;
+
+ // The length of a document that can be signed with the privKey
+ int signableDocumentLength;
+
+ // Container for the oil and vinegar variables of all the layers
+ private short[] x;
+
+ private ComputeInField cf = new ComputeInField();
+
+ RainbowKeyParameters key;
+
+ public void init(boolean forSigning,
+ CipherParameters param)
+ {
+ if (forSigning)
+ {
+ if (param instanceof ParametersWithRandom)
+ {
+ ParametersWithRandom rParam = (ParametersWithRandom)param;
+
+ this.random = rParam.getRandom();
+ this.key = (RainbowPrivateKeyParameters)rParam.getParameters();
+
+ }
+ else
+ {
+
+ this.random = new SecureRandom();
+ this.key = (RainbowPrivateKeyParameters)param;
+ }
+ }
+ else
+ {
+ this.key = (RainbowPublicKeyParameters)param;
+ }
+
+ this.signableDocumentLength = this.key.getDocLength();
+ }
+
+
+ /**
+ * initial operations before solving the Linear equation system.
+ *
+ * @param layer the current layer for which a LES is to be solved.
+ * @param msg the message that should be signed.
+ * @return Y_ the modified document needed for solving LES, (Y_ =
+ * A1^{-1}*(Y-b1)) linear map L1 = A1 x + b1.
+ */
+ private short[] initSign(Layer[] layer, short[] msg)
+ {
+
+ /* preparation: Modifies the document with the inverse of L1 */
+ // tmp = Y - b1:
+ short[] tmpVec = new short[msg.length];
+
+ tmpVec = cf.addVect(((RainbowPrivateKeyParameters)this.key).getB1(), msg);
+
+ // Y_ = A1^{-1} * (Y - b1) :
+ short[] Y_ = cf.multiplyMatrix(((RainbowPrivateKeyParameters)this.key).getInvA1(), tmpVec);
+
+ /* generates the vinegar vars of the first layer at random */
+ for (int i = 0; i < layer[0].getVi(); i++)
+ {
+ x[i] = (short)random.nextInt();
+ x[i] = (short)(x[i] & GF2Field.MASK);
+ }
+
+ return Y_;
+ }
+
+ /**
+ * This function signs the message that has been updated, making use of the
+ * private key.
+ *
+ * For computing the signature, L1 and L2 are needed, as well as LES should
+ * be solved for each layer in order to find the Oil-variables in the layer.
+ *
+ * The Vinegar-variables of the first layer are random generated.
+ *
+ * @param message the message
+ * @return the signature of the message.
+ */
+ public byte[] generateSignature(byte[] message)
+ {
+ Layer[] layer = ((RainbowPrivateKeyParameters)this.key).getLayers();
+ int numberOfLayers = layer.length;
+
+ x = new short[((RainbowPrivateKeyParameters)this.key).getInvA2().length]; // all variables
+
+ short[] Y_; // modified document
+ short[] y_i; // part of Y_ each polynomial
+ int counter; // index of the current part of the doc
+
+ short[] solVec; // the solution of LES pro layer
+ short[] tmpVec;
+
+ // the signature as an array of shorts:
+ short[] signature;
+ // the signature as a byte-array:
+ byte[] S = new byte[layer[numberOfLayers - 1].getViNext()];
+
+ short[] msgHashVals = makeMessageRepresentative(message);
+
+ // shows if an exception is caught
+ boolean ok;
+ do
+ {
+ ok = true;
+ counter = 0;
+ try
+ {
+ Y_ = initSign(layer, msgHashVals);
+
+ for (int i = 0; i < numberOfLayers; i++)
+ {
+
+ y_i = new short[layer[i].getOi()];
+ solVec = new short[layer[i].getOi()]; // solution of LES
+
+ /* copy oi elements of Y_ into y_i */
+ for (int k = 0; k < layer[i].getOi(); k++)
+ {
+ y_i[k] = Y_[counter];
+ counter++; // current index of Y_
+ }
+
+ /*
+ * plug in the vars of the previous layer in order to get
+ * the vars of the current layer
+ */
+ solVec = cf.solveEquation(layer[i].plugInVinegars(x), y_i);
+
+ if (solVec == null)
+ { // LES is not solveable
+ throw new Exception("LES is not solveable!");
+ }
+
+ /* copy the new vars into the x-array */
+ for (int j = 0; j < solVec.length; j++)
+ {
+ x[layer[i].getVi() + j] = solVec[j];
+ }
+ }
+
+ /* apply the inverse of L2: (signature = A2^{-1}*(b2+x)) */
+ tmpVec = cf.addVect(((RainbowPrivateKeyParameters)this.key).getB2(), x);
+ signature = cf.multiplyMatrix(((RainbowPrivateKeyParameters)this.key).getInvA2(), tmpVec);
+
+ /* cast signature from short[] to byte[] */
+ for (int i = 0; i < S.length; i++)
+ {
+ S[i] = ((byte)signature[i]);
+ }
+ }
+ catch (Exception se)
+ {
+ // if one of the LESs was not solveable - sign again
+ ok = false;
+ }
+ }
+ while (!ok);
+ /* return the signature in bytes */
+ return S;
+ }
+
+ /**
+ * This function verifies the signature of the message that has been
+ * updated, with the aid of the public key.
+ *
+ * @param message the message
+ * @param signature the signature of the message
+ * @return true if the signature has been verified, false otherwise.
+ */
+ public boolean verifySignature(byte[] message, byte[] signature)
+ {
+ short[] sigInt = new short[signature.length];
+ short tmp;
+
+ for (int i = 0; i < signature.length; i++)
+ {
+ tmp = (short)signature[i];
+ tmp &= (short)0xff;
+ sigInt[i] = tmp;
+ }
+
+ short[] msgHashVal = makeMessageRepresentative(message);
+
+ // verify
+ short[] verificationResult = verifySignatureIntern(sigInt);
+
+ // compare
+ boolean verified = true;
+ if (msgHashVal.length != verificationResult.length)
+ {
+ return false;
+ }
+ for (int i = 0; i < msgHashVal.length; i++)
+ {
+ verified = verified && msgHashVal[i] == verificationResult[i];
+ }
+
+ return verified;
+ }
+
+ /**
+ * Signature verification using public key
+ *
+ * @param signature vector of dimension n
+ * @return document hash of length n - v1
+ */
+ private short[] verifySignatureIntern(short[] signature)
+ {
+
+ short[][] coeff_quadratic = ((RainbowPublicKeyParameters)this.key).getCoeffQuadratic();
+ short[][] coeff_singular = ((RainbowPublicKeyParameters)this.key).getCoeffSingular();
+ short[] coeff_scalar = ((RainbowPublicKeyParameters)this.key).getCoeffScalar();
+
+ short[] rslt = new short[coeff_quadratic.length];// n - v1
+ int n = coeff_singular[0].length;
+ int offset = 0; // array position
+ short tmp = 0; // for scalar
+
+ for (int p = 0; p < coeff_quadratic.length; p++)
+ { // no of polynomials
+ offset = 0;
+ for (int x = 0; x < n; x++)
+ {
+ // calculate quadratic terms
+ for (int y = x; y < n; y++)
+ {
+ tmp = GF2Field.multElem(coeff_quadratic[p][offset],
+ GF2Field.multElem(signature[x], signature[y]));
+ rslt[p] = GF2Field.addElem(rslt[p], tmp);
+ offset++;
+ }
+ // calculate singular terms
+ tmp = GF2Field.multElem(coeff_singular[p][x], signature[x]);
+ rslt[p] = GF2Field.addElem(rslt[p], tmp);
+ }
+ // add scalar
+ rslt[p] = GF2Field.addElem(rslt[p], coeff_scalar[p]);
+ }
+
+ return rslt;
+ }
+
+ /**
+ * This function creates the representative of the message which gets signed
+ * or verified.
+ *
+ * @param message the message
+ * @return message representative
+ */
+ private short[] makeMessageRepresentative(byte[] message)
+ {
+ // the message representative
+ short[] output = new short[this.signableDocumentLength];
+
+ int h = 0;
+ int i = 0;
+ do
+ {
+ if (i >= message.length)
+ {
+ break;
+ }
+ output[i] = (short)message[h];
+ output[i] &= (short)0xff;
+ h++;
+ i++;
+ }
+ while (i < output.length);
+
+ return output;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/rainbow/util/ComputeInField.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/rainbow/util/ComputeInField.java
new file mode 100644
index 0000000..9b8b4de
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/rainbow/util/ComputeInField.java
@@ -0,0 +1,490 @@
+package org.bc.pqc.crypto.rainbow.util;
+
+/**
+ * This class offers different operations on matrices in field GF2^8.
+ *
+ * Implemented are functions:
+ * - finding inverse of a matrix
+ * - solving linear equation systems using the Gauss-Elimination method
+ * - basic operations like matrix multiplication, addition and so on.
+ */
+
+public class ComputeInField
+{
+
+ private short[][] A; // used by solveEquation and inverse
+ short[] x;
+
+ /**
+ * Constructor with no parameters
+ */
+ public ComputeInField()
+ {
+ }
+
+
+ /**
+ * This function finds a solution of the equation Bx = b.
+ * Exception is thrown if the linear equation system has no solution
+ *
+ * @param B this matrix is the left part of the
+ * equation (B in the equation above)
+ * @param b the right part of the equation
+ * (b in the equation above)
+ * @return x the solution of the equation if it is solvable
+ * null otherwise
+ * @throws RuntimeException if LES is not solvable
+ */
+ public short[] solveEquation(short[][] B, short[] b)
+ {
+ try
+ {
+
+ if (B.length != b.length)
+ {
+ throw new RuntimeException(
+ "The equation system is not solvable");
+ }
+
+ /** initialize **/
+ // this matrix stores B and b from the equation B*x = b
+ // b is stored as the last column.
+ // B contains one column more than rows.
+ // In this column we store a free coefficient that should be later subtracted from b
+ A = new short[B.length][B.length + 1];
+ // stores the solution of the LES
+ x = new short[B.length];
+
+ /** copy B into the global matrix A **/
+ for (int i = 0; i < B.length; i++)
+ { // rows
+ for (int j = 0; j < B[0].length; j++)
+ { // cols
+ A[i][j] = B[i][j];
+ }
+ }
+
+ /** copy the vector b into the global A **/
+ //the free coefficient, stored in the last column of A( A[i][b.length]
+ // is to be subtracted from b
+ for (int i = 0; i < b.length; i++)
+ {
+ A[i][b.length] = GF2Field.addElem(b[i], A[i][b.length]);
+ }
+
+ /** call the methods for gauss elimination and backward substitution **/
+ computeZerosUnder(false); // obtain zeros under the diagonal
+ substitute();
+
+ return x;
+
+ }
+ catch (RuntimeException rte)
+ {
+ return null; // the LES is not solvable!
+ }
+ }
+
+ /**
+ * This function computes the inverse of a given matrix using the Gauss-
+ * Elimination method.
+ *
+ * An exception is thrown if the matrix has no inverse
+ *
+ * @param coef the matrix which inverse matrix is needed
+ * @return inverse matrix of the input matrix.
+ * If the matrix is singular, null is returned.
+ * @throws RuntimeException if the given matrix is not invertible
+ */
+ public short[][] inverse(short[][] coef)
+ {
+ try
+ {
+ /** Initialization: **/
+ short factor;
+ short[][] inverse;
+ A = new short[coef.length][2 * coef.length];
+ if (coef.length != coef[0].length)
+ {
+ throw new RuntimeException(
+ "The matrix is not invertible. Please choose another one!");
+ }
+
+ /** prepare: Copy coef and the identity matrix into the global A. **/
+ for (int i = 0; i < coef.length; i++)
+ {
+ for (int j = 0; j < coef.length; j++)
+ {
+ //copy the input matrix coef into A
+ A[i][j] = coef[i][j];
+ }
+ // copy the identity matrix into A.
+ for (int j = coef.length; j < 2 * coef.length; j++)
+ {
+ A[i][j] = 0;
+ }
+ A[i][i + A.length] = 1;
+ }
+
+ /** Elimination operations to get the identity matrix from the left side of A. **/
+ // modify A to get 0s under the diagonal.
+ computeZerosUnder(true);
+
+ // modify A to get only 1s on the diagonal: A[i][j] =A[i][j]/A[i][i].
+ for (int i = 0; i < A.length; i++)
+ {
+ factor = GF2Field.invElem(A[i][i]);
+ for (int j = i; j < 2 * A.length; j++)
+ {
+ A[i][j] = GF2Field.multElem(A[i][j], factor);
+ }
+ }
+
+ //modify A to get only 0s above the diagonal.
+ computeZerosAbove();
+
+ // copy the result (the second half of A) in the matrix inverse.
+ inverse = new short[A.length][A.length];
+ for (int i = 0; i < A.length; i++)
+ {
+ for (int j = A.length; j < 2 * A.length; j++)
+ {
+ inverse[i][j - A.length] = A[i][j];
+ }
+ }
+ return inverse;
+
+ }
+ catch (RuntimeException rte)
+ {
+ // The matrix is not invertible! A new one should be generated!
+ return null;
+ }
+ }
+
+ /**
+ * Elimination under the diagonal.
+ * This function changes a matrix so that it contains only zeros under the
+ * diagonal(Ai,i) using only Gauss-Elimination operations.
+ *
+ * It is used in solveEquaton as well as in the function for
+ * finding an inverse of a matrix: {@link}inverse. Both of them use the
+ * Gauss-Elimination Method.
+ *
+ * The result is stored in the global matrix A
+ *
+ * @param usedForInverse This parameter shows if the function is used by the
+ * solveEquation-function or by the inverse-function and according
+ * to this creates matrices of different sizes.
+ * @throws RuntimeException in case a multiplicative inverse of 0 is needed
+ */
+ private void computeZerosUnder(boolean usedForInverse)
+ throws RuntimeException
+ {
+
+ //the number of columns in the global A where the tmp results are stored
+ int length;
+ short tmp = 0;
+
+ //the function is used in inverse() - A should have 2 times more columns than rows
+ if (usedForInverse)
+ {
+ length = 2 * A.length;
+ }
+ //the function is used in solveEquation - A has 1 column more than rows
+ else
+ {
+ length = A.length + 1;
+ }
+
+ //elimination operations to modify A so that that it contains only 0s under the diagonal
+ for (int k = 0; k < A.length - 1; k++)
+ { // the fixed row
+ for (int i = k + 1; i < A.length; i++)
+ { // rows
+ short factor1 = A[i][k];
+ short factor2 = GF2Field.invElem(A[k][k]);
+
+ //The element which multiplicative inverse is needed, is 0
+ //in this case is the input matrix not invertible
+ if (factor2 == 0)
+ {
+ throw new RuntimeException("Matrix not invertible! We have to choose another one!");
+ }
+
+ for (int j = k; j < length; j++)
+ {// columns
+ // tmp=A[k,j] / A[k,k]
+ tmp = GF2Field.multElem(A[k][j], factor2);
+ // tmp = A[i,k] * A[k,j] / A[k,k]
+ tmp = GF2Field.multElem(factor1, tmp);
+ // A[i,j]=A[i,j]-A[i,k]/A[k,k]*A[k,j];
+ A[i][j] = GF2Field.addElem(A[i][j], tmp);
+ }
+ }
+ }
+ }
+
+ /**
+ * Elimination above the diagonal.
+ * This function changes a matrix so that it contains only zeros above the
+ * diagonal(Ai,i) using only Gauss-Elimination operations.
+ *
+ * It is used in the inverse-function
+ * The result is stored in the global matrix A
+ *
+ * @throws RuntimeException in case a multiplicative inverse of 0 is needed
+ */
+ private void computeZerosAbove()
+ throws RuntimeException
+ {
+ short tmp = 0;
+ for (int k = A.length - 1; k > 0; k--)
+ { // the fixed row
+ for (int i = k - 1; i >= 0; i--)
+ { // rows
+ short factor1 = A[i][k];
+ short factor2 = GF2Field.invElem(A[k][k]);
+ if (factor2 == 0)
+ {
+ throw new RuntimeException("The matrix is not invertible");
+ }
+ for (int j = k; j < 2 * A.length; j++)
+ { // columns
+ // tmp = A[k,j] / A[k,k]
+ tmp = GF2Field.multElem(A[k][j], factor2);
+ // tmp = A[i,k] * A[k,j] / A[k,k]
+ tmp = GF2Field.multElem(factor1, tmp);
+ // A[i,j] = A[i,j] - A[i,k] / A[k,k] * A[k,j];
+ A[i][j] = GF2Field.addElem(A[i][j], tmp);
+ }
+ }
+ }
+ }
+
+
+ /**
+ * This function uses backward substitution to find x
+ * of the linear equation system (LES) B*x = b,
+ * where A a triangle-matrix is (contains only zeros under the diagonal)
+ * and b is a vector
+ *
+ * If the multiplicative inverse of 0 is needed, an exception is thrown.
+ * In this case is the LES not solvable
+ *
+ * @throws RuntimeException in case a multiplicative inverse of 0 is needed
+ */
+ private void substitute()
+ throws RuntimeException
+ {
+
+ // for the temporary results of the operations in field
+ short tmp, temp;
+
+ temp = GF2Field.invElem(A[A.length - 1][A.length - 1]);
+ if (temp == 0)
+ {
+ throw new RuntimeException("The equation system is not solvable");
+ }
+
+ /** backward substitution **/
+ x[A.length - 1] = GF2Field.multElem(A[A.length - 1][A.length], temp);
+ for (int i = A.length - 2; i >= 0; i--)
+ {
+ tmp = A[i][A.length];
+ for (int j = A.length - 1; j > i; j--)
+ {
+ temp = GF2Field.multElem(A[i][j], x[j]);
+ tmp = GF2Field.addElem(tmp, temp);
+ }
+
+ temp = GF2Field.invElem(A[i][i]);
+ if (temp == 0)
+ {
+ throw new RuntimeException("Not solvable equation system");
+ }
+ x[i] = GF2Field.multElem(tmp, temp);
+ }
+ }
+
+
+ /**
+ * This function multiplies two given matrices.
+ * If the given matrices cannot be multiplied due
+ * to different sizes, an exception is thrown.
+ *
+ * @param M1 -the 1st matrix
+ * @param M2 -the 2nd matrix
+ * @return A = M1*M2
+ * @throws RuntimeException in case the given matrices cannot be multiplied
+ * due to different dimensions.
+ */
+ public short[][] multiplyMatrix(short[][] M1, short[][] M2)
+ throws RuntimeException
+ {
+
+ if (M1[0].length != M2.length)
+ {
+ throw new RuntimeException("Multiplication is not possible!");
+ }
+ short tmp = 0;
+ A = new short[M1.length][M2[0].length];
+ for (int i = 0; i < M1.length; i++)
+ {
+ for (int j = 0; j < M2.length; j++)
+ {
+ for (int k = 0; k < M2[0].length; k++)
+ {
+ tmp = GF2Field.multElem(M1[i][j], M2[j][k]);
+ A[i][k] = GF2Field.addElem(A[i][k], tmp);
+ }
+ }
+ }
+ return A;
+ }
+
+ /**
+ * This function multiplies a given matrix with a one-dimensional array.
+ *
+ * An exception is thrown, if the number of columns in the matrix and
+ * the number of rows in the one-dim. array differ.
+ *
+ * @param M1 the matrix to be multiplied
+ * @param m the one-dimensional array to be multiplied
+ * @return M1*m
+ * @throws RuntimeException in case of dimension inconsistency
+ */
+ public short[] multiplyMatrix(short[][] M1, short[] m)
+ throws RuntimeException
+ {
+ if (M1[0].length != m.length)
+ {
+ throw new RuntimeException("Multiplication is not possible!");
+ }
+ short tmp = 0;
+ short[] B = new short[M1.length];
+ for (int i = 0; i < M1.length; i++)
+ {
+ for (int j = 0; j < m.length; j++)
+ {
+ tmp = GF2Field.multElem(M1[i][j], m[j]);
+ B[i] = GF2Field.addElem(B[i], tmp);
+ }
+ }
+ return B;
+ }
+
+ /**
+ * Addition of two vectors
+ *
+ * @param vector1 first summand, always of dim n
+ * @param vector2 second summand, always of dim n
+ * @return addition of vector1 and vector2
+ * @throws RuntimeException in case the addition is impossible
+ * due to inconsistency in the dimensions
+ */
+ public short[] addVect(short[] vector1, short[] vector2)
+ {
+ if (vector1.length != vector2.length)
+ {
+ throw new RuntimeException("Multiplication is not possible!");
+ }
+ short rslt[] = new short[vector1.length];
+ for (int n = 0; n < rslt.length; n++)
+ {
+ rslt[n] = GF2Field.addElem(vector1[n], vector2[n]);
+ }
+ return rslt;
+ }
+
+ /**
+ * Multiplication of column vector with row vector
+ *
+ * @param vector1 column vector, always n x 1
+ * @param vector2 row vector, always 1 x n
+ * @return resulting n x n matrix of multiplication
+ * @throws RuntimeException in case the multiplication is impossible due to
+ * inconsistency in the dimensions
+ */
+ public short[][] multVects(short[] vector1, short[] vector2)
+ {
+ if (vector1.length != vector2.length)
+ {
+ throw new RuntimeException("Multiplication is not possible!");
+ }
+ short rslt[][] = new short[vector1.length][vector2.length];
+ for (int i = 0; i < vector1.length; i++)
+ {
+ for (int j = 0; j < vector2.length; j++)
+ {
+ rslt[i][j] = GF2Field.multElem(vector1[i], vector2[j]);
+ }
+ }
+ return rslt;
+ }
+
+ /**
+ * Multiplies vector with scalar
+ *
+ * @param scalar galois element to multiply vector with
+ * @param vector vector to be multiplied
+ * @return vector multiplied with scalar
+ */
+ public short[] multVect(short scalar, short[] vector)
+ {
+ short rslt[] = new short[vector.length];
+ for (int n = 0; n < rslt.length; n++)
+ {
+ rslt[n] = GF2Field.multElem(scalar, vector[n]);
+ }
+ return rslt;
+ }
+
+ /**
+ * Multiplies matrix with scalar
+ *
+ * @param scalar galois element to multiply matrix with
+ * @param matrix 2-dim n x n matrix to be multiplied
+ * @return matrix multiplied with scalar
+ */
+ public short[][] multMatrix(short scalar, short[][] matrix)
+ {
+ short[][] rslt = new short[matrix.length][matrix[0].length];
+ for (int i = 0; i < matrix.length; i++)
+ {
+ for (int j = 0; j < matrix[0].length; j++)
+ {
+ rslt[i][j] = GF2Field.multElem(scalar, matrix[i][j]);
+ }
+ }
+ return rslt;
+ }
+
+ /**
+ * Adds the n x n matrices matrix1 and matrix2
+ *
+ * @param matrix1 first summand
+ * @param matrix2 second summand
+ * @return addition of matrix1 and matrix2; both having the dimensions n x n
+ * @throws RuntimeException in case the addition is not possible because of
+ * different dimensions of the matrices
+ */
+ public short[][] addSquareMatrix(short[][] matrix1, short[][] matrix2)
+ {
+ if (matrix1.length != matrix2.length || matrix1[0].length != matrix2[0].length)
+ {
+ throw new RuntimeException("Addition is not possible!");
+ }
+
+ short[][] rslt = new short[matrix1.length][matrix1.length];//
+ for (int i = 0; i < matrix1.length; i++)
+ {
+ for (int j = 0; j < matrix2.length; j++)
+ {
+ rslt[i][j] = GF2Field.addElem(matrix1[i][j], matrix2[i][j]);
+ }
+ }
+ return rslt;
+ }
+
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/rainbow/util/GF2Field.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/rainbow/util/GF2Field.java
new file mode 100644
index 0000000..d8bdc52
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/rainbow/util/GF2Field.java
@@ -0,0 +1,139 @@
+package org.bc.pqc.crypto.rainbow.util;
+
+/**
+ * This class provides the basic operations like addition, multiplication and
+ * finding the multiplicative inverse of an element in GF2^8.
+ *
+ * The operations are implemented using the irreducible polynomial
+ * 1+x^2+x^3+x^6+x^8 ( 1 0100 1101 = 0x14d )
+ *
+ * This class makes use of lookup tables(exps and logs) for implementing the
+ * operations in order to increase the efficiency of Rainbow.
+ */
+public class GF2Field
+{
+
+ public static final int MASK = 0xff;
+
+ /*
+ * this lookup table is needed for multiplication and computing the
+ * multiplicative inverse
+ */
+ static final short exps[] = {1, 2, 4, 8, 16, 32, 64, 128, 77, 154, 121, 242,
+ 169, 31, 62, 124, 248, 189, 55, 110, 220, 245, 167, 3, 6, 12, 24,
+ 48, 96, 192, 205, 215, 227, 139, 91, 182, 33, 66, 132, 69, 138, 89,
+ 178, 41, 82, 164, 5, 10, 20, 40, 80, 160, 13, 26, 52, 104, 208,
+ 237, 151, 99, 198, 193, 207, 211, 235, 155, 123, 246, 161, 15, 30,
+ 60, 120, 240, 173, 23, 46, 92, 184, 61, 122, 244, 165, 7, 14, 28,
+ 56, 112, 224, 141, 87, 174, 17, 34, 68, 136, 93, 186, 57, 114, 228,
+ 133, 71, 142, 81, 162, 9, 18, 36, 72, 144, 109, 218, 249, 191, 51,
+ 102, 204, 213, 231, 131, 75, 150, 97, 194, 201, 223, 243, 171, 27,
+ 54, 108, 216, 253, 183, 35, 70, 140, 85, 170, 25, 50, 100, 200,
+ 221, 247, 163, 11, 22, 44, 88, 176, 45, 90, 180, 37, 74, 148, 101,
+ 202, 217, 255, 179, 43, 86, 172, 21, 42, 84, 168, 29, 58, 116, 232,
+ 157, 119, 238, 145, 111, 222, 241, 175, 19, 38, 76, 152, 125, 250,
+ 185, 63, 126, 252, 181, 39, 78, 156, 117, 234, 153, 127, 254, 177,
+ 47, 94, 188, 53, 106, 212, 229, 135, 67, 134, 65, 130, 73, 146,
+ 105, 210, 233, 159, 115, 230, 129, 79, 158, 113, 226, 137, 95, 190,
+ 49, 98, 196, 197, 199, 195, 203, 219, 251, 187, 59, 118, 236, 149,
+ 103, 206, 209, 239, 147, 107, 214, 225, 143, 83, 166, 1};
+
+ /*
+ * this lookup table is needed for multiplication and computing the
+ * multiplicative inverse
+ */
+ static final short logs[] = {0, 0, 1, 23, 2, 46, 24, 83, 3, 106, 47, 147,
+ 25, 52, 84, 69, 4, 92, 107, 182, 48, 166, 148, 75, 26, 140, 53,
+ 129, 85, 170, 70, 13, 5, 36, 93, 135, 108, 155, 183, 193, 49, 43,
+ 167, 163, 149, 152, 76, 202, 27, 230, 141, 115, 54, 205, 130, 18,
+ 86, 98, 171, 240, 71, 79, 14, 189, 6, 212, 37, 210, 94, 39, 136,
+ 102, 109, 214, 156, 121, 184, 8, 194, 223, 50, 104, 44, 253, 168,
+ 138, 164, 90, 150, 41, 153, 34, 77, 96, 203, 228, 28, 123, 231, 59,
+ 142, 158, 116, 244, 55, 216, 206, 249, 131, 111, 19, 178, 87, 225,
+ 99, 220, 172, 196, 241, 175, 72, 10, 80, 66, 15, 186, 190, 199, 7,
+ 222, 213, 120, 38, 101, 211, 209, 95, 227, 40, 33, 137, 89, 103,
+ 252, 110, 177, 215, 248, 157, 243, 122, 58, 185, 198, 9, 65, 195,
+ 174, 224, 219, 51, 68, 105, 146, 45, 82, 254, 22, 169, 12, 139,
+ 128, 165, 74, 91, 181, 151, 201, 42, 162, 154, 192, 35, 134, 78,
+ 188, 97, 239, 204, 17, 229, 114, 29, 61, 124, 235, 232, 233, 60,
+ 234, 143, 125, 159, 236, 117, 30, 245, 62, 56, 246, 217, 63, 207,
+ 118, 250, 31, 132, 160, 112, 237, 20, 144, 179, 126, 88, 251, 226,
+ 32, 100, 208, 221, 119, 173, 218, 197, 64, 242, 57, 176, 247, 73,
+ 180, 11, 127, 81, 21, 67, 145, 16, 113, 187, 238, 191, 133, 200,
+ 161};
+
+ /**
+ * This function calculates the sum of two elements as an operation in GF2^8
+ *
+ * @param x the first element that is to be added
+ * @param y the second element that should be add
+ * @return the sum of the two elements x and y in GF2^8
+ */
+ public static short addElem(short x, short y)
+ {
+ return (short)(x ^ y);
+ }
+
+ /**
+ * This function computes the multiplicative inverse of a given element in
+ * GF2^8 The 0 has no multiplicative inverse and in this case 0 is returned.
+ *
+ * @param x the element which multiplicative inverse is to be computed
+ * @return the multiplicative inverse of the given element, in case it
+ * exists or 0, otherwise
+ */
+ public static short invElem(short x)
+ {
+ if (x == 0)
+ {
+ return 0;
+ }
+ return (exps[255 - logs[x]]);
+ }
+
+ /**
+ * This function multiplies two elements in GF2^8. If one of the two
+ * elements is 0, 0 is returned.
+ *
+ * @param x the first element to be multiplied.
+ * @param y the second element to be multiplied.
+ * @return the product of the two input elements in GF2^8.
+ */
+ public static short multElem(short x, short y)
+ {
+ if (x == 0 || y == 0)
+ {
+ return 0;
+ }
+ else
+ {
+ return (exps[(logs[x] + logs[y]) % 255]);
+ }
+ }
+
+ /**
+ * This function returns the values of exps-lookup table which correspond to
+ * the input
+ *
+ * @param x the index in the lookup table exps
+ * @return exps-value, corresponding to the input
+ */
+ public static short getExp(short x)
+ {
+ return exps[x];
+ }
+
+ /**
+ * This function returns the values of logs-lookup table which correspond to
+ * the input
+ *
+ * @param x the index in the lookup table logs
+ * @return logs-value, corresponding to the input
+ */
+ public static short getLog(short x)
+ {
+ return logs[x];
+ }
+
+
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/rainbow/util/RainbowUtil.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/rainbow/util/RainbowUtil.java
new file mode 100644
index 0000000..6a0a635
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/crypto/rainbow/util/RainbowUtil.java
@@ -0,0 +1,230 @@
+package org.bc.pqc.crypto.rainbow.util;
+
+/**
+ * This class is needed for the conversions while encoding and decoding, as well as for
+ * comparison between arrays of some dimensions
+ */
+public class RainbowUtil
+{
+
+ /**
+ * This function converts an one-dimensional array of bytes into a
+ * one-dimensional array of int
+ *
+ * @param in the array to be converted
+ * @return out
+ * the one-dimensional int-array that corresponds the input
+ */
+ public static int[] convertArraytoInt(byte[] in)
+ {
+ int[] out = new int[in.length];
+ for (int i = 0; i < in.length; i++)
+ {
+ out[i] = in[i] & GF2Field.MASK;
+ }
+ return out;
+ }
+
+ /**
+ * This function converts an one-dimensional array of bytes into a
+ * one-dimensional array of type short
+ *
+ * @param in the array to be converted
+ * @return out
+ * one-dimensional short-array that corresponds the input
+ */
+ public static short[] convertArray(byte[] in)
+ {
+ short[] out = new short[in.length];
+ for (int i = 0; i < in.length; i++)
+ {
+ out[i] = (short)(in[i] & GF2Field.MASK);
+ }
+ return out;
+ }
+
+ /**
+ * This function converts a matrix of bytes into a matrix of type short
+ *
+ * @param in the matrix to be converted
+ * @return out
+ * short-matrix that corresponds the input
+ */
+ public static short[][] convertArray(byte[][] in)
+ {
+ short[][] out = new short[in.length][in[0].length];
+ for (int i = 0; i < in.length; i++)
+ {
+ for (int j = 0; j < in[0].length; j++)
+ {
+ out[i][j] = (short)(in[i][j] & GF2Field.MASK);
+ }
+ }
+ return out;
+ }
+
+ /**
+ * This function converts a 3-dimensional array of bytes into a 3-dimensional array of type short
+ *
+ * @param in the array to be converted
+ * @return out
+ * short-array that corresponds the input
+ */
+ public static short[][][] convertArray(byte[][][] in)
+ {
+ short[][][] out = new short[in.length][in[0].length][in[0][0].length];
+ for (int i = 0; i < in.length; i++)
+ {
+ for (int j = 0; j < in[0].length; j++)
+ {
+ for (int k = 0; k < in[0][0].length; k++)
+ {
+ out[i][j][k] = (short)(in[i][j][k] & GF2Field.MASK);
+ }
+ }
+ }
+ return out;
+ }
+
+ /**
+ * This function converts an array of type int into an array of type byte
+ *
+ * @param in the array to be converted
+ * @return out
+ * the byte-array that corresponds the input
+ */
+ public static byte[] convertIntArray(int[] in)
+ {
+ byte[] out = new byte[in.length];
+ for (int i = 0; i < in.length; i++)
+ {
+ out[i] = (byte)in[i];
+ }
+ return out;
+ }
+
+
+ /**
+ * This function converts an array of type short into an array of type byte
+ *
+ * @param in the array to be converted
+ * @return out
+ * the byte-array that corresponds the input
+ */
+ public static byte[] convertArray(short[] in)
+ {
+ byte[] out = new byte[in.length];
+ for (int i = 0; i < in.length; i++)
+ {
+ out[i] = (byte)in[i];
+ }
+ return out;
+ }
+
+ /**
+ * This function converts a matrix of type short into a matrix of type byte
+ *
+ * @param in the matrix to be converted
+ * @return out
+ * the byte-matrix that corresponds the input
+ */
+ public static byte[][] convertArray(short[][] in)
+ {
+ byte[][] out = new byte[in.length][in[0].length];
+ for (int i = 0; i < in.length; i++)
+ {
+ for (int j = 0; j < in[0].length; j++)
+ {
+ out[i][j] = (byte)in[i][j];
+ }
+ }
+ return out;
+ }
+
+ /**
+ * This function converts a 3-dimensional array of type short into a 3-dimensional array of type byte
+ *
+ * @param in the array to be converted
+ * @return out
+ * the byte-array that corresponds the input
+ */
+ public static byte[][][] convertArray(short[][][] in)
+ {
+ byte[][][] out = new byte[in.length][in[0].length][in[0][0].length];
+ for (int i = 0; i < in.length; i++)
+ {
+ for (int j = 0; j < in[0].length; j++)
+ {
+ for (int k = 0; k < in[0][0].length; k++)
+ {
+ out[i][j][k] = (byte)in[i][j][k];
+ }
+ }
+ }
+ return out;
+ }
+
+ /**
+ * Compare two short arrays. No null checks are performed.
+ *
+ * @param left the first short array
+ * @param right the second short array
+ * @return the result of the comparison
+ */
+ public static boolean equals(short[] left, short[] right)
+ {
+ if (left.length != right.length)
+ {
+ return false;
+ }
+ boolean result = true;
+ for (int i = left.length - 1; i >= 0; i--)
+ {
+ result &= left[i] == right[i];
+ }
+ return result;
+ }
+
+ /**
+ * Compare two two-dimensional short arrays. No null checks are performed.
+ *
+ * @param left the first short array
+ * @param right the second short array
+ * @return the result of the comparison
+ */
+ public static boolean equals(short[][] left, short[][] right)
+ {
+ if (left.length != right.length)
+ {
+ return false;
+ }
+ boolean result = true;
+ for (int i = left.length - 1; i >= 0; i--)
+ {
+ result &= equals(left[i], right[i]);
+ }
+ return result;
+ }
+
+ /**
+ * Compare two three-dimensional short arrays. No null checks are performed.
+ *
+ * @param left the first short array
+ * @param right the second short array
+ * @return the result of the comparison
+ */
+ public static boolean equals(short[][][] left, short[][][] right)
+ {
+ if (left.length != right.length)
+ {
+ return false;
+ }
+ boolean result = true;
+ for (int i = left.length - 1; i >= 0; i--)
+ {
+ result &= equals(left[i], right[i]);
+ }
+ return result;
+ }
+
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/math/linearalgebra/BigEndianConversions.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/math/linearalgebra/BigEndianConversions.java
new file mode 100644
index 0000000..6d92639
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/math/linearalgebra/BigEndianConversions.java
@@ -0,0 +1,306 @@
+package org.bc.pqc.math.linearalgebra;
+
+
+/**
+ * This is a utility class containing data type conversions using big-endian
+ * byte order.
+ *
+ * @see LittleEndianConversions
+ */
+public final class BigEndianConversions
+{
+
+ /**
+ * Default constructor (private).
+ */
+ private BigEndianConversions()
+ {
+ // empty
+ }
+
+ /**
+ * Convert an integer to an octet string of length 4 according to IEEE 1363,
+ * Section 5.5.3.
+ *
+ * @param x the integer to convert
+ * @return the converted integer
+ */
+ public static byte[] I2OSP(int x)
+ {
+ byte[] result = new byte[4];
+ result[0] = (byte)(x >>> 24);
+ result[1] = (byte)(x >>> 16);
+ result[2] = (byte)(x >>> 8);
+ result[3] = (byte)x;
+ return result;
+ }
+
+ /**
+ * Convert an integer to an octet string according to IEEE 1363, Section
+ * 5.5.3. Length checking is performed.
+ *
+ * @param x the integer to convert
+ * @param oLen the desired length of the octet string
+ * @return an octet string of length oLen representing the
+ * integer x, or null if the integer is
+ * negative
+ * @throws ArithmeticException if x can't be encoded into oLen
+ * octets.
+ */
+ public static byte[] I2OSP(int x, int oLen)
+ throws ArithmeticException
+ {
+ if (x < 0)
+ {
+ return null;
+ }
+ int octL = IntegerFunctions.ceilLog256(x);
+ if (octL > oLen)
+ {
+ throw new ArithmeticException(
+ "Cannot encode given integer into specified number of octets.");
+ }
+ byte[] result = new byte[oLen];
+ for (int i = oLen - 1; i >= oLen - octL; i--)
+ {
+ result[i] = (byte)(x >>> (8 * (oLen - 1 - i)));
+ }
+ return result;
+ }
+
+ /**
+ * Convert an integer to an octet string of length 4 according to IEEE 1363,
+ * Section 5.5.3.
+ *
+ * @param input the integer to convert
+ * @param output byte array holding the output
+ * @param outOff offset in output array where the result is stored
+ */
+ public static void I2OSP(int input, byte[] output, int outOff)
+ {
+ output[outOff++] = (byte)(input >>> 24);
+ output[outOff++] = (byte)(input >>> 16);
+ output[outOff++] = (byte)(input >>> 8);
+ output[outOff] = (byte)input;
+ }
+
+ /**
+ * Convert an integer to an octet string of length 8 according to IEEE 1363,
+ * Section 5.5.3.
+ *
+ * @param input the integer to convert
+ * @return the converted integer
+ */
+ public static byte[] I2OSP(long input)
+ {
+ byte[] output = new byte[8];
+ output[0] = (byte)(input >>> 56);
+ output[1] = (byte)(input >>> 48);
+ output[2] = (byte)(input >>> 40);
+ output[3] = (byte)(input >>> 32);
+ output[4] = (byte)(input >>> 24);
+ output[5] = (byte)(input >>> 16);
+ output[6] = (byte)(input >>> 8);
+ output[7] = (byte)input;
+ return output;
+ }
+
+ /**
+ * Convert an integer to an octet string of length 8 according to IEEE 1363,
+ * Section 5.5.3.
+ *
+ * @param input the integer to convert
+ * @param output byte array holding the output
+ * @param outOff offset in output array where the result is stored
+ */
+ public static void I2OSP(long input, byte[] output, int outOff)
+ {
+ output[outOff++] = (byte)(input >>> 56);
+ output[outOff++] = (byte)(input >>> 48);
+ output[outOff++] = (byte)(input >>> 40);
+ output[outOff++] = (byte)(input >>> 32);
+ output[outOff++] = (byte)(input >>> 24);
+ output[outOff++] = (byte)(input >>> 16);
+ output[outOff++] = (byte)(input >>> 8);
+ output[outOff] = (byte)input;
+ }
+
+ /**
+ * Convert an integer to an octet string of the specified length according
+ * to IEEE 1363, Section 5.5.3. No length checking is performed (i.e., if
+ * the integer cannot be encoded into length octets, it is
+ * truncated).
+ *
+ * @param input the integer to convert
+ * @param output byte array holding the output
+ * @param outOff offset in output array where the result is stored
+ * @param length the length of the encoding
+ */
+ public static void I2OSP(int input, byte[] output, int outOff, int length)
+ {
+ for (int i = length - 1; i >= 0; i--)
+ {
+ output[outOff + i] = (byte)(input >>> (8 * (length - 1 - i)));
+ }
+ }
+
+ /**
+ * Convert an octet string to an integer according to IEEE 1363, Section
+ * 5.5.3.
+ *
+ * @param input the byte array holding the octet string
+ * @return an integer representing the octet string input, or
+ * 0 if the represented integer is negative or too large
+ * or the byte array is empty
+ * @throws ArithmeticException if the length of the given octet string is larger than 4.
+ */
+ public static int OS2IP(byte[] input)
+ {
+ if (input.length > 4)
+ {
+ throw new ArithmeticException("invalid input length");
+ }
+ if (input.length == 0)
+ {
+ return 0;
+ }
+ int result = 0;
+ for (int j = 0; j < input.length; j++)
+ {
+ result |= (input[j] & 0xff) << (8 * (input.length - 1 - j));
+ }
+ return result;
+ }
+
+ /**
+ * Convert a byte array of length 4 beginning at offset into an
+ * integer.
+ *
+ * @param input the byte array
+ * @param inOff the offset into the byte array
+ * @return the resulting integer
+ */
+ public static int OS2IP(byte[] input, int inOff)
+ {
+ int result = (input[inOff++] & 0xff) << 24;
+ result |= (input[inOff++] & 0xff) << 16;
+ result |= (input[inOff++] & 0xff) << 8;
+ result |= input[inOff] & 0xff;
+ return result;
+ }
+
+ /**
+ * Convert an octet string to an integer according to IEEE 1363, Section
+ * 5.5.3.
+ *
+ * @param input the byte array holding the octet string
+ * @param inOff the offset in the input byte array where the octet string
+ * starts
+ * @param inLen the length of the encoded integer
+ * @return an integer representing the octet string bytes, or
+ * 0 if the represented integer is negative or too large
+ * or the byte array is empty
+ */
+ public static int OS2IP(byte[] input, int inOff, int inLen)
+ {
+ if ((input.length == 0) || input.length < inOff + inLen - 1)
+ {
+ return 0;
+ }
+ int result = 0;
+ for (int j = 0; j < inLen; j++)
+ {
+ result |= (input[inOff + j] & 0xff) << (8 * (inLen - j - 1));
+ }
+ return result;
+ }
+
+ /**
+ * Convert a byte array of length 8 beginning at inOff into a
+ * long integer.
+ *
+ * @param input the byte array
+ * @param inOff the offset into the byte array
+ * @return the resulting long integer
+ */
+ public static long OS2LIP(byte[] input, int inOff)
+ {
+ long result = ((long)input[inOff++] & 0xff) << 56;
+ result |= ((long)input[inOff++] & 0xff) << 48;
+ result |= ((long)input[inOff++] & 0xff) << 40;
+ result |= ((long)input[inOff++] & 0xff) << 32;
+ result |= ((long)input[inOff++] & 0xff) << 24;
+ result |= (input[inOff++] & 0xff) << 16;
+ result |= (input[inOff++] & 0xff) << 8;
+ result |= input[inOff] & 0xff;
+ return result;
+ }
+
+ /**
+ * Convert an int array into a byte array.
+ *
+ * @param input the int array
+ * @return the converted array
+ */
+ public static byte[] toByteArray(final int[] input)
+ {
+ byte[] result = new byte[input.length << 2];
+ for (int i = 0; i < input.length; i++)
+ {
+ I2OSP(input[i], result, i << 2);
+ }
+ return result;
+ }
+
+ /**
+ * Convert an int array into a byte array of the specified length. No length
+ * checking is performed (i.e., if the last integer cannot be encoded into
+ * length % 4 octets, it is truncated).
+ *
+ * @param input the int array
+ * @param length the length of the converted array
+ * @return the converted array
+ */
+ public static byte[] toByteArray(final int[] input, int length)
+ {
+ final int intLen = input.length;
+ byte[] result = new byte[length];
+ int index = 0;
+ for (int i = 0; i <= intLen - 2; i++, index += 4)
+ {
+ I2OSP(input[i], result, index);
+ }
+ I2OSP(input[intLen - 1], result, index, length - index);
+ return result;
+ }
+
+ /**
+ * Convert a byte array into an int array.
+ *
+ * @param input the byte array
+ * @return the converted array
+ */
+ public static int[] toIntArray(byte[] input)
+ {
+ final int intLen = (input.length + 3) / 4;
+ final int lastLen = input.length & 0x03;
+ int[] result = new int[intLen];
+
+ int index = 0;
+ for (int i = 0; i <= intLen - 2; i++, index += 4)
+ {
+ result[i] = OS2IP(input, index);
+ }
+ if (lastLen != 0)
+ {
+ result[intLen - 1] = OS2IP(input, index, lastLen);
+ }
+ else
+ {
+ result[intLen - 1] = OS2IP(input, index);
+ }
+
+ return result;
+ }
+
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/math/linearalgebra/BigIntUtils.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/math/linearalgebra/BigIntUtils.java
new file mode 100644
index 0000000..ed1feda
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/math/linearalgebra/BigIntUtils.java
@@ -0,0 +1,138 @@
+package org.bc.pqc.math.linearalgebra;
+
+import java.math.BigInteger;
+
+/**
+ * FIXME: is this really necessary?!
+ */
+public final class BigIntUtils
+{
+
+ /**
+ * Default constructor (private).
+ */
+ private BigIntUtils()
+ {
+ // empty
+ }
+
+ /**
+ * Checks if two BigInteger arrays contain the same entries
+ *
+ * @param a first BigInteger array
+ * @param b second BigInteger array
+ * @return true or false
+ */
+ public static boolean equals(BigInteger[] a, BigInteger[] b)
+ {
+ int flag = 0;
+
+ if (a.length != b.length)
+ {
+ return false;
+ }
+ for (int i = 0; i < a.length; i++)
+ {
+ // avoid branches here!
+ // problem: compareTo on BigIntegers is not
+ // guaranteed constant-time!
+ flag |= a[i].compareTo(b[i]);
+ }
+ return flag == 0;
+ }
+
+ /**
+ * Fill the given BigInteger array with the given value.
+ *
+ * @param array the array
+ * @param value the value
+ */
+ public static void fill(BigInteger[] array, BigInteger value)
+ {
+ for (int i = array.length - 1; i >= 0; i--)
+ {
+ array[i] = value;
+ }
+ }
+
+ /**
+ * Generates a subarray of a given BigInteger array.
+ *
+ * @param input -
+ * the input BigInteger array
+ * @param start -
+ * the start index
+ * @param end -
+ * the end index
+ * @return a subarray of input, ranging from start to
+ * end
+ */
+ public static BigInteger[] subArray(BigInteger[] input, int start, int end)
+ {
+ BigInteger[] result = new BigInteger[end - start];
+ System.arraycopy(input, start, result, 0, end - start);
+ return result;
+ }
+
+ /**
+ * Converts a BigInteger array into an integer array
+ *
+ * @param input -
+ * the BigInteger array
+ * @return the integer array
+ */
+ public static int[] toIntArray(BigInteger[] input)
+ {
+ int[] result = new int[input.length];
+ for (int i = 0; i < input.length; i++)
+ {
+ result[i] = input[i].intValue();
+ }
+ return result;
+ }
+
+ /**
+ * Converts a BigInteger array into an integer array, reducing all
+ * BigIntegers mod q.
+ *
+ * @param q -
+ * the modulus
+ * @param input -
+ * the BigInteger array
+ * @return the integer array
+ */
+ public static int[] toIntArrayModQ(int q, BigInteger[] input)
+ {
+ BigInteger bq = BigInteger.valueOf(q);
+ int[] result = new int[input.length];
+ for (int i = 0; i < input.length; i++)
+ {
+ result[i] = input[i].mod(bq).intValue();
+ }
+ return result;
+ }
+
+ /**
+ * Return the value of big as a byte array. Although BigInteger
+ * has such a method, it uses an extra bit to indicate the sign of the
+ * number. For elliptic curve cryptography, the numbers usually are
+ * positive. Thus, this helper method returns a byte array of minimal
+ * length, ignoring the sign of the number.
+ *
+ * @param value the BigInteger value to be converted to a byte
+ * array
+ * @return the value big as byte array
+ */
+ public static byte[] toMinimalByteArray(BigInteger value)
+ {
+ byte[] valBytes = value.toByteArray();
+ if ((valBytes.length == 1) || (value.bitLength() & 0x07) != 0)
+ {
+ return valBytes;
+ }
+ byte[] result = new byte[value.bitLength() >> 3];
+ System.arraycopy(valBytes, 1, result, 0, result.length);
+ return result;
+ }
+
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/math/linearalgebra/ByteUtils.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/math/linearalgebra/ByteUtils.java
new file mode 100644
index 0000000..d4905ec
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/math/linearalgebra/ByteUtils.java
@@ -0,0 +1,414 @@
+package org.bc.pqc.math.linearalgebra;
+
+/**
+ * This class is a utility class for manipulating byte arrays.
+ */
+public final class ByteUtils
+{
+
+ private static final char[] HEX_CHARS = {'0', '1', '2', '3', '4', '5',
+ '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
+
+ /**
+ * Default constructor (private)
+ */
+ private ByteUtils()
+ {
+ // empty
+ }
+
+ /**
+ * Compare two byte arrays (perform null checks beforehand).
+ *
+ * @param left the first byte array
+ * @param right the second byte array
+ * @return the result of the comparison
+ */
+ public static boolean equals(byte[] left, byte[] right)
+ {
+ if (left == null)
+ {
+ return right == null;
+ }
+ if (right == null)
+ {
+ return false;
+ }
+
+ if (left.length != right.length)
+ {
+ return false;
+ }
+ boolean result = true;
+ for (int i = left.length - 1; i >= 0; i--)
+ {
+ result &= left[i] == right[i];
+ }
+ return result;
+ }
+
+ /**
+ * Compare two two-dimensional byte arrays. No null checks are performed.
+ *
+ * @param left the first byte array
+ * @param right the second byte array
+ * @return the result of the comparison
+ */
+ public static boolean equals(byte[][] left, byte[][] right)
+ {
+ if (left.length != right.length)
+ {
+ return false;
+ }
+
+ boolean result = true;
+ for (int i = left.length - 1; i >= 0; i--)
+ {
+ result &= ByteUtils.equals(left[i], right[i]);
+ }
+
+ return result;
+ }
+
+ /**
+ * Compare two three-dimensional byte arrays. No null checks are performed.
+ *
+ * @param left the first byte array
+ * @param right the second byte array
+ * @return the result of the comparison
+ */
+ public static boolean equals(byte[][][] left, byte[][][] right)
+ {
+ if (left.length != right.length)
+ {
+ return false;
+ }
+
+ boolean result = true;
+ for (int i = left.length - 1; i >= 0; i--)
+ {
+ if (left[i].length != right[i].length)
+ {
+ return false;
+ }
+ for (int j = left[i].length - 1; j >= 0; j--)
+ {
+ result &= ByteUtils.equals(left[i][j], right[i][j]);
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Computes a hashcode based on the contents of a one-dimensional byte array
+ * rather than its identity.
+ *
+ * @param array the array to compute the hashcode of
+ * @return the hashcode
+ */
+ public static int deepHashCode(byte[] array)
+ {
+ int result = 1;
+ for (int i = 0; i < array.length; i++)
+ {
+ result = 31 * result + array[i];
+ }
+ return result;
+ }
+
+ /**
+ * Computes a hashcode based on the contents of a two-dimensional byte array
+ * rather than its identity.
+ *
+ * @param array the array to compute the hashcode of
+ * @return the hashcode
+ */
+ public static int deepHashCode(byte[][] array)
+ {
+ int result = 1;
+ for (int i = 0; i < array.length; i++)
+ {
+ result = 31 * result + deepHashCode(array[i]);
+ }
+ return result;
+ }
+
+ /**
+ * Computes a hashcode based on the contents of a three-dimensional byte
+ * array rather than its identity.
+ *
+ * @param array the array to compute the hashcode of
+ * @return the hashcode
+ */
+ public static int deepHashCode(byte[][][] array)
+ {
+ int result = 1;
+ for (int i = 0; i < array.length; i++)
+ {
+ result = 31 * result + deepHashCode(array[i]);
+ }
+ return result;
+ }
+
+
+ /**
+ * Return a clone of the given byte array (performs null check beforehand).
+ *
+ * @param array the array to clone
+ * @return the clone of the given array, or null if the array is
+ * null
+ */
+ public static byte[] clone(byte[] array)
+ {
+ if (array == null)
+ {
+ return null;
+ }
+ byte[] result = new byte[array.length];
+ System.arraycopy(array, 0, result, 0, array.length);
+ return result;
+ }
+
+ /**
+ * Convert a string containing hexadecimal characters to a byte-array.
+ *
+ * @param s a hex string
+ * @return a byte array with the corresponding value
+ */
+ public static byte[] fromHexString(String s)
+ {
+ char[] rawChars = s.toUpperCase().toCharArray();
+
+ int hexChars = 0;
+ for (int i = 0; i < rawChars.length; i++)
+ {
+ if ((rawChars[i] >= '0' && rawChars[i] <= '9')
+ || (rawChars[i] >= 'A' && rawChars[i] <= 'F'))
+ {
+ hexChars++;
+ }
+ }
+
+ byte[] byteString = new byte[(hexChars + 1) >> 1];
+
+ int pos = hexChars & 1;
+
+ for (int i = 0; i < rawChars.length; i++)
+ {
+ if (rawChars[i] >= '0' && rawChars[i] <= '9')
+ {
+ byteString[pos >> 1] <<= 4;
+ byteString[pos >> 1] |= rawChars[i] - '0';
+ }
+ else if (rawChars[i] >= 'A' && rawChars[i] <= 'F')
+ {
+ byteString[pos >> 1] <<= 4;
+ byteString[pos >> 1] |= rawChars[i] - 'A' + 10;
+ }
+ else
+ {
+ continue;
+ }
+ pos++;
+ }
+
+ return byteString;
+ }
+
+ /**
+ * Convert a byte array to the corresponding hexstring.
+ *
+ * @param input the byte array to be converted
+ * @return the corresponding hexstring
+ */
+ public static String toHexString(byte[] input)
+ {
+ String result = "";
+ for (int i = 0; i < input.length; i++)
+ {
+ result += HEX_CHARS[(input[i] >>> 4) & 0x0f];
+ result += HEX_CHARS[(input[i]) & 0x0f];
+ }
+ return result;
+ }
+
+ /**
+ * Convert a byte array to the corresponding hex string.
+ *
+ * @param input the byte array to be converted
+ * @param prefix the prefix to put at the beginning of the hex string
+ * @param seperator a separator string
+ * @return the corresponding hex string
+ */
+ public static String toHexString(byte[] input, String prefix,
+ String seperator)
+ {
+ String result = new String(prefix);
+ for (int i = 0; i < input.length; i++)
+ {
+ result += HEX_CHARS[(input[i] >>> 4) & 0x0f];
+ result += HEX_CHARS[(input[i]) & 0x0f];
+ if (i < input.length - 1)
+ {
+ result += seperator;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Convert a byte array to the corresponding bit string.
+ *
+ * @param input the byte array to be converted
+ * @return the corresponding bit string
+ */
+ public static String toBinaryString(byte[] input)
+ {
+ String result = "";
+ int i;
+ for (i = 0; i < input.length; i++)
+ {
+ int e = input[i];
+ for (int ii = 0; ii < 8; ii++)
+ {
+ int b = (e >>> ii) & 1;
+ result += b;
+ }
+ if (i != input.length - 1)
+ {
+ result += " ";
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Compute the bitwise XOR of two arrays of bytes. The arrays have to be of
+ * same length. No length checking is performed.
+ *
+ * @param x1 the first array
+ * @param x2 the second array
+ * @return x1 XOR x2
+ */
+ public static byte[] xor(byte[] x1, byte[] x2)
+ {
+ byte[] out = new byte[x1.length];
+
+ for (int i = x1.length - 1; i >= 0; i--)
+ {
+ out[i] = (byte)(x1[i] ^ x2[i]);
+ }
+ return out;
+ }
+
+ /**
+ * Concatenate two byte arrays. No null checks are performed.
+ *
+ * @param x1 the first array
+ * @param x2 the second array
+ * @return (x2||x1) (little-endian order, i.e. x1 is at lower memory
+ * addresses)
+ */
+ public static byte[] concatenate(byte[] x1, byte[] x2)
+ {
+ byte[] result = new byte[x1.length + x2.length];
+
+ System.arraycopy(x1, 0, result, 0, x1.length);
+ System.arraycopy(x2, 0, result, x1.length, x2.length);
+
+ return result;
+ }
+
+ /**
+ * Convert a 2-dimensional byte array into a 1-dimensional byte array by
+ * concatenating all entries.
+ *
+ * @param array a 2-dimensional byte array
+ * @return the concatenated input array
+ */
+ public static byte[] concatenate(byte[][] array)
+ {
+ int rowLength = array[0].length;
+ byte[] result = new byte[array.length * rowLength];
+ int index = 0;
+ for (int i = 0; i < array.length; i++)
+ {
+ System.arraycopy(array[i], 0, result, index, rowLength);
+ index += rowLength;
+ }
+ return result;
+ }
+
+ /**
+ * Split a byte array input into two arrays at index,
+ * i.e. the first array will have the lower index bytes, the
+ * second one the higher input.length - index bytes.
+ *
+ * @param input the byte array to be split
+ * @param index the index where the byte array is split
+ * @return the splitted input array as an array of two byte arrays
+ * @throws ArrayIndexOutOfBoundsException if index is out of bounds
+ */
+ public static byte[][] split(byte[] input, int index)
+ throws ArrayIndexOutOfBoundsException
+ {
+ if (index > input.length)
+ {
+ throw new ArrayIndexOutOfBoundsException();
+ }
+ byte[][] result = new byte[2][];
+ result[0] = new byte[index];
+ result[1] = new byte[input.length - index];
+ System.arraycopy(input, 0, result[0], 0, index);
+ System.arraycopy(input, index, result[1], 0, input.length - index);
+ return result;
+ }
+
+ /**
+ * Generate a subarray of a given byte array.
+ *
+ * @param input the input byte array
+ * @param start the start index
+ * @param end the end index
+ * @return a subarray of input, ranging from start
+ * (inclusively) to end (exclusively)
+ */
+ public static byte[] subArray(byte[] input, int start, int end)
+ {
+ byte[] result = new byte[end - start];
+ System.arraycopy(input, start, result, 0, end - start);
+ return result;
+ }
+
+ /**
+ * Generate a subarray of a given byte array.
+ *
+ * @param input the input byte array
+ * @param start the start index
+ * @return a subarray of input, ranging from start to
+ * the end of the array
+ */
+ public static byte[] subArray(byte[] input, int start)
+ {
+ return subArray(input, start, input.length);
+ }
+
+ /**
+ * Rewrite a byte array as a char array
+ *
+ * @param input -
+ * the byte array
+ * @return char array
+ */
+ public static char[] toCharArray(byte[] input)
+ {
+ char[] result = new char[input.length];
+ for (int i = 0; i < input.length; i++)
+ {
+ result[i] = (char)input[i];
+ }
+ return result;
+ }
+
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/math/linearalgebra/CharUtils.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/math/linearalgebra/CharUtils.java
new file mode 100644
index 0000000..acf948e
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/math/linearalgebra/CharUtils.java
@@ -0,0 +1,98 @@
+package org.bc.pqc.math.linearalgebra;
+
+public final class CharUtils
+{
+
+ /**
+ * Default constructor (private)
+ */
+ private CharUtils()
+ {
+ // empty
+ }
+
+ /**
+ * Return a clone of the given char array. No null checks are performed.
+ *
+ * @param array the array to clone
+ * @return the clone of the given array
+ */
+ public static char[] clone(char[] array)
+ {
+ char[] result = new char[array.length];
+ System.arraycopy(array, 0, result, 0, array.length);
+ return result;
+ }
+
+ /**
+ * Convert the given char array into a byte array.
+ *
+ * @param chars the char array
+ * @return the converted array
+ */
+ public static byte[] toByteArray(char[] chars)
+ {
+ byte[] result = new byte[chars.length];
+ for (int i = chars.length - 1; i >= 0; i--)
+ {
+ result[i] = (byte)chars[i];
+ }
+ return result;
+ }
+
+ /**
+ * Convert the given char array into a
+ * byte array for use with PBE encryption.
+ *
+ * @param chars the char array
+ * @return the converted array
+ */
+ public static byte[] toByteArrayForPBE(char[] chars)
+ {
+
+ byte[] out = new byte[chars.length];
+
+ for (int i = 0; i < chars.length; i++)
+ {
+ out[i] = (byte)chars[i];
+ }
+
+ int length = out.length * 2;
+ byte[] ret = new byte[length + 2];
+
+ int j = 0;
+ for (int i = 0; i < out.length; i++)
+ {
+ j = i * 2;
+ ret[j] = 0;
+ ret[j + 1] = out[i];
+ }
+
+ ret[length] = 0;
+ ret[length + 1] = 0;
+
+ return ret;
+ }
+
+ /**
+ * Compare two char arrays. No null checks are performed.
+ *
+ * @param left the char byte array
+ * @param right the second char array
+ * @return the result of the comparison
+ */
+ public static boolean equals(char[] left, char[] right)
+ {
+ if (left.length != right.length)
+ {
+ return false;
+ }
+ boolean result = true;
+ for (int i = left.length - 1; i >= 0; i--)
+ {
+ result &= left[i] == right[i];
+ }
+ return result;
+ }
+
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/math/linearalgebra/GF2Matrix.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/math/linearalgebra/GF2Matrix.java
new file mode 100644
index 0000000..147747d
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/math/linearalgebra/GF2Matrix.java
@@ -0,0 +1,1323 @@
+package org.bc.pqc.math.linearalgebra;
+
+import java.security.SecureRandom;
+
+/**
+ * This class describes some operations with matrices over finite field GF(2)
+ * and is used in ecc and MQ-PKC (also has some specific methods and
+ * implementation)
+ */
+public class GF2Matrix
+ extends Matrix
+{
+
+ /**
+ * For the matrix representation the array of type int[][] is used, thus one
+ * element of the array keeps 32 elements of the matrix (from one row and 32
+ * columns)
+ */
+ private int[][] matrix;
+
+ /**
+ * the length of each array representing a row of this matrix, computed as
+ * (numColumns + 31) / 32
+ */
+ private int length;
+
+ /**
+ * Create the matrix from encoded form.
+ *
+ * @param enc the encoded matrix
+ */
+ public GF2Matrix(byte[] enc)
+ {
+ if (enc.length < 9)
+ {
+ throw new ArithmeticException(
+ "given array is not an encoded matrix over GF(2)");
+ }
+
+ numRows = LittleEndianConversions.OS2IP(enc, 0);
+ numColumns = LittleEndianConversions.OS2IP(enc, 4);
+
+ int n = ((numColumns + 7) >>> 3) * numRows;
+
+ if ((numRows <= 0) || (n != (enc.length - 8)))
+ {
+ throw new ArithmeticException(
+ "given array is not an encoded matrix over GF(2)");
+ }
+
+ length = (numColumns + 31) >>> 5;
+ matrix = new int[numRows][length];
+
+ // number of "full" integer
+ int q = numColumns >> 5;
+ // number of bits in non-full integer
+ int r = numColumns & 0x1f;
+
+ int count = 8;
+ for (int i = 0; i < numRows; i++)
+ {
+ for (int j = 0; j < q; j++, count += 4)
+ {
+ matrix[i][j] = LittleEndianConversions.OS2IP(enc, count);
+ }
+ for (int j = 0; j < r; j += 8)
+ {
+ matrix[i][q] ^= (enc[count++] & 0xff) << j;
+ }
+ }
+ }
+
+ /**
+ * Create the matrix with the contents of the given array. The matrix is not
+ * copied. Unused coefficients are masked out.
+ *
+ * @param numColumns the number of columns
+ * @param matrix the element array
+ */
+ public GF2Matrix(int numColumns, int[][] matrix)
+ {
+ if (matrix[0].length != (numColumns + 31) >> 5)
+ {
+ throw new ArithmeticException(
+ "Int array does not match given number of columns.");
+ }
+ this.numColumns = numColumns;
+ numRows = matrix.length;
+ length = matrix[0].length;
+ int rest = numColumns & 0x1f;
+ int bitMask;
+ if (rest == 0)
+ {
+ bitMask = 0xffffffff;
+ }
+ else
+ {
+ bitMask = (1 << rest) - 1;
+ }
+ for (int i = 0; i < numRows; i++)
+ {
+ matrix[i][length - 1] &= bitMask;
+ }
+ this.matrix = matrix;
+ }
+
+ /**
+ * Create an nxn matrix of the given type.
+ *
+ * @param n the number of rows (and columns)
+ * @param typeOfMatrix the martix type (see {@link Matrix} for predefined
+ * constants)
+ */
+ public GF2Matrix(int n, char typeOfMatrix)
+ {
+ this(n, typeOfMatrix, new java.security.SecureRandom());
+ }
+
+ /**
+ * Create an nxn matrix of the given type.
+ *
+ * @param n the matrix size
+ * @param typeOfMatrix the matrix type
+ * @param sr the source of randomness
+ */
+ public GF2Matrix(int n, char typeOfMatrix, SecureRandom sr)
+ {
+ if (n <= 0)
+ {
+ throw new ArithmeticException("Size of matrix is non-positive.");
+ }
+
+ switch (typeOfMatrix)
+ {
+
+ case Matrix.MATRIX_TYPE_ZERO:
+ assignZeroMatrix(n, n);
+ break;
+
+ case Matrix.MATRIX_TYPE_UNIT:
+ assignUnitMatrix(n);
+ break;
+
+ case Matrix.MATRIX_TYPE_RANDOM_LT:
+ assignRandomLowerTriangularMatrix(n, sr);
+ break;
+
+ case Matrix.MATRIX_TYPE_RANDOM_UT:
+ assignRandomUpperTriangularMatrix(n, sr);
+ break;
+
+ case Matrix.MATRIX_TYPE_RANDOM_REGULAR:
+ assignRandomRegularMatrix(n, sr);
+ break;
+
+ default:
+ throw new ArithmeticException("Unknown matrix type.");
+ }
+ }
+
+ /**
+ * Copy constructor.
+ *
+ * @param a another {@link GF2Matrix}
+ */
+ public GF2Matrix(GF2Matrix a)
+ {
+ numColumns = a.getNumColumns();
+ numRows = a.getNumRows();
+ length = a.length;
+ matrix = new int[a.matrix.length][];
+ for (int i = 0; i < matrix.length; i++)
+ {
+ matrix[i] = IntUtils.clone(a.matrix[i]);
+ }
+
+ }
+
+ /**
+ * create the mxn zero matrix
+ */
+ private GF2Matrix(int m, int n)
+ {
+ if ((n <= 0) || (m <= 0))
+ {
+ throw new ArithmeticException("size of matrix is non-positive");
+ }
+
+ assignZeroMatrix(m, n);
+ }
+
+ /**
+ * Create the mxn zero matrix.
+ *
+ * @param m number of rows
+ * @param n number of columns
+ */
+ private void assignZeroMatrix(int m, int n)
+ {
+ numRows = m;
+ numColumns = n;
+ length = (n + 31) >>> 5;
+ matrix = new int[numRows][length];
+ for (int i = 0; i < numRows; i++)
+ {
+ for (int j = 0; j < length; j++)
+ {
+ matrix[i][j] = 0;
+ }
+ }
+ }
+
+ /**
+ * Create the mxn unit matrix.
+ *
+ * @param n number of rows (and columns)
+ */
+ private void assignUnitMatrix(int n)
+ {
+ numRows = n;
+ numColumns = n;
+ length = (n + 31) >>> 5;
+ matrix = new int[numRows][length];
+ for (int i = 0; i < numRows; i++)
+ {
+ for (int j = 0; j < length; j++)
+ {
+ matrix[i][j] = 0;
+ }
+ }
+ for (int i = 0; i < numRows; i++)
+ {
+ int rest = i & 0x1f;
+ matrix[i][i >>> 5] = 1 << rest;
+ }
+ }
+
+ /**
+ * Create a nxn random lower triangular matrix.
+ *
+ * @param n number of rows (and columns)
+ * @param sr source of randomness
+ */
+ private void assignRandomLowerTriangularMatrix(int n, SecureRandom sr)
+ {
+ numRows = n;
+ numColumns = n;
+ length = (n + 31) >>> 5;
+ matrix = new int[numRows][length];
+ for (int i = 0; i < numRows; i++)
+ {
+ int q = i >>> 5;
+ int r = i & 0x1f;
+ int s = 31 - r;
+ r = 1 << r;
+ for (int j = 0; j < q; j++)
+ {
+ matrix[i][j] = sr.nextInt();
+ }
+ matrix[i][q] = (sr.nextInt() >>> s) | r;
+ for (int j = q + 1; j < length; j++)
+ {
+ matrix[i][j] = 0;
+ }
+
+ }
+
+ }
+
+ /**
+ * Create a nxn random upper triangular matrix.
+ *
+ * @param n number of rows (and columns)
+ * @param sr source of randomness
+ */
+ private void assignRandomUpperTriangularMatrix(int n, SecureRandom sr)
+ {
+ numRows = n;
+ numColumns = n;
+ length = (n + 31) >>> 5;
+ matrix = new int[numRows][length];
+ int rest = n & 0x1f;
+ int help;
+ if (rest == 0)
+ {
+ help = 0xffffffff;
+ }
+ else
+ {
+ help = (1 << rest) - 1;
+ }
+ for (int i = 0; i < numRows; i++)
+ {
+ int q = i >>> 5;
+ int r = i & 0x1f;
+ int s = r;
+ r = 1 << r;
+ for (int j = 0; j < q; j++)
+ {
+ matrix[i][j] = 0;
+ }
+ matrix[i][q] = (sr.nextInt() << s) | r;
+ for (int j = q + 1; j < length; j++)
+ {
+ matrix[i][j] = sr.nextInt();
+ }
+ matrix[i][length - 1] &= help;
+ }
+
+ }
+
+ /**
+ * Create an nxn random regular matrix.
+ *
+ * @param n number of rows (and columns)
+ * @param sr source of randomness
+ */
+ private void assignRandomRegularMatrix(int n, SecureRandom sr)
+ {
+ numRows = n;
+ numColumns = n;
+ length = (n + 31) >>> 5;
+ matrix = new int[numRows][length];
+ GF2Matrix lm = new GF2Matrix(n, Matrix.MATRIX_TYPE_RANDOM_LT, sr);
+ GF2Matrix um = new GF2Matrix(n, Matrix.MATRIX_TYPE_RANDOM_UT, sr);
+ GF2Matrix rm = (GF2Matrix)lm.rightMultiply(um);
+ Permutation perm = new Permutation(n, sr);
+ int[] p = perm.getVector();
+ for (int i = 0; i < n; i++)
+ {
+ System.arraycopy(rm.matrix[i], 0, matrix[p[i]], 0, length);
+ }
+ }
+
+ /**
+ * Create a nxn random regular matrix and its inverse.
+ *
+ * @param n number of rows (and columns)
+ * @param sr source of randomness
+ * @return the created random regular matrix and its inverse
+ */
+ public static GF2Matrix[] createRandomRegularMatrixAndItsInverse(int n,
+ SecureRandom sr)
+ {
+
+ GF2Matrix[] result = new GF2Matrix[2];
+
+ // ------------------------------------
+ // First part: create regular matrix
+ // ------------------------------------
+
+ // ------
+ int length = (n + 31) >> 5;
+ GF2Matrix lm = new GF2Matrix(n, Matrix.MATRIX_TYPE_RANDOM_LT, sr);
+ GF2Matrix um = new GF2Matrix(n, Matrix.MATRIX_TYPE_RANDOM_UT, sr);
+ GF2Matrix rm = (GF2Matrix)lm.rightMultiply(um);
+ Permutation p = new Permutation(n, sr);
+ int[] pVec = p.getVector();
+
+ int[][] matrix = new int[n][length];
+ for (int i = 0; i < n; i++)
+ {
+ System.arraycopy(rm.matrix[pVec[i]], 0, matrix[i], 0, length);
+ }
+
+ result[0] = new GF2Matrix(n, matrix);
+
+ // ------------------------------------
+ // Second part: create inverse matrix
+ // ------------------------------------
+
+ // inverse to lm
+ GF2Matrix invLm = new GF2Matrix(n, Matrix.MATRIX_TYPE_UNIT);
+ for (int i = 0; i < n; i++)
+ {
+ int rest = i & 0x1f;
+ int q = i >>> 5;
+ int r = 1 << rest;
+ for (int j = i + 1; j < n; j++)
+ {
+ int b = (lm.matrix[j][q]) & r;
+ if (b != 0)
+ {
+ for (int k = 0; k <= q; k++)
+ {
+ invLm.matrix[j][k] ^= invLm.matrix[i][k];
+ }
+ }
+ }
+ }
+ // inverse to um
+ GF2Matrix invUm = new GF2Matrix(n, Matrix.MATRIX_TYPE_UNIT);
+ for (int i = n - 1; i >= 0; i--)
+ {
+ int rest = i & 0x1f;
+ int q = i >>> 5;
+ int r = 1 << rest;
+ for (int j = i - 1; j >= 0; j--)
+ {
+ int b = (um.matrix[j][q]) & r;
+ if (b != 0)
+ {
+ for (int k = q; k < length; k++)
+ {
+ invUm.matrix[j][k] ^= invUm.matrix[i][k];
+ }
+ }
+ }
+ }
+
+ // inverse matrix
+ result[1] = (GF2Matrix)invUm.rightMultiply(invLm.rightMultiply(p));
+
+ return result;
+ }
+
+ /**
+ * @return the array keeping the matrix elements
+ */
+ public int[][] getIntArray()
+ {
+ return matrix;
+ }
+
+ /**
+ * @return the length of each array representing a row of this matrix
+ */
+ public int getLength()
+ {
+ return length;
+ }
+
+ /**
+ * Return the row of this matrix with the given index.
+ *
+ * @param index the index
+ * @return the row of this matrix with the given index
+ */
+ public int[] getRow(int index)
+ {
+ return matrix[index];
+ }
+
+ /**
+ * Returns encoded matrix, i.e., this matrix in byte array form
+ *
+ * @return the encoded matrix
+ */
+ public byte[] getEncoded()
+ {
+ int n = (numColumns + 7) >>> 3;
+ n *= numRows;
+ n += 8;
+ byte[] enc = new byte[n];
+
+ LittleEndianConversions.I2OSP(numRows, enc, 0);
+ LittleEndianConversions.I2OSP(numColumns, enc, 4);
+
+ // number of "full" integer
+ int q = numColumns >>> 5;
+ // number of bits in non-full integer
+ int r = numColumns & 0x1f;
+
+ int count = 8;
+ for (int i = 0; i < numRows; i++)
+ {
+ for (int j = 0; j < q; j++, count += 4)
+ {
+ LittleEndianConversions.I2OSP(matrix[i][j], enc, count);
+ }
+ for (int j = 0; j < r; j += 8)
+ {
+ enc[count++] = (byte)((matrix[i][q] >>> j) & 0xff);
+ }
+
+ }
+ return enc;
+ }
+
+
+ /**
+ * Returns the percentage of the number of "ones" in this matrix.
+ *
+ * @return the Hamming weight of this matrix (as a ratio).
+ */
+ public double getHammingWeight()
+ {
+ double counter = 0.0;
+ double elementCounter = 0.0;
+ int rest = numColumns & 0x1f;
+ int d;
+ if (rest == 0)
+ {
+ d = length;
+ }
+ else
+ {
+ d = length - 1;
+ }
+
+ for (int i = 0; i < numRows; i++)
+ {
+
+ for (int j = 0; j < d; j++)
+ {
+ int a = matrix[i][j];
+ for (int k = 0; k < 32; k++)
+ {
+ int b = (a >>> k) & 1;
+ counter = counter + b;
+ elementCounter = elementCounter + 1;
+ }
+ }
+ int a = matrix[i][length - 1];
+ for (int k = 0; k < rest; k++)
+ {
+ int b = (a >>> k) & 1;
+ counter = counter + b;
+ elementCounter = elementCounter + 1;
+ }
+ }
+
+ return counter / elementCounter;
+ }
+
+ /**
+ * Check if this is the zero matrix (i.e., all entries are zero).
+ *
+ * @return true if this is the zero matrix
+ */
+ public boolean isZero()
+ {
+ for (int i = 0; i < numRows; i++)
+ {
+ for (int j = 0; j < length; j++)
+ {
+ if (matrix[i][j] != 0)
+ {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Get the quadratic submatrix of this matrix consisting of the leftmost
+ * numRows columns.
+ *
+ * @return the (numRows x numRows) submatrix
+ */
+ public GF2Matrix getLeftSubMatrix()
+ {
+ if (numColumns <= numRows)
+ {
+ throw new ArithmeticException("empty submatrix");
+ }
+ int length = (numRows + 31) >> 5;
+ int[][] result = new int[numRows][length];
+ int bitMask = (1 << (numRows & 0x1f)) - 1;
+ if (bitMask == 0)
+ {
+ bitMask = -1;
+ }
+ for (int i = numRows - 1; i >= 0; i--)
+ {
+ System.arraycopy(matrix[i], 0, result[i], 0, length);
+ result[i][length - 1] &= bitMask;
+ }
+ return new GF2Matrix(numRows, result);
+ }
+
+ /**
+ * Compute the full form matrix (this | Id) from this matrix in
+ * left compact form, where Id is the k x k identity
+ * matrix and k is the number of rows of this matrix.
+ *
+ * @return (this | Id)
+ */
+ public GF2Matrix extendLeftCompactForm()
+ {
+ int newNumColumns = numColumns + numRows;
+ GF2Matrix result = new GF2Matrix(numRows, newNumColumns);
+
+ int ind = numRows - 1 + numColumns;
+ for (int i = numRows - 1; i >= 0; i--, ind--)
+ {
+ // copy this matrix to first columns
+ System.arraycopy(matrix[i], 0, result.matrix[i], 0, length);
+ // store the identity in last columns
+ result.matrix[i][ind >> 5] |= 1 << (ind & 0x1f);
+ }
+
+ return result;
+ }
+
+ /**
+ * Get the submatrix of this matrix consisting of the rightmost
+ * numColumns-numRows columns.
+ *
+ * @return the (numRows x (numColumns-numRows)) submatrix
+ */
+ public GF2Matrix getRightSubMatrix()
+ {
+ if (numColumns <= numRows)
+ {
+ throw new ArithmeticException("empty submatrix");
+ }
+
+ int q = numRows >> 5;
+ int r = numRows & 0x1f;
+
+ GF2Matrix result = new GF2Matrix(numRows, numColumns - numRows);
+
+ for (int i = numRows - 1; i >= 0; i--)
+ {
+ // if words have to be shifted
+ if (r != 0)
+ {
+ int ind = q;
+ // process all but last word
+ for (int j = 0; j < result.length - 1; j++)
+ {
+ // shift to correct position
+ result.matrix[i][j] = (matrix[i][ind++] >>> r)
+ | (matrix[i][ind] << (32 - r));
+ }
+ // process last word
+ result.matrix[i][result.length - 1] = matrix[i][ind++] >>> r;
+ if (ind < length)
+ {
+ result.matrix[i][result.length - 1] |= matrix[i][ind] << (32 - r);
+ }
+ }
+ else
+ {
+ // no shifting necessary
+ System.arraycopy(matrix[i], q, result.matrix[i], 0,
+ result.length);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Compute the full form matrix (Id | this) from this matrix in
+ * right compact form, where Id is the k x k identity
+ * matrix and k is the number of rows of this matrix.
+ *
+ * @return (Id | this)
+ */
+ public GF2Matrix extendRightCompactForm()
+ {
+ GF2Matrix result = new GF2Matrix(numRows, numRows + numColumns);
+
+ int q = numRows >> 5;
+ int r = numRows & 0x1f;
+
+ for (int i = numRows - 1; i >= 0; i--)
+ {
+ // store the identity in first columns
+ result.matrix[i][i >> 5] |= 1 << (i & 0x1f);
+
+ // copy this matrix to last columns
+
+ // if words have to be shifted
+ if (r != 0)
+ {
+ int ind = q;
+ // process all but last word
+ for (int j = 0; j < length - 1; j++)
+ {
+ // obtain matrix word
+ int mw = matrix[i][j];
+ // shift to correct position
+ result.matrix[i][ind++] |= mw << r;
+ result.matrix[i][ind] |= mw >>> (32 - r);
+ }
+ // process last word
+ int mw = matrix[i][length - 1];
+ result.matrix[i][ind++] |= mw << r;
+ if (ind < result.length)
+ {
+ result.matrix[i][ind] |= mw >>> (32 - r);
+ }
+ }
+ else
+ {
+ // no shifting necessary
+ System.arraycopy(matrix[i], 0, result.matrix[i], q, length);
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Compute the transpose of this matrix.
+ *
+ * @return (this)T
+ */
+ public Matrix computeTranspose()
+ {
+ int[][] result = new int[numColumns][(numRows + 31) >>> 5];
+ for (int i = 0; i < numRows; i++)
+ {
+ for (int j = 0; j < numColumns; j++)
+ {
+ int qs = j >>> 5;
+ int rs = j & 0x1f;
+ int b = (matrix[i][qs] >>> rs) & 1;
+ int qt = i >>> 5;
+ int rt = i & 0x1f;
+ if (b == 1)
+ {
+ result[j][qt] |= 1 << rt;
+ }
+ }
+ }
+
+ return new GF2Matrix(numRows, result);
+ }
+
+ /**
+ * Compute the inverse of this matrix.
+ *
+ * @return the inverse of this matrix (newly created).
+ * @throws ArithmeticException if this matrix is not invertible.
+ */
+ public Matrix computeInverse()
+ {
+ if (numRows != numColumns)
+ {
+ throw new ArithmeticException("Matrix is not invertible.");
+ }
+
+ // clone this matrix
+ int[][] tmpMatrix = new int[numRows][length];
+ for (int i = numRows - 1; i >= 0; i--)
+ {
+ tmpMatrix[i] = IntUtils.clone(matrix[i]);
+ }
+
+ // initialize inverse matrix as unit matrix
+ int[][] invMatrix = new int[numRows][length];
+ for (int i = numRows - 1; i >= 0; i--)
+ {
+ int q = i >> 5;
+ int r = i & 0x1f;
+ invMatrix[i][q] = 1 << r;
+ }
+
+ // simultaneously compute Gaussian reduction of tmpMatrix and unit
+ // matrix
+ for (int i = 0; i < numRows; i++)
+ {
+ // i = q * 32 + (i mod 32)
+ int q = i >> 5;
+ int bitMask = 1 << (i & 0x1f);
+ // if diagonal element is zero
+ if ((tmpMatrix[i][q] & bitMask) == 0)
+ {
+ boolean foundNonZero = false;
+ // find a non-zero element in the same column
+ for (int j = i + 1; j < numRows; j++)
+ {
+ if ((tmpMatrix[j][q] & bitMask) != 0)
+ {
+ // found it, swap rows ...
+ foundNonZero = true;
+ swapRows(tmpMatrix, i, j);
+ swapRows(invMatrix, i, j);
+ // ... and quit searching
+ j = numRows;
+ continue;
+ }
+ }
+ // if no non-zero element was found ...
+ if (!foundNonZero)
+ {
+ // ... the matrix is not invertible
+ throw new ArithmeticException("Matrix is not invertible.");
+ }
+ }
+
+ // normalize all but i-th row
+ for (int j = numRows - 1; j >= 0; j--)
+ {
+ if ((j != i) && ((tmpMatrix[j][q] & bitMask) != 0))
+ {
+ addToRow(tmpMatrix[i], tmpMatrix[j], q);
+ addToRow(invMatrix[i], invMatrix[j], 0);
+ }
+ }
+ }
+
+ return new GF2Matrix(numColumns, invMatrix);
+ }
+
+ /**
+ * Compute the product of a permutation matrix (which is generated from an
+ * n-permutation) and this matrix.
+ *
+ * @param p the permutation
+ * @return {@link GF2Matrix} P*this
+ */
+ public Matrix leftMultiply(Permutation p)
+ {
+ int[] pVec = p.getVector();
+ if (pVec.length != numRows)
+ {
+ throw new ArithmeticException("length mismatch");
+ }
+
+ int[][] result = new int[numRows][];
+
+ for (int i = numRows - 1; i >= 0; i--)
+ {
+ result[i] = IntUtils.clone(matrix[pVec[i]]);
+ }
+
+ return new GF2Matrix(numRows, result);
+ }
+
+ /**
+ * compute product a row vector and this matrix
+ *
+ * @param vec a vector over GF(2)
+ * @return Vector product a*matrix
+ */
+ public Vector leftMultiply(Vector vec)
+ {
+
+ if (!(vec instanceof GF2Vector))
+ {
+ throw new ArithmeticException("vector is not defined over GF(2)");
+ }
+
+ if (vec.length != numRows)
+ {
+ throw new ArithmeticException("length mismatch");
+ }
+
+ int[] v = ((GF2Vector)vec).getVecArray();
+ int[] res = new int[length];
+
+ int q = numRows >> 5;
+ int r = 1 << (numRows & 0x1f);
+
+ // compute scalar products with full words of vector
+ int row = 0;
+ for (int i = 0; i < q; i++)
+ {
+ int bitMask = 1;
+ do
+ {
+ int b = v[i] & bitMask;
+ if (b != 0)
+ {
+ for (int j = 0; j < length; j++)
+ {
+ res[j] ^= matrix[row][j];
+ }
+ }
+ row++;
+ bitMask <<= 1;
+ }
+ while (bitMask != 0);
+ }
+
+ // compute scalar products with last word of vector
+ int bitMask = 1;
+ while (bitMask != r)
+ {
+ int b = v[q] & bitMask;
+ if (b != 0)
+ {
+ for (int j = 0; j < length; j++)
+ {
+ res[j] ^= matrix[row][j];
+ }
+ }
+ row++;
+ bitMask <<= 1;
+ }
+
+ return new GF2Vector(res, numColumns);
+ }
+
+ /**
+ * Compute the product of the matrix (this | Id) and a column
+ * vector, where Id is a (numRows x numRows) unit
+ * matrix.
+ *
+ * @param vec the vector over GF(2)
+ * @return (this | Id)*vector
+ */
+ public Vector leftMultiplyLeftCompactForm(Vector vec)
+ {
+ if (!(vec instanceof GF2Vector))
+ {
+ throw new ArithmeticException("vector is not defined over GF(2)");
+ }
+
+ if (vec.length != numRows)
+ {
+ throw new ArithmeticException("length mismatch");
+ }
+
+ int[] v = ((GF2Vector)vec).getVecArray();
+ int[] res = new int[(numRows + numColumns + 31) >>> 5];
+
+ // process full words of vector
+ int words = numRows >>> 5;
+ int row = 0;
+ for (int i = 0; i < words; i++)
+ {
+ int bitMask = 1;
+ do
+ {
+ int b = v[i] & bitMask;
+ if (b != 0)
+ {
+ // compute scalar product part
+ for (int j = 0; j < length; j++)
+ {
+ res[j] ^= matrix[row][j];
+ }
+ // set last bit
+ int q = (numColumns + row) >>> 5;
+ int r = (numColumns + row) & 0x1f;
+ res[q] |= 1 << r;
+ }
+ row++;
+ bitMask <<= 1;
+ }
+ while (bitMask != 0);
+ }
+
+ // process last word of vector
+ int rem = 1 << (numRows & 0x1f);
+ int bitMask = 1;
+ while (bitMask != rem)
+ {
+ int b = v[words] & bitMask;
+ if (b != 0)
+ {
+ // compute scalar product part
+ for (int j = 0; j < length; j++)
+ {
+ res[j] ^= matrix[row][j];
+ }
+ // set last bit
+ int q = (numColumns + row) >>> 5;
+ int r = (numColumns + row) & 0x1f;
+ res[q] |= 1 << r;
+ }
+ row++;
+ bitMask <<= 1;
+ }
+
+ return new GF2Vector(res, numRows + numColumns);
+ }
+
+ /**
+ * Compute the product of this matrix and a matrix A over GF(2).
+ *
+ * @param mat a matrix A over GF(2)
+ * @return matrix product this*matrixA
+ */
+ public Matrix rightMultiply(Matrix mat)
+ {
+ if (!(mat instanceof GF2Matrix))
+ {
+ throw new ArithmeticException("matrix is not defined over GF(2)");
+ }
+
+ if (mat.numRows != numColumns)
+ {
+ throw new ArithmeticException("length mismatch");
+ }
+
+ GF2Matrix a = (GF2Matrix)mat;
+ GF2Matrix result = new GF2Matrix(numRows, mat.numColumns);
+
+ int d;
+ int rest = numColumns & 0x1f;
+ if (rest == 0)
+ {
+ d = length;
+ }
+ else
+ {
+ d = length - 1;
+ }
+ for (int i = 0; i < numRows; i++)
+ {
+ int count = 0;
+ for (int j = 0; j < d; j++)
+ {
+ int e = matrix[i][j];
+ for (int h = 0; h < 32; h++)
+ {
+ int b = e & (1 << h);
+ if (b != 0)
+ {
+ for (int g = 0; g < a.length; g++)
+ {
+ result.matrix[i][g] ^= a.matrix[count][g];
+ }
+ }
+ count++;
+ }
+ }
+ int e = matrix[i][length - 1];
+ for (int h = 0; h < rest; h++)
+ {
+ int b = e & (1 << h);
+ if (b != 0)
+ {
+ for (int g = 0; g < a.length; g++)
+ {
+ result.matrix[i][g] ^= a.matrix[count][g];
+ }
+ }
+ count++;
+ }
+
+ }
+
+ return result;
+ }
+
+ /**
+ * Compute the product of this matrix and a permutation matrix which is
+ * generated from an n-permutation.
+ *
+ * @param p the permutation
+ * @return {@link GF2Matrix} this*P
+ */
+ public Matrix rightMultiply(Permutation p)
+ {
+
+ int[] pVec = p.getVector();
+ if (pVec.length != numColumns)
+ {
+ throw new ArithmeticException("length mismatch");
+ }
+
+ GF2Matrix result = new GF2Matrix(numRows, numColumns);
+
+ for (int i = numColumns - 1; i >= 0; i--)
+ {
+ int q = i >>> 5;
+ int r = i & 0x1f;
+ int pq = pVec[i] >>> 5;
+ int pr = pVec[i] & 0x1f;
+ for (int j = numRows - 1; j >= 0; j--)
+ {
+ result.matrix[j][q] |= ((matrix[j][pq] >>> pr) & 1) << r;
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Compute the product of this matrix and the given column vector.
+ *
+ * @param vec the vector over GF(2)
+ * @return this*vector
+ */
+ public Vector rightMultiply(Vector vec)
+ {
+ if (!(vec instanceof GF2Vector))
+ {
+ throw new ArithmeticException("vector is not defined over GF(2)");
+ }
+
+ if (vec.length != numColumns)
+ {
+ throw new ArithmeticException("length mismatch");
+ }
+
+ int[] v = ((GF2Vector)vec).getVecArray();
+ int[] res = new int[(numRows + 31) >>> 5];
+
+ for (int i = 0; i < numRows; i++)
+ {
+ // compute full word scalar products
+ int help = 0;
+ for (int j = 0; j < length; j++)
+ {
+ help ^= matrix[i][j] & v[j];
+ }
+ // compute single word scalar product
+ int bitValue = 0;
+ for (int j = 0; j < 32; j++)
+ {
+ bitValue ^= (help >>> j) & 1;
+ }
+ // set result bit
+ if (bitValue == 1)
+ {
+ res[i >>> 5] |= 1 << (i & 0x1f);
+ }
+ }
+
+ return new GF2Vector(res, numRows);
+ }
+
+ /**
+ * Compute the product of the matrix (Id | this) and a column
+ * vector, where Id is a (numRows x numRows) unit
+ * matrix.
+ *
+ * @param vec the vector over GF(2)
+ * @return (Id | this)*vector
+ */
+ public Vector rightMultiplyRightCompactForm(Vector vec)
+ {
+ if (!(vec instanceof GF2Vector))
+ {
+ throw new ArithmeticException("vector is not defined over GF(2)");
+ }
+
+ if (vec.length != numColumns + numRows)
+ {
+ throw new ArithmeticException("length mismatch");
+ }
+
+ int[] v = ((GF2Vector)vec).getVecArray();
+ int[] res = new int[(numRows + 31) >>> 5];
+
+ int q = numRows >> 5;
+ int r = numRows & 0x1f;
+
+ // for all rows
+ for (int i = 0; i < numRows; i++)
+ {
+ // get vector bit
+ int help = (v[i >> 5] >>> (i & 0x1f)) & 1;
+
+ // compute full word scalar products
+ int vInd = q;
+ // if words have to be shifted
+ if (r != 0)
+ {
+ int vw = 0;
+ // process all but last word
+ for (int j = 0; j < length - 1; j++)
+ {
+ // shift to correct position
+ vw = (v[vInd++] >>> r) | (v[vInd] << (32 - r));
+ help ^= matrix[i][j] & vw;
+ }
+ // process last word
+ vw = v[vInd++] >>> r;
+ if (vInd < v.length)
+ {
+ vw |= v[vInd] << (32 - r);
+ }
+ help ^= matrix[i][length - 1] & vw;
+ }
+ else
+ {
+ // no shifting necessary
+ for (int j = 0; j < length; j++)
+ {
+ help ^= matrix[i][j] & v[vInd++];
+ }
+ }
+
+ // compute single word scalar product
+ int bitValue = 0;
+ for (int j = 0; j < 32; j++)
+ {
+ bitValue ^= help & 1;
+ help >>>= 1;
+ }
+
+ // set result bit
+ if (bitValue == 1)
+ {
+ res[i >> 5] |= 1 << (i & 0x1f);
+ }
+ }
+
+ return new GF2Vector(res, numRows);
+ }
+
+ /**
+ * Compare this matrix with another object.
+ *
+ * @param other another object
+ * @return the result of the comparison
+ */
+ public boolean equals(Object other)
+ {
+
+ if (!(other instanceof GF2Matrix))
+ {
+ return false;
+ }
+ GF2Matrix otherMatrix = (GF2Matrix)other;
+
+ if ((numRows != otherMatrix.numRows)
+ || (numColumns != otherMatrix.numColumns)
+ || (length != otherMatrix.length))
+ {
+ return false;
+ }
+
+ for (int i = 0; i < numRows; i++)
+ {
+ if (!IntUtils.equals(matrix[i], otherMatrix.matrix[i]))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * @return the hash code of this matrix
+ */
+ public int hashCode()
+ {
+ int hash = (numRows * 31 + numColumns) * 31 + length;
+ for (int i = 0; i < numRows; i++)
+ {
+ hash = hash * 31 + matrix[i].hashCode();
+ }
+ return hash;
+ }
+
+ /**
+ * @return a human readable form of the matrix
+ */
+ public String toString()
+ {
+ int rest = numColumns & 0x1f;
+ int d;
+ if (rest == 0)
+ {
+ d = length;
+ }
+ else
+ {
+ d = length - 1;
+ }
+
+ StringBuffer buf = new StringBuffer();
+ for (int i = 0; i < numRows; i++)
+ {
+ buf.append(i + ": ");
+ for (int j = 0; j < d; j++)
+ {
+ int a = matrix[i][j];
+ for (int k = 0; k < 32; k++)
+ {
+ int b = (a >>> k) & 1;
+ if (b == 0)
+ {
+ buf.append('0');
+ }
+ else
+ {
+ buf.append('1');
+ }
+ }
+ buf.append(' ');
+ }
+ int a = matrix[i][length - 1];
+ for (int k = 0; k < rest; k++)
+ {
+ int b = (a >>> k) & 1;
+ if (b == 0)
+ {
+ buf.append('0');
+ }
+ else
+ {
+ buf.append('1');
+ }
+ }
+ buf.append('\n');
+ }
+
+ return buf.toString();
+ }
+
+ /**
+ * Swap two rows of the given matrix.
+ *
+ * @param matrix the matrix
+ * @param first the index of the first row
+ * @param second the index of the second row
+ */
+ private static void swapRows(int[][] matrix, int first, int second)
+ {
+ int[] tmp = matrix[first];
+ matrix[first] = matrix[second];
+ matrix[second] = tmp;
+ }
+
+ /**
+ * Partially add one row to another.
+ *
+ * @param fromRow the addend
+ * @param toRow the row to add to
+ * @param startIndex the array index to start from
+ */
+ private static void addToRow(int[] fromRow, int[] toRow, int startIndex)
+ {
+ for (int i = toRow.length - 1; i >= startIndex; i--)
+ {
+ toRow[i] = fromRow[i] ^ toRow[i];
+ }
+ }
+
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/math/linearalgebra/GF2Polynomial.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/math/linearalgebra/GF2Polynomial.java
new file mode 100644
index 0000000..dff31b5
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/math/linearalgebra/GF2Polynomial.java
@@ -0,0 +1,2039 @@
+package org.bc.pqc.math.linearalgebra;
+
+
+import java.math.BigInteger;
+import java.util.Random;
+
+
+/**
+ * This class stores very long strings of bits and does some basic arithmetics.
+ * It is used by GF2nField, GF2nPolynomialField and
+ * GFnPolynomialElement.
+ *
+ * @see GF2nPolynomialElement
+ * @see GF2nField
+ */
+public class GF2Polynomial
+{
+
+ // number of bits stored in this GF2Polynomial
+ private int len;
+
+ // number of int used in value
+ private int blocks;
+
+ // storage
+ private int[] value;
+
+ // Random source
+ private static Random rand = new Random();
+
+ // Lookup-Table for vectorMult: parity[a]= #1(a) mod 2 == 1
+ private static final boolean[] parity = {false, true, true, false, true,
+ false, false, true, true, false, false, true, false, true, true,
+ false, true, false, false, true, false, true, true, false, false,
+ true, true, false, true, false, false, true, true, false, false,
+ true, false, true, true, false, false, true, true, false, true,
+ false, false, true, false, true, true, false, true, false, false,
+ true, true, false, false, true, false, true, true, false, true,
+ false, false, true, false, true, true, false, false, true, true,
+ false, true, false, false, true, false, true, true, false, true,
+ false, false, true, true, false, false, true, false, true, true,
+ false, false, true, true, false, true, false, false, true, true,
+ false, false, true, false, true, true, false, true, false, false,
+ true, false, true, true, false, false, true, true, false, true,
+ false, false, true, true, false, false, true, false, true, true,
+ false, false, true, true, false, true, false, false, true, false,
+ true, true, false, true, false, false, true, true, false, false,
+ true, false, true, true, false, false, true, true, false, true,
+ false, false, true, true, false, false, true, false, true, true,
+ false, true, false, false, true, false, true, true, false, false,
+ true, true, false, true, false, false, true, false, true, true,
+ false, true, false, false, true, true, false, false, true, false,
+ true, true, false, true, false, false, true, false, true, true,
+ false, false, true, true, false, true, false, false, true, true,
+ false, false, true, false, true, true, false, false, true, true,
+ false, true, false, false, true, false, true, true, false, true,
+ false, false, true, true, false, false, true, false, true, true,
+ false};
+
+ // Lookup-Table for Squaring: squaringTable[a]=a^2
+ private static final short[] squaringTable = {0x0000, 0x0001, 0x0004,
+ 0x0005, 0x0010, 0x0011, 0x0014, 0x0015, 0x0040, 0x0041, 0x0044,
+ 0x0045, 0x0050, 0x0051, 0x0054, 0x0055, 0x0100, 0x0101, 0x0104,
+ 0x0105, 0x0110, 0x0111, 0x0114, 0x0115, 0x0140, 0x0141, 0x0144,
+ 0x0145, 0x0150, 0x0151, 0x0154, 0x0155, 0x0400, 0x0401, 0x0404,
+ 0x0405, 0x0410, 0x0411, 0x0414, 0x0415, 0x0440, 0x0441, 0x0444,
+ 0x0445, 0x0450, 0x0451, 0x0454, 0x0455, 0x0500, 0x0501, 0x0504,
+ 0x0505, 0x0510, 0x0511, 0x0514, 0x0515, 0x0540, 0x0541, 0x0544,
+ 0x0545, 0x0550, 0x0551, 0x0554, 0x0555, 0x1000, 0x1001, 0x1004,
+ 0x1005, 0x1010, 0x1011, 0x1014, 0x1015, 0x1040, 0x1041, 0x1044,
+ 0x1045, 0x1050, 0x1051, 0x1054, 0x1055, 0x1100, 0x1101, 0x1104,
+ 0x1105, 0x1110, 0x1111, 0x1114, 0x1115, 0x1140, 0x1141, 0x1144,
+ 0x1145, 0x1150, 0x1151, 0x1154, 0x1155, 0x1400, 0x1401, 0x1404,
+ 0x1405, 0x1410, 0x1411, 0x1414, 0x1415, 0x1440, 0x1441, 0x1444,
+ 0x1445, 0x1450, 0x1451, 0x1454, 0x1455, 0x1500, 0x1501, 0x1504,
+ 0x1505, 0x1510, 0x1511, 0x1514, 0x1515, 0x1540, 0x1541, 0x1544,
+ 0x1545, 0x1550, 0x1551, 0x1554, 0x1555, 0x4000, 0x4001, 0x4004,
+ 0x4005, 0x4010, 0x4011, 0x4014, 0x4015, 0x4040, 0x4041, 0x4044,
+ 0x4045, 0x4050, 0x4051, 0x4054, 0x4055, 0x4100, 0x4101, 0x4104,
+ 0x4105, 0x4110, 0x4111, 0x4114, 0x4115, 0x4140, 0x4141, 0x4144,
+ 0x4145, 0x4150, 0x4151, 0x4154, 0x4155, 0x4400, 0x4401, 0x4404,
+ 0x4405, 0x4410, 0x4411, 0x4414, 0x4415, 0x4440, 0x4441, 0x4444,
+ 0x4445, 0x4450, 0x4451, 0x4454, 0x4455, 0x4500, 0x4501, 0x4504,
+ 0x4505, 0x4510, 0x4511, 0x4514, 0x4515, 0x4540, 0x4541, 0x4544,
+ 0x4545, 0x4550, 0x4551, 0x4554, 0x4555, 0x5000, 0x5001, 0x5004,
+ 0x5005, 0x5010, 0x5011, 0x5014, 0x5015, 0x5040, 0x5041, 0x5044,
+ 0x5045, 0x5050, 0x5051, 0x5054, 0x5055, 0x5100, 0x5101, 0x5104,
+ 0x5105, 0x5110, 0x5111, 0x5114, 0x5115, 0x5140, 0x5141, 0x5144,
+ 0x5145, 0x5150, 0x5151, 0x5154, 0x5155, 0x5400, 0x5401, 0x5404,
+ 0x5405, 0x5410, 0x5411, 0x5414, 0x5415, 0x5440, 0x5441, 0x5444,
+ 0x5445, 0x5450, 0x5451, 0x5454, 0x5455, 0x5500, 0x5501, 0x5504,
+ 0x5505, 0x5510, 0x5511, 0x5514, 0x5515, 0x5540, 0x5541, 0x5544,
+ 0x5545, 0x5550, 0x5551, 0x5554, 0x5555};
+
+ // pre-computed Bitmask for fast masking, bitMask[a]=0x1 << a
+ private static final int[] bitMask = {0x00000001, 0x00000002, 0x00000004,
+ 0x00000008, 0x00000010, 0x00000020, 0x00000040, 0x00000080,
+ 0x00000100, 0x00000200, 0x00000400, 0x00000800, 0x00001000,
+ 0x00002000, 0x00004000, 0x00008000, 0x00010000, 0x00020000,
+ 0x00040000, 0x00080000, 0x00100000, 0x00200000, 0x00400000,
+ 0x00800000, 0x01000000, 0x02000000, 0x04000000, 0x08000000,
+ 0x10000000, 0x20000000, 0x40000000, 0x80000000, 0x00000000};
+
+ // pre-computed Bitmask for fast masking, rightMask[a]=0xffffffff >>> (32-a)
+ private static final int[] reverseRightMask = {0x00000000, 0x00000001,
+ 0x00000003, 0x00000007, 0x0000000f, 0x0000001f, 0x0000003f,
+ 0x0000007f, 0x000000ff, 0x000001ff, 0x000003ff, 0x000007ff,
+ 0x00000fff, 0x00001fff, 0x00003fff, 0x00007fff, 0x0000ffff,
+ 0x0001ffff, 0x0003ffff, 0x0007ffff, 0x000fffff, 0x001fffff,
+ 0x003fffff, 0x007fffff, 0x00ffffff, 0x01ffffff, 0x03ffffff,
+ 0x07ffffff, 0x0fffffff, 0x1fffffff, 0x3fffffff, 0x7fffffff,
+ 0xffffffff};
+
+ /**
+ * Creates a new GF2Polynomial of the given length and value zero.
+ *
+ * @param length the desired number of bits to store
+ */
+ public GF2Polynomial(int length)
+ {
+ int l = length;
+ if (l < 1)
+ {
+ l = 1;
+ }
+ blocks = ((l - 1) >> 5) + 1;
+ value = new int[blocks];
+ len = l;
+ }
+
+ /**
+ * Creates a new GF2Polynomial of the given length and random value.
+ *
+ * @param length the desired number of bits to store
+ * @param rand SecureRandom to use for randomization
+ */
+ public GF2Polynomial(int length, Random rand)
+ {
+ int l = length;
+ if (l < 1)
+ {
+ l = 1;
+ }
+ blocks = ((l - 1) >> 5) + 1;
+ value = new int[blocks];
+ len = l;
+ randomize(rand);
+ }
+
+ /**
+ * Creates a new GF2Polynomial of the given length and value
+ * selected by value:
+ *
+ *
+ *
+ * @param length the desired number of bits to store
+ * @param value the value described by a String
+ */
+ public GF2Polynomial(int length, String value)
+ {
+ int l = length;
+ if (l < 1)
+ {
+ l = 1;
+ }
+ blocks = ((l - 1) >> 5) + 1;
+ this.value = new int[blocks];
+ len = l;
+ if (value.equalsIgnoreCase("ZERO"))
+ {
+ assignZero();
+ }
+ else if (value.equalsIgnoreCase("ONE"))
+ {
+ assignOne();
+ }
+ else if (value.equalsIgnoreCase("RANDOM"))
+ {
+ randomize();
+ }
+ else if (value.equalsIgnoreCase("X"))
+ {
+ assignX();
+ }
+ else if (value.equalsIgnoreCase("ALL"))
+ {
+ assignAll();
+ }
+ else
+ {
+ throw new IllegalArgumentException(
+ "Error: GF2Polynomial was called using " + value
+ + " as value!");
+ }
+
+ }
+
+ /**
+ * Creates a new GF2Polynomial of the given length using the given
+ * int[]. LSB is contained in bs[0].
+ *
+ * @param length the desired number of bits to store
+ * @param bs contains the desired value, LSB in bs[0]
+ */
+ public GF2Polynomial(int length, int[] bs)
+ {
+ int leng = length;
+ if (leng < 1)
+ {
+ leng = 1;
+ }
+ blocks = ((leng - 1) >> 5) + 1;
+ value = new int[blocks];
+ len = leng;
+ int l = Math.min(blocks, bs.length);
+ System.arraycopy(bs, 0, value, 0, l);
+ zeroUnusedBits();
+ }
+
+ /**
+ * Creates a new GF2Polynomial by converting the given byte[] os
+ * according to 1363 and using the given length.
+ *
+ * @param length the intended length of this polynomial
+ * @param os the octet string to assign to this polynomial
+ * @see "P1363 5.5.2 p22f, OS2BSP"
+ */
+ public GF2Polynomial(int length, byte[] os)
+ {
+ int l = length;
+ if (l < 1)
+ {
+ l = 1;
+ }
+ blocks = ((l - 1) >> 5) + 1;
+ value = new int[blocks];
+ len = l;
+ int i, m;
+ int k = Math.min(((os.length - 1) >> 2) + 1, blocks);
+ for (i = 0; i < k - 1; i++)
+ {
+ m = os.length - (i << 2) - 1;
+ value[i] = (os[m]) & 0x000000ff;
+ value[i] |= (os[m - 1] << 8) & 0x0000ff00;
+ value[i] |= (os[m - 2] << 16) & 0x00ff0000;
+ value[i] |= (os[m - 3] << 24) & 0xff000000;
+ }
+ i = k - 1;
+ m = os.length - (i << 2) - 1;
+ value[i] = os[m] & 0x000000ff;
+ if (m > 0)
+ {
+ value[i] |= (os[m - 1] << 8) & 0x0000ff00;
+ }
+ if (m > 1)
+ {
+ value[i] |= (os[m - 2] << 16) & 0x00ff0000;
+ }
+ if (m > 2)
+ {
+ value[i] |= (os[m - 3] << 24) & 0xff000000;
+ }
+ zeroUnusedBits();
+ reduceN();
+ }
+
+ /**
+ * Creates a new GF2Polynomial by converting the given FlexiBigInt bi
+ * according to 1363 and using the given length.
+ *
+ * @param length the intended length of this polynomial
+ * @param bi the FlexiBigInt to assign to this polynomial
+ * @see "P1363 5.5.1 p22, I2BSP"
+ */
+ public GF2Polynomial(int length, BigInteger bi)
+ {
+ int l = length;
+ if (l < 1)
+ {
+ l = 1;
+ }
+ blocks = ((l - 1) >> 5) + 1;
+ value = new int[blocks];
+ len = l;
+ int i;
+ byte[] val = bi.toByteArray();
+ if (val[0] == 0)
+ {
+ byte[] dummy = new byte[val.length - 1];
+ System.arraycopy(val, 1, dummy, 0, dummy.length);
+ val = dummy;
+ }
+ int ov = val.length & 0x03;
+ int k = ((val.length - 1) >> 2) + 1;
+ for (i = 0; i < ov; i++)
+ {
+ value[k - 1] |= (val[i] & 0x000000ff) << ((ov - 1 - i) << 3);
+ }
+ int m = 0;
+ for (i = 0; i <= (val.length - 4) >> 2; i++)
+ {
+ m = val.length - 1 - (i << 2);
+ value[i] = (val[m]) & 0x000000ff;
+ value[i] |= ((val[m - 1]) << 8) & 0x0000ff00;
+ value[i] |= ((val[m - 2]) << 16) & 0x00ff0000;
+ value[i] |= ((val[m - 3]) << 24) & 0xff000000;
+ }
+ if ((len & 0x1f) != 0)
+ {
+ value[blocks - 1] &= reverseRightMask[len & 0x1f];
+ }
+ reduceN();
+ }
+
+ /**
+ * Creates a new GF2Polynomial by cloneing the given GF2Polynomial b.
+ *
+ * @param b the GF2Polynomial to clone
+ */
+ public GF2Polynomial(GF2Polynomial b)
+ {
+ len = b.len;
+ blocks = b.blocks;
+ value = IntUtils.clone(b.value);
+ }
+
+ /**
+ * @return a copy of this GF2Polynomial
+ */
+ public Object clone()
+ {
+ return new GF2Polynomial(this);
+ }
+
+ /**
+ * Returns the length of this GF2Polynomial. The length can be greater than
+ * the degree. To get the degree call reduceN() before calling getLength().
+ *
+ * @return the length of this GF2Polynomial
+ */
+ public int getLength()
+ {
+ return len;
+ }
+
+ /**
+ * Returns the value of this GF2Polynomial in an int[].
+ *
+ * @return the value of this GF2Polynomial in a new int[], LSB in int[0]
+ */
+ public int[] toIntegerArray()
+ {
+ int[] result;
+ result = new int[blocks];
+ System.arraycopy(value, 0, result, 0, blocks);
+ return result;
+ }
+
+ /**
+ * Returns a string representing this GF2Polynomials value using hexadecimal
+ * or binary radix in MSB-first order.
+ *
+ * @param radix the radix to use (2 or 16, otherwise 2 is used)
+ * @return a String representing this GF2Polynomials value.
+ */
+ public String toString(int radix)
+ {
+ final char[] HEX_CHARS = {'0', '1', '2', '3', '4', '5', '6', '7', '8',
+ '9', 'a', 'b', 'c', 'd', 'e', 'f'};
+ final String[] BIN_CHARS = {"0000", "0001", "0010", "0011", "0100",
+ "0101", "0110", "0111", "1000", "1001", "1010", "1011", "1100",
+ "1101", "1110", "1111"};
+ String res;
+ int i;
+ res = new String();
+ if (radix == 16)
+ {
+ for (i = blocks - 1; i >= 0; i--)
+ {
+ res += HEX_CHARS[(value[i] >>> 28) & 0x0f];
+ res += HEX_CHARS[(value[i] >>> 24) & 0x0f];
+ res += HEX_CHARS[(value[i] >>> 20) & 0x0f];
+ res += HEX_CHARS[(value[i] >>> 16) & 0x0f];
+ res += HEX_CHARS[(value[i] >>> 12) & 0x0f];
+ res += HEX_CHARS[(value[i] >>> 8) & 0x0f];
+ res += HEX_CHARS[(value[i] >>> 4) & 0x0f];
+ res += HEX_CHARS[(value[i]) & 0x0f];
+ res += " ";
+ }
+ }
+ else
+ {
+ for (i = blocks - 1; i >= 0; i--)
+ {
+ res += BIN_CHARS[(value[i] >>> 28) & 0x0f];
+ res += BIN_CHARS[(value[i] >>> 24) & 0x0f];
+ res += BIN_CHARS[(value[i] >>> 20) & 0x0f];
+ res += BIN_CHARS[(value[i] >>> 16) & 0x0f];
+ res += BIN_CHARS[(value[i] >>> 12) & 0x0f];
+ res += BIN_CHARS[(value[i] >>> 8) & 0x0f];
+ res += BIN_CHARS[(value[i] >>> 4) & 0x0f];
+ res += BIN_CHARS[(value[i]) & 0x0f];
+ res += " ";
+ }
+ }
+ return res;
+ }
+
+ /**
+ * Converts this polynomial to a byte[] (octet string) according to 1363.
+ *
+ * @return a byte[] representing the value of this polynomial
+ * @see "P1363 5.5.2 p22f, BS2OSP"
+ */
+ public byte[] toByteArray()
+ {
+ int k = ((len - 1) >> 3) + 1;
+ int ov = k & 0x03;
+ int m;
+ byte[] res = new byte[k];
+ int i;
+ for (i = 0; i < (k >> 2); i++)
+ {
+ m = k - (i << 2) - 1;
+ res[m] = (byte)((value[i] & 0x000000ff));
+ res[m - 1] = (byte)((value[i] & 0x0000ff00) >>> 8);
+ res[m - 2] = (byte)((value[i] & 0x00ff0000) >>> 16);
+ res[m - 3] = (byte)((value[i] & 0xff000000) >>> 24);
+ }
+ for (i = 0; i < ov; i++)
+ {
+ m = (ov - i - 1) << 3;
+ res[i] = (byte)((value[blocks - 1] & (0x000000ff << m)) >>> m);
+ }
+ return res;
+ }
+
+ /**
+ * Converts this polynomial to an integer according to 1363.
+ *
+ * @return a FlexiBigInt representing the value of this polynomial
+ * @see "P1363 5.5.1 p22, BS2IP"
+ */
+ public BigInteger toFlexiBigInt()
+ {
+ if (len == 0 || isZero())
+ {
+ return new BigInteger(0, new byte[0]);
+ }
+ return new BigInteger(1, toByteArray());
+ }
+
+ /**
+ * Sets the LSB to 1 and all other to 0, assigning 'one' to this
+ * GF2Polynomial.
+ */
+ public void assignOne()
+ {
+ int i;
+ for (i = 1; i < blocks; i++)
+ {
+ value[i] = 0x00;
+ }
+ value[0] = 0x01;
+ }
+
+ /**
+ * Sets Bit 1 to 1 and all other to 0, assigning 'x' to this GF2Polynomial.
+ */
+ public void assignX()
+ {
+ int i;
+ for (i = 1; i < blocks; i++)
+ {
+ value[i] = 0x00;
+ }
+ value[0] = 0x02;
+ }
+
+ /**
+ * Sets all Bits to 1.
+ */
+ public void assignAll()
+ {
+ int i;
+ for (i = 0; i < blocks; i++)
+ {
+ value[i] = 0xffffffff;
+ }
+ zeroUnusedBits();
+ }
+
+ /**
+ * Resets all bits to zero.
+ */
+ public void assignZero()
+ {
+ int i;
+ for (i = 0; i < blocks; i++)
+ {
+ value[i] = 0x00;
+ }
+ }
+
+ /**
+ * Fills all len bits of this GF2Polynomial with random values.
+ */
+ public void randomize()
+ {
+ int i;
+ for (i = 0; i < blocks; i++)
+ {
+ value[i] = rand.nextInt();
+ }
+ zeroUnusedBits();
+ }
+
+ /**
+ * Fills all len bits of this GF2Polynomial with random values using the
+ * specified source of randomness.
+ *
+ * @param rand the source of randomness
+ */
+ public void randomize(Random rand)
+ {
+ int i;
+ for (i = 0; i < blocks; i++)
+ {
+ value[i] = rand.nextInt();
+ }
+ zeroUnusedBits();
+ }
+
+ /**
+ * Returns true if two GF2Polynomials have the same size and value and thus
+ * are equal.
+ *
+ * @param other the other GF2Polynomial
+ * @return true if this GF2Polynomial equals b (this ==
+ * b)
+ */
+ public boolean equals(Object other)
+ {
+ if (other == null || !(other instanceof GF2Polynomial))
+ {
+ return false;
+ }
+
+ GF2Polynomial otherPol = (GF2Polynomial)other;
+
+ if (len != otherPol.len)
+ {
+ return false;
+ }
+ for (int i = 0; i < blocks; i++)
+ {
+ if (value[i] != otherPol.value[i])
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * @return the hash code of this polynomial
+ */
+ public int hashCode()
+ {
+ return len + value.hashCode();
+ }
+
+ /**
+ * Tests if all bits equal zero.
+ *
+ * @return true if this GF2Polynomial equals 'zero' (this == 0)
+ */
+ public boolean isZero()
+ {
+ int i;
+ if (len == 0)
+ {
+ return true;
+ }
+ for (i = 0; i < blocks; i++)
+ {
+ if (value[i] != 0)
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Tests if all bits are reset to 0 and LSB is set to 1.
+ *
+ * @return true if this GF2Polynomial equals 'one' (this == 1)
+ */
+ public boolean isOne()
+ {
+ int i;
+ for (i = 1; i < blocks; i++)
+ {
+ if (value[i] != 0)
+ {
+ return false;
+ }
+ }
+ if (value[0] != 0x01)
+ {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Adds b to this GF2Polynomial and assigns the result to this
+ * GF2Polynomial. b can be of different size.
+ *
+ * @param b GF2Polynomial to add to this GF2Polynomial
+ */
+ public void addToThis(GF2Polynomial b)
+ {
+ expandN(b.len);
+ xorThisBy(b);
+ }
+
+ /**
+ * Adds two GF2Polynomials, this and b, and returns the
+ * result. this and b can be of different size.
+ *
+ * @param b a GF2Polynomial
+ * @return a new GF2Polynomial (this + b)
+ */
+ public GF2Polynomial add(GF2Polynomial b)
+ {
+ return xor(b);
+ }
+
+ /**
+ * Subtracts b from this GF2Polynomial and assigns the result to
+ * this GF2Polynomial. b can be of different size.
+ *
+ * @param b a GF2Polynomial
+ */
+ public void subtractFromThis(GF2Polynomial b)
+ {
+ expandN(b.len);
+ xorThisBy(b);
+ }
+
+ /**
+ * Subtracts two GF2Polynomials, this and b, and returns the
+ * result in a new GF2Polynomial. this and b can be of
+ * different size.
+ *
+ * @param b a GF2Polynomial
+ * @return a new GF2Polynomial (this - b)
+ */
+ public GF2Polynomial subtract(GF2Polynomial b)
+ {
+ return xor(b);
+ }
+
+ /**
+ * Toggles the LSB of this GF2Polynomial, increasing its value by 'one'.
+ */
+ public void increaseThis()
+ {
+ xorBit(0);
+ }
+
+ /**
+ * Toggles the LSB of this GF2Polynomial, increasing the value by 'one' and
+ * returns the result in a new GF2Polynomial.
+ *
+ * @return this + 1
+ */
+ public GF2Polynomial increase()
+ {
+ GF2Polynomial result = new GF2Polynomial(this);
+ result.increaseThis();
+ return result;
+ }
+
+ /**
+ * Multiplies this GF2Polynomial with b and returns the result in a
+ * new GF2Polynomial. This method does not reduce the result in GF(2^N).
+ * This method uses classic multiplication (schoolbook).
+ *
+ * @param b a GF2Polynomial
+ * @return a new GF2Polynomial (this * b)
+ */
+ public GF2Polynomial multiplyClassic(GF2Polynomial b)
+ {
+ GF2Polynomial result = new GF2Polynomial(Math.max(len, b.len) << 1);
+ GF2Polynomial[] m = new GF2Polynomial[32];
+ int i, j;
+ m[0] = new GF2Polynomial(this);
+ for (i = 1; i <= 31; i++)
+ {
+ m[i] = m[i - 1].shiftLeft();
+ }
+ for (i = 0; i < b.blocks; i++)
+ {
+ for (j = 0; j <= 31; j++)
+ {
+ if ((b.value[i] & bitMask[j]) != 0)
+ {
+ result.xorThisBy(m[j]);
+ }
+ }
+ for (j = 0; j <= 31; j++)
+ {
+ m[j].shiftBlocksLeft();
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Multiplies this GF2Polynomial with b and returns the result in a
+ * new GF2Polynomial. This method does not reduce the result in GF(2^N).
+ * This method uses Karatzuba multiplication.
+ *
+ * @param b a GF2Polynomial
+ * @return a new GF2Polynomial (this * b)
+ */
+ public GF2Polynomial multiply(GF2Polynomial b)
+ {
+ int n = Math.max(len, b.len);
+ expandN(n);
+ b.expandN(n);
+ return karaMult(b);
+ }
+
+ /**
+ * Does the recursion for Karatzuba multiplication.
+ */
+ private GF2Polynomial karaMult(GF2Polynomial b)
+ {
+ GF2Polynomial result = new GF2Polynomial(len << 1);
+ if (len <= 32)
+ {
+ result.value = mult32(value[0], b.value[0]);
+ return result;
+ }
+ if (len <= 64)
+ {
+ result.value = mult64(value, b.value);
+ return result;
+ }
+ if (len <= 128)
+ {
+ result.value = mult128(value, b.value);
+ return result;
+ }
+ if (len <= 256)
+ {
+ result.value = mult256(value, b.value);
+ return result;
+ }
+ if (len <= 512)
+ {
+ result.value = mult512(value, b.value);
+ return result;
+ }
+
+ int n = IntegerFunctions.floorLog(len - 1);
+ n = bitMask[n];
+
+ GF2Polynomial a0 = lower(((n - 1) >> 5) + 1);
+ GF2Polynomial a1 = upper(((n - 1) >> 5) + 1);
+ GF2Polynomial b0 = b.lower(((n - 1) >> 5) + 1);
+ GF2Polynomial b1 = b.upper(((n - 1) >> 5) + 1);
+
+ GF2Polynomial c = a1.karaMult(b1); // c = a1*b1
+ GF2Polynomial e = a0.karaMult(b0); // e = a0*b0
+ a0.addToThis(a1); // a0 = a0 + a1
+ b0.addToThis(b1); // b0 = b0 + b1
+ GF2Polynomial d = a0.karaMult(b0); // d = (a0+a1)*(b0+b1)
+
+ result.shiftLeftAddThis(c, n << 1);
+ result.shiftLeftAddThis(c, n);
+ result.shiftLeftAddThis(d, n);
+ result.shiftLeftAddThis(e, n);
+ result.addToThis(e);
+ return result;
+ }
+
+ /**
+ * 16-Integer Version of Karatzuba multiplication.
+ */
+ private static int[] mult512(int[] a, int[] b)
+ {
+ int[] result = new int[32];
+ int[] a0 = new int[8];
+ System.arraycopy(a, 0, a0, 0, Math.min(8, a.length));
+ int[] a1 = new int[8];
+ if (a.length > 8)
+ {
+ System.arraycopy(a, 8, a1, 0, Math.min(8, a.length - 8));
+ }
+ int[] b0 = new int[8];
+ System.arraycopy(b, 0, b0, 0, Math.min(8, b.length));
+ int[] b1 = new int[8];
+ if (b.length > 8)
+ {
+ System.arraycopy(b, 8, b1, 0, Math.min(8, b.length - 8));
+ }
+ int[] c = mult256(a1, b1);
+ result[31] ^= c[15];
+ result[30] ^= c[14];
+ result[29] ^= c[13];
+ result[28] ^= c[12];
+ result[27] ^= c[11];
+ result[26] ^= c[10];
+ result[25] ^= c[9];
+ result[24] ^= c[8];
+ result[23] ^= c[7] ^ c[15];
+ result[22] ^= c[6] ^ c[14];
+ result[21] ^= c[5] ^ c[13];
+ result[20] ^= c[4] ^ c[12];
+ result[19] ^= c[3] ^ c[11];
+ result[18] ^= c[2] ^ c[10];
+ result[17] ^= c[1] ^ c[9];
+ result[16] ^= c[0] ^ c[8];
+ result[15] ^= c[7];
+ result[14] ^= c[6];
+ result[13] ^= c[5];
+ result[12] ^= c[4];
+ result[11] ^= c[3];
+ result[10] ^= c[2];
+ result[9] ^= c[1];
+ result[8] ^= c[0];
+ a1[0] ^= a0[0];
+ a1[1] ^= a0[1];
+ a1[2] ^= a0[2];
+ a1[3] ^= a0[3];
+ a1[4] ^= a0[4];
+ a1[5] ^= a0[5];
+ a1[6] ^= a0[6];
+ a1[7] ^= a0[7];
+ b1[0] ^= b0[0];
+ b1[1] ^= b0[1];
+ b1[2] ^= b0[2];
+ b1[3] ^= b0[3];
+ b1[4] ^= b0[4];
+ b1[5] ^= b0[5];
+ b1[6] ^= b0[6];
+ b1[7] ^= b0[7];
+ int[] d = mult256(a1, b1);
+ result[23] ^= d[15];
+ result[22] ^= d[14];
+ result[21] ^= d[13];
+ result[20] ^= d[12];
+ result[19] ^= d[11];
+ result[18] ^= d[10];
+ result[17] ^= d[9];
+ result[16] ^= d[8];
+ result[15] ^= d[7];
+ result[14] ^= d[6];
+ result[13] ^= d[5];
+ result[12] ^= d[4];
+ result[11] ^= d[3];
+ result[10] ^= d[2];
+ result[9] ^= d[1];
+ result[8] ^= d[0];
+ int[] e = mult256(a0, b0);
+ result[23] ^= e[15];
+ result[22] ^= e[14];
+ result[21] ^= e[13];
+ result[20] ^= e[12];
+ result[19] ^= e[11];
+ result[18] ^= e[10];
+ result[17] ^= e[9];
+ result[16] ^= e[8];
+ result[15] ^= e[7] ^ e[15];
+ result[14] ^= e[6] ^ e[14];
+ result[13] ^= e[5] ^ e[13];
+ result[12] ^= e[4] ^ e[12];
+ result[11] ^= e[3] ^ e[11];
+ result[10] ^= e[2] ^ e[10];
+ result[9] ^= e[1] ^ e[9];
+ result[8] ^= e[0] ^ e[8];
+ result[7] ^= e[7];
+ result[6] ^= e[6];
+ result[5] ^= e[5];
+ result[4] ^= e[4];
+ result[3] ^= e[3];
+ result[2] ^= e[2];
+ result[1] ^= e[1];
+ result[0] ^= e[0];
+ return result;
+ }
+
+ /**
+ * 8-Integer Version of Karatzuba multiplication.
+ */
+ private static int[] mult256(int[] a, int[] b)
+ {
+ int[] result = new int[16];
+ int[] a0 = new int[4];
+ System.arraycopy(a, 0, a0, 0, Math.min(4, a.length));
+ int[] a1 = new int[4];
+ if (a.length > 4)
+ {
+ System.arraycopy(a, 4, a1, 0, Math.min(4, a.length - 4));
+ }
+ int[] b0 = new int[4];
+ System.arraycopy(b, 0, b0, 0, Math.min(4, b.length));
+ int[] b1 = new int[4];
+ if (b.length > 4)
+ {
+ System.arraycopy(b, 4, b1, 0, Math.min(4, b.length - 4));
+ }
+ if (a1[3] == 0 && a1[2] == 0 && b1[3] == 0 && b1[2] == 0)
+ {
+ if (a1[1] == 0 && b1[1] == 0)
+ {
+ if (a1[0] != 0 || b1[0] != 0)
+ { // [3]=[2]=[1]=0, [0]!=0
+ int[] c = mult32(a1[0], b1[0]);
+ result[9] ^= c[1];
+ result[8] ^= c[0];
+ result[5] ^= c[1];
+ result[4] ^= c[0];
+ }
+ }
+ else
+ { // [3]=[2]=0 [1]!=0, [0]!=0
+ int[] c = mult64(a1, b1);
+ result[11] ^= c[3];
+ result[10] ^= c[2];
+ result[9] ^= c[1];
+ result[8] ^= c[0];
+ result[7] ^= c[3];
+ result[6] ^= c[2];
+ result[5] ^= c[1];
+ result[4] ^= c[0];
+ }
+ }
+ else
+ { // [3]!=0 [2]!=0 [1]!=0, [0]!=0
+ int[] c = mult128(a1, b1);
+ result[15] ^= c[7];
+ result[14] ^= c[6];
+ result[13] ^= c[5];
+ result[12] ^= c[4];
+ result[11] ^= c[3] ^ c[7];
+ result[10] ^= c[2] ^ c[6];
+ result[9] ^= c[1] ^ c[5];
+ result[8] ^= c[0] ^ c[4];
+ result[7] ^= c[3];
+ result[6] ^= c[2];
+ result[5] ^= c[1];
+ result[4] ^= c[0];
+ }
+ a1[0] ^= a0[0];
+ a1[1] ^= a0[1];
+ a1[2] ^= a0[2];
+ a1[3] ^= a0[3];
+ b1[0] ^= b0[0];
+ b1[1] ^= b0[1];
+ b1[2] ^= b0[2];
+ b1[3] ^= b0[3];
+ int[] d = mult128(a1, b1);
+ result[11] ^= d[7];
+ result[10] ^= d[6];
+ result[9] ^= d[5];
+ result[8] ^= d[4];
+ result[7] ^= d[3];
+ result[6] ^= d[2];
+ result[5] ^= d[1];
+ result[4] ^= d[0];
+ int[] e = mult128(a0, b0);
+ result[11] ^= e[7];
+ result[10] ^= e[6];
+ result[9] ^= e[5];
+ result[8] ^= e[4];
+ result[7] ^= e[3] ^ e[7];
+ result[6] ^= e[2] ^ e[6];
+ result[5] ^= e[1] ^ e[5];
+ result[4] ^= e[0] ^ e[4];
+ result[3] ^= e[3];
+ result[2] ^= e[2];
+ result[1] ^= e[1];
+ result[0] ^= e[0];
+ return result;
+ }
+
+ /**
+ * 4-Integer Version of Karatzuba multiplication.
+ */
+ private static int[] mult128(int[] a, int[] b)
+ {
+ int[] result = new int[8];
+ int[] a0 = new int[2];
+ System.arraycopy(a, 0, a0, 0, Math.min(2, a.length));
+ int[] a1 = new int[2];
+ if (a.length > 2)
+ {
+ System.arraycopy(a, 2, a1, 0, Math.min(2, a.length - 2));
+ }
+ int[] b0 = new int[2];
+ System.arraycopy(b, 0, b0, 0, Math.min(2, b.length));
+ int[] b1 = new int[2];
+ if (b.length > 2)
+ {
+ System.arraycopy(b, 2, b1, 0, Math.min(2, b.length - 2));
+ }
+ if (a1[1] == 0 && b1[1] == 0)
+ {
+ if (a1[0] != 0 || b1[0] != 0)
+ {
+ int[] c = mult32(a1[0], b1[0]);
+ result[5] ^= c[1];
+ result[4] ^= c[0];
+ result[3] ^= c[1];
+ result[2] ^= c[0];
+ }
+ }
+ else
+ {
+ int[] c = mult64(a1, b1);
+ result[7] ^= c[3];
+ result[6] ^= c[2];
+ result[5] ^= c[1] ^ c[3];
+ result[4] ^= c[0] ^ c[2];
+ result[3] ^= c[1];
+ result[2] ^= c[0];
+ }
+ a1[0] ^= a0[0];
+ a1[1] ^= a0[1];
+ b1[0] ^= b0[0];
+ b1[1] ^= b0[1];
+ if (a1[1] == 0 && b1[1] == 0)
+ {
+ int[] d = mult32(a1[0], b1[0]);
+ result[3] ^= d[1];
+ result[2] ^= d[0];
+ }
+ else
+ {
+ int[] d = mult64(a1, b1);
+ result[5] ^= d[3];
+ result[4] ^= d[2];
+ result[3] ^= d[1];
+ result[2] ^= d[0];
+ }
+ if (a0[1] == 0 && b0[1] == 0)
+ {
+ int[] e = mult32(a0[0], b0[0]);
+ result[3] ^= e[1];
+ result[2] ^= e[0];
+ result[1] ^= e[1];
+ result[0] ^= e[0];
+ }
+ else
+ {
+ int[] e = mult64(a0, b0);
+ result[5] ^= e[3];
+ result[4] ^= e[2];
+ result[3] ^= e[1] ^ e[3];
+ result[2] ^= e[0] ^ e[2];
+ result[1] ^= e[1];
+ result[0] ^= e[0];
+ }
+ return result;
+ }
+
+ /**
+ * 2-Integer Version of Karatzuba multiplication.
+ */
+ private static int[] mult64(int[] a, int[] b)
+ {
+ int[] result = new int[4];
+ int a0 = a[0];
+ int a1 = 0;
+ if (a.length > 1)
+ {
+ a1 = a[1];
+ }
+ int b0 = b[0];
+ int b1 = 0;
+ if (b.length > 1)
+ {
+ b1 = b[1];
+ }
+ if (a1 != 0 || b1 != 0)
+ {
+ int[] c = mult32(a1, b1);
+ result[3] ^= c[1];
+ result[2] ^= c[0] ^ c[1];
+ result[1] ^= c[0];
+ }
+ int[] d = mult32(a0 ^ a1, b0 ^ b1);
+ result[2] ^= d[1];
+ result[1] ^= d[0];
+ int[] e = mult32(a0, b0);
+ result[2] ^= e[1];
+ result[1] ^= e[0] ^ e[1];
+ result[0] ^= e[0];
+ return result;
+ }
+
+ /**
+ * 4-Byte Version of Karatzuba multiplication. Here the actual work is done.
+ */
+ private static int[] mult32(int a, int b)
+ {
+ int[] result = new int[2];
+ if (a == 0 || b == 0)
+ {
+ return result;
+ }
+ long b2 = b;
+ b2 &= 0x00000000ffffffffL;
+ int i;
+ long h = 0;
+ for (i = 1; i <= 32; i++)
+ {
+ if ((a & bitMask[i - 1]) != 0)
+ {
+ h ^= b2;
+ }
+ b2 <<= 1;
+ }
+ result[1] = (int)(h >>> 32);
+ result[0] = (int)(h & 0x00000000ffffffffL);
+ return result;
+ }
+
+ /**
+ * Returns a new GF2Polynomial containing the upper k bytes of this
+ * GF2Polynomial.
+ *
+ * @param k
+ * @return a new GF2Polynomial containing the upper k bytes of this
+ * GF2Polynomial
+ * @see GF2Polynomial#karaMult
+ */
+ private GF2Polynomial upper(int k)
+ {
+ int j = Math.min(k, blocks - k);
+ GF2Polynomial result = new GF2Polynomial(j << 5);
+ if (blocks >= k)
+ {
+ System.arraycopy(value, k, result.value, 0, j);
+ }
+ return result;
+ }
+
+ /**
+ * Returns a new GF2Polynomial containing the lower k bytes of this
+ * GF2Polynomial.
+ *
+ * @param k
+ * @return a new GF2Polynomial containing the lower k bytes of this
+ * GF2Polynomial
+ * @see GF2Polynomial#karaMult
+ */
+ private GF2Polynomial lower(int k)
+ {
+ GF2Polynomial result = new GF2Polynomial(k << 5);
+ System.arraycopy(value, 0, result.value, 0, Math.min(k, blocks));
+ return result;
+ }
+
+ /**
+ * Returns the remainder of this divided by g in a new
+ * GF2Polynomial.
+ *
+ * @param g GF2Polynomial != 0
+ * @return a new GF2Polynomial (this % g)
+ * @throws PolynomialIsZeroException if g equals zero
+ */
+ public GF2Polynomial remainder(GF2Polynomial g)
+ throws RuntimeException
+ {
+ /* a div b = q / r */
+ GF2Polynomial a = new GF2Polynomial(this);
+ GF2Polynomial b = new GF2Polynomial(g);
+ GF2Polynomial j;
+ int i;
+ if (b.isZero())
+ {
+ throw new RuntimeException();
+ }
+ a.reduceN();
+ b.reduceN();
+ if (a.len < b.len)
+ {
+ return a;
+ }
+ i = a.len - b.len;
+ while (i >= 0)
+ {
+ j = b.shiftLeft(i);
+ a.subtractFromThis(j);
+ a.reduceN();
+ i = a.len - b.len;
+ }
+ return a;
+ }
+
+ /**
+ * Returns the absolute quotient of this divided by g in a
+ * new GF2Polynomial.
+ *
+ * @param g GF2Polynomial != 0
+ * @return a new GF2Polynomial |_ this / g _|
+ * @throws PolynomialIsZeroException if g equals zero
+ */
+ public GF2Polynomial quotient(GF2Polynomial g)
+ throws RuntimeException
+ {
+ /* a div b = q / r */
+ GF2Polynomial q = new GF2Polynomial(len);
+ GF2Polynomial a = new GF2Polynomial(this);
+ GF2Polynomial b = new GF2Polynomial(g);
+ GF2Polynomial j;
+ int i;
+ if (b.isZero())
+ {
+ throw new RuntimeException();
+ }
+ a.reduceN();
+ b.reduceN();
+ if (a.len < b.len)
+ {
+ return new GF2Polynomial(0);
+ }
+ i = a.len - b.len;
+ q.expandN(i + 1);
+
+ while (i >= 0)
+ {
+ j = b.shiftLeft(i);
+ a.subtractFromThis(j);
+ a.reduceN();
+ q.xorBit(i);
+ i = a.len - b.len;
+ }
+
+ return q;
+ }
+
+ /**
+ * Divides this by g and returns the quotient and remainder
+ * in a new GF2Polynomial[2], quotient in [0], remainder in [1].
+ *
+ * @param g GF2Polynomial != 0
+ * @return a new GF2Polynomial[2] containing quotient and remainder
+ * @throws PolynomialIsZeroException if g equals zero
+ */
+ public GF2Polynomial[] divide(GF2Polynomial g)
+ throws RuntimeException
+ {
+ /* a div b = q / r */
+ GF2Polynomial[] result = new GF2Polynomial[2];
+ GF2Polynomial q = new GF2Polynomial(len);
+ GF2Polynomial a = new GF2Polynomial(this);
+ GF2Polynomial b = new GF2Polynomial(g);
+ GF2Polynomial j;
+ int i;
+ if (b.isZero())
+ {
+ throw new RuntimeException();
+ }
+ a.reduceN();
+ b.reduceN();
+ if (a.len < b.len)
+ {
+ result[0] = new GF2Polynomial(0);
+ result[1] = a;
+ return result;
+ }
+ i = a.len - b.len;
+ q.expandN(i + 1);
+
+ while (i >= 0)
+ {
+ j = b.shiftLeft(i);
+ a.subtractFromThis(j);
+ a.reduceN();
+ q.xorBit(i);
+ i = a.len - b.len;
+ }
+
+ result[0] = q;
+ result[1] = a;
+ return result;
+ }
+
+ /**
+ * Returns the greatest common divisor of this and g in a
+ * new GF2Polynomial.
+ *
+ * @param g GF2Polynomial != 0
+ * @return a new GF2Polynomial gcd(this,g)
+ * @throws ArithmeticException if this and g both are equal to zero
+ * @throws PolynomialIsZeroException to be API-compliant (should never be thrown).
+ */
+ public GF2Polynomial gcd(GF2Polynomial g)
+ throws RuntimeException
+ {
+ if (isZero() && g.isZero())
+ {
+ throw new ArithmeticException("Both operands of gcd equal zero.");
+ }
+ if (isZero())
+ {
+ return new GF2Polynomial(g);
+ }
+ if (g.isZero())
+ {
+ return new GF2Polynomial(this);
+ }
+ GF2Polynomial a = new GF2Polynomial(this);
+ GF2Polynomial b = new GF2Polynomial(g);
+ GF2Polynomial c;
+
+ while (!b.isZero())
+ {
+ c = a.remainder(b);
+ a = b;
+ b = c;
+ }
+
+ return a;
+ }
+
+ /**
+ * Checks if this is irreducible, according to IEEE P1363, A.5.5,
+ * p103.
+ * Note: The algorithm from IEEE P1363, A5.5 can be used to check a
+ * polynomial with coefficients in GF(2^r) for irreducibility. As this class
+ * only represents polynomials with coefficients in GF(2), the algorithm is
+ * adapted to the case r=1.
+ *
+ * @return true if this is irreducible
+ * @see "P1363, A.5.5, p103"
+ */
+ public boolean isIrreducible()
+ {
+ if (isZero())
+ {
+ return false;
+ }
+ GF2Polynomial f = new GF2Polynomial(this);
+ int d, i;
+ GF2Polynomial u, g;
+ GF2Polynomial dummy;
+ f.reduceN();
+ d = f.len - 1;
+ u = new GF2Polynomial(f.len, "X");
+
+ for (i = 1; i <= (d >> 1); i++)
+ {
+ u.squareThisPreCalc();
+ u = u.remainder(f);
+ dummy = u.add(new GF2Polynomial(32, "X"));
+ if (!dummy.isZero())
+ {
+ g = f.gcd(dummy);
+ if (!g.isOne())
+ {
+ return false;
+ }
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Reduces this GF2Polynomial using the trinomial x^m + x^tc +
+ * 1.
+ *
+ * @param m the degree of the used field
+ * @param tc degree of the middle x in the trinomial
+ */
+ void reduceTrinomial(int m, int tc)
+ {
+ int i;
+ int p0, p1;
+ int q0, q1;
+ long t;
+ p0 = m >>> 5; // block which contains 2^m
+ q0 = 32 - (m & 0x1f); // (32-index) of 2^m within block p0
+ p1 = (m - tc) >>> 5; // block which contains 2^tc
+ q1 = 32 - ((m - tc) & 0x1f); // (32-index) of 2^tc within block q1
+ int max = ((m << 1) - 2) >>> 5; // block which contains 2^(2m-2)
+ int min = p0; // block which contains 2^m
+ for (i = max; i > min; i--)
+ { // for i = maxBlock to minBlock
+ // reduce coefficients contained in t
+ // t = block[i]
+ t = value[i] & 0x00000000ffffffffL;
+ // block[i-p0-1] ^= t << q0
+ value[i - p0 - 1] ^= (int)(t << q0);
+ // block[i-p0] ^= t >>> (32-q0)
+ value[i - p0] ^= t >>> (32 - q0);
+ // block[i-p1-1] ^= << q1
+ value[i - p1 - 1] ^= (int)(t << q1);
+ // block[i-p1] ^= t >>> (32-q1)
+ value[i - p1] ^= t >>> (32 - q1);
+ value[i] = 0x00;
+ }
+ // reduce last coefficients in block containing 2^m
+ t = value[min] & 0x00000000ffffffffL & (0xffffffffL << (m & 0x1f)); // t
+ // contains the last coefficients > m
+ value[0] ^= t >>> (32 - q0);
+ if (min - p1 - 1 >= 0)
+ {
+ value[min - p1 - 1] ^= (int)(t << q1);
+ }
+ value[min - p1] ^= t >>> (32 - q1);
+
+ value[min] &= reverseRightMask[m & 0x1f];
+ blocks = ((m - 1) >>> 5) + 1;
+ len = m;
+ }
+
+ /**
+ * Reduces this GF2Polynomial using the pentanomial x^m + x^pc[2] +
+ * x^pc[1] + x^pc[0] + 1.
+ *
+ * @param m the degree of the used field
+ * @param pc degrees of the middle x's in the pentanomial
+ */
+ void reducePentanomial(int m, int[] pc)
+ {
+ int i;
+ int p0, p1, p2, p3;
+ int q0, q1, q2, q3;
+ long t;
+ p0 = m >>> 5;
+ q0 = 32 - (m & 0x1f);
+ p1 = (m - pc[0]) >>> 5;
+ q1 = 32 - ((m - pc[0]) & 0x1f);
+ p2 = (m - pc[1]) >>> 5;
+ q2 = 32 - ((m - pc[1]) & 0x1f);
+ p3 = (m - pc[2]) >>> 5;
+ q3 = 32 - ((m - pc[2]) & 0x1f);
+ int max = ((m << 1) - 2) >>> 5;
+ int min = p0;
+ for (i = max; i > min; i--)
+ {
+ t = value[i] & 0x00000000ffffffffL;
+ value[i - p0 - 1] ^= (int)(t << q0);
+ value[i - p0] ^= t >>> (32 - q0);
+ value[i - p1 - 1] ^= (int)(t << q1);
+ value[i - p1] ^= t >>> (32 - q1);
+ value[i - p2 - 1] ^= (int)(t << q2);
+ value[i - p2] ^= t >>> (32 - q2);
+ value[i - p3 - 1] ^= (int)(t << q3);
+ value[i - p3] ^= t >>> (32 - q3);
+ value[i] = 0;
+ }
+ t = value[min] & 0x00000000ffffffffL & (0xffffffffL << (m & 0x1f));
+ value[0] ^= t >>> (32 - q0);
+ if (min - p1 - 1 >= 0)
+ {
+ value[min - p1 - 1] ^= (int)(t << q1);
+ }
+ value[min - p1] ^= t >>> (32 - q1);
+ if (min - p2 - 1 >= 0)
+ {
+ value[min - p2 - 1] ^= (int)(t << q2);
+ }
+ value[min - p2] ^= t >>> (32 - q2);
+ if (min - p3 - 1 >= 0)
+ {
+ value[min - p3 - 1] ^= (int)(t << q3);
+ }
+ value[min - p3] ^= t >>> (32 - q3);
+ value[min] &= reverseRightMask[m & 0x1f];
+
+ blocks = ((m - 1) >>> 5) + 1;
+ len = m;
+ }
+
+ /**
+ * Reduces len by finding the most significant bit set to one and reducing
+ * len and blocks.
+ */
+ public void reduceN()
+ {
+ int i, j, h;
+ i = blocks - 1;
+ while ((value[i] == 0) && (i > 0))
+ {
+ i--;
+ }
+ h = value[i];
+ j = 0;
+ while (h != 0)
+ {
+ h >>>= 1;
+ j++;
+ }
+ len = (i << 5) + j;
+ blocks = i + 1;
+ }
+
+ /**
+ * Expands len and int[] value to i. This is useful before adding
+ * two GF2Polynomials of different size.
+ *
+ * @param i the intended length
+ */
+ public void expandN(int i)
+ {
+ int k;
+ int[] bs;
+ if (len >= i)
+ {
+ return;
+ }
+ len = i;
+ k = ((i - 1) >>> 5) + 1;
+ if (blocks >= k)
+ {
+ return;
+ }
+ if (value.length >= k)
+ {
+ int j;
+ for (j = blocks; j < k; j++)
+ {
+ value[j] = 0;
+ }
+ blocks = k;
+ return;
+ }
+ bs = new int[k];
+ System.arraycopy(value, 0, bs, 0, blocks);
+ blocks = k;
+ value = null;
+ value = bs;
+ }
+
+ /**
+ * Squares this GF2Polynomial and expands it accordingly. This method does
+ * not reduce the result in GF(2^N). There exists a faster method for
+ * squaring in GF(2^N).
+ *
+ * @see GF2nPolynomialElement#square
+ */
+ public void squareThisBitwise()
+ {
+ int i, h, j, k;
+ if (isZero())
+ {
+ return;
+ }
+ int[] result = new int[blocks << 1];
+ for (i = blocks - 1; i >= 0; i--)
+ {
+ h = value[i];
+ j = 0x00000001;
+ for (k = 0; k < 16; k++)
+ {
+ if ((h & 0x01) != 0)
+ {
+ result[i << 1] |= j;
+ }
+ if ((h & 0x00010000) != 0)
+ {
+ result[(i << 1) + 1] |= j;
+ }
+ j <<= 2;
+ h >>>= 1;
+ }
+ }
+ value = null;
+ value = result;
+ blocks = result.length;
+ len = (len << 1) - 1;
+ }
+
+ /**
+ * Squares this GF2Polynomial by using precomputed values of squaringTable.
+ * This method does not reduce the result in GF(2^N).
+ */
+ public void squareThisPreCalc()
+ {
+ int i;
+ if (isZero())
+ {
+ return;
+ }
+ if (value.length >= (blocks << 1))
+ {
+ for (i = blocks - 1; i >= 0; i--)
+ {
+ value[(i << 1) + 1] = GF2Polynomial.squaringTable[(value[i] & 0x00ff0000) >>> 16]
+ | (GF2Polynomial.squaringTable[(value[i] & 0xff000000) >>> 24] << 16);
+ value[i << 1] = GF2Polynomial.squaringTable[value[i] & 0x000000ff]
+ | (GF2Polynomial.squaringTable[(value[i] & 0x0000ff00) >>> 8] << 16);
+ }
+ blocks <<= 1;
+ len = (len << 1) - 1;
+ }
+ else
+ {
+ int[] result = new int[blocks << 1];
+ for (i = 0; i < blocks; i++)
+ {
+ result[i << 1] = GF2Polynomial.squaringTable[value[i] & 0x000000ff]
+ | (GF2Polynomial.squaringTable[(value[i] & 0x0000ff00) >>> 8] << 16);
+ result[(i << 1) + 1] = GF2Polynomial.squaringTable[(value[i] & 0x00ff0000) >>> 16]
+ | (GF2Polynomial.squaringTable[(value[i] & 0xff000000) >>> 24] << 16);
+ }
+ value = null;
+ value = result;
+ blocks <<= 1;
+ len = (len << 1) - 1;
+ }
+ }
+
+ /**
+ * Does a vector-multiplication modulo 2 and returns the result as boolean.
+ *
+ * @param b GF2Polynomial
+ * @return this x b as boolean (1->true, 0->false)
+ * @throws PolynomialsHaveDifferentLengthException if this and b have a different length and
+ * thus cannot be vector-multiplied
+ */
+ public boolean vectorMult(GF2Polynomial b)
+ throws RuntimeException
+ {
+ int i;
+ int h;
+ boolean result = false;
+ if (len != b.len)
+ {
+ throw new RuntimeException();
+ }
+ for (i = 0; i < blocks; i++)
+ {
+ h = value[i] & b.value[i];
+ result ^= parity[h & 0x000000ff];
+ result ^= parity[(h >>> 8) & 0x000000ff];
+ result ^= parity[(h >>> 16) & 0x000000ff];
+ result ^= parity[(h >>> 24) & 0x000000ff];
+ }
+ return result;
+ }
+
+ /**
+ * Returns the bitwise exclusive-or of this and b in a new
+ * GF2Polynomial. this and b can be of different size.
+ *
+ * @param b GF2Polynomial
+ * @return a new GF2Polynomial (this ^ b)
+ */
+ public GF2Polynomial xor(GF2Polynomial b)
+ {
+ int i;
+ GF2Polynomial result;
+ int k = Math.min(blocks, b.blocks);
+ if (len >= b.len)
+ {
+ result = new GF2Polynomial(this);
+ for (i = 0; i < k; i++)
+ {
+ result.value[i] ^= b.value[i];
+ }
+ }
+ else
+ {
+ result = new GF2Polynomial(b);
+ for (i = 0; i < k; i++)
+ {
+ result.value[i] ^= value[i];
+ }
+ }
+ // If we xor'ed some bits too many by proceeding blockwise,
+ // restore them to zero:
+ result.zeroUnusedBits();
+ return result;
+ }
+
+ /**
+ * Computes the bitwise exclusive-or of this GF2Polynomial and b and
+ * stores the result in this GF2Polynomial. b can be of different
+ * size.
+ *
+ * @param b GF2Polynomial
+ */
+ public void xorThisBy(GF2Polynomial b)
+ {
+ int i;
+ for (i = 0; i < Math.min(blocks, b.blocks); i++)
+ {
+ value[i] ^= b.value[i];
+ }
+ // If we xor'ed some bits too many by proceeding blockwise,
+ // restore them to zero:
+ zeroUnusedBits();
+ }
+
+ /**
+ * If {@link #len} is not a multiple of the block size (32), some extra bits
+ * of the last block might have been modified during a blockwise operation.
+ * This method compensates for that by restoring these "extra" bits to zero.
+ */
+ private void zeroUnusedBits()
+ {
+ if ((len & 0x1f) != 0)
+ {
+ value[blocks - 1] &= reverseRightMask[len & 0x1f];
+ }
+ }
+
+ /**
+ * Sets the bit at position i.
+ *
+ * @param i int
+ * @throws BitDoesNotExistException if (i < 0) || (i > (len - 1))
+ */
+ public void setBit(int i)
+ throws RuntimeException
+ {
+ if (i < 0 || i > (len - 1))
+ {
+ throw new RuntimeException();
+ }
+ if (i > (len - 1))
+ {
+ return;
+ }
+ value[i >>> 5] |= bitMask[i & 0x1f];
+ return;
+ }
+
+ /**
+ * Returns the bit at position i.
+ *
+ * @param i int
+ * @return the bit at position i if i is a valid position, 0
+ * otherwise.
+ */
+ public int getBit(int i)
+ {
+ if (i < 0 || i > (len - 1))
+ {
+ return 0;
+ }
+ return ((value[i >>> 5] & bitMask[i & 0x1f]) != 0) ? 1 : 0;
+ }
+
+ /**
+ * Resets the bit at position i.
+ *
+ * @param i int
+ * @throws BitDoesNotExistException if (i < 0) || (i > (len - 1))
+ */
+ public void resetBit(int i)
+ throws RuntimeException
+ {
+ if (i < 0 || i > (len - 1))
+ {
+ throw new RuntimeException();
+ }
+ if (i > (len - 1))
+ {
+ return;
+ }
+ value[i >>> 5] &= ~bitMask[i & 0x1f];
+ }
+
+ /**
+ * Xors the bit at position i.
+ *
+ * @param i int
+ * @throws BitDoesNotExistException if (i < 0) || (i > (len - 1))
+ */
+ public void xorBit(int i)
+ throws RuntimeException
+ {
+ if (i < 0 || i > (len - 1))
+ {
+ throw new RuntimeException();
+ }
+ if (i > (len - 1))
+ {
+ return;
+ }
+ value[i >>> 5] ^= bitMask[i & 0x1f];
+ }
+
+ /**
+ * Tests the bit at position i.
+ *
+ * @param i the position of the bit to be tested
+ * @return true if the bit at position i is set (a(i) ==
+ * 1). False if (i < 0) || (i > (len - 1))
+ */
+ public boolean testBit(int i)
+ {
+ if (i < 0 || i > (len - 1))
+ {
+ return false;
+ }
+ return (value[i >>> 5] & bitMask[i & 0x1f]) != 0;
+ }
+
+ /**
+ * Returns this GF2Polynomial shift-left by 1 in a new GF2Polynomial.
+ *
+ * @return a new GF2Polynomial (this << 1)
+ */
+ public GF2Polynomial shiftLeft()
+ {
+ GF2Polynomial result = new GF2Polynomial(len + 1, value);
+ int i;
+ for (i = result.blocks - 1; i >= 1; i--)
+ {
+ result.value[i] <<= 1;
+ result.value[i] |= result.value[i - 1] >>> 31;
+ }
+ result.value[0] <<= 1;
+ return result;
+ }
+
+ /**
+ * Shifts-left this by one and enlarges the size of value if necesary.
+ */
+ public void shiftLeftThis()
+ {
+ /** @todo This is untested. */
+ int i;
+ if ((len & 0x1f) == 0)
+ { // check if blocks increases
+ len += 1;
+ blocks += 1;
+ if (blocks > value.length)
+ { // enlarge value
+ int[] bs = new int[blocks];
+ System.arraycopy(value, 0, bs, 0, value.length);
+ value = null;
+ value = bs;
+ }
+ for (i = blocks - 1; i >= 1; i--)
+ {
+ value[i] |= value[i - 1] >>> 31;
+ value[i - 1] <<= 1;
+ }
+ }
+ else
+ {
+ len += 1;
+ for (i = blocks - 1; i >= 1; i--)
+ {
+ value[i] <<= 1;
+ value[i] |= value[i - 1] >>> 31;
+ }
+ value[0] <<= 1;
+ }
+ }
+
+ /**
+ * Returns this GF2Polynomial shift-left by k in a new
+ * GF2Polynomial.
+ *
+ * @param k int
+ * @return a new GF2Polynomial (this << k)
+ */
+ public GF2Polynomial shiftLeft(int k)
+ {
+ // Variant 2, requiring a modified shiftBlocksLeft(k)
+ // In case of modification, consider a rename to doShiftBlocksLeft()
+ // with an explicit note that this method assumes that the polynomial
+ // has already been resized. Or consider doing things inline.
+ // Construct the resulting polynomial of appropriate length:
+ GF2Polynomial result = new GF2Polynomial(len + k, value);
+ // Shift left as many multiples of the block size as possible:
+ if (k >= 32)
+ {
+ result.doShiftBlocksLeft(k >>> 5);
+ }
+ // Shift left by the remaining (<32) amount:
+ final int remaining = k & 0x1f;
+ if (remaining != 0)
+ {
+ for (int i = result.blocks - 1; i >= 1; i--)
+ {
+ result.value[i] <<= remaining;
+ result.value[i] |= result.value[i - 1] >>> (32 - remaining);
+ }
+ result.value[0] <<= remaining;
+ }
+ return result;
+ }
+
+ /**
+ * Shifts left b and adds the result to Its a fast version of
+ * this = add(b.shl(k));
+ *
+ * @param b GF2Polynomial to shift and add to this
+ * @param k the amount to shift
+ * @see GF2nPolynomialElement#invertEEA
+ */
+ public void shiftLeftAddThis(GF2Polynomial b, int k)
+ {
+ if (k == 0)
+ {
+ addToThis(b);
+ return;
+ }
+ int i;
+ expandN(b.len + k);
+ int d = k >>> 5;
+ for (i = b.blocks - 1; i >= 0; i--)
+ {
+ if ((i + d + 1 < blocks) && ((k & 0x1f) != 0))
+ {
+ value[i + d + 1] ^= b.value[i] >>> (32 - (k & 0x1f));
+ }
+ value[i + d] ^= b.value[i] << (k & 0x1f);
+ }
+ }
+
+ /**
+ * Shifts-left this GF2Polynomial's value blockwise 1 block resulting in a
+ * shift-left by 32.
+ *
+ * @see GF2Polynomial#multiply
+ */
+ void shiftBlocksLeft()
+ {
+ blocks += 1;
+ len += 32;
+ if (blocks <= value.length)
+ {
+ int i;
+ for (i = blocks - 1; i >= 1; i--)
+ {
+ value[i] = value[i - 1];
+ }
+ value[0] = 0x00;
+ }
+ else
+ {
+ int[] result = new int[blocks];
+ System.arraycopy(value, 0, result, 1, blocks - 1);
+ value = null;
+ value = result;
+ }
+ }
+
+ /**
+ * Shifts left this GF2Polynomial's value blockwise b blocks
+ * resulting in a shift-left by b*32. This method assumes that {@link #len}
+ * and {@link #blocks} have already been updated to reflect the final state.
+ *
+ * @param b shift amount (in blocks)
+ */
+ private void doShiftBlocksLeft(int b)
+ {
+ if (blocks <= value.length)
+ {
+ int i;
+ for (i = blocks - 1; i >= b; i--)
+ {
+ value[i] = value[i - b];
+ }
+ for (i = 0; i < b; i++)
+ {
+ value[i] = 0x00;
+ }
+ }
+ else
+ {
+ int[] result = new int[blocks];
+ System.arraycopy(value, 0, result, b, blocks - b);
+ value = null;
+ value = result;
+ }
+ }
+
+ /**
+ * Returns this GF2Polynomial shift-right by 1 in a new GF2Polynomial.
+ *
+ * @return a new GF2Polynomial (this << 1)
+ */
+ public GF2Polynomial shiftRight()
+ {
+ GF2Polynomial result = new GF2Polynomial(len - 1);
+ int i;
+ System.arraycopy(value, 0, result.value, 0, result.blocks);
+ for (i = 0; i <= result.blocks - 2; i++)
+ {
+ result.value[i] >>>= 1;
+ result.value[i] |= result.value[i + 1] << 31;
+ }
+ result.value[result.blocks - 1] >>>= 1;
+ if (result.blocks < blocks)
+ {
+ result.value[result.blocks - 1] |= value[result.blocks] << 31;
+ }
+ return result;
+ }
+
+ /**
+ * Shifts-right this GF2Polynomial by 1.
+ */
+ public void shiftRightThis()
+ {
+ int i;
+ len -= 1;
+ blocks = ((len - 1) >>> 5) + 1;
+ for (i = 0; i <= blocks - 2; i++)
+ {
+ value[i] >>>= 1;
+ value[i] |= value[i + 1] << 31;
+ }
+ value[blocks - 1] >>>= 1;
+ if ((len & 0x1f) == 0)
+ {
+ value[blocks - 1] |= value[blocks] << 31;
+ }
+ }
+
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/math/linearalgebra/GF2Vector.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/math/linearalgebra/GF2Vector.java
new file mode 100644
index 0000000..c6323b2
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/math/linearalgebra/GF2Vector.java
@@ -0,0 +1,539 @@
+package org.bc.pqc.math.linearalgebra;
+
+import java.security.SecureRandom;
+
+/**
+ * This class implements the abstract class Vector for the case of
+ * vectors over the finite field GF(2).
+ * For the vector representation the array of type int[] is used, thus one
+ * element of the array holds 32 elements of the vector.
+ *
+ * @see Vector
+ */
+public class GF2Vector
+ extends Vector
+{
+
+ /**
+ * holds the elements of this vector
+ */
+ private int[] v;
+
+ /**
+ * Construct the zero vector of the given length.
+ *
+ * @param length the length of the vector
+ */
+ public GF2Vector(int length)
+ {
+ if (length < 0)
+ {
+ throw new ArithmeticException("Negative length.");
+ }
+ this.length = length;
+ v = new int[(length + 31) >> 5];
+ }
+
+ /**
+ * Construct a random GF2Vector of the given length.
+ *
+ * @param length the length of the vector
+ * @param sr the source of randomness
+ */
+ public GF2Vector(int length, SecureRandom sr)
+ {
+ this.length = length;
+
+ int size = (length + 31) >> 5;
+ v = new int[size];
+
+ // generate random elements
+ for (int i = size - 1; i >= 0; i--)
+ {
+ v[i] = sr.nextInt();
+ }
+
+ // erase unused bits
+ int r = length & 0x1f;
+ if (r != 0)
+ {
+ // erase unused bits
+ v[size - 1] &= (1 << r) - 1;
+ }
+ }
+
+ /**
+ * Construct a random GF2Vector of the given length with the specified
+ * number of non-zero coefficients.
+ *
+ * @param length the length of the vector
+ * @param t the number of non-zero coefficients
+ * @param sr the source of randomness
+ */
+ public GF2Vector(int length, int t, SecureRandom sr)
+ {
+ if (t > length)
+ {
+ throw new ArithmeticException(
+ "The hamming weight is greater than the length of vector.");
+ }
+ this.length = length;
+
+ int size = (length + 31) >> 5;
+ v = new int[size];
+
+ int[] help = new int[length];
+ for (int i = 0; i < length; i++)
+ {
+ help[i] = i;
+ }
+
+ int m = length;
+ for (int i = 0; i < t; i++)
+ {
+ int j = RandUtils.nextInt(sr, m);
+ setBit(help[j]);
+ m--;
+ help[j] = help[m];
+ }
+ }
+
+ /**
+ * Construct a GF2Vector of the given length and with elements from the
+ * given array. The array is copied and unused bits are masked out.
+ *
+ * @param length the length of the vector
+ * @param v the element array
+ */
+ public GF2Vector(int length, int[] v)
+ {
+ if (length < 0)
+ {
+ throw new ArithmeticException("negative length");
+ }
+ this.length = length;
+
+ int size = (length + 31) >> 5;
+
+ if (v.length != size)
+ {
+ throw new ArithmeticException("length mismatch");
+ }
+
+ this.v = IntUtils.clone(v);
+
+ int r = length & 0x1f;
+ if (r != 0)
+ {
+ // erase unused bits
+ this.v[size - 1] &= (1 << r) - 1;
+ }
+ }
+
+ /**
+ * Copy constructor.
+ *
+ * @param other another {@link GF2Vector}
+ */
+ public GF2Vector(GF2Vector other)
+ {
+ this.length = other.length;
+ this.v = IntUtils.clone(other.v);
+ }
+
+ /**
+ * Construct a new {@link GF2Vector} of the given length and with the given
+ * element array. The array is not changed and only a reference to the array
+ * is stored. No length checking is performed either.
+ *
+ * @param v the element array
+ * @param length the length of the vector
+ */
+ protected GF2Vector(int[] v, int length)
+ {
+ this.v = v;
+ this.length = length;
+ }
+
+ /**
+ * Construct a new GF2Vector with the given length out of the encoded
+ * vector.
+ *
+ * @param length the length of the vector
+ * @param encVec the encoded vector
+ * @return the decoded vector
+ */
+ public static GF2Vector OS2VP(int length, byte[] encVec)
+ {
+ if (length < 0)
+ {
+ throw new ArithmeticException("negative length");
+ }
+
+ int byteLen = (length + 7) >> 3;
+
+ if (encVec.length > byteLen)
+ {
+ throw new ArithmeticException("length mismatch");
+ }
+
+ return new GF2Vector(length, LittleEndianConversions.toIntArray(encVec));
+ }
+
+ /**
+ * Encode this vector as byte array.
+ *
+ * @return the encoded vector
+ */
+ public byte[] getEncoded()
+ {
+ int byteLen = (length + 7) >> 3;
+ return LittleEndianConversions.toByteArray(v, byteLen);
+ }
+
+ /**
+ * @return the int array representation of this vector
+ */
+ public int[] getVecArray()
+ {
+ return v;
+ }
+
+ /**
+ * Return the Hamming weight of this vector, i.e., compute the number of
+ * units of this vector.
+ *
+ * @return the Hamming weight of this vector
+ */
+ public int getHammingWeight()
+ {
+ int weight = 0;
+ for (int i = 0; i < v.length; i++)
+ {
+ int e = v[i];
+ for (int j = 0; j < 32; j++)
+ {
+ int b = e & 1;
+ if (b != 0)
+ {
+ weight++;
+ }
+ e >>>= 1;
+ }
+ }
+ return weight;
+ }
+
+ /**
+ * @return whether this is the zero vector (i.e., all elements are zero)
+ */
+ public boolean isZero()
+ {
+ for (int i = v.length - 1; i >= 0; i--)
+ {
+ if (v[i] != 0)
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Return the value of the bit of this vector at the specified index.
+ *
+ * @param index the index
+ * @return the value of the bit (0 or 1)
+ */
+ public int getBit(int index)
+ {
+ if (index >= length)
+ {
+ throw new IndexOutOfBoundsException();
+ }
+ int q = index >> 5;
+ int r = index & 0x1f;
+ return (v[q] & (1 << r)) >>> r;
+ }
+
+ /**
+ * Set the coefficient at the given index to 1. If the index is out of
+ * bounds, do nothing.
+ *
+ * @param index the index of the coefficient to set
+ */
+ public void setBit(int index)
+ {
+ if (index >= length)
+ {
+ throw new IndexOutOfBoundsException();
+ }
+ v[index >> 5] |= 1 << (index & 0x1f);
+ }
+
+ /**
+ * Adds another GF2Vector to this vector.
+ *
+ * @param other another GF2Vector
+ * @return this + other
+ * @throws ArithmeticException if the other vector is not a GF2Vector or has another
+ * length.
+ */
+ public Vector add(Vector other)
+ {
+ if (!(other instanceof GF2Vector))
+ {
+ throw new ArithmeticException("vector is not defined over GF(2)");
+ }
+
+ GF2Vector otherVec = (GF2Vector)other;
+ if (length != otherVec.length)
+ {
+ throw new ArithmeticException("length mismatch");
+ }
+
+ int[] vec = IntUtils.clone(((GF2Vector)other).v);
+
+ for (int i = vec.length - 1; i >= 0; i--)
+ {
+ vec[i] ^= v[i];
+ }
+
+ return new GF2Vector(length, vec);
+ }
+
+ /**
+ * Multiply this vector with a permutation.
+ *
+ * @param p the permutation
+ * @return this*p = p*this
+ */
+ public Vector multiply(Permutation p)
+ {
+ int[] pVec = p.getVector();
+ if (length != pVec.length)
+ {
+ throw new ArithmeticException("length mismatch");
+ }
+
+ GF2Vector result = new GF2Vector(length);
+
+ for (int i = 0; i < pVec.length; i++)
+ {
+ int e = v[pVec[i] >> 5] & (1 << (pVec[i] & 0x1f));
+ if (e != 0)
+ {
+ result.v[i >> 5] |= 1 << (i & 0x1f);
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Return a new vector consisting of the elements of this vector with the
+ * indices given by the set setJ.
+ *
+ * @param setJ the set of indices of elements to extract
+ * @return the new {@link GF2Vector}
+ * [this_setJ[0], this_setJ[1], ..., this_setJ[#setJ-1]]
+ */
+ public GF2Vector extractVector(int[] setJ)
+ {
+ int k = setJ.length;
+ if (setJ[k - 1] > length)
+ {
+ throw new ArithmeticException("invalid index set");
+ }
+
+ GF2Vector result = new GF2Vector(k);
+
+ for (int i = 0; i < k; i++)
+ {
+ int e = v[setJ[i] >> 5] & (1 << (setJ[i] & 0x1f));
+ if (e != 0)
+ {
+ result.v[i >> 5] |= 1 << (i & 0x1f);
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Return a new vector consisting of the first k elements of this
+ * vector.
+ *
+ * @param k the number of elements to extract
+ * @return a new {@link GF2Vector} consisting of the first k
+ * elements of this vector
+ */
+ public GF2Vector extractLeftVector(int k)
+ {
+ if (k > length)
+ {
+ throw new ArithmeticException("invalid length");
+ }
+
+ if (k == length)
+ {
+ return new GF2Vector(this);
+ }
+
+ GF2Vector result = new GF2Vector(k);
+
+ int q = k >> 5;
+ int r = k & 0x1f;
+
+ System.arraycopy(v, 0, result.v, 0, q);
+ if (r != 0)
+ {
+ result.v[q] = v[q] & ((1 << r) - 1);
+ }
+
+ return result;
+ }
+
+ /**
+ * Return a new vector consisting of the last k elements of this
+ * vector.
+ *
+ * @param k the number of elements to extract
+ * @return a new {@link GF2Vector} consisting of the last k
+ * elements of this vector
+ */
+ public GF2Vector extractRightVector(int k)
+ {
+ if (k > length)
+ {
+ throw new ArithmeticException("invalid length");
+ }
+
+ if (k == length)
+ {
+ return new GF2Vector(this);
+ }
+
+ GF2Vector result = new GF2Vector(k);
+
+ int q = (length - k) >> 5;
+ int r = (length - k) & 0x1f;
+ int length = (k + 31) >> 5;
+
+ int ind = q;
+ // if words have to be shifted
+ if (r != 0)
+ {
+ // process all but last word
+ for (int i = 0; i < length - 1; i++)
+ {
+ result.v[i] = (v[ind++] >>> r) | (v[ind] << (32 - r));
+ }
+ // process last word
+ result.v[length - 1] = v[ind++] >>> r;
+ if (ind < v.length)
+ {
+ result.v[length - 1] |= v[ind] << (32 - r);
+ }
+ }
+ else
+ {
+ // no shift necessary
+ System.arraycopy(v, q, result.v, 0, length);
+ }
+
+ return result;
+ }
+
+ /**
+ * Rewrite this vector as a vector over GF(2m) with
+ * t elements.
+ *
+ * @param field the finite field GF(2m)
+ * @return the converted vector over GF(2m)
+ */
+ public GF2mVector toExtensionFieldVector(GF2mField field)
+ {
+ int m = field.getDegree();
+ if ((length % m) != 0)
+ {
+ throw new ArithmeticException("conversion is impossible");
+ }
+
+ int t = length / m;
+ int[] result = new int[t];
+ int count = 0;
+ for (int i = t - 1; i >= 0; i--)
+ {
+ for (int j = field.getDegree() - 1; j >= 0; j--)
+ {
+ int q = count >>> 5;
+ int r = count & 0x1f;
+
+ int e = (v[q] >>> r) & 1;
+ if (e == 1)
+ {
+ result[i] ^= 1 << j;
+ }
+ count++;
+ }
+ }
+ return new GF2mVector(field, result);
+ }
+
+ /**
+ * Check if the given object is equal to this vector.
+ *
+ * @param other vector
+ * @return the result of the comparison
+ */
+ public boolean equals(Object other)
+ {
+
+ if (!(other instanceof GF2Vector))
+ {
+ return false;
+ }
+ GF2Vector otherVec = (GF2Vector)other;
+
+ return (length == otherVec.length) && IntUtils.equals(v, otherVec.v);
+ }
+
+ /**
+ * @return the hash code of this vector
+ */
+ public int hashCode()
+ {
+ int hash = length;
+ hash = hash * 31 + v.hashCode();
+ return hash;
+ }
+
+ /**
+ * @return a human readable form of this vector
+ */
+ public String toString()
+ {
+ StringBuffer buf = new StringBuffer();
+ for (int i = 0; i < length; i++)
+ {
+ if ((i != 0) && ((i & 0x1f) == 0))
+ {
+ buf.append(' ');
+ }
+ int q = i >> 5;
+ int r = i & 0x1f;
+ int bit = v[q] & (1 << r);
+ if (bit == 0)
+ {
+ buf.append('0');
+ }
+ else
+ {
+ buf.append('1');
+ }
+ }
+ return buf.toString();
+ }
+
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/math/linearalgebra/GF2mField.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/math/linearalgebra/GF2mField.java
new file mode 100644
index 0000000..b3a45f7
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/math/linearalgebra/GF2mField.java
@@ -0,0 +1,366 @@
+package org.bc.pqc.math.linearalgebra;
+
+import java.security.SecureRandom;
+
+/**
+ * This class describes operations with elements from the finite field F =
+ * GF(2^m). ( GF(2^m)= GF(2)[A] where A is a root of irreducible polynomial with
+ * degree m, each field element B has a polynomial basis representation, i.e. it
+ * is represented by a different binary polynomial of degree less than m, B =
+ * poly(A) ) All operations are defined only for field with 1< m <32. For the
+ * representation of field elements the map f: F->Z, poly(A)->poly(2) is used,
+ * where integers have the binary representation. For example: A^7+A^3+A+1 ->
+ * (00...0010001011)=139 Also for elements type Integer is used.
+ *
+ * @see PolynomialRingGF2
+ */
+public class GF2mField
+{
+
+ /*
+ * degree - degree of the field polynomial - the field polynomial ring -
+ * polynomial ring over the finite field GF(2)
+ */
+
+ private int degree = 0;
+
+ private int polynomial;
+
+ /**
+ * create a finite field GF(2^m)
+ *
+ * @param degree the degree of the field
+ */
+ public GF2mField(int degree)
+ {
+ if (degree >= 32)
+ {
+ throw new IllegalArgumentException(
+ " Error: the degree of field is too large ");
+ }
+ if (degree < 1)
+ {
+ throw new IllegalArgumentException(
+ " Error: the degree of field is non-positive ");
+ }
+ this.degree = degree;
+ polynomial = PolynomialRingGF2.getIrreduciblePolynomial(degree);
+ }
+
+ /**
+ * create a finite field GF(2^m) with the fixed field polynomial
+ *
+ * @param degree the degree of the field
+ * @param poly the field polynomial
+ */
+ public GF2mField(int degree, int poly)
+ {
+ if (degree != PolynomialRingGF2.degree(poly))
+ {
+ throw new IllegalArgumentException(
+ " Error: the degree is not correct");
+ }
+ if (!PolynomialRingGF2.isIrreducible(poly))
+ {
+ throw new IllegalArgumentException(
+ " Error: given polynomial is reducible");
+ }
+ this.degree = degree;
+ polynomial = poly;
+
+ }
+
+ public GF2mField(byte[] enc)
+ {
+ if (enc.length != 4)
+ {
+ throw new IllegalArgumentException(
+ "byte array is not an encoded finite field");
+ }
+ polynomial = LittleEndianConversions.OS2IP(enc);
+ if (!PolynomialRingGF2.isIrreducible(polynomial))
+ {
+ throw new IllegalArgumentException(
+ "byte array is not an encoded finite field");
+ }
+
+ degree = PolynomialRingGF2.degree(polynomial);
+ }
+
+ public GF2mField(GF2mField field)
+ {
+ degree = field.degree;
+ polynomial = field.polynomial;
+ }
+
+ /**
+ * return degree of the field
+ *
+ * @return degree of the field
+ */
+ public int getDegree()
+ {
+ return degree;
+ }
+
+ /**
+ * return the field polynomial
+ *
+ * @return the field polynomial
+ */
+ public int getPolynomial()
+ {
+ return polynomial;
+ }
+
+ /**
+ * return the encoded form of this field
+ *
+ * @return the field in byte array form
+ */
+ public byte[] getEncoded()
+ {
+ return LittleEndianConversions.I2OSP(polynomial);
+ }
+
+ /**
+ * Return sum of two elements
+ *
+ * @param a
+ * @param b
+ * @return a+b
+ */
+ public int add(int a, int b)
+ {
+ return a ^ b;
+ }
+
+ /**
+ * Return product of two elements
+ *
+ * @param a
+ * @param b
+ * @return a*b
+ */
+ public int mult(int a, int b)
+ {
+ return PolynomialRingGF2.modMultiply(a, b, polynomial);
+ }
+
+ /**
+ * compute exponentiation a^k
+ *
+ * @param a a field element a
+ * @param k k degree
+ * @return a^k
+ */
+ public int exp(int a, int k)
+ {
+ if (a == 0)
+ {
+ return 0;
+ }
+ if (a == 1)
+ {
+ return 1;
+ }
+ int result = 1;
+ if (k < 0)
+ {
+ a = inverse(a);
+ k = -k;
+ }
+ while (k != 0)
+ {
+ if ((k & 1) == 1)
+ {
+ result = mult(result, a);
+ }
+ a = mult(a, a);
+ k >>>= 1;
+ }
+ return result;
+ }
+
+ /**
+ * compute the multiplicative inverse of a
+ *
+ * @param a a field element a
+ * @return a-1
+ */
+ public int inverse(int a)
+ {
+ int d = (1 << degree) - 2;
+
+ return exp(a, d);
+ }
+
+ /**
+ * compute the square root of an integer
+ *
+ * @param a a field element a
+ * @return a1/2
+ */
+ public int sqRoot(int a)
+ {
+ for (int i = 1; i < degree; i++)
+ {
+ a = mult(a, a);
+ }
+ return a;
+ }
+
+ /**
+ * create a random field element using PRNG sr
+ *
+ * @param sr SecureRandom
+ * @return a random element
+ */
+ public int getRandomElement(SecureRandom sr)
+ {
+ int result = RandUtils.nextInt(sr, 1 << degree);
+ return result;
+ }
+
+ /**
+ * create a random non-zero field element
+ *
+ * @return a random element
+ */
+ public int getRandomNonZeroElement()
+ {
+ return getRandomNonZeroElement(new SecureRandom());
+ }
+
+ /**
+ * create a random non-zero field element using PRNG sr
+ *
+ * @param sr SecureRandom
+ * @return a random non-zero element
+ */
+ public int getRandomNonZeroElement(SecureRandom sr)
+ {
+ int controltime = 1 << 20;
+ int count = 0;
+ int result = RandUtils.nextInt(sr, 1 << degree);
+ while ((result == 0) && (count < controltime))
+ {
+ result = RandUtils.nextInt(sr, 1 << degree);
+ count++;
+ }
+ if (count == controltime)
+ {
+ result = 1;
+ }
+ return result;
+ }
+
+ /**
+ * @return true if e is encoded element of this field and false otherwise
+ */
+ public boolean isElementOfThisField(int e)
+ {
+ // e is encoded element of this field iff 0<= e < |2^m|
+ if (degree == 31)
+ {
+ return e >= 0;
+ }
+ return e >= 0 && e < (1 << degree);
+ }
+
+ /*
+ * help method for visual control
+ */
+ public String elementToStr(int a)
+ {
+ String s = "";
+ for (int i = 0; i < degree; i++)
+ {
+ if (((byte)a & 0x01) == 0)
+ {
+ s = "0" + s;
+ }
+ else
+ {
+ s = "1" + s;
+ }
+ a >>>= 1;
+ }
+ return s;
+ }
+
+ /**
+ * checks if given object is equal to this field.
+ *
+ * The method returns false whenever the given object is not GF2m.
+ *
+ * @param other object
+ * @return true or false
+ */
+ public boolean equals(Object other)
+ {
+ if ((other == null) || !(other instanceof GF2mField))
+ {
+ return false;
+ }
+
+ GF2mField otherField = (GF2mField)other;
+
+ if ((degree == otherField.degree)
+ && (polynomial == otherField.polynomial))
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ public int hashCode()
+ {
+ return polynomial;
+ }
+
+ /**
+ * Returns a human readable form of this field.
+ *
+ *
+ * @return a human readable form of this field.
+ */
+ public String toString()
+ {
+ String str = "Finite Field GF(2^" + degree + ") = " + "GF(2)[X]/<"
+ + polyToString(polynomial) + "> ";
+ return str;
+ }
+
+ private static String polyToString(int p)
+ {
+ String str = "";
+ if (p == 0)
+ {
+ str = "0";
+ }
+ else
+ {
+ byte b = (byte)(p & 0x01);
+ if (b == 1)
+ {
+ str = "1";
+ }
+ p >>>= 1;
+ int i = 1;
+ while (p != 0)
+ {
+ b = (byte)(p & 0x01);
+ if (b == 1)
+ {
+ str = str + "+x^" + i;
+ }
+ p >>>= 1;
+ i++;
+ }
+ }
+ return str;
+ }
+
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/math/linearalgebra/GF2mMatrix.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/math/linearalgebra/GF2mMatrix.java
new file mode 100644
index 0000000..d3b55e2
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/math/linearalgebra/GF2mMatrix.java
@@ -0,0 +1,377 @@
+package org.bc.pqc.math.linearalgebra;
+
+/**
+ * This class describes some operations with matrices over finite field GF(2m)
+ * with small m (1< m <32).
+ *
+ * @see Matrix
+ */
+public class GF2mMatrix
+ extends Matrix
+{
+
+ /**
+ * finite field GF(2^m)
+ */
+ protected GF2mField field;
+
+ /**
+ * For the matrix representation the array of type int[][] is used, thus
+ * every element of the array keeps one element of the matrix (element from
+ * finite field GF(2^m))
+ */
+ protected int[][] matrix;
+
+ /**
+ * Constructor.
+ *
+ * @param field a finite field GF(2^m)
+ * @param enc byte[] matrix in byte array form
+ */
+ public GF2mMatrix(GF2mField field, byte[] enc)
+ {
+
+ this.field = field;
+
+ // decode matrix
+ int d = 8;
+ int count = 1;
+ while (field.getDegree() > d)
+ {
+ count++;
+ d += 8;
+ }
+
+ if (enc.length < 5)
+ {
+ throw new IllegalArgumentException(
+ " Error: given array is not encoded matrix over GF(2^m)");
+ }
+
+ this.numRows = ((enc[3] & 0xff) << 24) ^ ((enc[2] & 0xff) << 16)
+ ^ ((enc[1] & 0xff) << 8) ^ (enc[0] & 0xff);
+
+ int n = count * this.numRows;
+
+ if ((this.numRows <= 0) || (((enc.length - 4) % n) != 0))
+ {
+ throw new IllegalArgumentException(
+ " Error: given array is not encoded matrix over GF(2^m)");
+ }
+
+ this.numColumns = (enc.length - 4) / n;
+
+ matrix = new int[this.numRows][this.numColumns];
+ count = 4;
+ for (int i = 0; i < this.numRows; i++)
+ {
+ for (int j = 0; j < this.numColumns; j++)
+ {
+ for (int jj = 0; jj < d; jj += 8)
+ {
+ matrix[i][j] ^= (enc[count++] & 0x000000ff) << jj;
+ }
+ if (!this.field.isElementOfThisField(matrix[i][j]))
+ {
+ throw new IllegalArgumentException(
+ " Error: given array is not encoded matrix over GF(2^m)");
+ }
+ }
+ }
+ }
+
+ /**
+ * Copy constructor.
+ *
+ * @param other another {@link GF2mMatrix}
+ */
+ public GF2mMatrix(GF2mMatrix other)
+ {
+ numRows = other.numRows;
+ numColumns = other.numColumns;
+ field = other.field;
+ matrix = new int[numRows][];
+ for (int i = 0; i < numRows; i++)
+ {
+ matrix[i] = IntUtils.clone(other.matrix[i]);
+ }
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param field a finite field GF(2^m)
+ * @param matrix the matrix as int array. Only the reference is copied.
+ */
+ protected GF2mMatrix(GF2mField field, int[][] matrix)
+ {
+ this.field = field;
+ this.matrix = matrix;
+ numRows = matrix.length;
+ numColumns = matrix[0].length;
+ }
+
+ /**
+ * @return a byte array encoding of this matrix
+ */
+ public byte[] getEncoded()
+ {
+ int d = 8;
+ int count = 1;
+ while (field.getDegree() > d)
+ {
+ count++;
+ d += 8;
+ }
+
+ byte[] bf = new byte[this.numRows * this.numColumns * count + 4];
+ bf[0] = (byte)(this.numRows & 0xff);
+ bf[1] = (byte)((this.numRows >>> 8) & 0xff);
+ bf[2] = (byte)((this.numRows >>> 16) & 0xff);
+ bf[3] = (byte)((this.numRows >>> 24) & 0xff);
+
+ count = 4;
+ for (int i = 0; i < this.numRows; i++)
+ {
+ for (int j = 0; j < this.numColumns; j++)
+ {
+ for (int jj = 0; jj < d; jj += 8)
+ {
+ bf[count++] = (byte)(matrix[i][j] >>> jj);
+ }
+ }
+ }
+
+ return bf;
+ }
+
+ /**
+ * Check if this is the zero matrix (i.e., all entries are zero).
+ *
+ * @return true if this is the zero matrix
+ */
+ public boolean isZero()
+ {
+ for (int i = 0; i < numRows; i++)
+ {
+ for (int j = 0; j < numColumns; j++)
+ {
+ if (matrix[i][j] != 0)
+ {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Compute the inverse of this matrix.
+ *
+ * @return the inverse of this matrix (newly created).
+ */
+ public Matrix computeInverse()
+ {
+ if (numRows != numColumns)
+ {
+ throw new ArithmeticException("Matrix is not invertible.");
+ }
+
+ // clone this matrix
+ int[][] tmpMatrix = new int[numRows][numRows];
+ for (int i = numRows - 1; i >= 0; i--)
+ {
+ tmpMatrix[i] = IntUtils.clone(matrix[i]);
+ }
+
+ // initialize inverse matrix as unit matrix
+ int[][] invMatrix = new int[numRows][numRows];
+ for (int i = numRows - 1; i >= 0; i--)
+ {
+ invMatrix[i][i] = 1;
+ }
+
+ // simultaneously compute Gaussian reduction of tmpMatrix and unit
+ // matrix
+ for (int i = 0; i < numRows; i++)
+ {
+ // if diagonal element is zero
+ if (tmpMatrix[i][i] == 0)
+ {
+ boolean foundNonZero = false;
+ // find a non-zero element in the same column
+ for (int j = i + 1; j < numRows; j++)
+ {
+ if (tmpMatrix[j][i] != 0)
+ {
+ // found it, swap rows ...
+ foundNonZero = true;
+ swapColumns(tmpMatrix, i, j);
+ swapColumns(invMatrix, i, j);
+ // ... and quit searching
+ j = numRows;
+ continue;
+ }
+ }
+ // if no non-zero element was found
+ if (!foundNonZero)
+ {
+ // the matrix is not invertible
+ throw new ArithmeticException("Matrix is not invertible.");
+ }
+ }
+
+ // normalize i-th row
+ int coef = tmpMatrix[i][i];
+ int invCoef = field.inverse(coef);
+ multRowWithElementThis(tmpMatrix[i], invCoef);
+ multRowWithElementThis(invMatrix[i], invCoef);
+
+ // normalize all other rows
+ for (int j = 0; j < numRows; j++)
+ {
+ if (j != i)
+ {
+ coef = tmpMatrix[j][i];
+ if (coef != 0)
+ {
+ int[] tmpRow = multRowWithElement(tmpMatrix[i], coef);
+ int[] tmpInvRow = multRowWithElement(invMatrix[i], coef);
+ addToRow(tmpRow, tmpMatrix[j]);
+ addToRow(tmpInvRow, invMatrix[j]);
+ }
+ }
+ }
+ }
+
+ return new GF2mMatrix(field, invMatrix);
+ }
+
+ private static void swapColumns(int[][] matrix, int first, int second)
+ {
+ int[] tmp = matrix[first];
+ matrix[first] = matrix[second];
+ matrix[second] = tmp;
+ }
+
+ private void multRowWithElementThis(int[] row, int element)
+ {
+ for (int i = row.length - 1; i >= 0; i--)
+ {
+ row[i] = field.mult(row[i], element);
+ }
+ }
+
+ private int[] multRowWithElement(int[] row, int element)
+ {
+ int[] result = new int[row.length];
+ for (int i = row.length - 1; i >= 0; i--)
+ {
+ result[i] = field.mult(row[i], element);
+ }
+ return result;
+ }
+
+ /**
+ * Add one row to another.
+ *
+ * @param fromRow the addend
+ * @param toRow the row to add to
+ */
+ private void addToRow(int[] fromRow, int[] toRow)
+ {
+ for (int i = toRow.length - 1; i >= 0; i--)
+ {
+ toRow[i] = field.add(fromRow[i], toRow[i]);
+ }
+ }
+
+ public Matrix rightMultiply(Matrix a)
+ {
+ throw new RuntimeException("Not implemented.");
+ }
+
+ public Matrix rightMultiply(Permutation perm)
+ {
+ throw new RuntimeException("Not implemented.");
+ }
+
+ public Vector leftMultiply(Vector vector)
+ {
+ throw new RuntimeException("Not implemented.");
+ }
+
+ public Vector rightMultiply(Vector vector)
+ {
+ throw new RuntimeException("Not implemented.");
+ }
+
+ /**
+ * Checks if given object is equal to this matrix. The method returns false
+ * whenever the given object is not a matrix over GF(2^m).
+ *
+ * @param other object
+ * @return true or false
+ */
+ public boolean equals(Object other)
+ {
+
+ if (other == null || !(other instanceof GF2mMatrix))
+ {
+ return false;
+ }
+
+ GF2mMatrix otherMatrix = (GF2mMatrix)other;
+
+ if ((!this.field.equals(otherMatrix.field))
+ || (otherMatrix.numRows != this.numColumns)
+ || (otherMatrix.numColumns != this.numColumns))
+ {
+ return false;
+ }
+
+ for (int i = 0; i < this.numRows; i++)
+ {
+ for (int j = 0; j < this.numColumns; j++)
+ {
+ if (this.matrix[i][j] != otherMatrix.matrix[i][j])
+ {
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ public int hashCode()
+ {
+ int hash = (this.field.hashCode() * 31 + numRows) * 31 + numColumns;
+ for (int i = 0; i < this.numRows; i++)
+ {
+ for (int j = 0; j < this.numColumns; j++)
+ {
+ hash = hash * 31 + matrix[i][j];
+ }
+ }
+ return hash;
+ }
+
+ public String toString()
+ {
+ String str = this.numRows + " x " + this.numColumns + " Matrix over "
+ + this.field.toString() + ": \n";
+
+ for (int i = 0; i < this.numRows; i++)
+ {
+ for (int j = 0; j < this.numColumns; j++)
+ {
+ str = str + this.field.elementToStr(matrix[i][j]) + " : ";
+ }
+ str = str + "\n";
+ }
+
+ return str;
+ }
+
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/math/linearalgebra/GF2mVector.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/math/linearalgebra/GF2mVector.java
new file mode 100644
index 0000000..485f984
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/math/linearalgebra/GF2mVector.java
@@ -0,0 +1,256 @@
+package org.bc.pqc.math.linearalgebra;
+
+
+/**
+ * This class implements vectors over the finite field
+ * GF(2m) for small m (i.e.,
+ * 1<m<32). It extends the abstract class {@link Vector}.
+ */
+public class GF2mVector
+ extends Vector
+{
+
+ /**
+ * the finite field this vector is defined over
+ */
+ private GF2mField field;
+
+ /**
+ * the element array
+ */
+ private int[] vector;
+
+ /**
+ * creates the vector over GF(2^m) of given length and with elements from
+ * array v (beginning at the first bit)
+ *
+ * @param field finite field
+ * @param v array with elements of vector
+ */
+ public GF2mVector(GF2mField field, byte[] v)
+ {
+ this.field = new GF2mField(field);
+
+ // decode vector
+ int d = 8;
+ int count = 1;
+ while (field.getDegree() > d)
+ {
+ count++;
+ d += 8;
+ }
+
+ if ((v.length % count) != 0)
+ {
+ throw new IllegalArgumentException(
+ "Byte array is not an encoded vector over the given finite field.");
+ }
+
+ length = v.length / count;
+ vector = new int[length];
+ count = 0;
+ for (int i = 0; i < vector.length; i++)
+ {
+ for (int j = 0; j < d; j += 8)
+ {
+ vector[i] |= (v[count++] & 0xff) << j;
+ }
+ if (!field.isElementOfThisField(vector[i]))
+ {
+ throw new IllegalArgumentException(
+ "Byte array is not an encoded vector over the given finite field.");
+ }
+ }
+ }
+
+ /**
+ * Create a new vector over GF(2m) of the given
+ * length and element array.
+ *
+ * @param field the finite field GF(2m)
+ * @param vector the element array
+ */
+ public GF2mVector(GF2mField field, int[] vector)
+ {
+ this.field = field;
+ length = vector.length;
+ for (int i = vector.length - 1; i >= 0; i--)
+ {
+ if (!field.isElementOfThisField(vector[i]))
+ {
+ throw new ArithmeticException(
+ "Element array is not specified over the given finite field.");
+ }
+ }
+ this.vector = IntUtils.clone(vector);
+ }
+
+ /**
+ * Copy constructor.
+ *
+ * @param other another {@link GF2mVector}
+ */
+ public GF2mVector(GF2mVector other)
+ {
+ field = new GF2mField(other.field);
+ length = other.length;
+ vector = IntUtils.clone(other.vector);
+ }
+
+ /**
+ * @return the finite field this vector is defined over
+ */
+ public GF2mField getField()
+ {
+ return field;
+ }
+
+ /**
+ * @return int[] form of this vector
+ */
+ public int[] getIntArrayForm()
+ {
+ return IntUtils.clone(vector);
+ }
+
+ /**
+ * @return a byte array encoding of this vector
+ */
+ public byte[] getEncoded()
+ {
+ int d = 8;
+ int count = 1;
+ while (field.getDegree() > d)
+ {
+ count++;
+ d += 8;
+ }
+
+ byte[] res = new byte[vector.length * count];
+ count = 0;
+ for (int i = 0; i < vector.length; i++)
+ {
+ for (int j = 0; j < d; j += 8)
+ {
+ res[count++] = (byte)(vector[i] >>> j);
+ }
+ }
+
+ return res;
+ }
+
+ /**
+ * @return whether this is the zero vector (i.e., all elements are zero)
+ */
+ public boolean isZero()
+ {
+ for (int i = vector.length - 1; i >= 0; i--)
+ {
+ if (vector[i] != 0)
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Add another vector to this vector. Method is not yet implemented.
+ *
+ * @param addend the other vector
+ * @return this + addend
+ * @throws ArithmeticException if the other vector is not defined over the same field as
+ * this vector.
+ *
+ * TODO: implement this method
+ */
+ public Vector add(Vector addend)
+ {
+ throw new RuntimeException("not implemented");
+ }
+
+ /**
+ * Multiply this vector with a permutation.
+ *
+ * @param p the permutation
+ * @return this*p = p*this
+ */
+ public Vector multiply(Permutation p)
+ {
+ int[] pVec = p.getVector();
+ if (length != pVec.length)
+ {
+ throw new ArithmeticException(
+ "permutation size and vector size mismatch");
+ }
+
+ int[] result = new int[length];
+ for (int i = 0; i < pVec.length; i++)
+ {
+ result[i] = vector[pVec[i]];
+ }
+
+ return new GF2mVector(field, result);
+ }
+
+ /**
+ * Compare this vector with another object.
+ *
+ * @param other the other object
+ * @return the result of the comparison
+ */
+ public boolean equals(Object other)
+ {
+
+ if (!(other instanceof GF2mVector))
+ {
+ return false;
+ }
+ GF2mVector otherVec = (GF2mVector)other;
+
+ if (!field.equals(otherVec.field))
+ {
+ return false;
+ }
+
+ return IntUtils.equals(vector, otherVec.vector);
+ }
+
+ /**
+ * @return the hash code of this vector
+ */
+ public int hashCode()
+ {
+ int hash = this.field.hashCode();
+ hash = hash * 31 + vector.hashCode();
+ return hash;
+ }
+
+ /**
+ * @return a human readable form of this vector
+ */
+ public String toString()
+ {
+ StringBuffer buf = new StringBuffer();
+ for (int i = 0; i < vector.length; i++)
+ {
+ for (int j = 0; j < field.getDegree(); j++)
+ {
+ int r = j & 0x1f;
+ int bitMask = 1 << r;
+ int coeff = vector[i] & bitMask;
+ if (coeff != 0)
+ {
+ buf.append('1');
+ }
+ else
+ {
+ buf.append('0');
+ }
+ }
+ buf.append(' ');
+ }
+ return buf.toString();
+ }
+
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/math/linearalgebra/GF2nElement.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/math/linearalgebra/GF2nElement.java
new file mode 100644
index 0000000..1f0105c
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/math/linearalgebra/GF2nElement.java
@@ -0,0 +1,186 @@
+package org.bc.pqc.math.linearalgebra;
+
+
+/**
+ * This abstract class implements an element of the finite field GF(2)n
+ * in either optimal normal basis representation (ONB)
+ * or in polynomial representation. It is extended by the classes GF2nONBElement and GF2nPolynomialElement .
+ *
+ * @see GF2nPolynomialElement
+ * @see GF2nONBElement
+ * @see GF2nONBField
+ */
+public abstract class GF2nElement
+ implements GFElement
+{
+
+ // /////////////////////////////////////////////////////////////////////
+ // member variables
+ // /////////////////////////////////////////////////////////////////////
+
+ /**
+ * holds a pointer to this element's corresponding field.
+ */
+ protected GF2nField mField;
+
+ /**
+ * holds the extension degree n of this element's corresponding
+ * field.
+ */
+ protected int mDegree;
+
+ // /////////////////////////////////////////////////////////////////////
+ // pseudo-constructors
+ // /////////////////////////////////////////////////////////////////////
+
+ /**
+ * @return a copy of this GF2nElement
+ */
+ public abstract Object clone();
+
+ // /////////////////////////////////////////////////////////////////////
+ // assignments
+ // /////////////////////////////////////////////////////////////////////
+
+ /**
+ * Assign the value 0 to this element.
+ */
+ abstract void assignZero();
+
+ /**
+ * Assigns the value 1 to this element.
+ */
+ abstract void assignOne();
+
+ // /////////////////////////////////////////////////////////////////////
+ // access
+ // /////////////////////////////////////////////////////////////////////
+
+ /**
+ * Returns whether the rightmost bit of the bit representation is set. This
+ * is needed for data conversion according to 1363.
+ *
+ * @return true if the rightmost bit of this element is set
+ */
+ public abstract boolean testRightmostBit();
+
+ /**
+ * Checks whether the indexed bit of the bit representation is set
+ *
+ * @param index the index of the bit to test
+ * @return true if the indexed bit is set
+ */
+ abstract boolean testBit(int index);
+
+ /**
+ * Returns the field of this element.
+ *
+ * @return the field of this element
+ */
+ public final GF2nField getField()
+ {
+ return mField;
+ }
+
+ // /////////////////////////////////////////////////////////////////////
+ // arithmetic
+ // /////////////////////////////////////////////////////////////////////
+
+ /**
+ * Returns this element + 1.
+ *
+ * @return this + 1
+ */
+ public abstract GF2nElement increase();
+
+ /**
+ * Increases this element by one.
+ */
+ public abstract void increaseThis();
+
+ /**
+ * Compute the difference of this element and minuend.
+ *
+ * @param minuend the minuend
+ * @return this - minuend (newly created)
+ * @throws DifferentFieldsException if the elements are of different fields.
+ */
+ public final GFElement subtract(GFElement minuend)
+ throws RuntimeException
+ {
+ return add(minuend);
+ }
+
+ /**
+ * Compute the difference of this element and minuend,
+ * overwriting this element.
+ *
+ * @param minuend the minuend
+ * @throws DifferentFieldsException if the elements are of different fields.
+ */
+ public final void subtractFromThis(GFElement minuend)
+ {
+ addToThis(minuend);
+ }
+
+ /**
+ * Returns this element to the power of 2.
+ *
+ * @return this2
+ */
+ public abstract GF2nElement square();
+
+ /**
+ * Squares this element.
+ */
+ public abstract void squareThis();
+
+ /**
+ * Compute the square root of this element and return the result in a new
+ * {@link GF2nElement}.
+ *
+ * @return this1/2 (newly created)
+ */
+ public abstract GF2nElement squareRoot();
+
+ /**
+ * Compute the square root of this element.
+ */
+ public abstract void squareRootThis();
+
+ /**
+ * Performs a basis transformation of this element to the given GF2nField
+ * basis.
+ *
+ * @param basis the GF2nField representation to transform this element to
+ * @return this element in the representation of basis
+ * @throws DifferentFieldsException if this cannot be converted according to
+ * basis.
+ */
+ public final GF2nElement convert(GF2nField basis)
+ throws RuntimeException
+ {
+ return mField.convert(this, basis);
+ }
+
+ /**
+ * Returns the trace of this element.
+ *
+ * @return the trace of this element
+ */
+ public abstract int trace();
+
+ /**
+ * Solves a quadratic equation.
+ * Let z2 + z = this. Then this method returns z.
+ *
+ * @return z with z2 + z = this
+ * @throws NoSolutionException if z2 + z = this does not have a
+ * solution
+ */
+ public abstract GF2nElement solveQuadraticEquation()
+ throws RuntimeException;
+
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/math/linearalgebra/GF2nField.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/math/linearalgebra/GF2nField.java
new file mode 100644
index 0000000..315e560
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/math/linearalgebra/GF2nField.java
@@ -0,0 +1,292 @@
+package org.bc.pqc.math.linearalgebra;
+
+
+import java.util.Vector;
+
+
+/**
+ * This abstract class defines the finite field GF(2n). It
+ * holds the extension degree n, the characteristic, the irreducible
+ * fieldpolynomial and conversion matrices. GF2nField is implemented by the
+ * classes GF2nPolynomialField and GF2nONBField.
+ *
+ * @see GF2nONBField
+ * @see GF2nPolynomialField
+ */
+public abstract class GF2nField
+{
+
+ /**
+ * the degree of this field
+ */
+ protected int mDegree;
+
+ /**
+ * the irreducible fieldPolynomial stored in normal order (also for ONB)
+ */
+ protected GF2Polynomial fieldPolynomial;
+
+ /**
+ * holds a list of GF2nFields to which elements have been converted and thus
+ * a COB-Matrix exists
+ */
+ protected Vector fields;
+
+ /**
+ * the COB matrices
+ */
+ protected Vector matrices;
+
+ /**
+ * Returns the degree n of this field.
+ *
+ * @return the degree n of this field
+ */
+ public final int getDegree()
+ {
+ return mDegree;
+ }
+
+ /**
+ * Returns the fieldpolynomial as a new Bitstring.
+ *
+ * @return a copy of the fieldpolynomial as a new Bitstring
+ */
+ public final GF2Polynomial getFieldPolynomial()
+ {
+ if (fieldPolynomial == null)
+ {
+ computeFieldPolynomial();
+ }
+ return new GF2Polynomial(fieldPolynomial);
+ }
+
+ /**
+ * Decides whether the given object other is the same as this
+ * field.
+ *
+ * @param other another object
+ * @return (this == other)
+ */
+ public final boolean equals(Object other)
+ {
+ if (other == null || !(other instanceof GF2nField))
+ {
+ return false;
+ }
+
+ GF2nField otherField = (GF2nField)other;
+
+ if (otherField.mDegree != mDegree)
+ {
+ return false;
+ }
+ if (!fieldPolynomial.equals(otherField.fieldPolynomial))
+ {
+ return false;
+ }
+ if ((this instanceof GF2nPolynomialField)
+ && !(otherField instanceof GF2nPolynomialField))
+ {
+ return false;
+ }
+ if ((this instanceof GF2nONBField)
+ && !(otherField instanceof GF2nONBField))
+ {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * @return the hash code of this field
+ */
+ public int hashCode()
+ {
+ return mDegree + fieldPolynomial.hashCode();
+ }
+
+ /**
+ * Computes a random root from the given irreducible fieldpolynomial
+ * according to IEEE 1363 algorithm A.5.6. This cal take very long for big
+ * degrees.
+ *
+ * @param B0FieldPolynomial the fieldpolynomial if the other basis as a Bitstring
+ * @return a random root of BOFieldPolynomial in representation according to
+ * this field
+ * @see "P1363 A.5.6, p103f"
+ */
+ protected abstract GF2nElement getRandomRoot(GF2Polynomial B0FieldPolynomial);
+
+ /**
+ * Computes the change-of-basis matrix for basis conversion according to
+ * 1363. The result is stored in the lists fields and matrices.
+ *
+ * @param B1 the GF2nField to convert to
+ * @see "P1363 A.7.3, p111ff"
+ */
+ protected abstract void computeCOBMatrix(GF2nField B1);
+
+ /**
+ * Computes the fieldpolynomial. This can take a long time for big degrees.
+ */
+ protected abstract void computeFieldPolynomial();
+
+ /**
+ * Inverts the given matrix represented as bitstrings.
+ *
+ * @param matrix the matrix to invert as a Bitstring[]
+ * @return matrix^(-1)
+ */
+ protected final GF2Polynomial[] invertMatrix(GF2Polynomial[] matrix)
+ {
+ GF2Polynomial[] a = new GF2Polynomial[matrix.length];
+ GF2Polynomial[] inv = new GF2Polynomial[matrix.length];
+ GF2Polynomial dummy;
+ int i, j;
+ // initialize a as a copy of matrix and inv as E(inheitsmatrix)
+ for (i = 0; i < mDegree; i++)
+ {
+ try
+ {
+ a[i] = new GF2Polynomial(matrix[i]);
+ inv[i] = new GF2Polynomial(mDegree);
+ inv[i].setBit(mDegree - 1 - i);
+ }
+ catch (RuntimeException BDNEExc)
+ {
+ BDNEExc.printStackTrace();
+ }
+ }
+ // construct triangle matrix so that for each a[i] the first i bits are
+ // zero
+ for (i = 0; i < mDegree - 1; i++)
+ {
+ // find column where bit i is set
+ j = i;
+ while ((j < mDegree) && !a[j].testBit(mDegree - 1 - i))
+ {
+ j++;
+ }
+ if (j >= mDegree)
+ {
+ throw new RuntimeException(
+ "GF2nField.invertMatrix: Matrix cannot be inverted!");
+ }
+ if (i != j)
+ { // swap a[i]/a[j] and inv[i]/inv[j]
+ dummy = a[i];
+ a[i] = a[j];
+ a[j] = dummy;
+ dummy = inv[i];
+ inv[i] = inv[j];
+ inv[j] = dummy;
+ }
+ for (j = i + 1; j < mDegree; j++)
+ { // add column i to all columns>i
+ // having their i-th bit set
+ if (a[j].testBit(mDegree - 1 - i))
+ {
+ a[j].addToThis(a[i]);
+ inv[j].addToThis(inv[i]);
+ }
+ }
+ }
+ // construct Einheitsmatrix from a
+ for (i = mDegree - 1; i > 0; i--)
+ {
+ for (j = i - 1; j >= 0; j--)
+ { // eliminate the i-th bit in all
+ // columns < i
+ if (a[j].testBit(mDegree - 1 - i))
+ {
+ a[j].addToThis(a[i]);
+ inv[j].addToThis(inv[i]);
+ }
+ }
+ }
+ return inv;
+ }
+
+ /**
+ * Converts the given element in representation according to this field to a
+ * new element in representation according to B1 using the change-of-basis
+ * matrix calculated by computeCOBMatrix.
+ *
+ * @param elem the GF2nElement to convert
+ * @param basis the basis to convert elem to
+ * @return elem converted to a new element representation
+ * according to basis
+ * @throws DifferentFieldsException if elem cannot be converted according to
+ * basis.
+ * @see GF2nField#computeCOBMatrix
+ * @see GF2nField#getRandomRoot
+ * @see GF2nPolynomial
+ * @see "P1363 A.7 p109ff"
+ */
+ public final GF2nElement convert(GF2nElement elem, GF2nField basis)
+ throws RuntimeException
+ {
+ if (basis == this)
+ {
+ return (GF2nElement)elem.clone();
+ }
+ if (fieldPolynomial.equals(basis.fieldPolynomial))
+ {
+ return (GF2nElement)elem.clone();
+ }
+ if (mDegree != basis.mDegree)
+ {
+ throw new RuntimeException("GF2nField.convert: B1 has a"
+ + " different degree and thus cannot be coverted to!");
+ }
+
+ int i;
+ GF2Polynomial[] COBMatrix;
+ i = fields.indexOf(basis);
+ if (i == -1)
+ {
+ computeCOBMatrix(basis);
+ i = fields.indexOf(basis);
+ }
+ COBMatrix = (GF2Polynomial[])matrices.elementAt(i);
+
+ GF2nElement elemCopy = (GF2nElement)elem.clone();
+ if (elemCopy instanceof GF2nONBElement)
+ {
+ // remember: ONB treats its bits in reverse order
+ ((GF2nONBElement)elemCopy).reverseOrder();
+ }
+ GF2Polynomial bs = new GF2Polynomial(mDegree, elemCopy.toFlexiBigInt());
+ bs.expandN(mDegree);
+ GF2Polynomial result = new GF2Polynomial(mDegree);
+ for (i = 0; i < mDegree; i++)
+ {
+ if (bs.vectorMult(COBMatrix[i]))
+ {
+ result.setBit(mDegree - 1 - i);
+ }
+ }
+ if (basis instanceof GF2nPolynomialField)
+ {
+ return new GF2nPolynomialElement((GF2nPolynomialField)basis,
+ result);
+ }
+ else if (basis instanceof GF2nONBField)
+ {
+ GF2nONBElement res = new GF2nONBElement((GF2nONBField)basis,
+ result.toFlexiBigInt());
+ // TODO Remember: ONB treats its Bits in reverse order !!!
+ res.reverseOrder();
+ return res;
+ }
+ else
+ {
+ throw new RuntimeException(
+ "GF2nField.convert: B1 must be an instance of "
+ + "GF2nPolynomialField or GF2nONBField!");
+ }
+
+ }
+
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/math/linearalgebra/GF2nONBElement.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/math/linearalgebra/GF2nONBElement.java
new file mode 100644
index 0000000..061393c
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/math/linearalgebra/GF2nONBElement.java
@@ -0,0 +1,1154 @@
+package org.bc.pqc.math.linearalgebra;
+
+
+import java.math.BigInteger;
+import java.util.Random;
+
+/**
+ * This class implements an element of the finite field GF(2n ).
+ * It is represented in an optimal normal basis representation and holds the
+ * pointer mField to its corresponding field.
+ *
+ * @see GF2nField
+ * @see GF2nElement
+ */
+public class GF2nONBElement
+ extends GF2nElement
+{
+
+ // /////////////////////////////////////////////////////////////////////
+ // member variables
+ // /////////////////////////////////////////////////////////////////////
+
+ private static final long[] mBitmask = new long[]{0x0000000000000001L,
+ 0x0000000000000002L, 0x0000000000000004L, 0x0000000000000008L,
+ 0x0000000000000010L, 0x0000000000000020L, 0x0000000000000040L,
+ 0x0000000000000080L, 0x0000000000000100L, 0x0000000000000200L,
+ 0x0000000000000400L, 0x0000000000000800L, 0x0000000000001000L,
+ 0x0000000000002000L, 0x0000000000004000L, 0x0000000000008000L,
+ 0x0000000000010000L, 0x0000000000020000L, 0x0000000000040000L,
+ 0x0000000000080000L, 0x0000000000100000L, 0x0000000000200000L,
+ 0x0000000000400000L, 0x0000000000800000L, 0x0000000001000000L,
+ 0x0000000002000000L, 0x0000000004000000L, 0x0000000008000000L,
+ 0x0000000010000000L, 0x0000000020000000L, 0x0000000040000000L,
+ 0x0000000080000000L, 0x0000000100000000L, 0x0000000200000000L,
+ 0x0000000400000000L, 0x0000000800000000L, 0x0000001000000000L,
+ 0x0000002000000000L, 0x0000004000000000L, 0x0000008000000000L,
+ 0x0000010000000000L, 0x0000020000000000L, 0x0000040000000000L,
+ 0x0000080000000000L, 0x0000100000000000L, 0x0000200000000000L,
+ 0x0000400000000000L, 0x0000800000000000L, 0x0001000000000000L,
+ 0x0002000000000000L, 0x0004000000000000L, 0x0008000000000000L,
+ 0x0010000000000000L, 0x0020000000000000L, 0x0040000000000000L,
+ 0x0080000000000000L, 0x0100000000000000L, 0x0200000000000000L,
+ 0x0400000000000000L, 0x0800000000000000L, 0x1000000000000000L,
+ 0x2000000000000000L, 0x4000000000000000L, 0x8000000000000000L};
+
+ private static final long[] mMaxmask = new long[]{0x0000000000000001L,
+ 0x0000000000000003L, 0x0000000000000007L, 0x000000000000000FL,
+ 0x000000000000001FL, 0x000000000000003FL, 0x000000000000007FL,
+ 0x00000000000000FFL, 0x00000000000001FFL, 0x00000000000003FFL,
+ 0x00000000000007FFL, 0x0000000000000FFFL, 0x0000000000001FFFL,
+ 0x0000000000003FFFL, 0x0000000000007FFFL, 0x000000000000FFFFL,
+ 0x000000000001FFFFL, 0x000000000003FFFFL, 0x000000000007FFFFL,
+ 0x00000000000FFFFFL, 0x00000000001FFFFFL, 0x00000000003FFFFFL,
+ 0x00000000007FFFFFL, 0x0000000000FFFFFFL, 0x0000000001FFFFFFL,
+ 0x0000000003FFFFFFL, 0x0000000007FFFFFFL, 0x000000000FFFFFFFL,
+ 0x000000001FFFFFFFL, 0x000000003FFFFFFFL, 0x000000007FFFFFFFL,
+ 0x00000000FFFFFFFFL, 0x00000001FFFFFFFFL, 0x00000003FFFFFFFFL,
+ 0x00000007FFFFFFFFL, 0x0000000FFFFFFFFFL, 0x0000001FFFFFFFFFL,
+ 0x0000003FFFFFFFFFL, 0x0000007FFFFFFFFFL, 0x000000FFFFFFFFFFL,
+ 0x000001FFFFFFFFFFL, 0x000003FFFFFFFFFFL, 0x000007FFFFFFFFFFL,
+ 0x00000FFFFFFFFFFFL, 0x00001FFFFFFFFFFFL, 0x00003FFFFFFFFFFFL,
+ 0x00007FFFFFFFFFFFL, 0x0000FFFFFFFFFFFFL, 0x0001FFFFFFFFFFFFL,
+ 0x0003FFFFFFFFFFFFL, 0x0007FFFFFFFFFFFFL, 0x000FFFFFFFFFFFFFL,
+ 0x001FFFFFFFFFFFFFL, 0x003FFFFFFFFFFFFFL, 0x007FFFFFFFFFFFFFL,
+ 0x00FFFFFFFFFFFFFFL, 0x01FFFFFFFFFFFFFFL, 0x03FFFFFFFFFFFFFFL,
+ 0x07FFFFFFFFFFFFFFL, 0x0FFFFFFFFFFFFFFFL, 0x1FFFFFFFFFFFFFFFL,
+ 0x3FFFFFFFFFFFFFFFL, 0x7FFFFFFFFFFFFFFFL, 0xFFFFFFFFFFFFFFFFL};
+
+ // mIBy64[j * 16 + i] = (j * 16 + i)/64
+ // i =
+ // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
+ //
+ private static final int[] mIBY64 = new int[]{
+ // j =
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 8
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 9
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 10
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 11
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 12
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 13
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 14
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 15
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, // 16
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, // 17
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, // 18
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, // 19
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, // 20
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, // 21
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, // 22
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 // 23
+ };
+
+ private static final int MAXLONG = 64;
+
+ /**
+ * holds the lenght of the polynomial with 64 bit sized fields.
+ */
+ private int mLength;
+
+ /**
+ * holds the value of mDeg % MAXLONG.
+ */
+ private int mBit;
+
+ /**
+ * holds this element in ONB representation.
+ */
+ private long[] mPol;
+
+ // /////////////////////////////////////////////////////////////////////
+ // constructors
+ // /////////////////////////////////////////////////////////////////////
+
+ /**
+ * Construct a random element over the field gf2n, using the
+ * specified source of randomness.
+ *
+ * @param gf2n the field
+ * @param rand the source of randomness
+ */
+ public GF2nONBElement(GF2nONBField gf2n, Random rand)
+ {
+ mField = gf2n;
+ mDegree = mField.getDegree();
+ mLength = gf2n.getONBLength();
+ mBit = gf2n.getONBBit();
+ mPol = new long[mLength];
+ if (mLength > 1)
+ {
+ for (int j = 0; j < mLength - 1; j++)
+ {
+ mPol[j] = rand.nextLong();
+ }
+ long last = rand.nextLong();
+ mPol[mLength - 1] = last >>> (MAXLONG - mBit);
+ }
+ else
+ {
+ mPol[0] = rand.nextLong();
+ mPol[0] = mPol[0] >>> (MAXLONG - mBit);
+ }
+ }
+
+ /**
+ * Construct a new GF2nONBElement from its encoding.
+ *
+ * @param gf2n the field
+ * @param e the encoded element
+ */
+ public GF2nONBElement(GF2nONBField gf2n, byte[] e)
+ {
+ mField = gf2n;
+ mDegree = mField.getDegree();
+ mLength = gf2n.getONBLength();
+ mBit = gf2n.getONBBit();
+ mPol = new long[mLength];
+ assign(e);
+ }
+
+ /**
+ * Construct the element of the field gf2n with the specified
+ * value val.
+ *
+ * @param gf2n the field
+ * @param val the value represented by a BigInteger
+ */
+ public GF2nONBElement(GF2nONBField gf2n, BigInteger val)
+ {
+ mField = gf2n;
+ mDegree = mField.getDegree();
+ mLength = gf2n.getONBLength();
+ mBit = gf2n.getONBBit();
+ mPol = new long[mLength];
+ assign(val);
+ }
+
+ /**
+ * Construct the element of the field gf2n with the specified
+ * value val.
+ *
+ * @param gf2n the field
+ * @param val the value in ONB representation
+ */
+ private GF2nONBElement(GF2nONBField gf2n, long[] val)
+ {
+ mField = gf2n;
+ mDegree = mField.getDegree();
+ mLength = gf2n.getONBLength();
+ mBit = gf2n.getONBBit();
+ mPol = val;
+ }
+
+ // /////////////////////////////////////////////////////////////////////
+ // pseudo-constructors
+ // /////////////////////////////////////////////////////////////////////
+
+ /**
+ * Copy constructor.
+ *
+ * @param gf2n the field
+ */
+ public GF2nONBElement(GF2nONBElement gf2n)
+ {
+
+ mField = gf2n.mField;
+ mDegree = mField.getDegree();
+ mLength = ((GF2nONBField)mField).getONBLength();
+ mBit = ((GF2nONBField)mField).getONBBit();
+ mPol = new long[mLength];
+ assign(gf2n.getElement());
+ }
+
+ /**
+ * Create a new GF2nONBElement by cloning this GF2nPolynomialElement.
+ *
+ * @return a copy of this element
+ */
+ public Object clone()
+ {
+ return new GF2nONBElement(this);
+ }
+
+ /**
+ * Create the zero element.
+ *
+ * @param gf2n the finite field
+ * @return the zero element in the given finite field
+ */
+ public static GF2nONBElement ZERO(GF2nONBField gf2n)
+ {
+ long[] polynomial = new long[gf2n.getONBLength()];
+ return new GF2nONBElement(gf2n, polynomial);
+ }
+
+ /**
+ * Create the one element.
+ *
+ * @param gf2n the finite field
+ * @return the one element in the given finite field
+ */
+ public static GF2nONBElement ONE(GF2nONBField gf2n)
+ {
+ int mLength = gf2n.getONBLength();
+ long[] polynomial = new long[mLength];
+
+ // fill mDegree coefficients with one's
+ for (int i = 0; i < mLength - 1; i++)
+ {
+ polynomial[i] = 0xffffffffffffffffL;
+ }
+ polynomial[mLength - 1] = mMaxmask[gf2n.getONBBit() - 1];
+
+ return new GF2nONBElement(gf2n, polynomial);
+ }
+
+ // /////////////////////////////////////////////////////////////////////
+ // assignments
+ // /////////////////////////////////////////////////////////////////////
+
+ /**
+ * assigns to this element the zero element
+ */
+ void assignZero()
+ {
+ mPol = new long[mLength];
+ }
+
+ /**
+ * assigns to this element the one element
+ */
+ void assignOne()
+ {
+ // fill mDegree coefficients with one's
+ for (int i = 0; i < mLength - 1; i++)
+ {
+ mPol[i] = 0xffffffffffffffffL;
+ }
+ mPol[mLength - 1] = mMaxmask[mBit - 1];
+ }
+
+ /**
+ * assigns to this element the value val.
+ *
+ * @param val the value represented by a BigInteger
+ */
+ private void assign(BigInteger val)
+ {
+ assign(val.toByteArray());
+ }
+
+ /**
+ * assigns to this element the value val.
+ *
+ * @param val the value in ONB representation
+ */
+ private void assign(long[] val)
+ {
+ System.arraycopy(val, 0, mPol, 0, mLength);
+ }
+
+ /**
+ * assigns to this element the value val. First: inverting the
+ * order of val into reversed[]. That means: reversed[0] = val[length - 1],
+ * ..., reversed[reversed.length - 1] = val[0]. Second: mPol[0] = sum{i = 0,
+ * ... 7} (val[i]<<(i*8)) .... mPol[1] = sum{i = 8, ... 15} (val[i]<<(i*8))
+ *
+ * @param val the value in ONB representation
+ */
+ private void assign(byte[] val)
+ {
+ int j;
+ mPol = new long[mLength];
+ for (j = 0; j < val.length; j++)
+ {
+ mPol[j >>> 3] |= (val[val.length - 1 - j] & 0x00000000000000ffL) << ((j & 0x07) << 3);
+ }
+ }
+
+ // /////////////////////////////////////////////////////////////////
+ // comparison
+ // /////////////////////////////////////////////////////////////////
+
+ /**
+ * Checks whether this element is zero.
+ *
+ * @return true if this is the zero element
+ */
+ public boolean isZero()
+ {
+
+ boolean result = true;
+
+ for (int i = 0; i < mLength && result; i++)
+ {
+ result = result && ((mPol[i] & 0xFFFFFFFFFFFFFFFFL) == 0);
+ }
+
+ return result;
+ }
+
+ /**
+ * Checks whether this element is one.
+ *
+ * @return true if this is the one element
+ */
+ public boolean isOne()
+ {
+
+ boolean result = true;
+
+ for (int i = 0; i < mLength - 1 && result; i++)
+ {
+ result = result
+ && ((mPol[i] & 0xFFFFFFFFFFFFFFFFL) == 0xFFFFFFFFFFFFFFFFL);
+ }
+
+ if (result)
+ {
+ result = result
+ && ((mPol[mLength - 1] & mMaxmask[mBit - 1]) == mMaxmask[mBit - 1]);
+ }
+
+ return result;
+ }
+
+ /**
+ * Compare this element with another object.
+ *
+ * @param other the other object
+ * @return true if the two objects are equal, false
+ * otherwise
+ */
+ public boolean equals(Object other)
+ {
+ if (other == null || !(other instanceof GF2nONBElement))
+ {
+ return false;
+ }
+
+ GF2nONBElement otherElem = (GF2nONBElement)other;
+
+ for (int i = 0; i < mLength; i++)
+ {
+ if (mPol[i] != otherElem.mPol[i])
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * @return the hash code of this element
+ */
+ public int hashCode()
+ {
+ return mPol.hashCode();
+ }
+
+ // /////////////////////////////////////////////////////////////////////
+ // access
+ // /////////////////////////////////////////////////////////////////////
+
+ /**
+ * Returns whether the highest bit of the bit representation is set
+ *
+ * @return true, if the highest bit of mPol is set, false, otherwise
+ */
+ public boolean testRightmostBit()
+ {
+ // due to the reverse bit order (compared to 1363) this method returns
+ // the value of the leftmost bit
+ return (mPol[mLength - 1] & mBitmask[mBit - 1]) != 0L;
+ }
+
+ /**
+ * Checks whether the indexed bit of the bit representation is set. Warning:
+ * GF2nONBElement currently stores its bits in reverse order (compared to
+ * 1363) !!!
+ *
+ * @param index the index of the bit to test
+ * @return true if the indexed bit of mPol is set, false
+ * otherwise.
+ */
+ boolean testBit(int index)
+ {
+ if (index < 0 || index > mDegree)
+ {
+ return false;
+ }
+ long test = mPol[index >>> 6] & mBitmask[index & 0x3f];
+ return test != 0x0L;
+ }
+
+ /**
+ * @return this element in its ONB representation
+ */
+ private long[] getElement()
+ {
+
+ long[] result = new long[mPol.length];
+ System.arraycopy(mPol, 0, result, 0, mPol.length);
+
+ return result;
+ }
+
+ /**
+ * Returns the ONB representation of this element. The Bit-Order is
+ * exchanged (according to 1363)!
+ *
+ * @return this element in its representation and reverse bit-order
+ */
+ private long[] getElementReverseOrder()
+ {
+ long[] result = new long[mPol.length];
+ for (int i = 0; i < mDegree; i++)
+ {
+ if (testBit(mDegree - i - 1))
+ {
+ result[i >>> 6] |= mBitmask[i & 0x3f];
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Reverses the bit-order in this element(according to 1363). This is a
+ * hack!
+ */
+ void reverseOrder()
+ {
+ mPol = getElementReverseOrder();
+ }
+
+ // /////////////////////////////////////////////////////////////////////
+ // arithmetic
+ // /////////////////////////////////////////////////////////////////////
+
+ /**
+ * Compute the sum of this element and addend.
+ *
+ * @param addend the addend
+ * @return this + other (newly created)
+ * @throws DifferentFieldsException if the elements are of different fields.
+ */
+ public GFElement add(GFElement addend)
+ throws RuntimeException
+ {
+ GF2nONBElement result = new GF2nONBElement(this);
+ result.addToThis(addend);
+ return result;
+ }
+
+ /**
+ * Compute this + addend (overwrite this).
+ *
+ * @param addend the addend
+ * @throws DifferentFieldsException if the elements are of different fields.
+ */
+ public void addToThis(GFElement addend)
+ throws RuntimeException
+ {
+ if (!(addend instanceof GF2nONBElement))
+ {
+ throw new RuntimeException();
+ }
+ if (!mField.equals(((GF2nONBElement)addend).mField))
+ {
+ throw new RuntimeException();
+ }
+
+ for (int i = 0; i < mLength; i++)
+ {
+ mPol[i] ^= ((GF2nONBElement)addend).mPol[i];
+ }
+ }
+
+ /**
+ * returns this element + 1.
+ *
+ * @return this + 1
+ */
+ public GF2nElement increase()
+ {
+ GF2nONBElement result = new GF2nONBElement(this);
+ result.increaseThis();
+ return result;
+ }
+
+ /**
+ * increases this element.
+ */
+ public void increaseThis()
+ {
+ addToThis(ONE((GF2nONBField)mField));
+ }
+
+ /**
+ * Compute the product of this element and factor.
+ *
+ * @param factor the factor
+ * @return this * factor (newly created)
+ * @throws DifferentFieldsException if the elements are of different fields.
+ */
+ public GFElement multiply(GFElement factor)
+ throws RuntimeException
+ {
+ GF2nONBElement result = new GF2nONBElement(this);
+ result.multiplyThisBy(factor);
+ return result;
+ }
+
+ /**
+ * Compute this * factor (overwrite this).
+ *
+ * @param factor the factor
+ * @throws DifferentFieldsException if the elements are of different fields.
+ */
+ public void multiplyThisBy(GFElement factor)
+ throws RuntimeException
+ {
+
+ if (!(factor instanceof GF2nONBElement))
+ {
+ throw new RuntimeException("The elements have different"
+ + " representation: not yet" + " implemented");
+ }
+ if (!mField.equals(((GF2nONBElement)factor).mField))
+ {
+ throw new RuntimeException();
+ }
+
+ if (equals(factor))
+ {
+ squareThis();
+ }
+ else
+ {
+
+ long[] a = mPol;
+ long[] b = ((GF2nONBElement)factor).mPol;
+ long[] c = new long[mLength];
+
+ int[][] m = ((GF2nONBField)mField).mMult;
+
+ int degf, degb, s, fielda, fieldb, bita, bitb;
+ degf = mLength - 1;
+ degb = mBit - 1;
+ s = 0;
+
+ long TWOTOMAXLONGM1 = mBitmask[MAXLONG - 1];
+ long TWOTODEGB = mBitmask[degb];
+
+ boolean old, now;
+
+ // the product c of a and b (a*b = c) is calculated in mDegree
+ // cicles
+ // in every cicle one coefficient of c is calculated and stored
+ // k indicates the coefficient
+ //
+ for (int k = 0; k < mDegree; k++)
+ {
+
+ s = 0;
+
+ for (int i = 0; i < mDegree; i++)
+ {
+
+ // fielda = i / MAXLONG
+ //
+ fielda = mIBY64[i];
+
+ // bita = i % MAXLONG
+ //
+ bita = i & (MAXLONG - 1);
+
+ // fieldb = m[i][0] / MAXLONG
+ //
+ fieldb = mIBY64[m[i][0]];
+
+ // bitb = m[i][0] % MAXLONG
+ //
+ bitb = m[i][0] & (MAXLONG - 1);
+
+ if ((a[fielda] & mBitmask[bita]) != 0)
+ {
+
+ if ((b[fieldb] & mBitmask[bitb]) != 0)
+ {
+ s ^= 1;
+ }
+
+ if (m[i][1] != -1)
+ {
+
+ // fieldb = m[i][1] / MAXLONG
+ //
+ fieldb = mIBY64[m[i][1]];
+
+ // bitb = m[i][1] % MAXLONG
+ //
+ bitb = m[i][1] & (MAXLONG - 1);
+
+ if ((b[fieldb] & mBitmask[bitb]) != 0)
+ {
+ s ^= 1;
+ }
+
+ }
+ }
+ }
+ fielda = mIBY64[k];
+ bita = k & (MAXLONG - 1);
+
+ if (s != 0)
+ {
+ c[fielda] ^= mBitmask[bita];
+ }
+
+ // Circular shift of x and y one bit to the right,
+ // respectively.
+
+ if (mLength > 1)
+ {
+
+ // Shift x.
+ //
+ old = (a[degf] & 1) == 1;
+
+ for (int i = degf - 1; i >= 0; i--)
+ {
+ now = (a[i] & 1) != 0;
+
+ a[i] = a[i] >>> 1;
+
+ if (old)
+ {
+ a[i] ^= TWOTOMAXLONGM1;
+ }
+
+ old = now;
+ }
+ a[degf] = a[degf] >>> 1;
+
+ if (old)
+ {
+ a[degf] ^= TWOTODEGB;
+ }
+
+ // Shift y.
+ //
+ old = (b[degf] & 1) == 1;
+
+ for (int i = degf - 1; i >= 0; i--)
+ {
+ now = (b[i] & 1) != 0;
+
+ b[i] = b[i] >>> 1;
+
+ if (old)
+ {
+ b[i] ^= TWOTOMAXLONGM1;
+ }
+
+ old = now;
+ }
+
+ b[degf] = b[degf] >>> 1;
+
+ if (old)
+ {
+ b[degf] ^= TWOTODEGB;
+ }
+ }
+ else
+ {
+ old = (a[0] & 1) == 1;
+ a[0] = a[0] >>> 1;
+
+ if (old)
+ {
+ a[0] ^= TWOTODEGB;
+ }
+
+ old = (b[0] & 1) == 1;
+ b[0] = b[0] >>> 1;
+
+ if (old)
+ {
+ b[0] ^= TWOTODEGB;
+ }
+ }
+ }
+ assign(c);
+ }
+ }
+
+ /**
+ * returns this element to the power of 2.
+ *
+ * @return this2
+ */
+ public GF2nElement square()
+ {
+ GF2nONBElement result = new GF2nONBElement(this);
+ result.squareThis();
+ return result;
+ }
+
+ /**
+ * squares this element.
+ */
+ public void squareThis()
+ {
+
+ long[] pol = getElement();
+
+ int f = mLength - 1;
+ int b = mBit - 1;
+
+ // Shift the coefficients one bit to the left.
+ //
+ long TWOTOMAXLONGM1 = mBitmask[MAXLONG - 1];
+ boolean old, now;
+
+ old = (pol[f] & mBitmask[b]) != 0;
+
+ for (int i = 0; i < f; i++)
+ {
+
+ now = (pol[i] & TWOTOMAXLONGM1) != 0;
+
+ pol[i] = pol[i] << 1;
+
+ if (old)
+ {
+ pol[i] ^= 1;
+ }
+
+ old = now;
+ }
+ now = (pol[f] & mBitmask[b]) != 0;
+
+ pol[f] = pol[f] << 1;
+
+ if (old)
+ {
+ pol[f] ^= 1;
+ }
+
+ // Set the bit with index mDegree to zero.
+ //
+ if (now)
+ {
+ pol[f] ^= mBitmask[b + 1];
+ }
+
+ assign(pol);
+ }
+
+ /**
+ * Compute the multiplicative inverse of this element.
+ *
+ * @return this-1 (newly created)
+ * @throws ArithmeticException if this is the zero element.
+ */
+ public GFElement invert()
+ throws ArithmeticException
+ {
+ GF2nONBElement result = new GF2nONBElement(this);
+ result.invertThis();
+ return result;
+ }
+
+ /**
+ * Multiplicatively invert of this element (overwrite this).
+ *
+ * @throws ArithmeticException if this is the zero element.
+ */
+ public void invertThis()
+ throws ArithmeticException
+ {
+
+ if (isZero())
+ {
+ throw new ArithmeticException();
+ }
+ int r = 31; // mDegree kann nur 31 Bits lang sein!!!
+
+ // Bitlaenge von mDegree:
+ for (boolean found = false; !found && r >= 0; r--)
+ {
+
+ if (((mDegree - 1) & mBitmask[r]) != 0)
+ {
+ found = true;
+ }
+ }
+ r++;
+
+ GF2nElement m = ZERO((GF2nONBField)mField);
+ GF2nElement n = new GF2nONBElement(this);
+
+ int k = 1;
+
+ for (int i = r - 1; i >= 0; i--)
+ {
+ m = (GF2nElement)n.clone();
+ for (int j = 1; j <= k; j++)
+ {
+ m.squareThis();
+ }
+
+ n.multiplyThisBy(m);
+
+ k <<= 1;
+ if (((mDegree - 1) & mBitmask[i]) != 0)
+ {
+ n.squareThis();
+
+ n.multiplyThisBy(this);
+
+ k++;
+ }
+ }
+ n.squareThis();
+ }
+
+ /**
+ * returns the root ofthis element.
+ *
+ * @return this1/2
+ */
+ public GF2nElement squareRoot()
+ {
+ GF2nONBElement result = new GF2nONBElement(this);
+ result.squareRootThis();
+ return result;
+ }
+
+ /**
+ * square roots this element.
+ */
+ public void squareRootThis()
+ {
+
+ long[] pol = getElement();
+
+ int f = mLength - 1;
+ int b = mBit - 1;
+
+ // Shift the coefficients one bit to the right.
+ //
+ long TWOTOMAXLONGM1 = mBitmask[MAXLONG - 1];
+ boolean old, now;
+
+ old = (pol[0] & 1) != 0;
+
+ for (int i = f; i >= 0; i--)
+ {
+ now = (pol[i] & 1) != 0;
+ pol[i] = pol[i] >>> 1;
+
+ if (old)
+ {
+ if (i == f)
+ {
+ pol[i] ^= mBitmask[b];
+ }
+ else
+ {
+ pol[i] ^= TWOTOMAXLONGM1;
+ }
+ }
+ old = now;
+ }
+ assign(pol);
+ }
+
+ /**
+ * Returns the trace of this element.
+ *
+ * @return the trace of this element
+ */
+ public int trace()
+ {
+
+ // trace = sum of coefficients
+ //
+
+ int result = 0;
+
+ int max = mLength - 1;
+
+ for (int i = 0; i < max; i++)
+ {
+
+ for (int j = 0; j < MAXLONG; j++)
+ {
+
+ if ((mPol[i] & mBitmask[j]) != 0)
+ {
+ result ^= 1;
+ }
+ }
+ }
+
+ int b = mBit;
+
+ for (int j = 0; j < b; j++)
+ {
+
+ if ((mPol[max] & mBitmask[j]) != 0)
+ {
+ result ^= 1;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Solves a quadratic equation.
+ * Let z2 + z = this. Then this method returns z.
+ *
+ * @return z with z2 + z = this
+ * @throws NoSolutionException if z2 + z = this does not have a
+ * solution
+ */
+ public GF2nElement solveQuadraticEquation()
+ throws RuntimeException
+ {
+
+ if (trace() == 1)
+ {
+ throw new RuntimeException();
+ }
+
+ long TWOTOMAXLONGM1 = mBitmask[MAXLONG - 1];
+ long ZERO = 0L;
+ long ONE = 1L;
+
+ long[] p = new long[mLength];
+ long z = 0L;
+ int j = 1;
+ for (int i = 0; i < mLength - 1; i++)
+ {
+
+ for (j = 1; j < MAXLONG; j++)
+ {
+
+ //
+ if (!((((mBitmask[j] & mPol[i]) != ZERO) && ((z & mBitmask[j - 1]) != ZERO)) || (((mPol[i] & mBitmask[j]) == ZERO) && ((z & mBitmask[j - 1]) == ZERO))))
+ {
+ z ^= mBitmask[j];
+ }
+ }
+ p[i] = z;
+
+ if (((TWOTOMAXLONGM1 & z) != ZERO && (ONE & mPol[i + 1]) == ONE)
+ || ((TWOTOMAXLONGM1 & z) == ZERO && (ONE & mPol[i + 1]) == ZERO))
+ {
+ z = ZERO;
+ }
+ else
+ {
+ z = ONE;
+ }
+ }
+
+ int b = mDegree & (MAXLONG - 1);
+
+ long LASTLONG = mPol[mLength - 1];
+
+ for (j = 1; j < b; j++)
+ {
+ if (!((((mBitmask[j] & LASTLONG) != ZERO) && ((mBitmask[j - 1] & z) != ZERO)) || (((mBitmask[j] & LASTLONG) == ZERO) && ((mBitmask[j - 1] & z) == ZERO))))
+ {
+ z ^= mBitmask[j];
+ }
+ }
+ p[mLength - 1] = z;
+ return new GF2nONBElement((GF2nONBField)mField, p);
+ }
+
+ // /////////////////////////////////////////////////////////////////
+ // conversion
+ // /////////////////////////////////////////////////////////////////
+
+ /**
+ * Returns a String representation of this element.
+ *
+ * @return String representation of this element with the specified radix
+ */
+ public String toString()
+ {
+ return toString(16);
+ }
+
+ /**
+ * Returns a String representation of this element. radix
+ * specifies the radix of the String representation.
+ * NOTE: ONLY radix = 2 or radix = 16 IS IMPLEMENTED>
+ *
+ * @param radix specifies the radix of the String representation
+ * @return String representation of this element with the specified radix
+ */
+ public String toString(int radix)
+ {
+ String s = "";
+
+ long[] a = getElement();
+ int b = mBit;
+
+ if (radix == 2)
+ {
+
+ for (int j = b - 1; j >= 0; j--)
+ {
+ if ((a[a.length - 1] & ((long)1 << j)) == 0)
+ {
+ s += "0";
+ }
+ else
+ {
+ s += "1";
+ }
+ }
+
+ for (int i = a.length - 2; i >= 0; i--)
+ {
+ for (int j = MAXLONG - 1; j >= 0; j--)
+ {
+ if ((a[i] & mBitmask[j]) == 0)
+ {
+ s += "0";
+ }
+ else
+ {
+ s += "1";
+ }
+ }
+ }
+ }
+ else if (radix == 16)
+ {
+ final char[] HEX_CHARS = {'0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
+ for (int i = a.length - 1; i >= 0; i--)
+ {
+ s += HEX_CHARS[(int)(a[i] >>> 60) & 0x0f];
+ s += HEX_CHARS[(int)(a[i] >>> 56) & 0x0f];
+ s += HEX_CHARS[(int)(a[i] >>> 52) & 0x0f];
+ s += HEX_CHARS[(int)(a[i] >>> 48) & 0x0f];
+ s += HEX_CHARS[(int)(a[i] >>> 44) & 0x0f];
+ s += HEX_CHARS[(int)(a[i] >>> 40) & 0x0f];
+ s += HEX_CHARS[(int)(a[i] >>> 36) & 0x0f];
+ s += HEX_CHARS[(int)(a[i] >>> 32) & 0x0f];
+ s += HEX_CHARS[(int)(a[i] >>> 28) & 0x0f];
+ s += HEX_CHARS[(int)(a[i] >>> 24) & 0x0f];
+ s += HEX_CHARS[(int)(a[i] >>> 20) & 0x0f];
+ s += HEX_CHARS[(int)(a[i] >>> 16) & 0x0f];
+ s += HEX_CHARS[(int)(a[i] >>> 12) & 0x0f];
+ s += HEX_CHARS[(int)(a[i] >>> 8) & 0x0f];
+ s += HEX_CHARS[(int)(a[i] >>> 4) & 0x0f];
+ s += HEX_CHARS[(int)(a[i]) & 0x0f];
+ s += " ";
+ }
+ }
+ return s;
+ }
+
+ /**
+ * Returns this element as FlexiBigInt. The conversion is P1363-conform.
+ *
+ * @return this element as BigInteger
+ */
+ public BigInteger toFlexiBigInt()
+ {
+ /** @todo this method does not reverse the bit-order as it should!!! */
+
+ return new BigInteger(1, toByteArray());
+ }
+
+ /**
+ * Returns this element as byte array. The conversion is P1363-conform.
+ *
+ * @return this element as byte array
+ */
+ public byte[] toByteArray()
+ {
+ /** @todo this method does not reverse the bit-order as it should!!! */
+
+ int k = ((mDegree - 1) >> 3) + 1;
+ byte[] result = new byte[k];
+ int i;
+ for (i = 0; i < k; i++)
+ {
+ result[k - i - 1] = (byte)((mPol[i >>> 3] & (0x00000000000000ffL << ((i & 0x07) << 3))) >>> ((i & 0x07) << 3));
+ }
+ return result;
+ }
+
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/math/linearalgebra/GF2nONBField.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/math/linearalgebra/GF2nONBField.java
new file mode 100644
index 0000000..d63adf1
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/math/linearalgebra/GF2nONBField.java
@@ -0,0 +1,546 @@
+package org.bc.pqc.math.linearalgebra;
+
+
+import java.util.Random;
+import java.util.Vector;
+
+
+/**
+ * This class implements the abstract class GF2nField for ONB
+ * representation. It computes the fieldpolynomial, multiplication matrix and
+ * one of its roots mONBRoot, (see for example Certicoms Whitepapers).
+ * GF2nField is used by GF2nONBElement which implements the elements of this
+ * field.
+ *
+ * @see GF2nField
+ * @see GF2nONBElement
+ */
+public class GF2nONBField
+ extends GF2nField
+{
+
+ // ///////////////////////////////////////////////////////////////////
+ // Hashtable for irreducible normal polynomials //
+ // ///////////////////////////////////////////////////////////////////
+
+ // i*5 + 0 i*5 + 1 i*5 + 2 i*5 + 3 i*5 + 4
+ /*
+ * private static int[][] mNB = {{0, 0, 0}, {0, 0, 0}, {1, 0, 0}, {1, 0, 0},
+ * {1, 0, 0}, // i = 0 {2, 0, 0}, {1, 0, 0}, {1, 0, 0}, {4, 3, 1}, {1, 0,
+ * 0}, // i = 1 {3, 0, 0}, {2, 0, 0}, {3, 0, 0}, {4, 3, 1}, {5, 0, 0}, // i =
+ * 2 {1, 0, 0}, {5, 3, 1}, {3, 0, 0}, {3, 0, 0}, {5, 2, 1}, // i = 3 {3, 0,
+ * 0}, {2, 0, 0}, {1, 0, 0}, {5, 0, 0}, {4, 3, 1}, // i = 4 {3, 0, 0}, {4,
+ * 3, 1}, {5, 2, 1}, {1, 0, 0}, {2, 0, 0}, // i = 5 {1, 0, 0}, {3, 0, 0},
+ * {7, 3, 2}, {10, 0, 0}, {7, 0, 0}, // i = 6 {2, 0, 0}, {9, 0, 0}, {6, 4,
+ * 1}, {6, 5, 1}, {4, 0, 0}, // i = 7 {5, 4, 3}, {3, 0, 0}, {7, 0, 0}, {6,
+ * 4, 3}, {5, 0, 0}, // i = 8 {4, 3, 1}, {1, 0, 0}, {5, 0, 0}, {5, 3, 2},
+ * {9, 0, 0}, // i = 9 {4, 3, 2}, {6, 3, 1}, {3, 0, 0}, {6, 2, 1}, {9, 0,
+ * 0}, // i = 10 {7, 0, 0}, {7, 4, 2}, {4, 0, 0}, {19, 0, 0}, {7, 4, 2}, //
+ * i = 11 {1, 0, 0}, {5, 2, 1}, {29, 0, 0}, {1, 0, 0}, {4, 3, 1}, // i = 12
+ * {18, 0, 0}, {3, 0, 0}, {5, 2, 1}, {9, 0, 0}, {6, 5, 2}, // i = 13 {5, 3,
+ * 1}, {6, 0, 0}, {10, 9, 3}, {25, 0, 0}, {35, 0, 0}, // i = 14 {6, 3, 1},
+ * {21, 0, 0}, {6, 5, 2}, {6, 5, 3}, {9, 0, 0}, // i = 15 {9, 4, 2}, {4, 0,
+ * 0}, {8, 3, 1}, {7, 4, 2}, {5, 0, 0}, // i = 16 {8, 2, 1}, {21, 0, 0},
+ * {13, 0, 0}, {7, 6, 2}, {38, 0, 0}, // i = 17 {27, 0, 0}, {8, 5, 1}, {21,
+ * 0, 0}, {2, 0, 0}, {21, 0, 0}, // i = 18 {11, 0, 0}, {10, 9, 6}, {6, 0,
+ * 0}, {11, 0, 0}, {6, 3, 1}, // i = 19 {15, 0, 0}, {7, 6, 1}, {29, 0, 0},
+ * {9, 0, 0}, {4, 3, 1}, // i = 20 {4, 0, 0}, {15, 0, 0}, {9, 7, 4}, {17, 0,
+ * 0}, {5, 4, 2}, // i = 21 {33, 0, 0}, {10, 0, 0}, {5, 4, 3}, {9, 0, 0},
+ * {5, 3, 2}, // i = 22 {8, 7, 5}, {4, 2, 1}, {5, 2, 1}, {33, 0, 0}, {8, 0,
+ * 0}, // i = 23 {4, 3, 1}, {18, 0, 0}, {6, 2, 1}, {2, 0, 0}, {19, 0, 0}, //
+ * i = 24 {7, 6, 5}, {21, 0, 0}, {1, 0, 0}, {7, 2, 1}, {5, 0, 0}, // i = 25
+ * {3, 0, 0}, {8, 3, 2}, {17, 0, 0}, {9, 8, 2}, {57, 0, 0}, // i = 26 {11,
+ * 0, 0}, {5, 3, 2}, {21, 0, 0}, {8, 7, 1}, {8, 5, 3}, // i = 27 {15, 0, 0},
+ * {10, 4, 1}, {21, 0, 0}, {5, 3, 2}, {7, 4, 2}, // i = 28 {52, 0, 0}, {71,
+ * 0, 0}, {14, 0, 0}, {27, 0, 0}, {10, 9, 7}, // i = 29 {53, 0, 0}, {3, 0,
+ * 0}, {6, 3, 2}, {1, 0, 0}, {15, 0, 0}, // i = 30 {62, 0, 0}, {9, 0, 0},
+ * {6, 5, 2}, {8, 6, 5}, {31, 0, 0}, // i = 31 {5, 3, 2}, {18, 0, 0 }, {27,
+ * 0, 0}, {7, 6, 3}, {10, 8, 7}, // i = 32 {9, 8, 3}, {37, 0, 0}, {6, 0, 0},
+ * {15, 3, 2}, {34, 0, 0}, // i = 33 {11, 0, 0}, {6, 5, 2}, {1, 0, 0}, {8,
+ * 5, 2}, {13, 0, 0}, // i = 34 {6, 0, 0}, {11, 3, 2}, {8, 0, 0}, {31, 0,
+ * 0}, {4, 2, 1}, // i = 35 {3, 0, 0}, {7, 6, 1}, {81, 0, 0}, {56, 0, 0},
+ * {9, 8, 7}, // i = 36 {24, 0, 0}, {11, 0, 0}, {7, 6, 5}, {6, 5, 2}, {6, 5,
+ * 2}, // i = 37 {8, 7, 6}, {9, 0, 0}, {7, 2, 1}, {15, 0, 0}, {87, 0, 0}, //
+ * i = 38 {8, 3, 2}, {3, 0, 0}, {9, 4, 2}, {9, 0, 0}, {34, 0, 0}, // i = 39
+ * {5, 3, 2}, {14, 0, 0}, {55, 0, 0}, {8, 7, 1}, {27, 0, 0}, // i = 40 {9,
+ * 5, 2}, {10, 9, 5}, {43, 0, 0}, {8, 6, 2}, {6, 0, 0}, // i = 41 {7, 0, 0},
+ * {11, 10, 8}, {105, 0, 0}, {6, 5, 2}, {73, 0, 0}}; // i = 42
+ */
+ // /////////////////////////////////////////////////////////////////////
+ // member variables
+ // /////////////////////////////////////////////////////////////////////
+ private static final int MAXLONG = 64;
+
+ /**
+ * holds the length of the array-representation of degree mDegree.
+ */
+ private int mLength;
+
+ /**
+ * holds the number of relevant bits in mONBPol[mLength-1].
+ */
+ private int mBit;
+
+ /**
+ * holds the type of mONB
+ */
+ private int mType;
+
+ /**
+ * holds the multiplication matrix
+ */
+ int[][] mMult;
+
+ // /////////////////////////////////////////////////////////////////////
+ // constructors
+ // /////////////////////////////////////////////////////////////////////
+
+ /**
+ * constructs an instance of the finite field with 2deg
+ * elements and characteristic 2.
+ *
+ * @param deg -
+ * the extention degree of this field
+ * @throws NoSuchBasisException if an ONB-implementation other than type 1 or type 2 is
+ * requested.
+ */
+ public GF2nONBField(int deg)
+ throws RuntimeException
+ {
+ if (deg < 3)
+ {
+ throw new IllegalArgumentException("k must be at least 3");
+ }
+
+ mDegree = deg;
+ mLength = mDegree / MAXLONG;
+ mBit = mDegree & (MAXLONG - 1);
+ if (mBit == 0)
+ {
+ mBit = MAXLONG;
+ }
+ else
+ {
+ mLength++;
+ }
+
+ computeType();
+
+ // only ONB-implementations for type 1 and type 2
+ //
+ if (mType < 3)
+ {
+ mMult = new int[mDegree][2];
+ for (int i = 0; i < mDegree; i++)
+ {
+ mMult[i][0] = -1;
+ mMult[i][1] = -1;
+ }
+ computeMultMatrix();
+ }
+ else
+ {
+ throw new RuntimeException("\nThe type of this field is "
+ + mType);
+ }
+ computeFieldPolynomial();
+ fields = new Vector();
+ matrices = new Vector();
+ }
+
+ // /////////////////////////////////////////////////////////////////////
+ // access
+ // /////////////////////////////////////////////////////////////////////
+
+ int getONBLength()
+ {
+ return mLength;
+ }
+
+ int getONBBit()
+ {
+ return mBit;
+ }
+
+ // /////////////////////////////////////////////////////////////////////
+ // arithmetic
+ // /////////////////////////////////////////////////////////////////////
+
+ /**
+ * Computes a random root of the given polynomial.
+ *
+ * @param polynomial a polynomial
+ * @return a random root of the polynomial
+ * @see "P1363 A.5.6, p103f"
+ */
+ protected GF2nElement getRandomRoot(GF2Polynomial polynomial)
+ {
+ // We are in B1!!!
+ GF2nPolynomial c;
+ GF2nPolynomial ut;
+ GF2nElement u;
+ GF2nPolynomial h;
+ int hDegree;
+ // 1. Set g(t) <- f(t)
+ GF2nPolynomial g = new GF2nPolynomial(polynomial, this);
+ int gDegree = g.getDegree();
+ int i;
+
+ // 2. while deg(g) > 1
+ while (gDegree > 1)
+ {
+ do
+ {
+ // 2.1 choose random u (element of) GF(2^m)
+ u = new GF2nONBElement(this, new Random());
+ ut = new GF2nPolynomial(2, GF2nONBElement.ZERO(this));
+ // 2.2 Set c(t) <- ut
+ ut.set(1, u);
+ c = new GF2nPolynomial(ut);
+ // 2.3 For i from 1 to m-1 do
+ for (i = 1; i <= mDegree - 1; i++)
+ {
+ // 2.3.1 c(t) <- (c(t)^2 + ut) mod g(t)
+ c = c.multiplyAndReduce(c, g);
+ c = c.add(ut);
+ }
+ // 2.4 set h(t) <- GCD(c(t), g(t))
+ h = c.gcd(g);
+ // 2.5 if h(t) is constant or deg(g) = deg(h) then go to
+ // step 2.1
+ hDegree = h.getDegree();
+ gDegree = g.getDegree();
+ }
+ while ((hDegree == 0) || (hDegree == gDegree));
+ // 2.6 If 2deg(h) > deg(g) then set g(t) <- g(t)/h(t) ...
+ if ((hDegree << 1) > gDegree)
+ {
+ g = g.quotient(h);
+ }
+ else
+ {
+ // ... else g(t) <- h(t)
+ g = new GF2nPolynomial(h);
+ }
+ gDegree = g.getDegree();
+ }
+ // 3. Output g(0)
+ return g.at(0);
+
+ }
+
+ /**
+ * Computes the change-of-basis matrix for basis conversion according to
+ * 1363. The result is stored in the lists fields and matrices.
+ *
+ * @param B1 the GF2nField to convert to
+ * @see "P1363 A.7.3, p111ff"
+ */
+ protected void computeCOBMatrix(GF2nField B1)
+ {
+ // we are in B0 here!
+ if (mDegree != B1.mDegree)
+ {
+ throw new IllegalArgumentException(
+ "GF2nField.computeCOBMatrix: B1 has a "
+ + "different degree and thus cannot be coverted to!");
+ }
+ int i, j;
+ GF2nElement[] gamma;
+ GF2nElement u;
+ GF2Polynomial[] COBMatrix = new GF2Polynomial[mDegree];
+ for (i = 0; i < mDegree; i++)
+ {
+ COBMatrix[i] = new GF2Polynomial(mDegree);
+ }
+
+ // find Random Root
+ do
+ {
+ // u is in representation according to B1
+ u = B1.getRandomRoot(fieldPolynomial);
+ }
+ while (u.isZero());
+
+ gamma = new GF2nPolynomialElement[mDegree];
+ // build gamma matrix by squaring
+ gamma[0] = (GF2nElement)u.clone();
+ for (i = 1; i < mDegree; i++)
+ {
+ gamma[i] = gamma[i - 1].square();
+ }
+ // convert horizontal gamma matrix by vertical Bitstrings
+ for (i = 0; i < mDegree; i++)
+ {
+ for (j = 0; j < mDegree; j++)
+ {
+ if (gamma[i].testBit(j))
+ {
+ COBMatrix[mDegree - j - 1].setBit(mDegree - i - 1);
+ }
+ }
+ }
+
+ fields.addElement(B1);
+ matrices.addElement(COBMatrix);
+ B1.fields.addElement(this);
+ B1.matrices.addElement(invertMatrix(COBMatrix));
+ }
+
+ /**
+ * Computes the field polynomial for a ONB according to IEEE 1363 A.7.2
+ * (p110f).
+ *
+ * @see "P1363 A.7.2, p110f"
+ */
+ protected void computeFieldPolynomial()
+ {
+ if (mType == 1)
+ {
+ fieldPolynomial = new GF2Polynomial(mDegree + 1, "ALL");
+ }
+ else if (mType == 2)
+ {
+ // 1. q = 1
+ GF2Polynomial q = new GF2Polynomial(mDegree + 1, "ONE");
+ // 2. p = t+1
+ GF2Polynomial p = new GF2Polynomial(mDegree + 1, "X");
+ p.addToThis(q);
+ GF2Polynomial r;
+ int i;
+ // 3. for i = 1 to (m-1) do
+ for (i = 1; i < mDegree; i++)
+ {
+ // r <- q
+ r = q;
+ // q <- p
+ q = p;
+ // p = tq+r
+ p = q.shiftLeft();
+ p.addToThis(r);
+ }
+ fieldPolynomial = p;
+ }
+ }
+
+ /**
+ * Compute the inverse of a matrix a.
+ *
+ * @param a the matrix
+ * @return a-1
+ */
+ int[][] invMatrix(int[][] a)
+ {
+
+ int[][] A = new int[mDegree][mDegree];
+ A = a;
+ int[][] inv = new int[mDegree][mDegree];
+
+ for (int i = 0; i < mDegree; i++)
+ {
+ inv[i][i] = 1;
+ }
+
+ for (int i = 0; i < mDegree; i++)
+ {
+ for (int j = i; j < mDegree; j++)
+ {
+ A[mDegree - 1 - i][j] = A[i][i];
+ }
+ }
+ return null;
+ }
+
+ private void computeType()
+ throws RuntimeException
+ {
+ if ((mDegree & 7) == 0)
+ {
+ throw new RuntimeException(
+ "The extension degree is divisible by 8!");
+ }
+ // checking for the type
+ int s = 0;
+ int k = 0;
+ mType = 1;
+ for (int d = 0; d != 1; mType++)
+ {
+ s = mType * mDegree + 1;
+ if (IntegerFunctions.isPrime(s))
+ {
+ k = IntegerFunctions.order(2, s);
+ d = IntegerFunctions.gcd(mType * mDegree / k, mDegree);
+ }
+ }
+ mType--;
+ if (mType == 1)
+ {
+ s = (mDegree << 1) + 1;
+ if (IntegerFunctions.isPrime(s))
+ {
+ k = IntegerFunctions.order(2, s);
+ int d = IntegerFunctions.gcd((mDegree << 1) / k, mDegree);
+ if (d == 1)
+ {
+ mType++;
+ }
+ }
+ }
+ }
+
+ private void computeMultMatrix()
+ {
+
+ if ((mType & 7) != 0)
+ {
+ int p = mType * mDegree + 1;
+
+ // compute sequence F[1] ... F[p-1] via A.3.7. of 1363.
+ // F[0] will not be filled!
+ //
+ int[] F = new int[p];
+
+ int u;
+ if (mType == 1)
+ {
+ u = 1;
+ }
+ else if (mType == 2)
+ {
+ u = p - 1;
+ }
+ else
+ {
+ u = elementOfOrder(mType, p);
+ }
+
+ int w = 1;
+ int n;
+ for (int j = 0; j < mType; j++)
+ {
+ n = w;
+
+ for (int i = 0; i < mDegree; i++)
+ {
+ F[n] = i;
+ n = (n << 1) % p;
+ if (n < 0)
+ {
+ n += p;
+ }
+ }
+ w = u * w % p;
+ if (w < 0)
+ {
+ w += p;
+ }
+ }
+
+ // building the matrix (mDegree * 2)
+ //
+ if (mType == 1)
+ {
+ for (int k = 1; k < p - 1; k++)
+ {
+ if (mMult[F[k + 1]][0] == -1)
+ {
+ mMult[F[k + 1]][0] = F[p - k];
+ }
+ else
+ {
+ mMult[F[k + 1]][1] = F[p - k];
+ }
+ }
+
+ int m_2 = mDegree >> 1;
+ for (int k = 1; k <= m_2; k++)
+ {
+
+ if (mMult[k - 1][0] == -1)
+ {
+ mMult[k - 1][0] = m_2 + k - 1;
+ }
+ else
+ {
+ mMult[k - 1][1] = m_2 + k - 1;
+ }
+
+ if (mMult[m_2 + k - 1][0] == -1)
+ {
+ mMult[m_2 + k - 1][0] = k - 1;
+ }
+ else
+ {
+ mMult[m_2 + k - 1][1] = k - 1;
+ }
+ }
+ }
+ else if (mType == 2)
+ {
+ for (int k = 1; k < p - 1; k++)
+ {
+ if (mMult[F[k + 1]][0] == -1)
+ {
+ mMult[F[k + 1]][0] = F[p - k];
+ }
+ else
+ {
+ mMult[F[k + 1]][1] = F[p - k];
+ }
+ }
+ }
+ else
+ {
+ throw new RuntimeException("only type 1 or type 2 implemented");
+ }
+ }
+ else
+ {
+ throw new RuntimeException("bisher nur fuer Gausssche Normalbasen"
+ + " implementiert");
+ }
+ }
+
+ private int elementOfOrder(int k, int p)
+ {
+ Random random = new Random();
+ int m = 0;
+ while (m == 0)
+ {
+ m = random.nextInt();
+ m %= p - 1;
+ if (m < 0)
+ {
+ m += p - 1;
+ }
+ }
+
+ int l = IntegerFunctions.order(m, p);
+
+ while (l % k != 0 || l == 0)
+ {
+ while (m == 0)
+ {
+ m = random.nextInt();
+ m %= p - 1;
+ if (m < 0)
+ {
+ m += p - 1;
+ }
+ }
+ l = IntegerFunctions.order(m, p);
+ }
+ int r = m;
+
+ l = k / l;
+
+ for (int i = 2; i <= l; i++)
+ {
+ r *= m;
+ }
+
+ return r;
+ }
+
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/math/linearalgebra/GF2nPolynomial.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/math/linearalgebra/GF2nPolynomial.java
new file mode 100644
index 0000000..596cf68
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/math/linearalgebra/GF2nPolynomial.java
@@ -0,0 +1,587 @@
+package org.bc.pqc.math.linearalgebra;
+
+
+/**
+ * This class implements polynomials over GF2nElements.
+ *
+ * @see GF2nElement
+ */
+
+public class GF2nPolynomial
+{
+
+ private GF2nElement[] coeff; // keeps the coefficients of this polynomial
+
+ private int size; // the size of this polynomial
+
+ /**
+ * Creates a new PolynomialGF2n of size deg and elem as
+ * coefficients.
+ *
+ * @param deg -
+ * the maximum degree + 1
+ * @param elem -
+ * a GF2nElement
+ */
+ public GF2nPolynomial(int deg, GF2nElement elem)
+ {
+ size = deg;
+ coeff = new GF2nElement[size];
+ for (int i = 0; i < size; i++)
+ {
+ coeff[i] = (GF2nElement)elem.clone();
+ }
+ }
+
+ /**
+ * Creates a new PolynomialGF2n of size deg.
+ *
+ * @param deg the maximum degree + 1
+ */
+ private GF2nPolynomial(int deg)
+ {
+ size = deg;
+ coeff = new GF2nElement[size];
+ }
+
+ /**
+ * Creates a new PolynomialGF2n by cloning the given PolynomialGF2n a.
+ *
+ * @param a the PolynomialGF2n to clone
+ */
+ public GF2nPolynomial(GF2nPolynomial a)
+ {
+ int i;
+ coeff = new GF2nElement[a.size];
+ size = a.size;
+ for (i = 0; i < size; i++)
+ {
+ coeff[i] = (GF2nElement)a.coeff[i].clone();
+ }
+ }
+
+ /**
+ * Creates a new PolynomialGF2n from the given Bitstring polynomial
+ * over the GF2nField B1.
+ *
+ * @param polynomial the Bitstring to use
+ * @param B1 the field
+ */
+ public GF2nPolynomial(GF2Polynomial polynomial, GF2nField B1)
+ {
+ size = B1.getDegree() + 1;
+ coeff = new GF2nElement[size];
+ int i;
+ if (B1 instanceof GF2nONBField)
+ {
+ for (i = 0; i < size; i++)
+ {
+ if (polynomial.testBit(i))
+ {
+ coeff[i] = GF2nONBElement.ONE((GF2nONBField)B1);
+ }
+ else
+ {
+ coeff[i] = GF2nONBElement.ZERO((GF2nONBField)B1);
+ }
+ }
+ }
+ else if (B1 instanceof GF2nPolynomialField)
+ {
+ for (i = 0; i < size; i++)
+ {
+ if (polynomial.testBit(i))
+ {
+ coeff[i] = GF2nPolynomialElement
+ .ONE((GF2nPolynomialField)B1);
+ }
+ else
+ {
+ coeff[i] = GF2nPolynomialElement
+ .ZERO((GF2nPolynomialField)B1);
+ }
+ }
+ }
+ else
+ {
+ throw new IllegalArgumentException(
+ "PolynomialGF2n(Bitstring, GF2nField): B1 must be "
+ + "an instance of GF2nONBField or GF2nPolynomialField!");
+ }
+ }
+
+ public final void assignZeroToElements()
+ {
+ int i;
+ for (i = 0; i < size; i++)
+ {
+ coeff[i].assignZero();
+ }
+ }
+
+ /**
+ * Returns the size (=maximum degree + 1) of this PolynomialGF2n. This is
+ * not the degree, use getDegree instead.
+ *
+ * @return the size (=maximum degree + 1) of this PolynomialGF2n.
+ */
+ public final int size()
+ {
+ return size;
+ }
+
+ /**
+ * Returns the degree of this PolynomialGF2n.
+ *
+ * @return the degree of this PolynomialGF2n.
+ */
+ public final int getDegree()
+ {
+ int i;
+ for (i = size - 1; i >= 0; i--)
+ {
+ if (!coeff[i].isZero())
+ {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Enlarges the size of this PolynomialGF2n to k + 1.
+ *
+ * @param k the new maximum degree
+ */
+ public final void enlarge(int k)
+ {
+ if (k <= size)
+ {
+ return;
+ }
+ int i;
+ GF2nElement[] res = new GF2nElement[k];
+ System.arraycopy(coeff, 0, res, 0, size);
+ GF2nField f = coeff[0].getField();
+ if (coeff[0] instanceof GF2nPolynomialElement)
+ {
+ for (i = size; i < k; i++)
+ {
+ res[i] = GF2nPolynomialElement.ZERO((GF2nPolynomialField)f);
+ }
+ }
+ else if (coeff[0] instanceof GF2nONBElement)
+ {
+ for (i = size; i < k; i++)
+ {
+ res[i] = GF2nONBElement.ZERO((GF2nONBField)f);
+ }
+ }
+ size = k;
+ coeff = res;
+ }
+
+ public final void shrink()
+ {
+ int i = size - 1;
+ while (coeff[i].isZero() && (i > 0))
+ {
+ i--;
+ }
+ i++;
+ if (i < size)
+ {
+ GF2nElement[] res = new GF2nElement[i];
+ System.arraycopy(coeff, 0, res, 0, i);
+ coeff = res;
+ size = i;
+ }
+ }
+
+ /**
+ * Sets the coefficient at index to elem.
+ *
+ * @param index the index
+ * @param elem the GF2nElement to store as coefficient index
+ */
+ public final void set(int index, GF2nElement elem)
+ {
+ if (!(elem instanceof GF2nPolynomialElement)
+ && !(elem instanceof GF2nONBElement))
+ {
+ throw new IllegalArgumentException(
+ "PolynomialGF2n.set f must be an "
+ + "instance of either GF2nPolynomialElement or GF2nONBElement!");
+ }
+ coeff[index] = (GF2nElement)elem.clone();
+ }
+
+ /**
+ * Returns the coefficient at index.
+ *
+ * @param index the index
+ * @return the GF2nElement stored as coefficient index
+ */
+ public final GF2nElement at(int index)
+ {
+ return coeff[index];
+ }
+
+ /**
+ * Returns true if all coefficients equal zero.
+ *
+ * @return true if all coefficients equal zero.
+ */
+ public final boolean isZero()
+ {
+ int i;
+ for (i = 0; i < size; i++)
+ {
+ if (coeff[i] != null)
+ {
+ if (!coeff[i].isZero())
+ {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ public final boolean equals(Object other)
+ {
+ if (other == null || !(other instanceof GF2nPolynomial))
+ {
+ return false;
+ }
+
+ GF2nPolynomial otherPol = (GF2nPolynomial)other;
+
+ if (getDegree() != otherPol.getDegree())
+ {
+ return false;
+ }
+ int i;
+ for (i = 0; i < size; i++)
+ {
+ if (!coeff[i].equals(otherPol.coeff[i]))
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * @return the hash code of this polynomial
+ */
+ public int hashCode()
+ {
+ return getDegree() + coeff.hashCode();
+ }
+
+ /**
+ * Adds the PolynomialGF2n b to this and returns the
+ * result in a new PolynomialGF2n.
+ *
+ * @param b -
+ * the PolynomialGF2n to add
+ * @return this + b
+ * @throws DifferentFieldsException if this and b are not defined over
+ * the same field.
+ */
+ public final GF2nPolynomial add(GF2nPolynomial b)
+ throws RuntimeException
+ {
+ GF2nPolynomial result;
+ if (size() >= b.size())
+ {
+ result = new GF2nPolynomial(size());
+ int i;
+ for (i = 0; i < b.size(); i++)
+ {
+ result.coeff[i] = (GF2nElement)coeff[i].add(b.coeff[i]);
+ }
+ for (; i < size(); i++)
+ {
+ result.coeff[i] = coeff[i];
+ }
+ }
+ else
+ {
+ result = new GF2nPolynomial(b.size());
+ int i;
+ for (i = 0; i < size(); i++)
+ {
+ result.coeff[i] = (GF2nElement)coeff[i].add(b.coeff[i]);
+ }
+ for (; i < b.size(); i++)
+ {
+ result.coeff[i] = b.coeff[i];
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Multiplies the scalar s to each coefficient of this
+ * PolynomialGF2n and returns the result in a new PolynomialGF2n.
+ *
+ * @param s the scalar to multiply
+ * @return this x s
+ * @throws DifferentFieldsException if this and s are not defined over
+ * the same field.
+ */
+ public final GF2nPolynomial scalarMultiply(GF2nElement s)
+ throws RuntimeException
+ {
+ GF2nPolynomial result = new GF2nPolynomial(size());
+ int i;
+ for (i = 0; i < size(); i++)
+ {
+ result.coeff[i] = (GF2nElement)coeff[i].multiply(s); // result[i]
+ // =
+ // a[i]*s
+ }
+ return result;
+ }
+
+ /**
+ * Multiplies this by b and returns the result in a new
+ * PolynomialGF2n.
+ *
+ * @param b the PolynomialGF2n to multiply
+ * @return this * b
+ * @throws DifferentFieldsException if this and b are not defined over
+ * the same field.
+ */
+ public final GF2nPolynomial multiply(GF2nPolynomial b)
+ throws RuntimeException
+ {
+ int i, j;
+ int aDegree = size();
+ int bDegree = b.size();
+ if (aDegree != bDegree)
+ {
+ throw new IllegalArgumentException(
+ "PolynomialGF2n.multiply: this and b must "
+ + "have the same size!");
+ }
+ GF2nPolynomial result = new GF2nPolynomial((aDegree << 1) - 1);
+ for (i = 0; i < size(); i++)
+ {
+ for (j = 0; j < b.size(); j++)
+ {
+ if (result.coeff[i + j] == null)
+ {
+ result.coeff[i + j] = (GF2nElement)coeff[i]
+ .multiply(b.coeff[j]);
+ }
+ else
+ {
+ result.coeff[i + j] = (GF2nElement)result.coeff[i + j]
+ .add(coeff[i].multiply(b.coeff[j]));
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Multiplies this by b, reduces the result by g and
+ * returns it in a new PolynomialGF2n.
+ *
+ * @param b the PolynomialGF2n to multiply
+ * @param g the modul
+ * @return this * b mod g
+ * @throws DifferentFieldsException if this, b and g are
+ * not all defined over the same field.
+ */
+ public final GF2nPolynomial multiplyAndReduce(GF2nPolynomial b,
+ GF2nPolynomial g)
+ throws RuntimeException,
+ ArithmeticException
+ {
+ return multiply(b).reduce(g);
+ }
+
+ /**
+ * Reduces this by g and returns the result in a new
+ * PolynomialGF2n.
+ *
+ * @param g -
+ * the modulus
+ * @return this % g
+ * @throws DifferentFieldsException if this and g are not defined over
+ * the same field.
+ */
+ public final GF2nPolynomial reduce(GF2nPolynomial g)
+ throws RuntimeException, ArithmeticException
+ {
+ return remainder(g); // return this % g
+ }
+
+ /**
+ * Shifts left this by amount and stores the result in
+ * this PolynomialGF2n.
+ *
+ * @param amount the amount to shift the coefficients
+ */
+ public final void shiftThisLeft(int amount)
+ {
+ if (amount > 0)
+ {
+ int i;
+ int oldSize = size;
+ GF2nField f = coeff[0].getField();
+ enlarge(size + amount);
+ for (i = oldSize - 1; i >= 0; i--)
+ {
+ coeff[i + amount] = coeff[i];
+ }
+ if (coeff[0] instanceof GF2nPolynomialElement)
+ {
+ for (i = amount - 1; i >= 0; i--)
+ {
+ coeff[i] = GF2nPolynomialElement
+ .ZERO((GF2nPolynomialField)f);
+ }
+ }
+ else if (coeff[0] instanceof GF2nONBElement)
+ {
+ for (i = amount - 1; i >= 0; i--)
+ {
+ coeff[i] = GF2nONBElement.ZERO((GF2nONBField)f);
+ }
+ }
+ }
+ }
+
+ public final GF2nPolynomial shiftLeft(int amount)
+ {
+ if (amount <= 0)
+ {
+ return new GF2nPolynomial(this);
+ }
+ GF2nPolynomial result = new GF2nPolynomial(size + amount, coeff[0]);
+ result.assignZeroToElements();
+ for (int i = 0; i < size; i++)
+ {
+ result.coeff[i + amount] = coeff[i];
+ }
+ return result;
+ }
+
+ /**
+ * Divides this by b and stores the result in a new
+ * PolynomialGF2n[2], quotient in result[0] and remainder in result[1].
+ *
+ * @param b the divisor
+ * @return the quotient and remainder of this / b
+ * @throws DifferentFieldsException if this and b are not defined over
+ * the same field.
+ */
+ public final GF2nPolynomial[] divide(GF2nPolynomial b)
+ throws RuntimeException, ArithmeticException
+ {
+ GF2nPolynomial[] result = new GF2nPolynomial[2];
+ GF2nPolynomial a = new GF2nPolynomial(this);
+ a.shrink();
+ GF2nPolynomial shift;
+ GF2nElement factor;
+ int bDegree = b.getDegree();
+ GF2nElement inv = (GF2nElement)b.coeff[bDegree].invert();
+ if (a.getDegree() < bDegree)
+ {
+ result[0] = new GF2nPolynomial(this);
+ result[0].assignZeroToElements();
+ result[0].shrink();
+ result[1] = new GF2nPolynomial(this);
+ result[1].shrink();
+ return result;
+ }
+ result[0] = new GF2nPolynomial(this);
+ result[0].assignZeroToElements();
+ int i = a.getDegree() - bDegree;
+ while (i >= 0)
+ {
+ factor = (GF2nElement)a.coeff[a.getDegree()].multiply(inv);
+ shift = b.scalarMultiply(factor);
+ shift.shiftThisLeft(i);
+ a = a.add(shift);
+ a.shrink();
+ result[0].coeff[i] = (GF2nElement)factor.clone();
+ i = a.getDegree() - bDegree;
+ }
+ result[1] = a;
+ result[0].shrink();
+ return result;
+ }
+
+ /**
+ * Divides this by b and stores the remainder in a new
+ * PolynomialGF2n.
+ *
+ * @param b the divisor
+ * @return the remainder this % b
+ * @throws DifferentFieldsException if this and b are not defined over
+ * the same field.
+ */
+ public final GF2nPolynomial remainder(GF2nPolynomial b)
+ throws RuntimeException, ArithmeticException
+ {
+ GF2nPolynomial[] result = new GF2nPolynomial[2];
+ result = divide(b);
+ return result[1];
+ }
+
+ /**
+ * Divides this by b and stores the quotient in a new
+ * PolynomialGF2n.
+ *
+ * @param b the divisor
+ * @return the quotient this / b
+ * @throws DifferentFieldsException if this and b are not defined over
+ * the same field.
+ */
+ public final GF2nPolynomial quotient(GF2nPolynomial b)
+ throws RuntimeException, ArithmeticException
+ {
+ GF2nPolynomial[] result = new GF2nPolynomial[2];
+ result = divide(b);
+ return result[0];
+ }
+
+ /**
+ * Computes the greatest common divisor of this and g and
+ * returns the result in a new PolynomialGF2n.
+ *
+ * @param g -
+ * a GF2nPolynomial
+ * @return gcd(this, g)
+ * @throws DifferentFieldsException if the coefficients of this and g use
+ * different fields
+ * @throws ArithmeticException if coefficients are zero.
+ */
+ public final GF2nPolynomial gcd(GF2nPolynomial g)
+ throws RuntimeException, ArithmeticException
+ {
+ GF2nPolynomial a = new GF2nPolynomial(this);
+ GF2nPolynomial b = new GF2nPolynomial(g);
+ a.shrink();
+ b.shrink();
+ GF2nPolynomial c;
+ GF2nPolynomial result;
+ GF2nElement alpha;
+ while (!b.isZero())
+ {
+ c = a.remainder(b);
+ a = b;
+ b = c;
+ }
+ alpha = a.coeff[a.getDegree()];
+ result = a.scalarMultiply((GF2nElement)alpha.invert());
+ return result;
+ }
+
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/math/linearalgebra/GF2nPolynomialElement.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/math/linearalgebra/GF2nPolynomialElement.java
new file mode 100644
index 0000000..d51b856
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/math/linearalgebra/GF2nPolynomialElement.java
@@ -0,0 +1,1021 @@
+package org.bc.pqc.math.linearalgebra;
+
+
+import java.math.BigInteger;
+import java.util.Random;
+
+
+/**
+ * This class implements elements of finite binary fields GF(2n)
+ * using polynomial representation. For more information on the arithmetic see
+ * for example IEEE Standard 1363 or Certicom online-tutorial.
+ *
+ * @see "GF2nField"
+ * @see GF2nPolynomialField
+ * @see GF2nONBElement
+ * @see GF2Polynomial
+ */
+public class GF2nPolynomialElement
+ extends GF2nElement
+{
+
+ // pre-computed Bitmask for fast masking, bitMask[a]=0x1 << a
+ private static final int[] bitMask = {0x00000001, 0x00000002, 0x00000004,
+ 0x00000008, 0x00000010, 0x00000020, 0x00000040, 0x00000080,
+ 0x00000100, 0x00000200, 0x00000400, 0x00000800, 0x00001000,
+ 0x00002000, 0x00004000, 0x00008000, 0x00010000, 0x00020000,
+ 0x00040000, 0x00080000, 0x00100000, 0x00200000, 0x00400000,
+ 0x00800000, 0x01000000, 0x02000000, 0x04000000, 0x08000000,
+ 0x10000000, 0x20000000, 0x40000000, 0x80000000, 0x00000000};
+
+ // the used GF2Polynomial which stores the coefficients
+ private GF2Polynomial polynomial;
+
+ /**
+ * Create a new random GF2nPolynomialElement using the given field and
+ * source of randomness.
+ *
+ * @param f the GF2nField to use
+ * @param rand the source of randomness
+ */
+ public GF2nPolynomialElement(GF2nPolynomialField f, Random rand)
+ {
+ mField = f;
+ mDegree = mField.getDegree();
+ polynomial = new GF2Polynomial(mDegree);
+ randomize(rand);
+ }
+
+ /**
+ * Creates a new GF2nPolynomialElement using the given field and Bitstring.
+ *
+ * @param f the GF2nPolynomialField to use
+ * @param bs the desired value as Bitstring
+ */
+ public GF2nPolynomialElement(GF2nPolynomialField f, GF2Polynomial bs)
+ {
+ mField = f;
+ mDegree = mField.getDegree();
+ polynomial = new GF2Polynomial(bs);
+ polynomial.expandN(mDegree);
+ }
+
+ /**
+ * Creates a new GF2nPolynomialElement using the given field f and
+ * byte[] os as value. The conversion is done according to 1363.
+ *
+ * @param f the GF2nField to use
+ * @param os the octet string to assign to this GF2nPolynomialElement
+ * @see "P1363 5.5.5 p23, OS2FEP/OS2BSP"
+ */
+ public GF2nPolynomialElement(GF2nPolynomialField f, byte[] os)
+ {
+ mField = f;
+ mDegree = mField.getDegree();
+ polynomial = new GF2Polynomial(mDegree, os);
+ polynomial.expandN(mDegree);
+ }
+
+ /**
+ * Creates a new GF2nPolynomialElement using the given field f and
+ * int[] is as value.
+ *
+ * @param f the GF2nField to use
+ * @param is the integer string to assign to this GF2nPolynomialElement
+ */
+ public GF2nPolynomialElement(GF2nPolynomialField f, int[] is)
+ {
+ mField = f;
+ mDegree = mField.getDegree();
+ polynomial = new GF2Polynomial(mDegree, is);
+ polynomial.expandN(f.mDegree);
+ }
+
+ /**
+ * Creates a new GF2nPolynomialElement by cloning the given
+ * GF2nPolynomialElement b.
+ *
+ * @param other the GF2nPolynomialElement to clone
+ */
+ public GF2nPolynomialElement(GF2nPolynomialElement other)
+ {
+ mField = other.mField;
+ mDegree = other.mDegree;
+ polynomial = new GF2Polynomial(other.polynomial);
+ }
+
+ // /////////////////////////////////////////////////////////////////////
+ // pseudo-constructors
+ // /////////////////////////////////////////////////////////////////////
+
+ /**
+ * Creates a new GF2nPolynomialElement by cloning this
+ * GF2nPolynomialElement.
+ *
+ * @return a copy of this element
+ */
+ public Object clone()
+ {
+ return new GF2nPolynomialElement(this);
+ }
+
+ // /////////////////////////////////////////////////////////////////////
+ // assignments
+ // /////////////////////////////////////////////////////////////////////
+
+ /**
+ * Assigns the value 'zero' to this Polynomial.
+ */
+ void assignZero()
+ {
+ polynomial.assignZero();
+ }
+
+ /**
+ * Create the zero element.
+ *
+ * @param f the finite field
+ * @return the zero element in the given finite field
+ */
+ public static GF2nPolynomialElement ZERO(GF2nPolynomialField f)
+ {
+ GF2Polynomial polynomial = new GF2Polynomial(f.getDegree());
+ return new GF2nPolynomialElement(f, polynomial);
+ }
+
+ /**
+ * Create the one element.
+ *
+ * @param f the finite field
+ * @return the one element in the given finite field
+ */
+ public static GF2nPolynomialElement ONE(GF2nPolynomialField f)
+ {
+ GF2Polynomial polynomial = new GF2Polynomial(f.getDegree(),
+ new int[]{1});
+ return new GF2nPolynomialElement(f, polynomial);
+ }
+
+ /**
+ * Assigns the value 'one' to this Polynomial.
+ */
+ void assignOne()
+ {
+ polynomial.assignOne();
+ }
+
+ /**
+ * Assign a random value to this GF2nPolynomialElement using the specified
+ * source of randomness.
+ *
+ * @param rand the source of randomness
+ */
+ private void randomize(Random rand)
+ {
+ polynomial.expandN(mDegree);
+ polynomial.randomize(rand);
+ }
+
+ // /////////////////////////////////////////////////////////////////////
+ // comparison
+ // /////////////////////////////////////////////////////////////////////
+
+ /**
+ * Checks whether this element is zero.
+ *
+ * @return true if this is the zero element
+ */
+ public boolean isZero()
+ {
+ return polynomial.isZero();
+ }
+
+ /**
+ * Tests if the GF2nPolynomialElement has 'one' as value.
+ *
+ * @return true if this equals one (this == 1)
+ */
+ public boolean isOne()
+ {
+ return polynomial.isOne();
+ }
+
+ /**
+ * Compare this element with another object.
+ *
+ * @param other the other object
+ * @return true if the two objects are equal, false
+ * otherwise
+ */
+ public boolean equals(Object other)
+ {
+ if (other == null || !(other instanceof GF2nPolynomialElement))
+ {
+ return false;
+ }
+ GF2nPolynomialElement otherElem = (GF2nPolynomialElement)other;
+
+ if (mField != otherElem.mField)
+ {
+ if (!mField.getFieldPolynomial().equals(
+ otherElem.mField.getFieldPolynomial()))
+ {
+ return false;
+ }
+ }
+
+ return polynomial.equals(otherElem.polynomial);
+ }
+
+ /**
+ * @return the hash code of this element
+ */
+ public int hashCode()
+ {
+ return mField.hashCode() + polynomial.hashCode();
+ }
+
+ // /////////////////////////////////////////////////////////////////////
+ // access
+ // /////////////////////////////////////////////////////////////////////
+
+ /**
+ * Returns the value of this GF2nPolynomialElement in a new Bitstring.
+ *
+ * @return the value of this GF2nPolynomialElement in a new Bitstring
+ */
+ private GF2Polynomial getGF2Polynomial()
+ {
+ return new GF2Polynomial(polynomial);
+ }
+
+ /**
+ * Checks whether the indexed bit of the bit representation is set.
+ *
+ * @param index the index of the bit to test
+ * @return true if the indexed bit is set
+ */
+ boolean testBit(int index)
+ {
+ return polynomial.testBit(index);
+ }
+
+ /**
+ * Returns whether the rightmost bit of the bit representation is set. This
+ * is needed for data conversion according to 1363.
+ *
+ * @return true if the rightmost bit of this element is set
+ */
+ public boolean testRightmostBit()
+ {
+ return polynomial.testBit(0);
+ }
+
+ /**
+ * Compute the sum of this element and addend.
+ *
+ * @param addend the addend
+ * @return this + other (newly created)
+ * @throws DifferentFieldsException if the elements are of different fields.
+ */
+ public GFElement add(GFElement addend)
+ throws RuntimeException
+ {
+ GF2nPolynomialElement result = new GF2nPolynomialElement(this);
+ result.addToThis(addend);
+ return result;
+ }
+
+ /**
+ * Compute this + addend (overwrite this).
+ *
+ * @param addend the addend
+ * @throws DifferentFieldsException if the elements are of different fields.
+ */
+ public void addToThis(GFElement addend)
+ throws RuntimeException
+ {
+ if (!(addend instanceof GF2nPolynomialElement))
+ {
+ throw new RuntimeException();
+ }
+ if (!mField.equals(((GF2nPolynomialElement)addend).mField))
+ {
+ throw new RuntimeException();
+ }
+ polynomial.addToThis(((GF2nPolynomialElement)addend).polynomial);
+ }
+
+ /**
+ * Returns this element + 'one".
+ *
+ * @return this + 'one'
+ */
+ public GF2nElement increase()
+ {
+ GF2nPolynomialElement result = new GF2nPolynomialElement(this);
+ result.increaseThis();
+ return result;
+ }
+
+ /**
+ * Increases this element by 'one'.
+ */
+ public void increaseThis()
+ {
+ polynomial.increaseThis();
+ }
+
+ /**
+ * Compute the product of this element and factor.
+ *
+ * @param factor the factor
+ * @return this * factor (newly created)
+ * @throws DifferentFieldsException if the elements are of different fields.
+ */
+ public GFElement multiply(GFElement factor)
+ throws RuntimeException
+ {
+ GF2nPolynomialElement result = new GF2nPolynomialElement(this);
+ result.multiplyThisBy(factor);
+ return result;
+ }
+
+ /**
+ * Compute this * factor (overwrite this).
+ *
+ * @param factor the factor
+ * @throws DifferentFieldsException if the elements are of different fields.
+ */
+ public void multiplyThisBy(GFElement factor)
+ throws RuntimeException
+ {
+ if (!(factor instanceof GF2nPolynomialElement))
+ {
+ throw new RuntimeException();
+ }
+ if (!mField.equals(((GF2nPolynomialElement)factor).mField))
+ {
+ throw new RuntimeException();
+ }
+ if (equals(factor))
+ {
+ squareThis();
+ return;
+ }
+ polynomial = polynomial
+ .multiply(((GF2nPolynomialElement)factor).polynomial);
+ reduceThis();
+ }
+
+ /**
+ * Compute the multiplicative inverse of this element.
+ *
+ * @return this-1 (newly created)
+ * @throws ArithmeticException if this is the zero element.
+ * @see GF2nPolynomialElement#invertMAIA
+ * @see GF2nPolynomialElement#invertEEA
+ * @see GF2nPolynomialElement#invertSquare
+ */
+ public GFElement invert()
+ throws ArithmeticException
+ {
+ return invertMAIA();
+ }
+
+ /**
+ * Calculates the multiplicative inverse of this and returns the
+ * result in a new GF2nPolynomialElement.
+ *
+ * @return this^(-1)
+ * @throws ArithmeticException if this equals zero
+ */
+ public GF2nPolynomialElement invertEEA()
+ throws ArithmeticException
+ {
+ if (isZero())
+ {
+ throw new ArithmeticException();
+ }
+ GF2Polynomial b = new GF2Polynomial(mDegree + 32, "ONE");
+ b.reduceN();
+ GF2Polynomial c = new GF2Polynomial(mDegree + 32);
+ c.reduceN();
+ GF2Polynomial u = getGF2Polynomial();
+ GF2Polynomial v = mField.getFieldPolynomial();
+ GF2Polynomial h;
+ int j;
+ u.reduceN();
+ while (!u.isOne())
+ {
+ u.reduceN();
+ v.reduceN();
+ j = u.getLength() - v.getLength();
+ if (j < 0)
+ {
+ h = u;
+ u = v;
+ v = h;
+ h = b;
+ b = c;
+ c = h;
+ j = -j;
+ c.reduceN(); // this increases the performance
+ }
+ u.shiftLeftAddThis(v, j);
+ b.shiftLeftAddThis(c, j);
+ }
+ b.reduceN();
+ return new GF2nPolynomialElement((GF2nPolynomialField)mField, b);
+ }
+
+ /**
+ * Calculates the multiplicative inverse of this and returns the
+ * result in a new GF2nPolynomialElement.
+ *
+ * @return this^(-1)
+ * @throws ArithmeticException if this equals zero
+ */
+ public GF2nPolynomialElement invertSquare()
+ throws ArithmeticException
+ {
+ GF2nPolynomialElement n;
+ GF2nPolynomialElement u;
+ int i, j, k, b;
+
+ if (isZero())
+ {
+ throw new ArithmeticException();
+ }
+ // b = (n-1)
+ b = mField.getDegree() - 1;
+ // n = a
+ n = new GF2nPolynomialElement(this);
+ n.polynomial.expandN((mDegree << 1) + 32); // increase performance
+ n.polynomial.reduceN();
+ // k = 1
+ k = 1;
+
+ // for i = (r-1) downto 0 do, r=bitlength(b)
+ for (i = IntegerFunctions.floorLog(b) - 1; i >= 0; i--)
+ {
+ // u = n
+ u = new GF2nPolynomialElement(n);
+ // for j = 1 to k do
+ for (j = 1; j <= k; j++)
+ {
+ // u = u^2
+ u.squareThisPreCalc();
+ }
+ // n = nu
+ n.multiplyThisBy(u);
+ // k = 2k
+ k <<= 1;
+ // if b(i)==1
+ if ((b & bitMask[i]) != 0)
+ {
+ // n = n^2 * b
+ n.squareThisPreCalc();
+ n.multiplyThisBy(this);
+ // k = k+1
+ k += 1;
+ }
+ }
+
+ // outpur n^2
+ n.squareThisPreCalc();
+ return n;
+ }
+
+ /**
+ * Calculates the multiplicative inverse of this using the modified
+ * almost inverse algorithm and returns the result in a new
+ * GF2nPolynomialElement.
+ *
+ * @return this^(-1)
+ * @throws ArithmeticException if this equals zero
+ */
+ public GF2nPolynomialElement invertMAIA()
+ throws ArithmeticException
+ {
+ if (isZero())
+ {
+ throw new ArithmeticException();
+ }
+ GF2Polynomial b = new GF2Polynomial(mDegree, "ONE");
+ GF2Polynomial c = new GF2Polynomial(mDegree);
+ GF2Polynomial u = getGF2Polynomial();
+ GF2Polynomial v = mField.getFieldPolynomial();
+ GF2Polynomial h;
+ while (true)
+ {
+ while (!u.testBit(0))
+ { // x|u (x divides u)
+ u.shiftRightThis(); // u = u / x
+ if (!b.testBit(0))
+ {
+ b.shiftRightThis();
+ }
+ else
+ {
+ b.addToThis(mField.getFieldPolynomial());
+ b.shiftRightThis();
+ }
+ }
+ if (u.isOne())
+ {
+ return new GF2nPolynomialElement((GF2nPolynomialField)mField,
+ b);
+ }
+ u.reduceN();
+ v.reduceN();
+ if (u.getLength() < v.getLength())
+ {
+ h = u;
+ u = v;
+ v = h;
+ h = b;
+ b = c;
+ c = h;
+ }
+ u.addToThis(v);
+ b.addToThis(c);
+ }
+ }
+
+ /**
+ * This method is used internally to map the square()-calls within
+ * GF2nPolynomialElement to one of the possible squaring methods.
+ *
+ * @return this2 (newly created)
+ * @see GF2nPolynomialElement#squarePreCalc
+ */
+ public GF2nElement square()
+ {
+ return squarePreCalc();
+ }
+
+ /**
+ * This method is used internally to map the square()-calls within
+ * GF2nPolynomialElement to one of the possible squaring methods.
+ */
+ public void squareThis()
+ {
+ squareThisPreCalc();
+ }
+
+ /**
+ * Squares this GF2nPolynomialElement using GF2nField's squaring matrix.
+ * This is supposed to be fast when using a polynomial (no tri- or
+ * pentanomial) as fieldpolynomial. Use squarePreCalc when using a tri- or
+ * pentanomial as fieldpolynomial instead.
+ *
+ * @return this2 (newly created)
+ * @see GF2Polynomial#vectorMult
+ * @see GF2nPolynomialElement#squarePreCalc
+ * @see GF2nPolynomialElement#squareBitwise
+ */
+ public GF2nPolynomialElement squareMatrix()
+ {
+ GF2nPolynomialElement result = new GF2nPolynomialElement(this);
+ result.squareThisMatrix();
+ result.reduceThis();
+ return result;
+ }
+
+ /**
+ * Squares this GF2nPolynomialElement using GF2nFields squaring matrix. This
+ * is supposed to be fast when using a polynomial (no tri- or pentanomial)
+ * as fieldpolynomial. Use squarePreCalc when using a tri- or pentanomial as
+ * fieldpolynomial instead.
+ *
+ * @see GF2Polynomial#vectorMult
+ * @see GF2nPolynomialElement#squarePreCalc
+ * @see GF2nPolynomialElement#squareBitwise
+ */
+ public void squareThisMatrix()
+ {
+ GF2Polynomial result = new GF2Polynomial(mDegree);
+ for (int i = 0; i < mDegree; i++)
+ {
+ if (polynomial
+ .vectorMult(((GF2nPolynomialField)mField).squaringMatrix[mDegree
+ - i - 1]))
+ {
+ result.setBit(i);
+
+ }
+ }
+ polynomial = result;
+ }
+
+ /**
+ * Squares this GF2nPolynomialElement by shifting left its Bitstring and
+ * reducing. This is supposed to be the slowest method. Use squarePreCalc or
+ * squareMatrix instead.
+ *
+ * @return this2 (newly created)
+ * @see GF2nPolynomialElement#squareMatrix
+ * @see GF2nPolynomialElement#squarePreCalc
+ * @see GF2Polynomial#squareThisBitwise
+ */
+ public GF2nPolynomialElement squareBitwise()
+ {
+ GF2nPolynomialElement result = new GF2nPolynomialElement(this);
+ result.squareThisBitwise();
+ result.reduceThis();
+ return result;
+ }
+
+ /**
+ * Squares this GF2nPolynomialElement by shifting left its Bitstring and
+ * reducing. This is supposed to be the slowest method. Use squarePreCalc or
+ * squareMatrix instead.
+ *
+ * @see GF2nPolynomialElement#squareMatrix
+ * @see GF2nPolynomialElement#squarePreCalc
+ * @see GF2Polynomial#squareThisBitwise
+ */
+ public void squareThisBitwise()
+ {
+ polynomial.squareThisBitwise();
+ reduceThis();
+ }
+
+ /**
+ * Squares this GF2nPolynomialElement by using precalculated values and
+ * reducing. This is supposed to de fastest when using a trinomial or
+ * pentanomial as field polynomial. Use squareMatrix when using a ordinary
+ * polynomial as field polynomial.
+ *
+ * @return this2 (newly created)
+ * @see GF2nPolynomialElement#squareMatrix
+ * @see GF2Polynomial#squareThisPreCalc
+ */
+ public GF2nPolynomialElement squarePreCalc()
+ {
+ GF2nPolynomialElement result = new GF2nPolynomialElement(this);
+ result.squareThisPreCalc();
+ result.reduceThis();
+ return result;
+ }
+
+ /**
+ * Squares this GF2nPolynomialElement by using precalculated values and
+ * reducing. This is supposed to de fastest when using a tri- or pentanomial
+ * as fieldpolynomial. Use squareMatrix when using a ordinary polynomial as
+ * fieldpolynomial.
+ *
+ * @see GF2nPolynomialElement#squareMatrix
+ * @see GF2Polynomial#squareThisPreCalc
+ */
+ public void squareThisPreCalc()
+ {
+ polynomial.squareThisPreCalc();
+ reduceThis();
+ }
+
+ /**
+ * Calculates this to the power of k and returns the result
+ * in a new GF2nPolynomialElement.
+ *
+ * @param k the power
+ * @return this^k in a new GF2nPolynomialElement
+ */
+ public GF2nPolynomialElement power(int k)
+ {
+ if (k == 1)
+ {
+ return new GF2nPolynomialElement(this);
+ }
+
+ GF2nPolynomialElement result = GF2nPolynomialElement
+ .ONE((GF2nPolynomialField)mField);
+ if (k == 0)
+ {
+ return result;
+ }
+
+ GF2nPolynomialElement x = new GF2nPolynomialElement(this);
+ x.polynomial.expandN((x.mDegree << 1) + 32); // increase performance
+ x.polynomial.reduceN();
+
+ for (int i = 0; i < mDegree; i++)
+ {
+ if ((k & (1 << i)) != 0)
+ {
+ result.multiplyThisBy(x);
+ }
+ x.square();
+ }
+
+ return result;
+ }
+
+ /**
+ * Compute the square root of this element and return the result in a new
+ * {@link GF2nPolynomialElement}.
+ *
+ * @return this1/2 (newly created)
+ */
+ public GF2nElement squareRoot()
+ {
+ GF2nPolynomialElement result = new GF2nPolynomialElement(this);
+ result.squareRootThis();
+ return result;
+ }
+
+ /**
+ * Compute the square root of this element.
+ */
+ public void squareRootThis()
+ {
+ // increase performance
+ polynomial.expandN((mDegree << 1) + 32);
+ polynomial.reduceN();
+ for (int i = 0; i < mField.getDegree() - 1; i++)
+ {
+ squareThis();
+ }
+ }
+
+ /**
+ * Solves the quadratic equation z2 + z = this if
+ * such a solution exists. This method returns one of the two possible
+ * solutions. The other solution is z + 1. Use z.increase() to
+ * compute this solution.
+ *
+ * @return a GF2nPolynomialElement representing one z satisfying the
+ * equation z2 + z = this
+ * @throws NoSolutionException if no solution exists
+ * @see "IEEE 1363, Annex A.4.7"
+ */
+ public GF2nElement solveQuadraticEquation()
+ throws RuntimeException
+ {
+ if (isZero())
+ {
+ return ZERO((GF2nPolynomialField)mField);
+ }
+
+ if ((mDegree & 1) == 1)
+ {
+ return halfTrace();
+ }
+
+ // TODO this can be sped-up by precomputation of p and w's
+ GF2nPolynomialElement z, w;
+ do
+ {
+ // step 1.
+ GF2nPolynomialElement p = new GF2nPolynomialElement(
+ (GF2nPolynomialField)mField, new Random());
+ // step 2.
+ z = ZERO((GF2nPolynomialField)mField);
+ w = (GF2nPolynomialElement)p.clone();
+ // step 3.
+ for (int i = 1; i < mDegree; i++)
+ {
+ // compute z = z^2 + w^2 * this
+ // and w = w^2 + p
+ z.squareThis();
+ w.squareThis();
+ z.addToThis(w.multiply(this));
+ w.addToThis(p);
+ }
+ }
+ while (w.isZero()); // step 4.
+
+ if (!equals(z.square().add(z)))
+ {
+ throw new RuntimeException();
+ }
+
+ // step 5.
+ return z;
+ }
+
+ /**
+ * Returns the trace of this GF2nPolynomialElement.
+ *
+ * @return the trace of this GF2nPolynomialElement
+ */
+ public int trace()
+ {
+ GF2nPolynomialElement t = new GF2nPolynomialElement(this);
+ int i;
+
+ for (i = 1; i < mDegree; i++)
+ {
+ t.squareThis();
+ t.addToThis(this);
+ }
+
+ if (t.isOne())
+ {
+ return 1;
+ }
+ return 0;
+ }
+
+ /**
+ * Returns the half-trace of this GF2nPolynomialElement.
+ *
+ * @return a GF2nPolynomialElement representing the half-trace of this
+ * GF2nPolynomialElement.
+ * @throws DegreeIsEvenException if the degree of this GF2nPolynomialElement is even.
+ */
+ private GF2nPolynomialElement halfTrace()
+ throws RuntimeException
+ {
+ if ((mDegree & 0x01) == 0)
+ {
+ throw new RuntimeException();
+ }
+ int i;
+ GF2nPolynomialElement h = new GF2nPolynomialElement(this);
+
+ for (i = 1; i <= ((mDegree - 1) >> 1); i++)
+ {
+ h.squareThis();
+ h.squareThis();
+ h.addToThis(this);
+ }
+
+ return h;
+ }
+
+ /**
+ * Reduces this GF2nPolynomialElement modulo the field-polynomial.
+ *
+ * @see GF2Polynomial#reduceTrinomial
+ * @see GF2Polynomial#reducePentanomial
+ */
+ private void reduceThis()
+ {
+ if (polynomial.getLength() > mDegree)
+ { // really reduce ?
+ if (((GF2nPolynomialField)mField).isTrinomial())
+ { // fieldpolonomial
+ // is trinomial
+ int tc;
+ try
+ {
+ tc = ((GF2nPolynomialField)mField).getTc();
+ }
+ catch (RuntimeException NATExc)
+ {
+ throw new RuntimeException(
+ "GF2nPolynomialElement.reduce: the field"
+ + " polynomial is not a trinomial");
+ }
+ if (((mDegree - tc) <= 32) // do we have to use slow
+ // bitwise reduction ?
+ || (polynomial.getLength() > (mDegree << 1)))
+ {
+ reduceTrinomialBitwise(tc);
+ return;
+ }
+ polynomial.reduceTrinomial(mDegree, tc);
+ return;
+ }
+ else if (((GF2nPolynomialField)mField).isPentanomial())
+ { // fieldpolynomial
+ // is
+ // pentanomial
+ int[] pc;
+ try
+ {
+ pc = ((GF2nPolynomialField)mField).getPc();
+ }
+ catch (RuntimeException NATExc)
+ {
+ throw new RuntimeException(
+ "GF2nPolynomialElement.reduce: the field"
+ + " polynomial is not a pentanomial");
+ }
+ if (((mDegree - pc[2]) <= 32) // do we have to use slow
+ // bitwise reduction ?
+ || (polynomial.getLength() > (mDegree << 1)))
+ {
+ reducePentanomialBitwise(pc);
+ return;
+ }
+ polynomial.reducePentanomial(mDegree, pc);
+ return;
+ }
+ else
+ { // fieldpolynomial is something else
+ polynomial = polynomial.remainder(mField.getFieldPolynomial());
+ polynomial.expandN(mDegree);
+ return;
+ }
+ }
+ if (polynomial.getLength() < mDegree)
+ {
+ polynomial.expandN(mDegree);
+ }
+ }
+
+ /**
+ * Reduce this GF2nPolynomialElement using the trinomial x^n + x^tc + 1 as
+ * fieldpolynomial. The coefficients are reduced bit by bit.
+ */
+ private void reduceTrinomialBitwise(int tc)
+ {
+ int i;
+ int k = mDegree - tc;
+ for (i = polynomial.getLength() - 1; i >= mDegree; i--)
+ {
+ if (polynomial.testBit(i))
+ {
+
+ polynomial.xorBit(i);
+ polynomial.xorBit(i - k);
+ polynomial.xorBit(i - mDegree);
+
+ }
+ }
+ polynomial.reduceN();
+ polynomial.expandN(mDegree);
+ }
+
+ /**
+ * Reduce this GF2nPolynomialElement using the pentanomial x^n + x^pc[2] +
+ * x^pc[1] + x^pc[0] + 1 as fieldpolynomial. The coefficients are reduced
+ * bit by bit.
+ */
+ private void reducePentanomialBitwise(int[] pc)
+ {
+ int i;
+ int k = mDegree - pc[2];
+ int l = mDegree - pc[1];
+ int m = mDegree - pc[0];
+ for (i = polynomial.getLength() - 1; i >= mDegree; i--)
+ {
+ if (polynomial.testBit(i))
+ {
+ polynomial.xorBit(i);
+ polynomial.xorBit(i - k);
+ polynomial.xorBit(i - l);
+ polynomial.xorBit(i - m);
+ polynomial.xorBit(i - mDegree);
+
+ }
+ }
+ polynomial.reduceN();
+ polynomial.expandN(mDegree);
+ }
+
+ // /////////////////////////////////////////////////////////////////////
+ // conversion
+ // /////////////////////////////////////////////////////////////////////
+
+ /**
+ * Returns a string representing this Bitstrings value using hexadecimal
+ * radix in MSB-first order.
+ *
+ * @return a String representing this Bitstrings value.
+ */
+ public String toString()
+ {
+ return polynomial.toString(16);
+ }
+
+ /**
+ * Returns a string representing this Bitstrings value using hexadecimal or
+ * binary radix in MSB-first order.
+ *
+ * @param radix the radix to use (2 or 16, otherwise 2 is used)
+ * @return a String representing this Bitstrings value.
+ */
+ public String toString(int radix)
+ {
+ return polynomial.toString(radix);
+ }
+
+ /**
+ * Converts this GF2nPolynomialElement to a byte[] according to 1363.
+ *
+ * @return a byte[] representing the value of this GF2nPolynomialElement
+ * @see "P1363 5.5.2 p22f BS2OSP, FE2OSP"
+ */
+ public byte[] toByteArray()
+ {
+ return polynomial.toByteArray();
+ }
+
+ /**
+ * Converts this GF2nPolynomialElement to an integer according to 1363.
+ *
+ * @return a BigInteger representing the value of this
+ * GF2nPolynomialElement
+ * @see "P1363 5.5.1 p22 BS2IP"
+ */
+ public BigInteger toFlexiBigInt()
+ {
+ return polynomial.toFlexiBigInt();
+ }
+
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/math/linearalgebra/GF2nPolynomialField.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/math/linearalgebra/GF2nPolynomialField.java
new file mode 100644
index 0000000..c0b9fab
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/math/linearalgebra/GF2nPolynomialField.java
@@ -0,0 +1,553 @@
+package org.bc.pqc.math.linearalgebra;
+
+
+import java.util.Random;
+import java.util.Vector;
+
+
+/**
+ * This class implements the abstract class GF2nField for polynomial
+ * representation. It computes the field polynomial and the squaring matrix.
+ * GF2nField is used by GF2nPolynomialElement which implements the elements of
+ * this field.
+ *
+ * @see GF2nField
+ * @see GF2nPolynomialElement
+ */
+public class GF2nPolynomialField
+ extends GF2nField
+{
+
+ /**
+ * Matrix used for fast squaring
+ */
+ GF2Polynomial[] squaringMatrix;
+
+ // field polynomial is a trinomial
+ private boolean isTrinomial = false;
+
+ // field polynomial is a pentanomial
+ private boolean isPentanomial = false;
+
+ // middle coefficient of the field polynomial in case it is a trinomial
+ private int tc;
+
+ // middle 3 coefficients of the field polynomial in case it is a pentanomial
+ private int[] pc = new int[3];
+
+ /**
+ * constructs an instance of the finite field with 2deg
+ * elements and characteristic 2.
+ *
+ * @param deg the extention degree of this field
+ */
+ public GF2nPolynomialField(int deg)
+ {
+ if (deg < 3)
+ {
+ throw new IllegalArgumentException("k must be at least 3");
+ }
+ mDegree = deg;
+ computeFieldPolynomial();
+ computeSquaringMatrix();
+ fields = new Vector();
+ matrices = new Vector();
+ }
+
+ /**
+ * constructs an instance of the finite field with 2deg
+ * elements and characteristic 2.
+ *
+ * @param deg the degree of this field
+ * @param file true if you want to read the field polynomial from the
+ * file false if you want to use a random fielpolynomial
+ * (this can take very long for huge degrees)
+ */
+ public GF2nPolynomialField(int deg, boolean file)
+ {
+ if (deg < 3)
+ {
+ throw new IllegalArgumentException("k must be at least 3");
+ }
+ mDegree = deg;
+ if (file)
+ {
+ computeFieldPolynomial();
+ }
+ else
+ {
+ computeFieldPolynomial2();
+ }
+ computeSquaringMatrix();
+ fields = new Vector();
+ matrices = new Vector();
+ }
+
+ /**
+ * Creates a new GF2nField of degree i and uses the given
+ * polynomial as field polynomial. The polynomial is checked
+ * whether it is irreducible. This can take some time if i is huge!
+ *
+ * @param deg degree of the GF2nField
+ * @param polynomial the field polynomial to use
+ * @throws PolynomialIsNotIrreducibleException if the given polynomial is not irreducible in GF(2^i)
+ */
+ public GF2nPolynomialField(int deg, GF2Polynomial polynomial)
+ throws RuntimeException
+ {
+ if (deg < 3)
+ {
+ throw new IllegalArgumentException("degree must be at least 3");
+ }
+ if (polynomial.getLength() != deg + 1)
+ {
+ throw new RuntimeException();
+ }
+ if (!polynomial.isIrreducible())
+ {
+ throw new RuntimeException();
+ }
+ mDegree = deg;
+ // fieldPolynomial = new Bitstring(polynomial);
+ fieldPolynomial = polynomial;
+ computeSquaringMatrix();
+ int k = 2; // check if the polynomial is a trinomial or pentanomial
+ for (int j = 1; j < fieldPolynomial.getLength() - 1; j++)
+ {
+ if (fieldPolynomial.testBit(j))
+ {
+ k++;
+ if (k == 3)
+ {
+ tc = j;
+ }
+ if (k <= 5)
+ {
+ pc[k - 3] = j;
+ }
+ }
+ }
+ if (k == 3)
+ {
+ isTrinomial = true;
+ }
+ if (k == 5)
+ {
+ isPentanomial = true;
+ }
+ fields = new Vector();
+ matrices = new Vector();
+ }
+
+ /**
+ * Returns true if the field polynomial is a trinomial. The coefficient can
+ * be retrieved using getTc().
+ *
+ * @return true if the field polynomial is a trinomial
+ */
+ public boolean isTrinomial()
+ {
+ return isTrinomial;
+ }
+
+ /**
+ * Returns true if the field polynomial is a pentanomial. The coefficients
+ * can be retrieved using getPc().
+ *
+ * @return true if the field polynomial is a pentanomial
+ */
+ public boolean isPentanomial()
+ {
+ return isPentanomial;
+ }
+
+ /**
+ * Returns the degree of the middle coefficient of the used field trinomial
+ * (x^n + x^(getTc()) + 1).
+ *
+ * @return the middle coefficient of the used field trinomial
+ * @throws GFException if the field polynomial is not a trinomial
+ */
+ public int getTc()
+ throws RuntimeException
+ {
+ if (!isTrinomial)
+ {
+ throw new RuntimeException();
+ }
+ return tc;
+ }
+
+ /**
+ * Returns the degree of the middle coefficients of the used field
+ * pentanomial (x^n + x^(getPc()[2]) + x^(getPc()[1]) + x^(getPc()[0]) + 1).
+ *
+ * @return the middle coefficients of the used field pentanomial
+ * @throws GFException if the field polynomial is not a pentanomial
+ */
+ public int[] getPc()
+ throws RuntimeException
+ {
+ if (!isPentanomial)
+ {
+ throw new RuntimeException();
+ }
+ int[] result = new int[3];
+ System.arraycopy(pc, 0, result, 0, 3);
+ return result;
+ }
+
+ /**
+ * Return row vector i of the squaring matrix.
+ *
+ * @param i the index of the row vector to return
+ * @return a copy of squaringMatrix[i]
+ * @see GF2nPolynomialElement#squareMatrix
+ */
+ public GF2Polynomial getSquaringVector(int i)
+ {
+ return new GF2Polynomial(squaringMatrix[i]);
+ }
+
+ /**
+ * Compute a random root of the given GF2Polynomial.
+ *
+ * @param polynomial the polynomial
+ * @return a random root of polynomial
+ */
+ protected GF2nElement getRandomRoot(GF2Polynomial polynomial)
+ {
+ // We are in B1!!!
+ GF2nPolynomial c;
+ GF2nPolynomial ut;
+ GF2nElement u;
+ GF2nPolynomial h;
+ int hDegree;
+ // 1. Set g(t) <- f(t)
+ GF2nPolynomial g = new GF2nPolynomial(polynomial, this);
+ int gDegree = g.getDegree();
+ int i;
+
+ // 2. while deg(g) > 1
+ while (gDegree > 1)
+ {
+ do
+ {
+ // 2.1 choose random u (element of) GF(2^m)
+ u = new GF2nPolynomialElement(this, new Random());
+ ut = new GF2nPolynomial(2, GF2nPolynomialElement.ZERO(this));
+ // 2.2 Set c(t) <- ut
+ ut.set(1, u);
+ c = new GF2nPolynomial(ut);
+ // 2.3 For i from 1 to m-1 do
+ for (i = 1; i <= mDegree - 1; i++)
+ {
+ // 2.3.1 c(t) <- (c(t)^2 + ut) mod g(t)
+ c = c.multiplyAndReduce(c, g);
+ c = c.add(ut);
+ }
+ // 2.4 set h(t) <- GCD(c(t), g(t))
+ h = c.gcd(g);
+ // 2.5 if h(t) is constant or deg(g) = deg(h) then go to
+ // step 2.1
+ hDegree = h.getDegree();
+ gDegree = g.getDegree();
+ }
+ while ((hDegree == 0) || (hDegree == gDegree));
+ // 2.6 If 2deg(h) > deg(g) then set g(t) <- g(t)/h(t) ...
+ if ((hDegree << 1) > gDegree)
+ {
+ g = g.quotient(h);
+ }
+ else
+ {
+ // ... else g(t) <- h(t)
+ g = new GF2nPolynomial(h);
+ }
+ gDegree = g.getDegree();
+ }
+ // 3. Output g(0)
+ return g.at(0);
+
+ }
+
+ /**
+ * Computes the change-of-basis matrix for basis conversion according to
+ * 1363. The result is stored in the lists fields and matrices.
+ *
+ * @param B1 the GF2nField to convert to
+ * @see "P1363 A.7.3, p111ff"
+ */
+ protected void computeCOBMatrix(GF2nField B1)
+ {
+ // we are in B0 here!
+ if (mDegree != B1.mDegree)
+ {
+ throw new IllegalArgumentException(
+ "GF2nPolynomialField.computeCOBMatrix: B1 has a different "
+ + "degree and thus cannot be coverted to!");
+ }
+ if (B1 instanceof GF2nONBField)
+ {
+ // speedup (calculation is done in PolynomialElements instead of
+ // ONB)
+ B1.computeCOBMatrix(this);
+ return;
+ }
+ int i, j;
+ GF2nElement[] gamma;
+ GF2nElement u;
+ GF2Polynomial[] COBMatrix = new GF2Polynomial[mDegree];
+ for (i = 0; i < mDegree; i++)
+ {
+ COBMatrix[i] = new GF2Polynomial(mDegree);
+ }
+
+ // find Random Root
+ do
+ {
+ // u is in representation according to B1
+ u = B1.getRandomRoot(fieldPolynomial);
+ }
+ while (u.isZero());
+
+ // build gamma matrix by multiplying by u
+ if (u instanceof GF2nONBElement)
+ {
+ gamma = new GF2nONBElement[mDegree];
+ gamma[mDegree - 1] = GF2nONBElement.ONE((GF2nONBField)B1);
+ }
+ else
+ {
+ gamma = new GF2nPolynomialElement[mDegree];
+ gamma[mDegree - 1] = GF2nPolynomialElement
+ .ONE((GF2nPolynomialField)B1);
+ }
+ gamma[mDegree - 2] = u;
+ for (i = mDegree - 3; i >= 0; i--)
+ {
+ gamma[i] = (GF2nElement)gamma[i + 1].multiply(u);
+ }
+ if (B1 instanceof GF2nONBField)
+ {
+ // convert horizontal gamma matrix by vertical Bitstrings
+ for (i = 0; i < mDegree; i++)
+ {
+ for (j = 0; j < mDegree; j++)
+ {
+ // TODO remember: ONB treats its Bits in reverse order !!!
+ if (gamma[i].testBit(mDegree - j - 1))
+ {
+ COBMatrix[mDegree - j - 1].setBit(mDegree - i - 1);
+ }
+ }
+ }
+ }
+ else
+ {
+ // convert horizontal gamma matrix by vertical Bitstrings
+ for (i = 0; i < mDegree; i++)
+ {
+ for (j = 0; j < mDegree; j++)
+ {
+ if (gamma[i].testBit(j))
+ {
+ COBMatrix[mDegree - j - 1].setBit(mDegree - i - 1);
+ }
+ }
+ }
+ }
+
+ // store field and matrix for further use
+ fields.addElement(B1);
+ matrices.addElement(COBMatrix);
+ // store field and inverse matrix for further use in B1
+ B1.fields.addElement(this);
+ B1.matrices.addElement(invertMatrix(COBMatrix));
+ }
+
+ /**
+ * Computes a new squaring matrix used for fast squaring.
+ *
+ * @see GF2nPolynomialElement#square
+ */
+ private void computeSquaringMatrix()
+ {
+ GF2Polynomial[] d = new GF2Polynomial[mDegree - 1];
+ int i, j;
+ squaringMatrix = new GF2Polynomial[mDegree];
+ for (i = 0; i < squaringMatrix.length; i++)
+ {
+ squaringMatrix[i] = new GF2Polynomial(mDegree, "ZERO");
+ }
+
+ for (i = 0; i < mDegree - 1; i++)
+ {
+ d[i] = new GF2Polynomial(1, "ONE").shiftLeft(mDegree + i)
+ .remainder(fieldPolynomial);
+ }
+ for (i = 1; i <= Math.abs(mDegree >> 1); i++)
+ {
+ for (j = 1; j <= mDegree; j++)
+ {
+ if (d[mDegree - (i << 1)].testBit(mDegree - j))
+ {
+ squaringMatrix[j - 1].setBit(mDegree - i);
+ }
+ }
+ }
+ for (i = Math.abs(mDegree >> 1) + 1; i <= mDegree; i++)
+ {
+ squaringMatrix[(i << 1) - mDegree - 1].setBit(mDegree - i);
+ }
+
+ }
+
+ /**
+ * Computes the field polynomial. This can take a long time for big degrees.
+ */
+ protected void computeFieldPolynomial()
+ {
+ if (testTrinomials())
+ {
+ return;
+ }
+ if (testPentanomials())
+ {
+ return;
+ }
+ testRandom();
+ }
+
+ /**
+ * Computes the field polynomial. This can take a long time for big degrees.
+ */
+ protected void computeFieldPolynomial2()
+ {
+ if (testTrinomials())
+ {
+ return;
+ }
+ if (testPentanomials())
+ {
+ return;
+ }
+ testRandom();
+ }
+
+ /**
+ * Tests all trinomials of degree (n+1) until a irreducible is found and
+ * stores the result in field polynomial. Returns false if no
+ * irreducible trinomial exists in GF(2^n). This can take very long for huge
+ * degrees.
+ *
+ * @return true if an irreducible trinomial is found
+ */
+ private boolean testTrinomials()
+ {
+ int i, l;
+ boolean done = false;
+ l = 0;
+
+ fieldPolynomial = new GF2Polynomial(mDegree + 1);
+ fieldPolynomial.setBit(0);
+ fieldPolynomial.setBit(mDegree);
+ for (i = 1; (i < mDegree) && !done; i++)
+ {
+ fieldPolynomial.setBit(i);
+ done = fieldPolynomial.isIrreducible();
+ l++;
+ if (done)
+ {
+ isTrinomial = true;
+ tc = i;
+ return done;
+ }
+ fieldPolynomial.resetBit(i);
+ done = fieldPolynomial.isIrreducible();
+ }
+
+ return done;
+ }
+
+ /**
+ * Tests all pentanomials of degree (n+1) until a irreducible is found and
+ * stores the result in field polynomial. Returns false if no
+ * irreducible pentanomial exists in GF(2^n). This can take very long for
+ * huge degrees.
+ *
+ * @return true if an irreducible pentanomial is found
+ */
+ private boolean testPentanomials()
+ {
+ int i, j, k, l;
+ boolean done = false;
+ l = 0;
+
+ fieldPolynomial = new GF2Polynomial(mDegree + 1);
+ fieldPolynomial.setBit(0);
+ fieldPolynomial.setBit(mDegree);
+ for (i = 1; (i <= (mDegree - 3)) && !done; i++)
+ {
+ fieldPolynomial.setBit(i);
+ for (j = i + 1; (j <= (mDegree - 2)) && !done; j++)
+ {
+ fieldPolynomial.setBit(j);
+ for (k = j + 1; (k <= (mDegree - 1)) && !done; k++)
+ {
+ fieldPolynomial.setBit(k);
+ if (((mDegree & 1) != 0) | ((i & 1) != 0) | ((j & 1) != 0)
+ | ((k & 1) != 0))
+ {
+ done = fieldPolynomial.isIrreducible();
+ l++;
+ if (done)
+ {
+ isPentanomial = true;
+ pc[0] = i;
+ pc[1] = j;
+ pc[2] = k;
+ return done;
+ }
+ }
+ fieldPolynomial.resetBit(k);
+ }
+ fieldPolynomial.resetBit(j);
+ }
+ fieldPolynomial.resetBit(i);
+ }
+
+ return done;
+ }
+
+ /**
+ * Tests random polynomials of degree (n+1) until an irreducible is found
+ * and stores the result in field polynomial. This can take very
+ * long for huge degrees.
+ *
+ * @return true
+ */
+ private boolean testRandom()
+ {
+ int l;
+ boolean done = false;
+
+ fieldPolynomial = new GF2Polynomial(mDegree + 1);
+ l = 0;
+ while (!done)
+ {
+ l++;
+ fieldPolynomial.randomize();
+ fieldPolynomial.setBit(mDegree);
+ fieldPolynomial.setBit(0);
+ if (fieldPolynomial.isIrreducible())
+ {
+ done = true;
+ return done;
+ }
+ }
+
+ return done;
+ }
+
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/math/linearalgebra/GFElement.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/math/linearalgebra/GFElement.java
new file mode 100644
index 0000000..d155a28
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/math/linearalgebra/GFElement.java
@@ -0,0 +1,158 @@
+package org.bc.pqc.math.linearalgebra;
+
+import java.math.BigInteger;
+
+
+/**
+ * This interface defines a finite field element. It is implemented by the
+ * classes {@link GFPElement} and {@link GF2nElement}.
+ *
+ * @see GFPElement
+ * @see GF2nElement
+ */
+public interface GFElement
+{
+
+ /**
+ * @return a copy of this GFElement
+ */
+ Object clone();
+
+ // /////////////////////////////////////////////////////////////////
+ // comparison
+ // /////////////////////////////////////////////////////////////////
+
+ /**
+ * Compare this curve with another object.
+ *
+ * @param other the other object
+ * @return the result of the comparison
+ */
+ boolean equals(Object other);
+
+ /**
+ * @return the hash code of this element
+ */
+ int hashCode();
+
+ /**
+ * Checks whether this element is zero.
+ *
+ * @return true if this is the zero element
+ */
+ boolean isZero();
+
+ /**
+ * Checks whether this element is one.
+ *
+ * @return true if this is the one element
+ */
+ boolean isOne();
+
+ // /////////////////////////////////////////////////////////////////////
+ // arithmetic
+ // /////////////////////////////////////////////////////////////////////
+
+ /**
+ * Compute the sum of this element and the addend.
+ *
+ * @param addend the addend
+ * @return this + other (newly created)
+ * @throws DifferentFieldsException if the elements are of different fields.
+ */
+ GFElement add(GFElement addend)
+ throws RuntimeException;
+
+ /**
+ * Compute the sum of this element and the addend, overwriting this element.
+ *
+ * @param addend the addend
+ * @throws DifferentFieldsException if the elements are of different fields.
+ */
+ void addToThis(GFElement addend)
+ throws RuntimeException;
+
+ /**
+ * Compute the difference of this element and minuend.
+ *
+ * @param minuend the minuend
+ * @return this - minuend (newly created)
+ * @throws DifferentFieldsException if the elements are of different fields.
+ */
+ GFElement subtract(GFElement minuend)
+ throws RuntimeException;
+
+ /**
+ * Compute the difference of this element and minuend,
+ * overwriting this element.
+ *
+ * @param minuend the minuend
+ * @throws DifferentFieldsException if the elements are of different fields.
+ */
+ void subtractFromThis(GFElement minuend);
+
+ /**
+ * Compute the product of this element and factor.
+ *
+ * @param factor the factor
+ * @return this * factor (newly created)
+ * @throws DifferentFieldsException if the elements are of different fields.
+ */
+ GFElement multiply(GFElement factor)
+ throws RuntimeException;
+
+ /**
+ * Compute this * factor (overwrite this).
+ *
+ * @param factor the factor
+ * @throws DifferentFieldsException if the elements are of different fields.
+ */
+ void multiplyThisBy(GFElement factor)
+ throws RuntimeException;
+
+ /**
+ * Compute the multiplicative inverse of this element.
+ *
+ * @return this-1 (newly created)
+ * @throws ArithmeticException if this is the zero element.
+ */
+ GFElement invert()
+ throws ArithmeticException;
+
+ // /////////////////////////////////////////////////////////////////////
+ // conversion
+ // /////////////////////////////////////////////////////////////////////
+
+ /**
+ * Returns this element as FlexiBigInt. The conversion is P1363-conform.
+ *
+ * @return this element as BigInt
+ */
+ BigInteger toFlexiBigInt();
+
+ /**
+ * Returns this element as byte array. The conversion is P1363-conform.
+ *
+ * @return this element as byte array
+ */
+ byte[] toByteArray();
+
+ /**
+ * Return a String representation of this element.
+ *
+ * @return String representation of this element
+ */
+ String toString();
+
+ /**
+ * Return a String representation of this element. radix
+ * specifies the radix of the String representation.
+ *
+ * @param radix specifies the radix of the String representation
+ * @return String representation of this element with the specified radix
+ */
+ String toString(int radix);
+
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/math/linearalgebra/GoppaCode.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/math/linearalgebra/GoppaCode.java
new file mode 100644
index 0000000..c30b29b
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/math/linearalgebra/GoppaCode.java
@@ -0,0 +1,310 @@
+package org.bc.pqc.math.linearalgebra;
+
+import java.security.SecureRandom;
+
+/**
+ * This class describes decoding operations of an irreducible binary Goppa code.
+ * A check matrix H of the Goppa code and an irreducible Goppa polynomial are
+ * used the operations are worked over a finite field GF(2^m)
+ *
+ * @see GF2mField
+ * @see PolynomialGF2mSmallM
+ */
+public final class GoppaCode
+{
+
+ /**
+ * Default constructor (private).
+ */
+ private GoppaCode()
+ {
+ // empty
+ }
+
+ /**
+ * This class is a container for two instances of {@link GF2Matrix} and one
+ * instance of {@link Permutation}. It is used to hold the systematic form
+ * S*H*P = (Id|M) of the check matrix H as returned by
+ * {@link GoppaCode#computeSystematicForm(GF2Matrix, SecureRandom)}.
+ *
+ * @see GF2Matrix
+ * @see Permutation
+ */
+ public static class MaMaPe
+ {
+
+ private GF2Matrix s, h;
+
+ private Permutation p;
+
+ /**
+ * Construct a new {@link MaMaPe} container with the given parameters.
+ *
+ * @param s the first matrix
+ * @param h the second matrix
+ * @param p the permutation
+ */
+ public MaMaPe(GF2Matrix s, GF2Matrix h, Permutation p)
+ {
+ this.s = s;
+ this.h = h;
+ this.p = p;
+ }
+
+ /**
+ * @return the first matrix
+ */
+ public GF2Matrix getFirstMatrix()
+ {
+ return s;
+ }
+
+ /**
+ * @return the second matrix
+ */
+ public GF2Matrix getSecondMatrix()
+ {
+ return h;
+ }
+
+ /**
+ * @return the permutation
+ */
+ public Permutation getPermutation()
+ {
+ return p;
+ }
+ }
+
+ /**
+ * This class is a container for an instance of {@link GF2Matrix} and one
+ * int[]. It is used to hold a generator matrix and the set of indices such
+ * that the submatrix of the generator matrix consisting of the specified
+ * columns is the identity.
+ *
+ * @see GF2Matrix
+ * @see Permutation
+ */
+ public static class MatrixSet
+ {
+
+ private GF2Matrix g;
+
+ private int[] setJ;
+
+ /**
+ * Construct a new {@link MatrixSet} container with the given
+ * parameters.
+ *
+ * @param g the generator matrix
+ * @param setJ the set of indices such that the submatrix of the
+ * generator matrix consisting of the specified columns
+ * is the identity
+ */
+ public MatrixSet(GF2Matrix g, int[] setJ)
+ {
+ this.g = g;
+ this.setJ = setJ;
+ }
+
+ /**
+ * @return the generator matrix
+ */
+ public GF2Matrix getG()
+ {
+ return g;
+ }
+
+ /**
+ * @return the set of indices such that the submatrix of the generator
+ * matrix consisting of the specified columns is the identity
+ */
+ public int[] getSetJ()
+ {
+ return setJ;
+ }
+ }
+
+ /**
+ * Construct the check matrix of a Goppa code in canonical form from the
+ * irreducible Goppa polynomial over the finite field
+ * GF(2m).
+ *
+ * @param field the finite field
+ * @param gp the irreducible Goppa polynomial
+ */
+ public static GF2Matrix createCanonicalCheckMatrix(GF2mField field,
+ PolynomialGF2mSmallM gp)
+ {
+ int m = field.getDegree();
+ int n = 1 << m;
+ int t = gp.getDegree();
+
+ /* create matrix H over GF(2^m) */
+
+ int[][] hArray = new int[t][n];
+
+ // create matrix YZ
+ int[][] yz = new int[t][n];
+ for (int j = 0; j < n; j++)
+ {
+ // here j is used as index and as element of field GF(2^m)
+ yz[0][j] = field.inverse(gp.evaluateAt(j));
+ }
+
+ for (int i = 1; i < t; i++)
+ {
+ for (int j = 0; j < n; j++)
+ {
+ // here j is used as index and as element of field GF(2^m)
+ yz[i][j] = field.mult(yz[i - 1][j], j);
+ }
+ }
+
+ // create matrix H = XYZ
+ for (int i = 0; i < t; i++)
+ {
+ for (int j = 0; j < n; j++)
+ {
+ for (int k = 0; k <= i; k++)
+ {
+ hArray[i][j] = field.add(hArray[i][j], field.mult(yz[k][j],
+ gp.getCoefficient(t + k - i)));
+ }
+ }
+ }
+
+ /* convert to matrix over GF(2) */
+
+ int[][] result = new int[t * m][(n + 31) >>> 5];
+
+ for (int j = 0; j < n; j++)
+ {
+ int q = j >>> 5;
+ int r = 1 << (j & 0x1f);
+ for (int i = 0; i < t; i++)
+ {
+ int e = hArray[i][j];
+ for (int u = 0; u < m; u++)
+ {
+ int b = (e >>> u) & 1;
+ if (b != 0)
+ {
+ int ind = (i + 1) * m - u - 1;
+ result[ind][q] ^= r;
+ }
+ }
+ }
+ }
+
+ return new GF2Matrix(n, result);
+ }
+
+ /**
+ * Given a check matrix H, compute matrices S,
+ * M, and a random permutation P such that
+ * S*H*P = (Id|M). Return S^-1, M, and
+ * P as {@link MaMaPe}. The matrix (Id | M) is called
+ * the systematic form of H.
+ *
+ * @param h the check matrix
+ * @param sr a source of randomness
+ * @return the tuple (S^-1, M, P)
+ */
+ public static MaMaPe computeSystematicForm(GF2Matrix h, SecureRandom sr)
+ {
+ int n = h.getNumColumns();
+ GF2Matrix hp, sInv;
+ GF2Matrix s = null;
+ Permutation p;
+ boolean found = false;
+
+ do
+ {
+ p = new Permutation(n, sr);
+ hp = (GF2Matrix)h.rightMultiply(p);
+ sInv = hp.getLeftSubMatrix();
+ try
+ {
+ found = true;
+ s = (GF2Matrix)sInv.computeInverse();
+ }
+ catch (ArithmeticException ae)
+ {
+ found = false;
+ }
+ }
+ while (!found);
+
+ GF2Matrix shp = (GF2Matrix)s.rightMultiply(hp);
+ GF2Matrix m = shp.getRightSubMatrix();
+
+ return new MaMaPe(sInv, m, p);
+ }
+
+ /**
+ * Find an error vector e over GF(2) from an input
+ * syndrome s over GF(2m).
+ *
+ * @param syndVec the syndrome
+ * @param field the finite field
+ * @param gp the irreducible Goppa polynomial
+ * @param sqRootMatrix the matrix for computing square roots in
+ * (GF(2m))t
+ * @return the error vector
+ */
+ public static GF2Vector syndromeDecode(GF2Vector syndVec, GF2mField field,
+ PolynomialGF2mSmallM gp, PolynomialGF2mSmallM[] sqRootMatrix)
+ {
+
+ int n = 1 << field.getDegree();
+
+ // the error vector
+ GF2Vector errors = new GF2Vector(n);
+
+ // if the syndrome vector is zero, the error vector is also zero
+ if (!syndVec.isZero())
+ {
+ // convert syndrome vector to polynomial over GF(2^m)
+ PolynomialGF2mSmallM syndrome = new PolynomialGF2mSmallM(syndVec
+ .toExtensionFieldVector(field));
+
+ // compute T = syndrome^-1 mod gp
+ PolynomialGF2mSmallM t = syndrome.modInverse(gp);
+
+ // compute tau = sqRoot(T + X) mod gp
+ PolynomialGF2mSmallM tau = t.addMonomial(1);
+ tau = tau.modSquareRootMatrix(sqRootMatrix);
+
+ // compute polynomials a and b satisfying a + b*tau = 0 mod gp
+ PolynomialGF2mSmallM[] ab = tau.modPolynomialToFracton(gp);
+
+ // compute the polynomial a^2 + X*b^2
+ PolynomialGF2mSmallM a2 = ab[0].multiply(ab[0]);
+ PolynomialGF2mSmallM b2 = ab[1].multiply(ab[1]);
+ PolynomialGF2mSmallM xb2 = b2.multWithMonomial(1);
+ PolynomialGF2mSmallM a2plusXb2 = a2.add(xb2);
+
+ // normalize a^2 + X*b^2 to obtain the error locator polynomial
+ int headCoeff = a2plusXb2.getHeadCoefficient();
+ int invHeadCoeff = field.inverse(headCoeff);
+ PolynomialGF2mSmallM elp = a2plusXb2.multWithElement(invHeadCoeff);
+
+ // for all elements i of GF(2^m)
+ for (int i = 0; i < n; i++)
+ {
+ // evaluate the error locator polynomial at i
+ int z = elp.evaluateAt(i);
+ // if polynomial evaluates to zero
+ if (z == 0)
+ {
+ // set the i-th coefficient of the error vector
+ errors.setBit(i);
+ }
+ }
+ }
+
+ return errors;
+ }
+
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/math/linearalgebra/IntUtils.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/math/linearalgebra/IntUtils.java
new file mode 100644
index 0000000..4662f9c
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/math/linearalgebra/IntUtils.java
@@ -0,0 +1,203 @@
+package org.bc.pqc.math.linearalgebra;
+
+import java.math.BigInteger;
+
+/**
+ *
+ *
+ *
+ */
+public final class IntUtils
+{
+
+ /**
+ * Default constructor (private).
+ */
+ private IntUtils()
+ {
+ // empty
+ }
+
+ /**
+ * Compare two int arrays. No null checks are performed.
+ *
+ * @param left the first int array
+ * @param right the second int array
+ * @return the result of the comparison
+ */
+ public static boolean equals(int[] left, int[] right)
+ {
+ if (left.length != right.length)
+ {
+ return false;
+ }
+ boolean result = true;
+ for (int i = left.length - 1; i >= 0; i--)
+ {
+ result &= left[i] == right[i];
+ }
+ return result;
+ }
+
+ /**
+ * Return a clone of the given int array. No null checks are performed.
+ *
+ * @param array the array to clone
+ * @return the clone of the given array
+ */
+ public static int[] clone(int[] array)
+ {
+ int[] result = new int[array.length];
+ System.arraycopy(array, 0, result, 0, array.length);
+ return result;
+ }
+
+ /**
+ * Fill the given int array with the given value.
+ *
+ * @param array the array
+ * @param value the value
+ */
+ public static void fill(int[] array, int value)
+ {
+ for (int i = array.length - 1; i >= 0; i--)
+ {
+ array[i] = value;
+ }
+ }
+
+ /**
+ * Sorts this array of integers according to the Quicksort algorithm. After
+ * calling this method this array is sorted in ascending order with the
+ * smallest integer taking position 0 in the array.
+ *
+ *
+ * This implementation is based on the quicksort algorithm as described in
+ * Data Structures In Java
by Thomas A. Standish, Chapter 10,
+ * ISBN 0-201-30564-X.
+ *
+ * @param source the array of integers that needs to be sorted.
+ */
+ public static void quicksort(int[] source)
+ {
+ quicksort(source, 0, source.length - 1);
+ }
+
+ /**
+ * Sort a subarray of a source array. The subarray is specified by its start
+ * and end index.
+ *
+ * @param source the int array to be sorted
+ * @param left the start index of the subarray
+ * @param right the end index of the subarray
+ */
+ public static void quicksort(int[] source, int left, int right)
+ {
+ if (right > left)
+ {
+ int index = partition(source, left, right, right);
+ quicksort(source, left, index - 1);
+ quicksort(source, index + 1, right);
+ }
+ }
+
+ /**
+ * Split a subarray of a source array into two partitions. The left
+ * partition contains elements that have value less than or equal to the
+ * pivot element, the right partition contains the elements that have larger
+ * value.
+ *
+ * @param source the int array whose subarray will be splitted
+ * @param left the start position of the subarray
+ * @param right the end position of the subarray
+ * @param pivotIndex the index of the pivot element inside the array
+ * @return the new index of the pivot element inside the array
+ */
+ private static int partition(int[] source, int left, int right,
+ int pivotIndex)
+ {
+
+ int pivot = source[pivotIndex];
+ source[pivotIndex] = source[right];
+ source[right] = pivot;
+
+ int index = left;
+
+ for (int i = left; i < right; i++)
+ {
+ if (source[i] <= pivot)
+ {
+ int tmp = source[index];
+ source[index] = source[i];
+ source[i] = tmp;
+ index++;
+ }
+ }
+
+ int tmp = source[index];
+ source[index] = source[right];
+ source[right] = tmp;
+
+ return index;
+ }
+
+ /**
+ * Generates a subarray of a given int array.
+ *
+ * @param input -
+ * the input int array
+ * @param start -
+ * the start index
+ * @param end -
+ * the end index
+ * @return a subarray of input, ranging from start to
+ * end
+ */
+ public static int[] subArray(final int[] input, final int start,
+ final int end)
+ {
+ int[] result = new int[end - start];
+ System.arraycopy(input, start, result, 0, end - start);
+ return result;
+ }
+
+ /**
+ * Convert an int array to a {@link FlexiBigInt} array.
+ *
+ * @param input the int array
+ * @return the {@link FlexiBigInt} array
+ */
+ public static BigInteger[] toFlexiBigIntArray(int[] input)
+ {
+ BigInteger[] result = new BigInteger[input.length];
+ for (int i = 0; i < input.length; i++)
+ {
+ result[i] = BigInteger.valueOf(input[i]);
+ }
+ return result;
+ }
+
+ /**
+ * @param input an int array
+ * @return a human readable form of the given int array
+ */
+ public static String toString(int[] input)
+ {
+ String result = "";
+ for (int i = 0; i < input.length; i++)
+ {
+ result += input[i] + " ";
+ }
+ return result;
+ }
+
+ /**
+ * @param input an int arary
+ * @return the int array as hex string
+ */
+ public static String toHexString(int[] input)
+ {
+ return ByteUtils.toHexString(BigEndianConversions.toByteArray(input));
+ }
+
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/math/linearalgebra/IntegerFunctions.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/math/linearalgebra/IntegerFunctions.java
new file mode 100644
index 0000000..b56f900
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/math/linearalgebra/IntegerFunctions.java
@@ -0,0 +1,1424 @@
+package org.bc.pqc.math.linearalgebra;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
+/**
+ * Class of number-theory related functions for use with integers represented as
+ * int's or BigInteger objects.
+ */
+public final class IntegerFunctions
+{
+
+ private static final BigInteger ZERO = BigInteger.valueOf(0);
+
+ private static final BigInteger ONE = BigInteger.valueOf(1);
+
+ private static final BigInteger TWO = BigInteger.valueOf(2);
+
+ private static final BigInteger FOUR = BigInteger.valueOf(4);
+
+ private static final int[] SMALL_PRIMES = {3, 5, 7, 11, 13, 17, 19, 23,
+ 29, 31, 37, 41};
+
+ private static final long SMALL_PRIME_PRODUCT = 3L * 5 * 7 * 11 * 13 * 17
+ * 19 * 23 * 29 * 31 * 37 * 41;
+
+ private static SecureRandom sr = null;
+
+ // the jacobi function uses this lookup table
+ private static final int[] jacobiTable = {0, 1, 0, -1, 0, -1, 0, 1};
+
+ private IntegerFunctions()
+ {
+ // empty
+ }
+
+ /**
+ * Computes the value of the Jacobi symbol (A|B). The following properties
+ * hold for the Jacobi symbol which makes it a very efficient way to
+ * evaluate the Legendre symbol
+ *
+ * (A|B) = 0 IF gcd(A,B) > 1
+ * (-1|B) = 1 IF n = 1 (mod 1)
+ * (-1|B) = -1 IF n = 3 (mod 4)
+ * (A|B) (C|B) = (AC|B)
+ * (A|B) (A|C) = (A|CB)
+ * (A|B) = (C|B) IF A = C (mod B)
+ * (2|B) = 1 IF N = 1 OR 7 (mod 8)
+ * (2|B) = 1 IF N = 3 OR 5 (mod 8)
+ *
+ *
+ * @param A integer value
+ * @param B integer value
+ * @return value of the jacobi symbol (A|B)
+ */
+ public static int jacobi(BigInteger A, BigInteger B)
+ {
+ BigInteger a, b, v;
+ long k = 1;
+
+ k = 1;
+
+ // test trivial cases
+ if (B.equals(ZERO))
+ {
+ a = A.abs();
+ return a.equals(ONE) ? 1 : 0;
+ }
+
+ if (!A.testBit(0) && !B.testBit(0))
+ {
+ return 0;
+ }
+
+ a = A;
+ b = B;
+
+ if (b.signum() == -1)
+ { // b < 0
+ b = b.negate(); // b = -b
+ if (a.signum() == -1)
+ {
+ k = -1;
+ }
+ }
+
+ v = ZERO;
+ while (!b.testBit(0))
+ {
+ v = v.add(ONE); // v = v + 1
+ b = b.divide(TWO); // b = b/2
+ }
+
+ if (v.testBit(0))
+ {
+ k = k * jacobiTable[a.intValue() & 7];
+ }
+
+ if (a.signum() < 0)
+ { // a < 0
+ if (b.testBit(1))
+ {
+ k = -k; // k = -k
+ }
+ a = a.negate(); // a = -a
+ }
+
+ // main loop
+ while (a.signum() != 0)
+ {
+ v = ZERO;
+ while (!a.testBit(0))
+ { // a is even
+ v = v.add(ONE);
+ a = a.divide(TWO);
+ }
+ if (v.testBit(0))
+ {
+ k = k * jacobiTable[b.intValue() & 7];
+ }
+
+ if (a.compareTo(b) < 0)
+ { // a < b
+ // swap and correct intermediate result
+ BigInteger x = a;
+ a = b;
+ b = x;
+ if (a.testBit(1) && b.testBit(1))
+ {
+ k = -k;
+ }
+ }
+ a = a.subtract(b);
+ }
+
+ return b.equals(ONE) ? (int)k : 0;
+ }
+
+ /**
+ * Computes the square root of a BigInteger modulo a prime employing the
+ * Shanks-Tonelli algorithm.
+ *
+ * @param a value out of which we extract the square root
+ * @param p prime modulus that determines the underlying field
+ * @return a number b such that b2 = a (mod p) if
+ * a is a quadratic residue modulo p.
+ * @throws NoQuadraticResidueException if a is a quadratic non-residue modulo p
+ */
+ public static BigInteger ressol(BigInteger a, BigInteger p)
+ throws IllegalArgumentException
+ {
+
+ BigInteger v = null;
+
+ if (a.compareTo(ZERO) < 0)
+ {
+ a = a.add(p);
+ }
+
+ if (a.equals(ZERO))
+ {
+ return ZERO;
+ }
+
+ if (p.equals(TWO))
+ {
+ return a;
+ }
+
+ // p = 3 mod 4
+ if (p.testBit(0) && p.testBit(1))
+ {
+ if (jacobi(a, p) == 1)
+ { // a quadr. residue mod p
+ v = p.add(ONE); // v = p+1
+ v = v.shiftRight(2); // v = v/4
+ return a.modPow(v, p); // return a^v mod p
+ // return --> a^((p+1)/4) mod p
+ }
+ throw new IllegalArgumentException("No quadratic residue: " + a + ", " + p);
+ }
+
+ long t = 0;
+
+ // initialization
+ // compute k and s, where p = 2^s (2k+1) +1
+
+ BigInteger k = p.subtract(ONE); // k = p-1
+ long s = 0;
+ while (!k.testBit(0))
+ { // while k is even
+ s++; // s = s+1
+ k = k.shiftRight(1); // k = k/2
+ }
+
+ k = k.subtract(ONE); // k = k - 1
+ k = k.shiftRight(1); // k = k/2
+
+ // initial values
+ BigInteger r = a.modPow(k, p); // r = a^k mod p
+
+ BigInteger n = r.multiply(r).remainder(p); // n = r^2 % p
+ n = n.multiply(a).remainder(p); // n = n * a % p
+ r = r.multiply(a).remainder(p); // r = r * a %p
+
+ if (n.equals(ONE))
+ {
+ return r;
+ }
+
+ // non-quadratic residue
+ BigInteger z = TWO; // z = 2
+ while (jacobi(z, p) == 1)
+ {
+ // while z quadratic residue
+ z = z.add(ONE); // z = z + 1
+ }
+
+ v = k;
+ v = v.multiply(TWO); // v = 2k
+ v = v.add(ONE); // v = 2k + 1
+ BigInteger c = z.modPow(v, p); // c = z^v mod p
+
+ // iteration
+ while (n.compareTo(ONE) == 1)
+ { // n > 1
+ k = n; // k = n
+ t = s; // t = s
+ s = 0;
+
+ while (!k.equals(ONE))
+ { // k != 1
+ k = k.multiply(k).mod(p); // k = k^2 % p
+ s++; // s = s + 1
+ }
+
+ t -= s; // t = t - s
+ if (t == 0)
+ {
+ throw new IllegalArgumentException("No quadratic residue: " + a + ", " + p);
+ }
+
+ v = ONE;
+ for (long i = 0; i < t - 1; i++)
+ {
+ v = v.shiftLeft(1); // v = 1 * 2^(t - 1)
+ }
+ c = c.modPow(v, p); // c = c^v mod p
+ r = r.multiply(c).remainder(p); // r = r * c % p
+ c = c.multiply(c).remainder(p); // c = c^2 % p
+ n = n.multiply(c).mod(p); // n = n * c % p
+ }
+ return r;
+ }
+
+ /**
+ * Computes the greatest common divisor of the two specified integers
+ *
+ * @param u - first integer
+ * @param v - second integer
+ * @return gcd(a, b)
+ */
+ public static int gcd(int u, int v)
+ {
+ return BigInteger.valueOf(u).gcd(BigInteger.valueOf(v)).intValue();
+ }
+
+ /**
+ * Extended euclidian algorithm (computes gcd and representation).
+ *
+ * @param a the first integer
+ * @param b the second integer
+ * @return (g,u,v), where g = gcd(abs(a),abs(b)) = ua + vb
+ */
+ public static int[] extGCD(int a, int b)
+ {
+ BigInteger ba = BigInteger.valueOf(a);
+ BigInteger bb = BigInteger.valueOf(b);
+ BigInteger[] bresult = extgcd(ba, bb);
+ int[] result = new int[3];
+ result[0] = bresult[0].intValue();
+ result[1] = bresult[1].intValue();
+ result[2] = bresult[2].intValue();
+ return result;
+ }
+
+ public static BigInteger divideAndRound(BigInteger a, BigInteger b)
+ {
+ if (a.signum() < 0)
+ {
+ return divideAndRound(a.negate(), b).negate();
+ }
+ if (b.signum() < 0)
+ {
+ return divideAndRound(a, b.negate()).negate();
+ }
+ return a.shiftLeft(1).add(b).divide(b.shiftLeft(1));
+ }
+
+ public static BigInteger[] divideAndRound(BigInteger[] a, BigInteger b)
+ {
+ BigInteger[] out = new BigInteger[a.length];
+ for (int i = 0; i < a.length; i++)
+ {
+ out[i] = divideAndRound(a[i], b);
+ }
+ return out;
+ }
+
+ /**
+ * Compute the smallest integer that is greater than or equal to the
+ * logarithm to the base 2 of the given BigInteger.
+ *
+ * @param a the integer
+ * @return ceil[log(a)]
+ */
+ public static int ceilLog(BigInteger a)
+ {
+ int result = 0;
+ BigInteger p = ONE;
+ while (p.compareTo(a) < 0)
+ {
+ result++;
+ p = p.shiftLeft(1);
+ }
+ return result;
+ }
+
+ /**
+ * Compute the smallest integer that is greater than or equal to the
+ * logarithm to the base 2 of the given integer.
+ *
+ * @param a the integer
+ * @return ceil[log(a)]
+ */
+ public static int ceilLog(int a)
+ {
+ int log = 0;
+ int i = 1;
+ while (i < a)
+ {
+ i <<= 1;
+ log++;
+ }
+ return log;
+ }
+
+ /**
+ * Compute ceil(log_256 n), the number of bytes needed to encode
+ * the integer n.
+ *
+ * @param n the integer
+ * @return the number of bytes needed to encode n
+ */
+ public static int ceilLog256(int n)
+ {
+ if (n == 0)
+ {
+ return 1;
+ }
+ int m;
+ if (n < 0)
+ {
+ m = -n;
+ }
+ else
+ {
+ m = n;
+ }
+
+ int d = 0;
+ while (m > 0)
+ {
+ d++;
+ m >>>= 8;
+ }
+ return d;
+ }
+
+ /**
+ * Compute ceil(log_256 n), the number of bytes needed to encode
+ * the long integer n.
+ *
+ * @param n the long integer
+ * @return the number of bytes needed to encode n
+ */
+ public static int ceilLog256(long n)
+ {
+ if (n == 0)
+ {
+ return 1;
+ }
+ long m;
+ if (n < 0)
+ {
+ m = -n;
+ }
+ else
+ {
+ m = n;
+ }
+
+ int d = 0;
+ while (m > 0)
+ {
+ d++;
+ m >>>= 8;
+ }
+ return d;
+ }
+
+ /**
+ * Compute the integer part of the logarithm to the base 2 of the given
+ * integer.
+ *
+ * @param a the integer
+ * @return floor[log(a)]
+ */
+ public static int floorLog(BigInteger a)
+ {
+ int result = -1;
+ BigInteger p = ONE;
+ while (p.compareTo(a) <= 0)
+ {
+ result++;
+ p = p.shiftLeft(1);
+ }
+ return result;
+ }
+
+ /**
+ * Compute the integer part of the logarithm to the base 2 of the given
+ * integer.
+ *
+ * @param a the integer
+ * @return floor[log(a)]
+ */
+ public static int floorLog(int a)
+ {
+ int h = 0;
+ if (a <= 0)
+ {
+ return -1;
+ }
+ int p = a >>> 1;
+ while (p > 0)
+ {
+ h++;
+ p >>>= 1;
+ }
+
+ return h;
+ }
+
+ /**
+ * Compute the largest h with 2^h | a if a!=0.
+ *
+ * @param a an integer
+ * @return the largest h with 2^h | a if a!=0,
+ * 0 otherwise
+ */
+ public static int maxPower(int a)
+ {
+ int h = 0;
+ if (a != 0)
+ {
+ int p = 1;
+ while ((a & p) == 0)
+ {
+ h++;
+ p <<= 1;
+ }
+ }
+
+ return h;
+ }
+
+ /**
+ * @param a an integer
+ * @return the number of ones in the binary representation of an integer
+ * a
+ */
+ public static int bitCount(int a)
+ {
+ int h = 0;
+ while (a != 0)
+ {
+ h += a & 1;
+ a >>>= 1;
+ }
+
+ return h;
+ }
+
+ /**
+ * determines the order of g modulo p, p prime and 1 < g < p. This algorithm
+ * is only efficient for small p (see X9.62-1998, p. 68).
+ *
+ * @param g an integer with 1 < g < p
+ * @param p a prime
+ * @return the order k of g (that is k is the smallest integer with
+ * gk = 1 mod p
+ */
+ public static int order(int g, int p)
+ {
+ int b, j;
+
+ b = g % p; // Reduce g mod p first.
+ j = 1;
+
+ // Check whether g == 0 mod p (avoiding endless loop).
+ if (b == 0)
+ {
+ throw new IllegalArgumentException(g + " is not an element of Z/("
+ + p + "Z)^*; it is not meaningful to compute its order.");
+ }
+
+ // Compute the order of g mod p:
+ while (b != 1)
+ {
+ b *= g;
+ b %= p;
+ if (b < 0)
+ {
+ b += p;
+ }
+ j++;
+ }
+
+ return j;
+ }
+
+ /**
+ * Reduces an integer into a given interval
+ *
+ * @param n - the integer
+ * @param begin - left bound of the interval
+ * @param end - right bound of the interval
+ * @return n reduced into [begin,end]
+ */
+ public static BigInteger reduceInto(BigInteger n, BigInteger begin,
+ BigInteger end)
+ {
+ return n.subtract(begin).mod(end.subtract(begin)).add(begin);
+ }
+
+ /**
+ * Compute ae.
+ *
+ * @param a the base
+ * @param e the exponent
+ * @return ae
+ */
+ public static int pow(int a, int e)
+ {
+ int result = 1;
+ while (e > 0)
+ {
+ if ((e & 1) == 1)
+ {
+ result *= a;
+ }
+ a *= a;
+ e >>>= 1;
+ }
+ return result;
+ }
+
+ /**
+ * Compute ae.
+ *
+ * @param a the base
+ * @param e the exponent
+ * @return ae
+ */
+ public static long pow(long a, int e)
+ {
+ long result = 1;
+ while (e > 0)
+ {
+ if ((e & 1) == 1)
+ {
+ result *= a;
+ }
+ a *= a;
+ e >>>= 1;
+ }
+ return result;
+ }
+
+ /**
+ * Compute ae mod n.
+ *
+ * @param a the base
+ * @param e the exponent
+ * @param n the modulus
+ * @return ae mod n
+ */
+ public static int modPow(int a, int e, int n)
+ {
+ if (n <= 0 || (n * n) > Integer.MAX_VALUE || e < 0)
+ {
+ return 0;
+ }
+ int result = 1;
+ a = (a % n + n) % n;
+ while (e > 0)
+ {
+ if ((e & 1) == 1)
+ {
+ result = (result * a) % n;
+ }
+ a = (a * a) % n;
+ e >>>= 1;
+ }
+ return result;
+ }
+
+ /**
+ * Extended euclidian algorithm (computes gcd and representation).
+ *
+ * @param a - the first integer
+ * @param b - the second integer
+ * @return (d,u,v), where d = gcd(a,b) = ua + vb
+ */
+ public static BigInteger[] extgcd(BigInteger a, BigInteger b)
+ {
+ BigInteger u = ONE;
+ BigInteger v = ZERO;
+ BigInteger d = a;
+ if (b.signum() != 0)
+ {
+ BigInteger v1 = ZERO;
+ BigInteger v3 = b;
+ while (v3.signum() != 0)
+ {
+ BigInteger[] tmp = d.divideAndRemainder(v3);
+ BigInteger q = tmp[0];
+ BigInteger t3 = tmp[1];
+ BigInteger t1 = u.subtract(q.multiply(v1));
+ u = v1;
+ d = v3;
+ v1 = t1;
+ v3 = t3;
+ }
+ v = d.subtract(a.multiply(u)).divide(b);
+ }
+ return new BigInteger[]{d, u, v};
+ }
+
+ /**
+ * Computation of the least common multiple of a set of BigIntegers.
+ *
+ * @param numbers - the set of numbers
+ * @return the lcm(numbers)
+ */
+ public static BigInteger leastCommonMultiple(BigInteger[] numbers)
+ {
+ int n = numbers.length;
+ BigInteger result = numbers[0];
+ for (int i = 1; i < n; i++)
+ {
+ BigInteger gcd = result.gcd(numbers[i]);
+ result = result.multiply(numbers[i]).divide(gcd);
+ }
+ return result;
+ }
+
+ /**
+ * Returns a long integer whose value is (a mod m). This method
+ * differs from % in that it always returns a non-negative
+ * integer.
+ *
+ * @param a value on which the modulo operation has to be performed.
+ * @param m the modulus.
+ * @return a mod m
+ */
+ public static long mod(long a, long m)
+ {
+ long result = a % m;
+ if (result < 0)
+ {
+ result += m;
+ }
+ return result;
+ }
+
+ /**
+ * Computes the modular inverse of an integer a
+ *
+ * @param a - the integer to invert
+ * @param mod - the modulus
+ * @return a-1 mod n
+ */
+ public static int modInverse(int a, int mod)
+ {
+ return BigInteger.valueOf(a).modInverse(BigInteger.valueOf(mod))
+ .intValue();
+ }
+
+ /**
+ * Computes the modular inverse of an integer a
+ *
+ * @param a - the integer to invert
+ * @param mod - the modulus
+ * @return a-1 mod n
+ */
+ public static long modInverse(long a, long mod)
+ {
+ return BigInteger.valueOf(a).modInverse(BigInteger.valueOf(mod))
+ .longValue();
+ }
+
+ /**
+ * Tests whether an integer a is power of another integer
+ * p.
+ *
+ * @param a - the first integer
+ * @param p - the second integer
+ * @return n if a = p^n or -1 otherwise
+ */
+ public static int isPower(int a, int p)
+ {
+ if (a <= 0)
+ {
+ return -1;
+ }
+ int n = 0;
+ int d = a;
+ while (d > 1)
+ {
+ if (d % p != 0)
+ {
+ return -1;
+ }
+ d /= p;
+ n++;
+ }
+ return n;
+ }
+
+ /**
+ * Find and return the least non-trivial divisor of an integer a.
+ *
+ * @param a - the integer
+ * @return divisor p >1 or 1 if a = -1,0,1
+ */
+ public static int leastDiv(int a)
+ {
+ if (a < 0)
+ {
+ a = -a;
+ }
+ if (a == 0)
+ {
+ return 1;
+ }
+ if ((a & 1) == 0)
+ {
+ return 2;
+ }
+ int p = 3;
+ while (p <= (a / p))
+ {
+ if ((a % p) == 0)
+ {
+ return p;
+ }
+ p += 2;
+ }
+
+ return a;
+ }
+
+ /**
+ * Miller-Rabin-Test, determines wether the given integer is probably prime
+ * or composite. This method returns true if the given integer is
+ * prime with probability 1 - 2-20.
+ *
+ * @param n the integer to test for primality
+ * @return true if the given integer is prime with probability
+ * 2-100, false otherwise
+ */
+ public static boolean isPrime(int n)
+ {
+ if (n < 2)
+ {
+ return false;
+ }
+ if (n == 2)
+ {
+ return true;
+ }
+ if ((n & 1) == 0)
+ {
+ return false;
+ }
+ if (n < 42)
+ {
+ for (int i = 0; i < SMALL_PRIMES.length; i++)
+ {
+ if (n == SMALL_PRIMES[i])
+ {
+ return true;
+ }
+ }
+ }
+
+ if ((n % 3 == 0) || (n % 5 == 0) || (n % 7 == 0) || (n % 11 == 0)
+ || (n % 13 == 0) || (n % 17 == 0) || (n % 19 == 0)
+ || (n % 23 == 0) || (n % 29 == 0) || (n % 31 == 0)
+ || (n % 37 == 0) || (n % 41 == 0))
+ {
+ return false;
+ }
+
+ return BigInteger.valueOf(n).isProbablePrime(20);
+ }
+
+ /**
+ * Short trial-division test to find out whether a number is not prime. This
+ * test is usually used before a Miller-Rabin primality test.
+ *
+ * @param candidate the number to test
+ * @return true if the number has no factor of the tested primes,
+ * false if the number is definitely composite
+ */
+ public static boolean passesSmallPrimeTest(BigInteger candidate)
+ {
+ final int[] smallPrime = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37,
+ 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103,
+ 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167,
+ 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233,
+ 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307,
+ 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379,
+ 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449,
+ 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523,
+ 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607,
+ 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677,
+ 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761,
+ 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853,
+ 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937,
+ 941, 947, 953, 967, 971, 977, 983, 991, 997, 1009, 1013, 1019,
+ 1021, 1031, 1033, 1039, 1049, 1051, 1061, 1063, 1069, 1087,
+ 1091, 1093, 1097, 1103, 1109, 1117, 1123, 1129, 1151, 1153,
+ 1163, 1171, 1181, 1187, 1193, 1201, 1213, 1217, 1223, 1229,
+ 1231, 1237, 1249, 1259, 1277, 1279, 1283, 1289, 1291, 1297,
+ 1301, 1303, 1307, 1319, 1321, 1327, 1361, 1367, 1373, 1381,
+ 1399, 1409, 1423, 1427, 1429, 1433, 1439, 1447, 1451, 1453,
+ 1459, 1471, 1481, 1483, 1487, 1489, 1493, 1499};
+
+ for (int i = 0; i < smallPrime.length; i++)
+ {
+ if (candidate.mod(BigInteger.valueOf(smallPrime[i])).equals(
+ ZERO))
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Returns the largest prime smaller than the given integer
+ *
+ * @param n - upper bound
+ * @return the largest prime smaller than n, or 1 if
+ * n <= 2
+ */
+ public static int nextSmallerPrime(int n)
+ {
+ if (n <= 2)
+ {
+ return 1;
+ }
+
+ if (n == 3)
+ {
+ return 2;
+ }
+
+ if ((n & 1) == 0)
+ {
+ n--;
+ }
+ else
+ {
+ n -= 2;
+ }
+
+ while (n > 3 & !isPrime(n))
+ {
+ n -= 2;
+ }
+ return n;
+ }
+
+ /**
+ * Compute the next probable prime greater than n with the
+ * specified certainty.
+ *
+ * @param n a integer number
+ * @param certainty the certainty that the generated number is prime
+ * @return the next prime greater than n
+ */
+ public static BigInteger nextProbablePrime(BigInteger n, int certainty)
+ {
+
+ if (n.signum() < 0 || n.signum() == 0 || n.equals(ONE))
+ {
+ return TWO;
+ }
+
+ BigInteger result = n.add(ONE);
+
+ // Ensure an odd number
+ if (!result.testBit(0))
+ {
+ result = result.add(ONE);
+ }
+
+ while (true)
+ {
+ // Do cheap "pre-test" if applicable
+ if (result.bitLength() > 6)
+ {
+ long r = result.remainder(
+ BigInteger.valueOf(SMALL_PRIME_PRODUCT)).longValue();
+ if ((r % 3 == 0) || (r % 5 == 0) || (r % 7 == 0)
+ || (r % 11 == 0) || (r % 13 == 0) || (r % 17 == 0)
+ || (r % 19 == 0) || (r % 23 == 0) || (r % 29 == 0)
+ || (r % 31 == 0) || (r % 37 == 0) || (r % 41 == 0))
+ {
+ result = result.add(TWO);
+ continue; // Candidate is composite; try another
+ }
+ }
+
+ // All candidates of bitLength 2 and 3 are prime by this point
+ if (result.bitLength() < 4)
+ {
+ return result;
+ }
+
+ // The expensive test
+ if (result.isProbablePrime(certainty))
+ {
+ return result;
+ }
+
+ result = result.add(TWO);
+ }
+ }
+
+ /**
+ * Compute the next probable prime greater than n with the default
+ * certainty (20).
+ *
+ * @param n a integer number
+ * @return the next prime greater than n
+ */
+ public static BigInteger nextProbablePrime(BigInteger n)
+ {
+ return nextProbablePrime(n, 20);
+ }
+
+ /**
+ * Computes the next prime greater than n.
+ *
+ * @param n a integer number
+ * @return the next prime greater than n
+ */
+ public static BigInteger nextPrime(long n)
+ {
+ long i;
+ boolean found = false;
+ long result = 0;
+
+ if (n <= 1)
+ {
+ return BigInteger.valueOf(2);
+ }
+ if (n == 2)
+ {
+ return BigInteger.valueOf(3);
+ }
+
+ for (i = n + 1 + (n & 1); (i <= n << 1) && !found; i += 2)
+ {
+ for (long j = 3; (j <= i >> 1) && !found; j += 2)
+ {
+ if (i % j == 0)
+ {
+ found = true;
+ }
+ }
+ if (found)
+ {
+ found = false;
+ }
+ else
+ {
+ result = i;
+ found = true;
+ }
+ }
+ return BigInteger.valueOf(result);
+ }
+
+ /**
+ * Computes the binomial coefficient (n|t) ("n over t"). Formula:
+ *
+ *
+ *
+ * @param n - the "upper" integer
+ * @param t - the "lower" integer
+ * @return the binomialcoefficient "n over t" as BigInteger
+ */
+ public static BigInteger binomial(int n, int t)
+ {
+
+ BigInteger result = ONE;
+
+ if (n == 0)
+ {
+ if (t == 0)
+ {
+ return result;
+ }
+ return ZERO;
+ }
+
+ // the property (n|t) = (n|n-t) be used to reduce numbers of operations
+ if (t > (n >>> 1))
+ {
+ t = n - t;
+ }
+
+ for (int i = 1; i <= t; i++)
+ {
+ result = (result.multiply(BigInteger.valueOf(n - (i - 1))))
+ .divide(BigInteger.valueOf(i));
+ }
+
+ return result;
+ }
+
+ public static BigInteger randomize(BigInteger upperBound)
+ {
+ if (sr == null)
+ {
+ sr = new SecureRandom();
+ }
+ return randomize(upperBound, sr);
+ }
+
+ public static BigInteger randomize(BigInteger upperBound,
+ SecureRandom prng)
+ {
+ int blen = upperBound.bitLength();
+ BigInteger randomNum = BigInteger.valueOf(0);
+
+ if (prng == null)
+ {
+ prng = sr != null ? sr : new SecureRandom();
+ }
+
+ for (int i = 0; i < 20; i++)
+ {
+ randomNum = new BigInteger(blen, prng);
+ if (randomNum.compareTo(upperBound) < 0)
+ {
+ return randomNum;
+ }
+ }
+ return randomNum.mod(upperBound);
+ }
+
+ /**
+ * Extract the truncated square root of a BigInteger.
+ *
+ * @param a - value out of which we extract the square root
+ * @return the truncated square root of a
+ */
+ public static BigInteger squareRoot(BigInteger a)
+ {
+ int bl;
+ BigInteger result, remainder, b;
+
+ if (a.compareTo(ZERO) < 0)
+ {
+ throw new ArithmeticException(
+ "cannot extract root of negative number" + a + ".");
+ }
+
+ bl = a.bitLength();
+ result = ZERO;
+ remainder = ZERO;
+
+ // if the bit length is odd then extra step
+ if ((bl & 1) != 0)
+ {
+ result = result.add(ONE);
+ bl--;
+ }
+
+ while (bl > 0)
+ {
+ remainder = remainder.multiply(FOUR);
+ remainder = remainder.add(BigInteger.valueOf((a.testBit(--bl) ? 2
+ : 0)
+ + (a.testBit(--bl) ? 1 : 0)));
+ b = result.multiply(FOUR).add(ONE);
+ result = result.multiply(TWO);
+ if (remainder.compareTo(b) != -1)
+ {
+ result = result.add(ONE);
+ remainder = remainder.subtract(b);
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Takes an approximation of the root from an integer base, using newton's
+ * algorithm
+ *
+ * @param base the base to take the root from
+ * @param root the root, for example 2 for a square root
+ */
+ public static float intRoot(int base, int root)
+ {
+ float gNew = base / root;
+ float gOld = 0;
+ int counter = 0;
+ while (Math.abs(gOld - gNew) > 0.0001)
+ {
+ float gPow = floatPow(gNew, root);
+ while (Float.isInfinite(gPow))
+ {
+ gNew = (gNew + gOld) / 2;
+ gPow = floatPow(gNew, root);
+ }
+ counter += 1;
+ gOld = gNew;
+ gNew = gOld - (gPow - base) / (root * floatPow(gOld, root - 1));
+ }
+ return gNew;
+ }
+
+ /**
+ * Calculation of a logarithmus of a float param
+ *
+ * @param param
+ * @return
+ */
+ public static float floatLog(float param)
+ {
+ double arg = (param - 1) / (param + 1);
+ double arg2 = arg;
+ int counter = 1;
+ float result = (float)arg;
+
+ while (arg2 > 0.001)
+ {
+ counter += 2;
+ arg2 *= arg * arg;
+ result += (1. / counter) * arg2;
+ }
+ return 2 * result;
+ }
+
+ /**
+ * int power of a base float, only use for small ints
+ *
+ * @param f
+ * @param i
+ * @return
+ */
+ public static float floatPow(float f, int i)
+ {
+ float g = 1;
+ for (; i > 0; i--)
+ {
+ g *= f;
+ }
+ return g;
+ }
+
+ /**
+ * calculate the logarithm to the base 2.
+ *
+ * @param x any double value
+ * @return log_2(x)
+ * @deprecated use MathFunctions.log(double) instead
+ */
+ public static double log(double x)
+ {
+ if (x > 0 && x < 1)
+ {
+ double d = 1 / x;
+ double result = -log(d);
+ return result;
+ }
+
+ int tmp = 0;
+ double tmp2 = 1;
+ double d = x;
+
+ while (d > 2)
+ {
+ d = d / 2;
+ tmp += 1;
+ tmp2 *= 2;
+ }
+ double rem = x / tmp2;
+ rem = logBKM(rem);
+ return tmp + rem;
+ }
+
+ /**
+ * calculate the logarithm to the base 2.
+ *
+ * @param x any long value >=1
+ * @return log_2(x)
+ * @deprecated use MathFunctions.log(long) instead
+ */
+ public static double log(long x)
+ {
+ int tmp = floorLog(BigInteger.valueOf(x));
+ long tmp2 = 1 << tmp;
+ double rem = (double)x / (double)tmp2;
+ rem = logBKM(rem);
+ return tmp + rem;
+ }
+
+ /**
+ * BKM Algorithm to calculate logarithms to the base 2.
+ *
+ * @param arg a double value with 1<= arg<= 4.768462058
+ * @return log_2(arg)
+ * @deprecated use MathFunctions.logBKM(double) instead
+ */
+ private static double logBKM(double arg)
+ {
+ double ae[] = // A_e[k] = log_2 (1 + 0.5^k)
+ {
+ 1.0000000000000000000000000000000000000000000000000000000000000000000000000000,
+ 0.5849625007211561814537389439478165087598144076924810604557526545410982276485,
+ 0.3219280948873623478703194294893901758648313930245806120547563958159347765589,
+ 0.1699250014423123629074778878956330175196288153849621209115053090821964552970,
+ 0.0874628412503394082540660108104043540112672823448206881266090643866965081686,
+ 0.0443941193584534376531019906736094674630459333742491317685543002674288465967,
+ 0.0223678130284545082671320837460849094932677948156179815932199216587899627785,
+ 0.0112272554232541203378805844158839407281095943600297940811823651462712311786,
+ 0.0056245491938781069198591026740666017211096815383520359072957784732489771013,
+ 0.0028150156070540381547362547502839489729507927389771959487826944878598909400,
+ 0.0014081943928083889066101665016890524233311715793462235597709051792834906001,
+ 0.0007042690112466432585379340422201964456668872087249334581924550139514213168,
+ 0.0003521774803010272377989609925281744988670304302127133979341729842842377649,
+ 0.0001760994864425060348637509459678580940163670081839283659942864068257522373,
+ 0.0000880524301221769086378699983597183301490534085738474534831071719854721939,
+ 0.0000440268868273167176441087067175806394819146645511899503059774914593663365,
+ 0.0000220136113603404964890728830697555571275493801909791504158295359319433723,
+ 0.0000110068476674814423006223021573490183469930819844945565597452748333526464,
+ 0.0000055034343306486037230640321058826431606183125807276574241540303833251704,
+ 0.0000027517197895612831123023958331509538486493412831626219340570294203116559,
+ 0.0000013758605508411382010566802834037147561973553922354232704569052932922954,
+ 0.0000006879304394358496786728937442939160483304056131990916985043387874690617,
+ 0.0000003439652607217645360118314743718005315334062644619363447395987584138324,
+ 0.0000001719826406118446361936972479533123619972434705828085978955697643547921,
+ 0.0000000859913228686632156462565208266682841603921494181830811515318381744650,
+ 0.0000000429956620750168703982940244684787907148132725669106053076409624949917,
+ 0.0000000214978311976797556164155504126645192380395989504741781512309853438587,
+ 0.0000000107489156388827085092095702361647949603617203979413516082280717515504,
+ 0.0000000053744578294520620044408178949217773318785601260677517784797554422804,
+ 0.0000000026872289172287079490026152352638891824761667284401180026908031182361,
+ 0.0000000013436144592400232123622589569799954658536700992739887706412976115422,
+ 0.0000000006718072297764289157920422846078078155859484240808550018085324187007,
+ 0.0000000003359036149273187853169587152657145221968468364663464125722491530858,
+ 0.0000000001679518074734354745159899223037458278711244127245990591908996412262,
+ 0.0000000000839759037391617577226571237484864917411614198675604731728132152582,
+ 0.0000000000419879518701918839775296677020135040214077417929807824842667285938,
+ 0.0000000000209939759352486932678195559552767641474249812845414125580747434389,
+ 0.0000000000104969879676625344536740142096218372850561859495065136990936290929,
+ 0.0000000000052484939838408141817781356260462777942148580518406975851213868092,
+ 0.0000000000026242469919227938296243586262369156865545638305682553644113887909,
+ 0.0000000000013121234959619935994960031017850191710121890821178731821983105443,
+ 0.0000000000006560617479811459709189576337295395590603644549624717910616347038,
+ 0.0000000000003280308739906102782522178545328259781415615142931952662153623493,
+ 0.0000000000001640154369953144623242936888032768768777422997704541618141646683,
+ 0.0000000000000820077184976595619616930350508356401599552034612281802599177300,
+ 0.0000000000000410038592488303636807330652208397742314215159774270270147020117,
+ 0.0000000000000205019296244153275153381695384157073687186580546938331088730952,
+ 0.0000000000000102509648122077001764119940017243502120046885379813510430378661,
+ 0.0000000000000051254824061038591928917243090559919209628584150482483994782302,
+ 0.0000000000000025627412030519318726172939815845367496027046030028595094737777,
+ 0.0000000000000012813706015259665053515049475574143952543145124550608158430592,
+ 0.0000000000000006406853007629833949364669629701200556369782295210193569318434,
+ 0.0000000000000003203426503814917330334121037829290364330169106716787999052925,
+ 0.0000000000000001601713251907458754080007074659337446341494733882570243497196,
+ 0.0000000000000000800856625953729399268240176265844257044861248416330071223615,
+ 0.0000000000000000400428312976864705191179247866966320469710511619971334577509,
+ 0.0000000000000000200214156488432353984854413866994246781519154793320684126179,
+ 0.0000000000000000100107078244216177339743404416874899847406043033792202127070,
+ 0.0000000000000000050053539122108088756700751579281894640362199287591340285355,
+ 0.0000000000000000025026769561054044400057638132352058574658089256646014899499,
+ 0.0000000000000000012513384780527022205455634651853807110362316427807660551208,
+ 0.0000000000000000006256692390263511104084521222346348012116229213309001913762,
+ 0.0000000000000000003128346195131755552381436585278035120438976487697544916191,
+ 0.0000000000000000001564173097565877776275512286165232838833090480508502328437,
+ 0.0000000000000000000782086548782938888158954641464170239072244145219054734086,
+ 0.0000000000000000000391043274391469444084776945327473574450334092075712154016,
+ 0.0000000000000000000195521637195734722043713378812583900953755962557525252782,
+ 0.0000000000000000000097760818597867361022187915943503728909029699365320287407,
+ 0.0000000000000000000048880409298933680511176764606054809062553340323879609794,
+ 0.0000000000000000000024440204649466840255609083961603140683286362962192177597,
+ 0.0000000000000000000012220102324733420127809717395445504379645613448652614939,
+ 0.0000000000000000000006110051162366710063906152551383735699323415812152114058,
+ 0.0000000000000000000003055025581183355031953399739107113727036860315024588989,
+ 0.0000000000000000000001527512790591677515976780735407368332862218276873443537,
+ 0.0000000000000000000000763756395295838757988410584167137033767056170417508383,
+ 0.0000000000000000000000381878197647919378994210346199431733717514843471513618,
+ 0.0000000000000000000000190939098823959689497106436628681671067254111334889005,
+ 0.0000000000000000000000095469549411979844748553534196582286585751228071408728,
+ 0.0000000000000000000000047734774705989922374276846068851506055906657137209047,
+ 0.0000000000000000000000023867387352994961187138442777065843718711089344045782,
+ 0.0000000000000000000000011933693676497480593569226324192944532044984865894525,
+ 0.0000000000000000000000005966846838248740296784614396011477934194852481410926,
+ 0.0000000000000000000000002983423419124370148392307506484490384140516252814304,
+ 0.0000000000000000000000001491711709562185074196153830361933046331030629430117,
+ 0.0000000000000000000000000745855854781092537098076934460888486730708440475045,
+ 0.0000000000000000000000000372927927390546268549038472050424734256652501673274,
+ 0.0000000000000000000000000186463963695273134274519237230207489851150821191330,
+ 0.0000000000000000000000000093231981847636567137259618916352525606281553180093,
+ 0.0000000000000000000000000046615990923818283568629809533488457973317312233323,
+ 0.0000000000000000000000000023307995461909141784314904785572277779202790023236,
+ 0.0000000000000000000000000011653997730954570892157452397493151087737428485431,
+ 0.0000000000000000000000000005826998865477285446078726199923328593402722606924,
+ 0.0000000000000000000000000002913499432738642723039363100255852559084863397344,
+ 0.0000000000000000000000000001456749716369321361519681550201473345138307215067,
+ 0.0000000000000000000000000000728374858184660680759840775119123438968122488047,
+ 0.0000000000000000000000000000364187429092330340379920387564158411083803465567,
+ 0.0000000000000000000000000000182093714546165170189960193783228378441837282509,
+ 0.0000000000000000000000000000091046857273082585094980096891901482445902524441,
+ 0.0000000000000000000000000000045523428636541292547490048446022564529197237262,
+ 0.0000000000000000000000000000022761714318270646273745024223029238091160103901};
+ int n = 53;
+ double x = 1;
+ double y = 0;
+ double z;
+ double s = 1;
+ int k;
+
+ for (k = 0; k < n; k++)
+ {
+ z = x + x * s;
+ if (z <= arg)
+ {
+ x = z;
+ y += ae[k];
+ }
+ s *= 0.5;
+ }
+ return y;
+ }
+
+ public static boolean isIncreasing(int[] a)
+ {
+ for (int i = 1; i < a.length; i++)
+ {
+ if (a[i - 1] >= a[i])
+ {
+ System.out.println("a[" + (i - 1) + "] = " + a[i - 1] + " >= "
+ + a[i] + " = a[" + i + "]");
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public static byte[] integerToOctets(BigInteger val)
+ {
+ byte[] valBytes = val.abs().toByteArray();
+
+ // check whether the array includes a sign bit
+ if ((val.bitLength() & 7) != 0)
+ {
+ return valBytes;
+ }
+ // get rid of the sign bit (first byte)
+ byte[] tmp = new byte[val.bitLength() >> 3];
+ System.arraycopy(valBytes, 1, tmp, 0, tmp.length);
+ return tmp;
+ }
+
+ public static BigInteger octetsToInteger(byte[] data, int offset,
+ int length)
+ {
+ byte[] val = new byte[length + 1];
+
+ val[0] = 0;
+ System.arraycopy(data, offset, val, 1, length);
+ return new BigInteger(val);
+ }
+
+ public static BigInteger octetsToInteger(byte[] data)
+ {
+ return octetsToInteger(data, 0, data.length);
+ }
+
+ public static void main(String[] args)
+ {
+ System.out.println("test");
+ // System.out.println(intRoot(37, 5));
+ // System.out.println(floatPow((float)2.5, 4));
+ System.out.println(floatLog(10));
+ System.out.println("test2");
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/math/linearalgebra/LittleEndianConversions.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/math/linearalgebra/LittleEndianConversions.java
new file mode 100644
index 0000000..40b5e2d
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/math/linearalgebra/LittleEndianConversions.java
@@ -0,0 +1,230 @@
+package org.bc.pqc.math.linearalgebra;
+
+/**
+ * This is a utility class containing data type conversions using little-endian
+ * byte order.
+ *
+ * @see BigEndianConversions
+ */
+public final class LittleEndianConversions
+{
+
+ /**
+ * Default constructor (private).
+ */
+ private LittleEndianConversions()
+ {
+ // empty
+ }
+
+ /**
+ * Convert an octet string of length 4 to an integer. No length checking is
+ * performed.
+ *
+ * @param input the byte array holding the octet string
+ * @return an integer representing the octet string input
+ * @throws ArithmeticException if the length of the given octet string is larger than 4.
+ */
+ public static int OS2IP(byte[] input)
+ {
+ return ((input[0] & 0xff)) | ((input[1] & 0xff) << 8)
+ | ((input[2] & 0xff) << 16) | ((input[3] & 0xff)) << 24;
+ }
+
+ /**
+ * Convert an byte array of length 4 beginning at offset into an
+ * integer.
+ *
+ * @param input the byte array
+ * @param inOff the offset into the byte array
+ * @return the resulting integer
+ */
+ public static int OS2IP(byte[] input, int inOff)
+ {
+ int result = input[inOff++] & 0xff;
+ result |= (input[inOff++] & 0xff) << 8;
+ result |= (input[inOff++] & 0xff) << 16;
+ result |= (input[inOff] & 0xff) << 24;
+ return result;
+ }
+
+ /**
+ * Convert a byte array of the given length beginning at offset
+ * into an integer.
+ *
+ * @param input the byte array
+ * @param inOff the offset into the byte array
+ * @param inLen the length of the encoding
+ * @return the resulting integer
+ */
+ public static int OS2IP(byte[] input, int inOff, int inLen)
+ {
+ int result = 0;
+ for (int i = inLen - 1; i >= 0; i--)
+ {
+ result |= (input[inOff + i] & 0xff) << (8 * i);
+ }
+ return result;
+ }
+
+ /**
+ * Convert a byte array of length 8 beginning at inOff into a
+ * long integer.
+ *
+ * @param input the byte array
+ * @param inOff the offset into the byte array
+ * @return the resulting long integer
+ */
+ public static long OS2LIP(byte[] input, int inOff)
+ {
+ long result = input[inOff++] & 0xff;
+ result |= (input[inOff++] & 0xff) << 8;
+ result |= (input[inOff++] & 0xff) << 16;
+ result |= ((long)input[inOff++] & 0xff) << 24;
+ result |= ((long)input[inOff++] & 0xff) << 32;
+ result |= ((long)input[inOff++] & 0xff) << 40;
+ result |= ((long)input[inOff++] & 0xff) << 48;
+ result |= ((long)input[inOff++] & 0xff) << 56;
+ return result;
+ }
+
+ /**
+ * Convert an integer to an octet string of length 4.
+ *
+ * @param x the integer to convert
+ * @return the converted integer
+ */
+ public static byte[] I2OSP(int x)
+ {
+ byte[] result = new byte[4];
+ result[0] = (byte)x;
+ result[1] = (byte)(x >>> 8);
+ result[2] = (byte)(x >>> 16);
+ result[3] = (byte)(x >>> 24);
+ return result;
+ }
+
+ /**
+ * Convert an integer into a byte array beginning at the specified offset.
+ *
+ * @param value the integer to convert
+ * @param output the byte array to hold the result
+ * @param outOff the integer offset into the byte array
+ */
+ public static void I2OSP(int value, byte[] output, int outOff)
+ {
+ output[outOff++] = (byte)value;
+ output[outOff++] = (byte)(value >>> 8);
+ output[outOff++] = (byte)(value >>> 16);
+ output[outOff++] = (byte)(value >>> 24);
+ }
+
+ /**
+ * Convert an integer to a byte array beginning at the specified offset. No
+ * length checking is performed (i.e., if the integer cannot be encoded with
+ * length octets, it is truncated).
+ *
+ * @param value the integer to convert
+ * @param output the byte array to hold the result
+ * @param outOff the integer offset into the byte array
+ * @param outLen the length of the encoding
+ */
+ public static void I2OSP(int value, byte[] output, int outOff, int outLen)
+ {
+ for (int i = outLen - 1; i >= 0; i--)
+ {
+ output[outOff + i] = (byte)(value >>> (8 * i));
+ }
+ }
+
+ /**
+ * Convert an integer to a byte array of length 8.
+ *
+ * @param input the integer to convert
+ * @return the converted integer
+ */
+ public static byte[] I2OSP(long input)
+ {
+ byte[] output = new byte[8];
+ output[0] = (byte)input;
+ output[1] = (byte)(input >>> 8);
+ output[2] = (byte)(input >>> 16);
+ output[3] = (byte)(input >>> 24);
+ output[4] = (byte)(input >>> 32);
+ output[5] = (byte)(input >>> 40);
+ output[6] = (byte)(input >>> 48);
+ output[7] = (byte)(input >>> 56);
+ return output;
+ }
+
+ /**
+ * Convert an integer to a byte array of length 8.
+ *
+ * @param input the integer to convert
+ * @param output byte array holding the output
+ * @param outOff offset in output array where the result is stored
+ */
+ public static void I2OSP(long input, byte[] output, int outOff)
+ {
+ output[outOff++] = (byte)input;
+ output[outOff++] = (byte)(input >>> 8);
+ output[outOff++] = (byte)(input >>> 16);
+ output[outOff++] = (byte)(input >>> 24);
+ output[outOff++] = (byte)(input >>> 32);
+ output[outOff++] = (byte)(input >>> 40);
+ output[outOff++] = (byte)(input >>> 48);
+ output[outOff] = (byte)(input >>> 56);
+ }
+
+ /**
+ * Convert an int array to a byte array of the specified length. No length
+ * checking is performed (i.e., if the last integer cannot be encoded with
+ * length % 4 octets, it is truncated).
+ *
+ * @param input the int array
+ * @param outLen the length of the converted array
+ * @return the converted array
+ */
+ public static byte[] toByteArray(int[] input, int outLen)
+ {
+ int intLen = input.length;
+ byte[] result = new byte[outLen];
+ int index = 0;
+ for (int i = 0; i <= intLen - 2; i++, index += 4)
+ {
+ I2OSP(input[i], result, index);
+ }
+ I2OSP(input[intLen - 1], result, index, outLen - index);
+ return result;
+ }
+
+ /**
+ * Convert a byte array to an int array.
+ *
+ * @param input the byte array
+ * @return the converted array
+ */
+ public static int[] toIntArray(byte[] input)
+ {
+ int intLen = (input.length + 3) / 4;
+ int lastLen = input.length & 0x03;
+ int[] result = new int[intLen];
+
+ int index = 0;
+ for (int i = 0; i <= intLen - 2; i++, index += 4)
+ {
+ result[i] = OS2IP(input, index);
+ }
+ if (lastLen != 0)
+ {
+ result[intLen - 1] = OS2IP(input, index, lastLen);
+ }
+ else
+ {
+ result[intLen - 1] = OS2IP(input, index);
+ }
+
+ return result;
+ }
+
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/math/linearalgebra/Matrix.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/math/linearalgebra/Matrix.java
new file mode 100644
index 0000000..793d79c
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/math/linearalgebra/Matrix.java
@@ -0,0 +1,131 @@
+package org.bc.pqc.math.linearalgebra;
+
+/**
+ * This abstract class defines matrices. It holds the number of rows and the
+ * number of columns of the matrix and defines some basic methods.
+ */
+public abstract class Matrix
+{
+
+ /**
+ * number of rows
+ */
+ protected int numRows;
+
+ /**
+ * number of columns
+ */
+ protected int numColumns;
+
+ // ----------------------------------------------------
+ // some constants (matrix types)
+ // ----------------------------------------------------
+
+ /**
+ * zero matrix
+ */
+ public static final char MATRIX_TYPE_ZERO = 'Z';
+
+ /**
+ * unit matrix
+ */
+ public static final char MATRIX_TYPE_UNIT = 'I';
+
+ /**
+ * random lower triangular matrix
+ */
+ public static final char MATRIX_TYPE_RANDOM_LT = 'L';
+
+ /**
+ * random upper triangular matrix
+ */
+ public static final char MATRIX_TYPE_RANDOM_UT = 'U';
+
+ /**
+ * random regular matrix
+ */
+ public static final char MATRIX_TYPE_RANDOM_REGULAR = 'R';
+
+ // ----------------------------------------------------
+ // getters
+ // ----------------------------------------------------
+
+ /**
+ * @return the number of rows in the matrix
+ */
+ public int getNumRows()
+ {
+ return numRows;
+ }
+
+ /**
+ * @return the number of columns in the binary matrix
+ */
+ public int getNumColumns()
+ {
+ return numColumns;
+ }
+
+ /**
+ * @return the encoded matrix, i.e., this matrix in byte array form.
+ */
+ public abstract byte[] getEncoded();
+
+ // ----------------------------------------------------
+ // arithmetic
+ // ----------------------------------------------------
+
+ /**
+ * Compute the inverse of this matrix.
+ *
+ * @return the inverse of this matrix (newly created).
+ */
+ public abstract Matrix computeInverse();
+
+ /**
+ * Check if this is the zero matrix (i.e., all entries are zero).
+ *
+ * @return true if this is the zero matrix
+ */
+ public abstract boolean isZero();
+
+ /**
+ * Compute the product of this matrix and another matrix.
+ *
+ * @param a the other matrix
+ * @return this * a (newly created)
+ */
+ public abstract Matrix rightMultiply(Matrix a);
+
+ /**
+ * Compute the product of this matrix and a permutation.
+ *
+ * @param p the permutation
+ * @return this * p (newly created)
+ */
+ public abstract Matrix rightMultiply(Permutation p);
+
+ /**
+ * Compute the product of a vector and this matrix. If the length of the
+ * vector is greater than the number of rows of this matrix, the matrix is
+ * multiplied by each m-bit part of the vector.
+ *
+ * @param vector a vector
+ * @return vector * this (newly created)
+ */
+ public abstract Vector leftMultiply(Vector vector);
+
+ /**
+ * Compute the product of this matrix and a vector.
+ *
+ * @param vector a vector
+ * @return this * vector (newly created)
+ */
+ public abstract Vector rightMultiply(Vector vector);
+
+ /**
+ * @return a human readable form of the matrix.
+ */
+ public abstract String toString();
+
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/math/linearalgebra/Permutation.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/math/linearalgebra/Permutation.java
new file mode 100644
index 0000000..364db3b
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/math/linearalgebra/Permutation.java
@@ -0,0 +1,247 @@
+package org.bc.pqc.math.linearalgebra;
+
+import java.security.SecureRandom;
+
+/**
+ * This class implements permutations of the set {0,1,...,n-1} for some given n
+ * > 0, i.e., ordered sequences containing each number m (0 <=
+ * m < n)
+ * once and only once.
+ */
+public class Permutation
+{
+
+ /**
+ * perm holds the elements of the permutation vector, i.e. [perm(0),
+ * perm(1), ..., perm(n-1)]
+ */
+ private int[] perm;
+
+ /**
+ * Create the identity permutation of the given size.
+ *
+ * @param n the size of the permutation
+ */
+ public Permutation(int n)
+ {
+ if (n <= 0)
+ {
+ throw new IllegalArgumentException("invalid length");
+ }
+
+ perm = new int[n];
+ for (int i = n - 1; i >= 0; i--)
+ {
+ perm[i] = i;
+ }
+ }
+
+ /**
+ * Create a permutation using the given permutation vector.
+ *
+ * @param perm the permutation vector
+ */
+ public Permutation(int[] perm)
+ {
+ if (!isPermutation(perm))
+ {
+ throw new IllegalArgumentException(
+ "array is not a permutation vector");
+ }
+
+ this.perm = IntUtils.clone(perm);
+ }
+
+ /**
+ * Create a permutation from an encoded permutation.
+ *
+ * @param enc the encoded permutation
+ */
+ public Permutation(byte[] enc)
+ {
+ if (enc.length <= 4)
+ {
+ throw new IllegalArgumentException("invalid encoding");
+ }
+
+ int n = LittleEndianConversions.OS2IP(enc, 0);
+ int size = IntegerFunctions.ceilLog256(n - 1);
+
+ if (enc.length != 4 + n * size)
+ {
+ throw new IllegalArgumentException("invalid encoding");
+ }
+
+ perm = new int[n];
+ for (int i = 0; i < n; i++)
+ {
+ perm[i] = LittleEndianConversions.OS2IP(enc, 4 + i * size, size);
+ }
+
+ if (!isPermutation(perm))
+ {
+ throw new IllegalArgumentException("invalid encoding");
+ }
+
+ }
+
+ /**
+ * Create a random permutation of the given size.
+ *
+ * @param n the size of the permutation
+ * @param sr the source of randomness
+ */
+ public Permutation(int n, SecureRandom sr)
+ {
+ if (n <= 0)
+ {
+ throw new IllegalArgumentException("invalid length");
+ }
+
+ perm = new int[n];
+
+ int[] help = new int[n];
+ for (int i = 0; i < n; i++)
+ {
+ help[i] = i;
+ }
+
+ int k = n;
+ for (int j = 0; j < n; j++)
+ {
+ int i = RandUtils.nextInt(sr, k);
+ k--;
+ perm[j] = help[i];
+ help[i] = help[k];
+ }
+ }
+
+ /**
+ * Encode this permutation as byte array.
+ *
+ * @return the encoded permutation
+ */
+ public byte[] getEncoded()
+ {
+ int n = perm.length;
+ int size = IntegerFunctions.ceilLog256(n - 1);
+ byte[] result = new byte[4 + n * size];
+ LittleEndianConversions.I2OSP(n, result, 0);
+ for (int i = 0; i < n; i++)
+ {
+ LittleEndianConversions.I2OSP(perm[i], result, 4 + i * size, size);
+ }
+ return result;
+ }
+
+ /**
+ * @return the permutation vector (perm(0),perm(1),...,perm(n-1))
+ */
+ public int[] getVector()
+ {
+ return IntUtils.clone(perm);
+ }
+
+ /**
+ * Compute the inverse permutation P-1.
+ *
+ * @return this-1
+ */
+ public Permutation computeInverse()
+ {
+ Permutation result = new Permutation(perm.length);
+ for (int i = perm.length - 1; i >= 0; i--)
+ {
+ result.perm[perm[i]] = i;
+ }
+ return result;
+ }
+
+ /**
+ * Compute the product of this permutation and another permutation.
+ *
+ * @param p the other permutation
+ * @return this * p
+ */
+ public Permutation rightMultiply(Permutation p)
+ {
+ if (p.perm.length != perm.length)
+ {
+ throw new IllegalArgumentException("length mismatch");
+ }
+ Permutation result = new Permutation(perm.length);
+ for (int i = perm.length - 1; i >= 0; i--)
+ {
+ result.perm[i] = perm[p.perm[i]];
+ }
+ return result;
+ }
+
+ /**
+ * checks if given object is equal to this permutation.
+ *
+ * The method returns false whenever the given object is not permutation.
+ *
+ * @param other -
+ * permutation
+ * @return true or false
+ */
+ public boolean equals(Object other)
+ {
+
+ if (!(other instanceof Permutation))
+ {
+ return false;
+ }
+ Permutation otherPerm = (Permutation)other;
+
+ return IntUtils.equals(perm, otherPerm.perm);
+ }
+
+ /**
+ * @return a human readable form of the permutation
+ */
+ public String toString()
+ {
+ String result = "[" + perm[0];
+ for (int i = 1; i < perm.length; i++)
+ {
+ result += ", " + perm[i];
+ }
+ result += "]";
+ return result;
+ }
+
+ /**
+ * @return the hash code of this permutation
+ */
+ public int hashCode()
+ {
+ return perm.hashCode();
+ }
+
+ /**
+ * Check that the given array corresponds to a permutation of the set
+ * {0, 1, ..., n-1}.
+ *
+ * @param perm permutation vector
+ * @return true if perm represents an n-permutation and false otherwise
+ */
+ private boolean isPermutation(int[] perm)
+ {
+ int n = perm.length;
+ boolean[] onlyOnce = new boolean[n];
+
+ for (int i = 0; i < n; i++)
+ {
+ if ((perm[i] < 0) || (perm[i] >= n) || onlyOnce[perm[i]])
+ {
+ return false;
+ }
+ onlyOnce[perm[i]] = true;
+ }
+
+ return true;
+ }
+
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/math/linearalgebra/PolynomialGF2mSmallM.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/math/linearalgebra/PolynomialGF2mSmallM.java
new file mode 100644
index 0000000..d37b579
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/math/linearalgebra/PolynomialGF2mSmallM.java
@@ -0,0 +1,1125 @@
+package org.bc.pqc.math.linearalgebra;
+
+import java.security.SecureRandom;
+
+/**
+ * This class describes operations with polynomials from the ring R =
+ * GF(2^m)[X], where 2 <= m <=31.
+ *
+ * @see GF2mField
+ * @see PolynomialRingGF2m
+ */
+public class PolynomialGF2mSmallM
+{
+
+ /**
+ * the finite field GF(2^m)
+ */
+ private GF2mField field;
+
+ /**
+ * the degree of this polynomial
+ */
+ private int degree;
+
+ /**
+ * For the polynomial representation the map f: R->Z*,
+ * poly(X) -> [coef_0, coef_1, ...] is used, where
+ * coef_i is the ith coefficient of the polynomial
+ * represented as int (see {@link GF2mField}). The polynomials are stored
+ * as int arrays.
+ */
+ private int[] coefficients;
+
+ /*
+ * some types of polynomials
+ */
+
+ /**
+ * Constant used for polynomial construction (see constructor
+ * {@link #PolynomialGF2mSmallM(GF2mField, int, char, SecureRandom)}).
+ */
+ public static final char RANDOM_IRREDUCIBLE_POLYNOMIAL = 'I';
+
+ /**
+ * Construct the zero polynomial over the finite field GF(2^m).
+ *
+ * @param field the finite field GF(2^m)
+ */
+ public PolynomialGF2mSmallM(GF2mField field)
+ {
+ this.field = field;
+ degree = -1;
+ coefficients = new int[1];
+ }
+
+ /**
+ * Construct a polynomial over the finite field GF(2^m).
+ *
+ * @param field the finite field GF(2^m)
+ * @param deg degree of polynomial
+ * @param typeOfPolynomial type of polynomial
+ * @param sr PRNG
+ */
+ public PolynomialGF2mSmallM(GF2mField field, int deg,
+ char typeOfPolynomial, SecureRandom sr)
+ {
+ this.field = field;
+
+ switch (typeOfPolynomial)
+ {
+ case PolynomialGF2mSmallM.RANDOM_IRREDUCIBLE_POLYNOMIAL:
+ coefficients = createRandomIrreduciblePolynomial(deg, sr);
+ break;
+ default:
+ throw new IllegalArgumentException(" Error: type "
+ + typeOfPolynomial
+ + " is not defined for GF2smallmPolynomial");
+ }
+ computeDegree();
+ }
+
+ /**
+ * Create an irreducible polynomial with the given degree over the field
+ * GF(2^m).
+ *
+ * @param deg polynomial degree
+ * @param sr source of randomness
+ * @return the generated irreducible polynomial
+ */
+ private int[] createRandomIrreduciblePolynomial(int deg, SecureRandom sr)
+ {
+ int[] resCoeff = new int[deg + 1];
+ resCoeff[deg] = 1;
+ resCoeff[0] = field.getRandomNonZeroElement(sr);
+ for (int i = 1; i < deg; i++)
+ {
+ resCoeff[i] = field.getRandomElement(sr);
+ }
+ while (!isIrreducible(resCoeff))
+ {
+ int n = RandUtils.nextInt(sr, deg);
+ if (n == 0)
+ {
+ resCoeff[0] = field.getRandomNonZeroElement(sr);
+ }
+ else
+ {
+ resCoeff[n] = field.getRandomElement(sr);
+ }
+ }
+ return resCoeff;
+ }
+
+ /**
+ * Construct a monomial of the given degree over the finite field GF(2^m).
+ *
+ * @param field the finite field GF(2^m)
+ * @param degree the degree of the monomial
+ */
+ public PolynomialGF2mSmallM(GF2mField field, int degree)
+ {
+ this.field = field;
+ this.degree = degree;
+ coefficients = new int[degree + 1];
+ coefficients[degree] = 1;
+ }
+
+ /**
+ * Construct the polynomial over the given finite field GF(2^m) from the
+ * given coefficient vector.
+ *
+ * @param field finite field GF2m
+ * @param coeffs the coefficient vector
+ */
+ public PolynomialGF2mSmallM(GF2mField field, int[] coeffs)
+ {
+ this.field = field;
+ coefficients = normalForm(coeffs);
+ computeDegree();
+ }
+
+ /**
+ * Create a polynomial over the finite field GF(2^m).
+ *
+ * @param field the finite field GF(2^m)
+ * @param enc byte[] polynomial in byte array form
+ */
+ public PolynomialGF2mSmallM(GF2mField field, byte[] enc)
+ {
+ this.field = field;
+
+ // decodes polynomial
+ int d = 8;
+ int count = 1;
+ while (field.getDegree() > d)
+ {
+ count++;
+ d += 8;
+ }
+
+ if ((enc.length % count) != 0)
+ {
+ throw new IllegalArgumentException(
+ " Error: byte array is not encoded polynomial over given finite field GF2m");
+ }
+
+ coefficients = new int[enc.length / count];
+ count = 0;
+ for (int i = 0; i < coefficients.length; i++)
+ {
+ for (int j = 0; j < d; j += 8)
+ {
+ coefficients[i] ^= (enc[count++] & 0x000000ff) << j;
+ }
+ if (!this.field.isElementOfThisField(coefficients[i]))
+ {
+ throw new IllegalArgumentException(
+ " Error: byte array is not encoded polynomial over given finite field GF2m");
+ }
+ }
+ // if HC = 0 for non-zero polynomial, returns error
+ if ((coefficients.length != 1)
+ && (coefficients[coefficients.length - 1] == 0))
+ {
+ throw new IllegalArgumentException(
+ " Error: byte array is not encoded polynomial over given finite field GF2m");
+ }
+ computeDegree();
+ }
+
+ /**
+ * Copy constructor.
+ *
+ * @param other another {@link PolynomialGF2mSmallM}
+ */
+ public PolynomialGF2mSmallM(PolynomialGF2mSmallM other)
+ {
+ // field needs not to be cloned since it is immutable
+ field = other.field;
+ degree = other.degree;
+ coefficients = IntUtils.clone(other.coefficients);
+ }
+
+ /**
+ * Create a polynomial over the finite field GF(2^m) out of the given
+ * coefficient vector. The finite field is also obtained from the
+ * {@link GF2mVector}.
+ *
+ * @param vect the coefficient vector
+ */
+ public PolynomialGF2mSmallM(GF2mVector vect)
+ {
+ this(vect.getField(), vect.getIntArrayForm());
+ }
+
+ /*
+ * ------------------------
+ */
+
+ /**
+ * Return the degree of this polynomial
+ *
+ * @return int degree of this polynomial if this is zero polynomial return
+ * -1
+ */
+ public int getDegree()
+ {
+ int d = coefficients.length - 1;
+ if (coefficients[d] == 0)
+ {
+ return -1;
+ }
+ return d;
+ }
+
+ /**
+ * @return the head coefficient of this polynomial
+ */
+ public int getHeadCoefficient()
+ {
+ if (degree == -1)
+ {
+ return 0;
+ }
+ return coefficients[degree];
+ }
+
+ /**
+ * Return the head coefficient of a polynomial.
+ *
+ * @param a the polynomial
+ * @return the head coefficient of a
+ */
+ private static int headCoefficient(int[] a)
+ {
+ int degree = computeDegree(a);
+ if (degree == -1)
+ {
+ return 0;
+ }
+ return a[degree];
+ }
+
+ /**
+ * Return the coefficient with the given index.
+ *
+ * @param index the index
+ * @return the coefficient with the given index
+ */
+ public int getCoefficient(int index)
+ {
+ if ((index < 0) || (index > degree))
+ {
+ return 0;
+ }
+ return coefficients[index];
+ }
+
+ /**
+ * Returns encoded polynomial, i.e., this polynomial in byte array form
+ *
+ * @return the encoded polynomial
+ */
+ public byte[] getEncoded()
+ {
+ int d = 8;
+ int count = 1;
+ while (field.getDegree() > d)
+ {
+ count++;
+ d += 8;
+ }
+
+ byte[] res = new byte[coefficients.length * count];
+ count = 0;
+ for (int i = 0; i < coefficients.length; i++)
+ {
+ for (int j = 0; j < d; j += 8)
+ {
+ res[count++] = (byte)(coefficients[i] >>> j);
+ }
+ }
+
+ return res;
+ }
+
+ /**
+ * Evaluate this polynomial p at a value e (in
+ * GF(2^m)) with the Horner scheme.
+ *
+ * @param e the element of the finite field GF(2^m)
+ * @return this(e)
+ */
+ public int evaluateAt(int e)
+ {
+ int result = coefficients[degree];
+ for (int i = degree - 1; i >= 0; i--)
+ {
+ result = field.mult(result, e) ^ coefficients[i];
+ }
+ return result;
+ }
+
+ /**
+ * Compute the sum of this polynomial and the given polynomial.
+ *
+ * @param addend the addend
+ * @return this + a (newly created)
+ */
+ public PolynomialGF2mSmallM add(PolynomialGF2mSmallM addend)
+ {
+ int[] resultCoeff = add(coefficients, addend.coefficients);
+ return new PolynomialGF2mSmallM(field, resultCoeff);
+ }
+
+ /**
+ * Add the given polynomial to this polynomial (overwrite this).
+ *
+ * @param addend the addend
+ */
+ public void addToThis(PolynomialGF2mSmallM addend)
+ {
+ coefficients = add(coefficients, addend.coefficients);
+ computeDegree();
+ }
+
+ /**
+ * Compute the sum of two polynomials a and b over the finite field
+ * GF(2^m).
+ *
+ * @param a the first polynomial
+ * @param b the second polynomial
+ * @return a + b
+ */
+ private int[] add(int[] a, int[] b)
+ {
+ int[] result, addend;
+ if (a.length < b.length)
+ {
+ result = new int[b.length];
+ System.arraycopy(b, 0, result, 0, b.length);
+ addend = a;
+ }
+ else
+ {
+ result = new int[a.length];
+ System.arraycopy(a, 0, result, 0, a.length);
+ addend = b;
+ }
+
+ for (int i = addend.length - 1; i >= 0; i--)
+ {
+ result[i] = field.add(result[i], addend[i]);
+ }
+
+ return result;
+ }
+
+ /**
+ * Compute the sum of this polynomial and the monomial of the given degree.
+ *
+ * @param degree the degree of the monomial
+ * @return this + X^k
+ */
+ public PolynomialGF2mSmallM addMonomial(int degree)
+ {
+ int[] monomial = new int[degree + 1];
+ monomial[degree] = 1;
+ int[] resultCoeff = add(coefficients, monomial);
+ return new PolynomialGF2mSmallM(field, resultCoeff);
+ }
+
+ /**
+ * Compute the product of this polynomial with an element from GF(2^m).
+ *
+ * @param element an element of the finite field GF(2^m)
+ * @return this * element (newly created)
+ * @throws ArithmeticException if element is not an element of the finite
+ * field this polynomial is defined over.
+ */
+ public PolynomialGF2mSmallM multWithElement(int element)
+ {
+ if (!field.isElementOfThisField(element))
+ {
+ throw new ArithmeticException(
+ "Not an element of the finite field this polynomial is defined over.");
+ }
+ int[] resultCoeff = multWithElement(coefficients, element);
+ return new PolynomialGF2mSmallM(field, resultCoeff);
+ }
+
+ /**
+ * Multiply this polynomial with an element from GF(2^m).
+ *
+ * @param element an element of the finite field GF(2^m)
+ * @throws ArithmeticException if element is not an element of the finite
+ * field this polynomial is defined over.
+ */
+ public void multThisWithElement(int element)
+ {
+ if (!field.isElementOfThisField(element))
+ {
+ throw new ArithmeticException(
+ "Not an element of the finite field this polynomial is defined over.");
+ }
+ coefficients = multWithElement(coefficients, element);
+ computeDegree();
+ }
+
+ /**
+ * Compute the product of a polynomial a with an element from the finite
+ * field GF(2^m).
+ *
+ * @param a the polynomial
+ * @param element an element of the finite field GF(2^m)
+ * @return a * element
+ */
+ private int[] multWithElement(int[] a, int element)
+ {
+ int degree = computeDegree(a);
+ if (degree == -1 || element == 0)
+ {
+ return new int[1];
+ }
+
+ if (element == 1)
+ {
+ return IntUtils.clone(a);
+ }
+
+ int[] result = new int[degree + 1];
+ for (int i = degree; i >= 0; i--)
+ {
+ result[i] = field.mult(a[i], element);
+ }
+
+ return result;
+ }
+
+ /**
+ * Compute the product of this polynomial with a monomial X^k.
+ *
+ * @param k the degree of the monomial
+ * @return this * X^k
+ */
+ public PolynomialGF2mSmallM multWithMonomial(int k)
+ {
+ int[] resultCoeff = multWithMonomial(coefficients, k);
+ return new PolynomialGF2mSmallM(field, resultCoeff);
+ }
+
+ /**
+ * Compute the product of a polynomial with a monomial X^k.
+ *
+ * @param a the polynomial
+ * @param k the degree of the monomial
+ * @return a * X^k
+ */
+ private static int[] multWithMonomial(int[] a, int k)
+ {
+ int d = computeDegree(a);
+ if (d == -1)
+ {
+ return new int[1];
+ }
+ int[] result = new int[d + k + 1];
+ System.arraycopy(a, 0, result, k, d + 1);
+ return result;
+ }
+
+ /**
+ * Divide this polynomial by the given polynomial.
+ *
+ * @param f a polynomial
+ * @return polynomial pair = {q,r} where this = q*f+r and deg(r) <
+ * deg(f);
+ */
+ public PolynomialGF2mSmallM[] div(PolynomialGF2mSmallM f)
+ {
+ int[][] resultCoeffs = div(coefficients, f.coefficients);
+ return new PolynomialGF2mSmallM[]{
+ new PolynomialGF2mSmallM(field, resultCoeffs[0]),
+ new PolynomialGF2mSmallM(field, resultCoeffs[1])};
+ }
+
+ /**
+ * Compute the result of the division of two polynomials over the field
+ * GF(2^m).
+ *
+ * @param a the first polynomial
+ * @param f the second polynomial
+ * @return int[][] {q,r}, where a = q*f+r and deg(r) < deg(f);
+ */
+ private int[][] div(int[] a, int[] f)
+ {
+ int df = computeDegree(f);
+ int da = computeDegree(a) + 1;
+ if (df == -1)
+ {
+ throw new ArithmeticException("Division by zero.");
+ }
+ int[][] result = new int[2][];
+ result[0] = new int[1];
+ result[1] = new int[da];
+ int hc = headCoefficient(f);
+ hc = field.inverse(hc);
+ result[0][0] = 0;
+ System.arraycopy(a, 0, result[1], 0, result[1].length);
+ while (df <= computeDegree(result[1]))
+ {
+ int[] q;
+ int[] coeff = new int[1];
+ coeff[0] = field.mult(headCoefficient(result[1]), hc);
+ q = multWithElement(f, coeff[0]);
+ int n = computeDegree(result[1]) - df;
+ q = multWithMonomial(q, n);
+ coeff = multWithMonomial(coeff, n);
+ result[0] = add(coeff, result[0]);
+ result[1] = add(q, result[1]);
+ }
+ return result;
+ }
+
+ /**
+ * Return the greatest common divisor of this and a polynomial f
+ *
+ * @param f polynomial
+ * @return GCD(this, f)
+ */
+ public PolynomialGF2mSmallM gcd(PolynomialGF2mSmallM f)
+ {
+ int[] resultCoeff = gcd(coefficients, f.coefficients);
+ return new PolynomialGF2mSmallM(field, resultCoeff);
+ }
+
+ /**
+ * Return the greatest common divisor of two polynomials over the field
+ * GF(2^m).
+ *
+ * @param f the first polynomial
+ * @param g the second polynomial
+ * @return gcd(f, g)
+ */
+ private int[] gcd(int[] f, int[] g)
+ {
+ int[] a = f;
+ int[] b = g;
+ if (computeDegree(a) == -1)
+ {
+ return b;
+ }
+ while (computeDegree(b) != -1)
+ {
+ int[] c = mod(a, b);
+ a = new int[b.length];
+ System.arraycopy(b, 0, a, 0, a.length);
+ b = new int[c.length];
+ System.arraycopy(c, 0, b, 0, b.length);
+ }
+ int coeff = field.inverse(headCoefficient(a));
+ return multWithElement(a, coeff);
+ }
+
+ /**
+ * Compute the product of this polynomial and the given factor using a
+ * Karatzuba like scheme.
+ *
+ * @param factor the polynomial
+ * @return this * factor
+ */
+ public PolynomialGF2mSmallM multiply(PolynomialGF2mSmallM factor)
+ {
+ int[] resultCoeff = multiply(coefficients, factor.coefficients);
+ return new PolynomialGF2mSmallM(field, resultCoeff);
+ }
+
+ /**
+ * Compute the product of two polynomials over the field GF(2^m)
+ * using a Karatzuba like multiplication.
+ *
+ * @param a the first polynomial
+ * @param b the second polynomial
+ * @return a * b
+ */
+ private int[] multiply(int[] a, int[] b)
+ {
+ int[] mult1, mult2;
+ if (computeDegree(a) < computeDegree(b))
+ {
+ mult1 = b;
+ mult2 = a;
+ }
+ else
+ {
+ mult1 = a;
+ mult2 = b;
+ }
+
+ mult1 = normalForm(mult1);
+ mult2 = normalForm(mult2);
+
+ if (mult2.length == 1)
+ {
+ return multWithElement(mult1, mult2[0]);
+ }
+
+ int d1 = mult1.length;
+ int d2 = mult2.length;
+ int[] result = new int[d1 + d2 - 1];
+
+ if (d2 != d1)
+ {
+ int[] res1 = new int[d2];
+ int[] res2 = new int[d1 - d2];
+ System.arraycopy(mult1, 0, res1, 0, res1.length);
+ System.arraycopy(mult1, d2, res2, 0, res2.length);
+ res1 = multiply(res1, mult2);
+ res2 = multiply(res2, mult2);
+ res2 = multWithMonomial(res2, d2);
+ result = add(res1, res2);
+ }
+ else
+ {
+ d2 = (d1 + 1) >>> 1;
+ int d = d1 - d2;
+ int[] firstPartMult1 = new int[d2];
+ int[] firstPartMult2 = new int[d2];
+ int[] secondPartMult1 = new int[d];
+ int[] secondPartMult2 = new int[d];
+ System
+ .arraycopy(mult1, 0, firstPartMult1, 0,
+ firstPartMult1.length);
+ System.arraycopy(mult1, d2, secondPartMult1, 0,
+ secondPartMult1.length);
+ System
+ .arraycopy(mult2, 0, firstPartMult2, 0,
+ firstPartMult2.length);
+ System.arraycopy(mult2, d2, secondPartMult2, 0,
+ secondPartMult2.length);
+ int[] helpPoly1 = add(firstPartMult1, secondPartMult1);
+ int[] helpPoly2 = add(firstPartMult2, secondPartMult2);
+ int[] res1 = multiply(firstPartMult1, firstPartMult2);
+ int[] res2 = multiply(helpPoly1, helpPoly2);
+ int[] res3 = multiply(secondPartMult1, secondPartMult2);
+ res2 = add(res2, res1);
+ res2 = add(res2, res3);
+ res3 = multWithMonomial(res3, d2);
+ result = add(res2, res3);
+ result = multWithMonomial(result, d2);
+ result = add(result, res1);
+ }
+
+ return result;
+ }
+
+ /*
+ * ---------------- PART II ----------------
+ *
+ */
+
+ /**
+ * Check a polynomial for irreducibility over the field GF(2^m).
+ *
+ * @param a the polynomial to check
+ * @return true if a is irreducible, false otherwise
+ */
+ private boolean isIrreducible(int[] a)
+ {
+ if (a[0] == 0)
+ {
+ return false;
+ }
+ int d = computeDegree(a) >> 1;
+ int[] u = {0, 1};
+ final int[] Y = {0, 1};
+ int fieldDegree = field.getDegree();
+ for (int i = 0; i < d; i++)
+ {
+ for (int j = fieldDegree - 1; j >= 0; j--)
+ {
+ u = modMultiply(u, u, a);
+ }
+ u = normalForm(u);
+ int[] g = gcd(add(u, Y), a);
+ if (computeDegree(g) != 0)
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Reduce this polynomial modulo another polynomial.
+ *
+ * @param f the reduction polynomial
+ * @return this mod f
+ */
+ public PolynomialGF2mSmallM mod(PolynomialGF2mSmallM f)
+ {
+ int[] resultCoeff = mod(coefficients, f.coefficients);
+ return new PolynomialGF2mSmallM(field, resultCoeff);
+ }
+
+ /**
+ * Reduce a polynomial modulo another polynomial.
+ *
+ * @param a the polynomial
+ * @param f the reduction polynomial
+ * @return a mod f
+ */
+ private int[] mod(int[] a, int[] f)
+ {
+ int df = computeDegree(f);
+ if (df == -1)
+ {
+ throw new ArithmeticException("Division by zero");
+ }
+ int[] result = new int[a.length];
+ int hc = headCoefficient(f);
+ hc = field.inverse(hc);
+ System.arraycopy(a, 0, result, 0, result.length);
+ while (df <= computeDegree(result))
+ {
+ int[] q;
+ int coeff = field.mult(headCoefficient(result), hc);
+ q = multWithMonomial(f, computeDegree(result) - df);
+ q = multWithElement(q, coeff);
+ result = add(q, result);
+ }
+ return result;
+ }
+
+ /**
+ * Compute the product of this polynomial and another polynomial modulo a
+ * third polynomial.
+ *
+ * @param a another polynomial
+ * @param b the reduction polynomial
+ * @return this * a mod b
+ */
+ public PolynomialGF2mSmallM modMultiply(PolynomialGF2mSmallM a,
+ PolynomialGF2mSmallM b)
+ {
+ int[] resultCoeff = modMultiply(coefficients, a.coefficients,
+ b.coefficients);
+ return new PolynomialGF2mSmallM(field, resultCoeff);
+ }
+
+ /**
+ * Square this polynomial using a squaring matrix.
+ *
+ * @param matrix the squaring matrix
+ * @return this^2 modulo the reduction polynomial implicitly
+ * given via the squaring matrix
+ */
+ public PolynomialGF2mSmallM modSquareMatrix(PolynomialGF2mSmallM[] matrix)
+ {
+
+ int length = matrix.length;
+
+ int[] resultCoeff = new int[length];
+ int[] thisSquare = new int[length];
+
+ // square each entry of this polynomial
+ for (int i = 0; i < coefficients.length; i++)
+ {
+ thisSquare[i] = field.mult(coefficients[i], coefficients[i]);
+ }
+
+ // do matrix-vector multiplication
+ for (int i = 0; i < length; i++)
+ {
+ // compute scalar product of i-th row and coefficient vector
+ for (int j = 0; j < length; j++)
+ {
+ if (i >= matrix[j].coefficients.length)
+ {
+ continue;
+ }
+ int scalarTerm = field.mult(matrix[j].coefficients[i],
+ thisSquare[j]);
+ resultCoeff[i] = field.add(resultCoeff[i], scalarTerm);
+ }
+ }
+
+ return new PolynomialGF2mSmallM(field, resultCoeff);
+ }
+
+ /**
+ * Compute the product of two polynomials modulo a third polynomial over the
+ * finite field GF(2^m).
+ *
+ * @param a the first polynomial
+ * @param b the second polynomial
+ * @param g the reduction polynomial
+ * @return a * b mod g
+ */
+ private int[] modMultiply(int[] a, int[] b, int[] g)
+ {
+ return mod(multiply(a, b), g);
+ }
+
+ /**
+ * Compute the square root of this polynomial modulo the given polynomial.
+ *
+ * @param a the reduction polynomial
+ * @return this^(1/2) mod a
+ */
+ public PolynomialGF2mSmallM modSquareRoot(PolynomialGF2mSmallM a)
+ {
+ int[] resultCoeff = IntUtils.clone(coefficients);
+ int[] help = modMultiply(resultCoeff, resultCoeff, a.coefficients);
+ while (!isEqual(help, coefficients))
+ {
+ resultCoeff = normalForm(help);
+ help = modMultiply(resultCoeff, resultCoeff, a.coefficients);
+ }
+
+ return new PolynomialGF2mSmallM(field, resultCoeff);
+ }
+
+ /**
+ * Compute the square root of this polynomial using a square root matrix.
+ *
+ * @param matrix the matrix for computing square roots in
+ * (GF(2^m))^t the polynomial ring defining the
+ * square root matrix
+ * @return this^(1/2) modulo the reduction polynomial implicitly
+ * given via the square root matrix
+ */
+ public PolynomialGF2mSmallM modSquareRootMatrix(
+ PolynomialGF2mSmallM[] matrix)
+ {
+
+ int length = matrix.length;
+
+ int[] resultCoeff = new int[length];
+
+ // do matrix multiplication
+ for (int i = 0; i < length; i++)
+ {
+ // compute scalar product of i-th row and j-th column
+ for (int j = 0; j < length; j++)
+ {
+ if (i >= matrix[j].coefficients.length)
+ {
+ continue;
+ }
+ if (j < coefficients.length)
+ {
+ int scalarTerm = field.mult(matrix[j].coefficients[i],
+ coefficients[j]);
+ resultCoeff[i] = field.add(resultCoeff[i], scalarTerm);
+ }
+ }
+ }
+
+ // compute the square root of each entry of the result coefficients
+ for (int i = 0; i < length; i++)
+ {
+ resultCoeff[i] = field.sqRoot(resultCoeff[i]);
+ }
+
+ return new PolynomialGF2mSmallM(field, resultCoeff);
+ }
+
+ /**
+ * Compute the result of the division of this polynomial by another
+ * polynomial modulo a third polynomial.
+ *
+ * @param divisor the divisor
+ * @param modulus the reduction polynomial
+ * @return this * divisor^(-1) mod modulus
+ */
+ public PolynomialGF2mSmallM modDiv(PolynomialGF2mSmallM divisor,
+ PolynomialGF2mSmallM modulus)
+ {
+ int[] resultCoeff = modDiv(coefficients, divisor.coefficients,
+ modulus.coefficients);
+ return new PolynomialGF2mSmallM(field, resultCoeff);
+ }
+
+ /**
+ * Compute the result of the division of two polynomials modulo a third
+ * polynomial over the field GF(2^m).
+ *
+ * @param a the first polynomial
+ * @param b the second polynomial
+ * @param g the reduction polynomial
+ * @return a * b^(-1) mod g
+ */
+ private int[] modDiv(int[] a, int[] b, int[] g)
+ {
+ int[] r0 = normalForm(g);
+ int[] r1 = mod(b, g);
+ int[] s0 = {0};
+ int[] s1 = mod(a, g);
+ int[] s2;
+ int[][] q;
+ while (computeDegree(r1) != -1)
+ {
+ q = div(r0, r1);
+ r0 = normalForm(r1);
+ r1 = normalForm(q[1]);
+ s2 = add(s0, modMultiply(q[0], s1, g));
+ s0 = normalForm(s1);
+ s1 = normalForm(s2);
+
+ }
+ int hc = headCoefficient(r0);
+ s0 = multWithElement(s0, field.inverse(hc));
+ return s0;
+ }
+
+ /**
+ * Compute the inverse of this polynomial modulo the given polynomial.
+ *
+ * @param a the reduction polynomial
+ * @return this^(-1) mod a
+ */
+ public PolynomialGF2mSmallM modInverse(PolynomialGF2mSmallM a)
+ {
+ int[] unit = {1};
+ int[] resultCoeff = modDiv(unit, coefficients, a.coefficients);
+ return new PolynomialGF2mSmallM(field, resultCoeff);
+ }
+
+ /**
+ * Compute a polynomial pair (a,b) from this polynomial and the given
+ * polynomial g with the property b*this = a mod g and deg(a)<=deg(g)/2.
+ *
+ * @param g the reduction polynomial
+ * @return PolynomialGF2mSmallM[] {a,b} with b*this = a mod g and deg(a)<=
+ * deg(g)/2
+ */
+ public PolynomialGF2mSmallM[] modPolynomialToFracton(PolynomialGF2mSmallM g)
+ {
+ int dg = g.degree >> 1;
+ int[] a0 = normalForm(g.coefficients);
+ int[] a1 = mod(coefficients, g.coefficients);
+ int[] b0 = {0};
+ int[] b1 = {1};
+ while (computeDegree(a1) > dg)
+ {
+ int[][] q = div(a0, a1);
+ a0 = a1;
+ a1 = q[1];
+ int[] b2 = add(b0, modMultiply(q[0], b1, g.coefficients));
+ b0 = b1;
+ b1 = b2;
+ }
+
+ return new PolynomialGF2mSmallM[]{
+ new PolynomialGF2mSmallM(field, a1),
+ new PolynomialGF2mSmallM(field, b1)};
+ }
+
+ /**
+ * checks if given object is equal to this polynomial.
+ *
+ * The method returns false whenever the given object is not polynomial over
+ * GF(2^m).
+ *
+ * @param other object
+ * @return true or false
+ */
+ public boolean equals(Object other)
+ {
+
+ if (other == null || !(other instanceof PolynomialGF2mSmallM))
+ {
+ return false;
+ }
+
+ PolynomialGF2mSmallM p = (PolynomialGF2mSmallM)other;
+
+ if ((field.equals(p.field)) && (degree == p.degree)
+ && (isEqual(coefficients, p.coefficients)))
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Compare two polynomials given as int arrays.
+ *
+ * @param a the first polynomial
+ * @param b the second polynomial
+ * @return true if a and b represent the
+ * same polynomials, false otherwise
+ */
+ private static boolean isEqual(int[] a, int[] b)
+ {
+ int da = computeDegree(a);
+ int db = computeDegree(b);
+ if (da != db)
+ {
+ return false;
+ }
+ for (int i = 0; i <= da; i++)
+ {
+ if (a[i] != b[i])
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * @return the hash code of this polynomial
+ */
+ public int hashCode()
+ {
+ int hash = field.hashCode();
+ for (int j = 0; j < coefficients.length; j++)
+ {
+ hash = hash * 31 + coefficients[j];
+ }
+ return hash;
+ }
+
+ /**
+ * Returns a human readable form of the polynomial.
+ *
+ *
+ * @return a human readable form of the polynomial.
+ */
+ public String toString()
+ {
+ String str = " Polynomial over " + field.toString() + ": \n";
+
+ for (int i = 0; i < coefficients.length; i++)
+ {
+ str = str + field.elementToStr(coefficients[i]) + "Y^" + i + "+";
+ }
+ str = str + ";";
+
+ return str;
+ }
+
+ /**
+ * Compute the degree of this polynomial. If this is the zero polynomial,
+ * the degree is -1.
+ */
+ private void computeDegree()
+ {
+ for (degree = coefficients.length - 1; degree >= 0
+ && coefficients[degree] == 0; degree--)
+ {
+ ;
+ }
+ }
+
+ /**
+ * Compute the degree of a polynomial.
+ *
+ * @param a the polynomial
+ * @return the degree of the polynomial a. If a is
+ * the zero polynomial, return -1.
+ */
+ private static int computeDegree(int[] a)
+ {
+ int degree;
+ for (degree = a.length - 1; degree >= 0 && a[degree] == 0; degree--)
+ {
+ ;
+ }
+ return degree;
+ }
+
+ /**
+ * Strip leading zero coefficients from the given polynomial.
+ *
+ * @param a the polynomial
+ * @return the reduced polynomial
+ */
+ private static int[] normalForm(int[] a)
+ {
+ int d = computeDegree(a);
+
+ // if a is the zero polynomial
+ if (d == -1)
+ {
+ // return new zero polynomial
+ return new int[1];
+ }
+
+ // if a already is in normal form
+ if (a.length == d + 1)
+ {
+ // return a clone of a
+ return IntUtils.clone(a);
+ }
+
+ // else, reduce a
+ int[] result = new int[d + 1];
+ System.arraycopy(a, 0, result, 0, d + 1);
+ return result;
+ }
+
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/math/linearalgebra/PolynomialRingGF2.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/math/linearalgebra/PolynomialRingGF2.java
new file mode 100644
index 0000000..095660e
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/math/linearalgebra/PolynomialRingGF2.java
@@ -0,0 +1,278 @@
+package org.bc.pqc.math.linearalgebra;
+
+/**
+ * This class describes operations with polynomials over finite field GF(2), i e
+ * polynomial ring R = GF(2)[X]. All operations are defined only for polynomials
+ * with degree <=32. For the polynomial representation the map f: R->Z,
+ * poly(X)->poly(2) is used, where integers have the binary representation. For
+ * example: X^7+X^3+X+1 -> (00...0010001011)=139 Also for polynomials type
+ * Integer is used.
+ *
+ * @see GF2mField
+ */
+public final class PolynomialRingGF2
+{
+
+ /**
+ * Default constructor (private).
+ */
+ private PolynomialRingGF2()
+ {
+ // empty
+ }
+
+ /**
+ * Return sum of two polyomials
+ *
+ * @param p polynomial
+ * @param q polynomial
+ * @return p+q
+ */
+
+ public static int add(int p, int q)
+ {
+ return p ^ q;
+ }
+
+ /**
+ * Return product of two polynomials
+ *
+ * @param p polynomial
+ * @param q polynomial
+ * @return p*q
+ */
+
+ public static long multiply(int p, int q)
+ {
+ long result = 0;
+ if (q != 0)
+ {
+ long q1 = q & 0x00000000ffffffffL;
+
+ while (p != 0)
+ {
+ byte b = (byte)(p & 0x01);
+ if (b == 1)
+ {
+ result ^= q1;
+ }
+ p >>>= 1;
+ q1 <<= 1;
+
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Compute the product of two polynomials modulo a third polynomial.
+ *
+ * @param a the first polynomial
+ * @param b the second polynomial
+ * @param r the reduction polynomial
+ * @return a * b mod r
+ */
+ public static int modMultiply(int a, int b, int r)
+ {
+ int result = 0;
+ int p = remainder(a, r);
+ int q = remainder(b, r);
+ if (q != 0)
+ {
+ int d = 1 << degree(r);
+
+ while (p != 0)
+ {
+ byte pMod2 = (byte)(p & 0x01);
+ if (pMod2 == 1)
+ {
+ result ^= q;
+ }
+ p >>>= 1;
+ q <<= 1;
+ if (q >= d)
+ {
+ q ^= r;
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Return the degree of a polynomial
+ *
+ * @param p polynomial p
+ * @return degree(p)
+ */
+
+ public static int degree(int p)
+ {
+ int result = -1;
+ while (p != 0)
+ {
+ result++;
+ p >>>= 1;
+ }
+ return result;
+ }
+
+ /**
+ * Return the degree of a polynomial
+ *
+ * @param p polynomial p
+ * @return degree(p)
+ */
+
+ public static int degree(long p)
+ {
+ int result = 0;
+ while (p != 0)
+ {
+ result++;
+ p >>>= 1;
+ }
+ return result - 1;
+ }
+
+ /**
+ * Return the remainder of a polynomial division of two polynomials.
+ *
+ * @param p dividend
+ * @param q divisor
+ * @return p mod q
+ */
+ public static int remainder(int p, int q)
+ {
+ int result = p;
+
+ if (q == 0)
+ {
+ System.err.println("Error: to be divided by 0");
+ return 0;
+ }
+
+ while (degree(result) >= degree(q))
+ {
+ result ^= q << (degree(result) - degree(q));
+ }
+
+ return result;
+ }
+
+ /**
+ * Return the rest of devision two polynomials
+ *
+ * @param p polinomial
+ * @param q polinomial
+ * @return p mod q
+ */
+
+ public static int rest(long p, int q)
+ {
+ long p1 = p;
+ if (q == 0)
+ {
+ System.err.println("Error: to be divided by 0");
+ return 0;
+ }
+ long q1 = q & 0x00000000ffffffffL;
+ while ((p1 >>> 32) != 0)
+ {
+ p1 ^= q1 << (degree(p1) - degree(q1));
+ }
+
+ int result = (int)(p1 & 0xffffffff);
+ while (degree(result) >= degree(q))
+ {
+ result ^= q << (degree(result) - degree(q));
+ }
+
+ return result;
+ }
+
+ /**
+ * Return the greatest common divisor of two polynomials
+ *
+ * @param p polinomial
+ * @param q polinomial
+ * @return GCD(p, q)
+ */
+
+ public static int gcd(int p, int q)
+ {
+ int a, b, c;
+ a = p;
+ b = q;
+ while (b != 0)
+ {
+ c = remainder(a, b);
+ a = b;
+ b = c;
+
+ }
+ return a;
+ }
+
+ /**
+ * Checking polynomial for irreducibility
+ *
+ * @param p polinomial
+ * @return true if p is irreducible and false otherwise
+ */
+
+ public static boolean isIrreducible(int p)
+ {
+ if (p == 0)
+ {
+ return false;
+ }
+ int d = degree(p) >>> 1;
+ int u = 2;
+ for (int i = 0; i < d; i++)
+ {
+ u = modMultiply(u, u, p);
+ if (gcd(u ^ 2, p) != 1)
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Creates irreducible polynomial with degree d
+ *
+ * @param deg polynomial degree
+ * @return irreducible polynomial p
+ */
+ public static int getIrreduciblePolynomial(int deg)
+ {
+ if (deg < 0)
+ {
+ System.err.println("The Degree is negative");
+ return 0;
+ }
+ if (deg > 31)
+ {
+ System.err.println("The Degree is more then 31");
+ return 0;
+ }
+ if (deg == 0)
+ {
+ return 1;
+ }
+ int a = 1 << deg;
+ a++;
+ int b = 1 << (deg + 1);
+ for (int i = a; i < b; i += 2)
+ {
+ if (isIrreducible(i))
+ {
+ return i;
+ }
+ }
+ return 0;
+ }
+
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/math/linearalgebra/PolynomialRingGF2m.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/math/linearalgebra/PolynomialRingGF2m.java
new file mode 100644
index 0000000..dc26471
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/math/linearalgebra/PolynomialRingGF2m.java
@@ -0,0 +1,175 @@
+package org.bc.pqc.math.linearalgebra;
+
+/**
+ * This class represents polynomial rings GF(2^m)[X]/p(X) for
+ * m<<;32. If p(X) is irreducible, the polynomial ring
+ * is in fact an extension field of GF(2^m).
+ */
+public class PolynomialRingGF2m
+{
+
+ /**
+ * the finite field this polynomial ring is defined over
+ */
+ private GF2mField field;
+
+ /**
+ * the reduction polynomial
+ */
+ private PolynomialGF2mSmallM p;
+
+ /**
+ * the squaring matrix for this polynomial ring (given as the array of its
+ * row vectors)
+ */
+ protected PolynomialGF2mSmallM[] sqMatrix;
+
+ /**
+ * the matrix for computing square roots in this polynomial ring (given as
+ * the array of its row vectors). This matrix is computed as the inverse of
+ * the squaring matrix.
+ */
+ protected PolynomialGF2mSmallM[] sqRootMatrix;
+
+ /**
+ * Constructor.
+ *
+ * @param field the finite field
+ * @param p the reduction polynomial
+ */
+ public PolynomialRingGF2m(GF2mField field, PolynomialGF2mSmallM p)
+ {
+ this.field = field;
+ this.p = p;
+ computeSquaringMatrix();
+ computeSquareRootMatrix();
+ }
+
+ /**
+ * @return the squaring matrix for this polynomial ring
+ */
+ public PolynomialGF2mSmallM[] getSquaringMatrix()
+ {
+ return sqMatrix;
+ }
+
+ /**
+ * @return the matrix for computing square roots for this polynomial ring
+ */
+ public PolynomialGF2mSmallM[] getSquareRootMatrix()
+ {
+ return sqRootMatrix;
+ }
+
+ /**
+ * Compute the squaring matrix for this polynomial ring, using the base
+ * field and the reduction polynomial.
+ */
+ private void computeSquaringMatrix()
+ {
+ int numColumns = p.getDegree();
+ sqMatrix = new PolynomialGF2mSmallM[numColumns];
+ for (int i = 0; i < numColumns >> 1; i++)
+ {
+ int[] monomCoeffs = new int[(i << 1) + 1];
+ monomCoeffs[i << 1] = 1;
+ sqMatrix[i] = new PolynomialGF2mSmallM(field, monomCoeffs);
+ }
+ for (int i = numColumns >> 1; i < numColumns; i++)
+ {
+ int[] monomCoeffs = new int[(i << 1) + 1];
+ monomCoeffs[i << 1] = 1;
+ PolynomialGF2mSmallM monomial = new PolynomialGF2mSmallM(field,
+ monomCoeffs);
+ sqMatrix[i] = monomial.mod(p);
+ }
+ }
+
+ /**
+ * Compute the matrix for computing square roots in this polynomial ring by
+ * inverting the squaring matrix.
+ */
+ private void computeSquareRootMatrix()
+ {
+ int numColumns = p.getDegree();
+
+ // clone squaring matrix
+ PolynomialGF2mSmallM[] tmpMatrix = new PolynomialGF2mSmallM[numColumns];
+ for (int i = numColumns - 1; i >= 0; i--)
+ {
+ tmpMatrix[i] = new PolynomialGF2mSmallM(sqMatrix[i]);
+ }
+
+ // initialize square root matrix as unit matrix
+ sqRootMatrix = new PolynomialGF2mSmallM[numColumns];
+ for (int i = numColumns - 1; i >= 0; i--)
+ {
+ sqRootMatrix[i] = new PolynomialGF2mSmallM(field, i);
+ }
+
+ // simultaneously compute Gaussian reduction of squaring matrix and unit
+ // matrix
+ for (int i = 0; i < numColumns; i++)
+ {
+ // if diagonal element is zero
+ if (tmpMatrix[i].getCoefficient(i) == 0)
+ {
+ boolean foundNonZero = false;
+ // find a non-zero element in the same row
+ for (int j = i + 1; j < numColumns; j++)
+ {
+ if (tmpMatrix[j].getCoefficient(i) != 0)
+ {
+ // found it, swap columns ...
+ foundNonZero = true;
+ swapColumns(tmpMatrix, i, j);
+ swapColumns(sqRootMatrix, i, j);
+ // ... and quit searching
+ j = numColumns;
+ continue;
+ }
+ }
+ // if no non-zero element was found
+ if (!foundNonZero)
+ {
+ // the matrix is not invertible
+ throw new ArithmeticException(
+ "Squaring matrix is not invertible.");
+ }
+ }
+
+ // normalize i-th column
+ int coef = tmpMatrix[i].getCoefficient(i);
+ int invCoef = field.inverse(coef);
+ tmpMatrix[i].multThisWithElement(invCoef);
+ sqRootMatrix[i].multThisWithElement(invCoef);
+
+ // normalize all other columns
+ for (int j = 0; j < numColumns; j++)
+ {
+ if (j != i)
+ {
+ coef = tmpMatrix[j].getCoefficient(i);
+ if (coef != 0)
+ {
+ PolynomialGF2mSmallM tmpSqColumn = tmpMatrix[i]
+ .multWithElement(coef);
+ PolynomialGF2mSmallM tmpInvColumn = sqRootMatrix[i]
+ .multWithElement(coef);
+ tmpMatrix[j].addToThis(tmpSqColumn);
+ sqRootMatrix[j].addToThis(tmpInvColumn);
+ }
+ }
+ }
+ }
+ }
+
+ private static void swapColumns(PolynomialGF2mSmallM[] matrix, int first,
+ int second)
+ {
+ PolynomialGF2mSmallM tmp = matrix[first];
+ matrix[first] = matrix[second];
+ matrix[second] = tmp;
+ }
+
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/math/linearalgebra/RandUtils.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/math/linearalgebra/RandUtils.java
new file mode 100644
index 0000000..955dbd2
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/math/linearalgebra/RandUtils.java
@@ -0,0 +1,25 @@
+package org.bc.pqc.math.linearalgebra;
+
+import java.security.SecureRandom;
+
+public class RandUtils
+{
+ static int nextInt(SecureRandom rand, int n)
+ {
+
+ if ((n & -n) == n) // i.e., n is a power of 2
+ {
+ return (int)((n * (long)(rand.nextInt() >>> 1)) >> 31);
+ }
+
+ int bits, value;
+ do
+ {
+ bits = rand.nextInt() >>> 1;
+ value = bits % n;
+ }
+ while (bits - value + (n - 1) < 0);
+
+ return value;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/math/linearalgebra/Vector.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/math/linearalgebra/Vector.java
new file mode 100644
index 0000000..b732c76
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/pqc/math/linearalgebra/Vector.java
@@ -0,0 +1,69 @@
+package org.bc.pqc.math.linearalgebra;
+
+/**
+ * This abstract class defines vectors. It holds the length of vector.
+ */
+public abstract class Vector
+{
+
+ /**
+ * the length of this vector
+ */
+ protected int length;
+
+ /**
+ * @return the length of this vector
+ */
+ public final int getLength()
+ {
+ return length;
+ }
+
+ /**
+ * @return this vector as byte array
+ */
+ public abstract byte[] getEncoded();
+
+ /**
+ * Return whether this is the zero vector (i.e., all elements are zero).
+ *
+ * @return true if this is the zero vector, false
+ * otherwise
+ */
+ public abstract boolean isZero();
+
+ /**
+ * Add another vector to this vector.
+ *
+ * @param addend the other vector
+ * @return this + addend
+ */
+ public abstract Vector add(Vector addend);
+
+ /**
+ * Multiply this vector with a permutation.
+ *
+ * @param p the permutation
+ * @return this*p = p*this
+ */
+ public abstract Vector multiply(Permutation p);
+
+ /**
+ * Check if the given object is equal to this vector.
+ *
+ * @param other vector
+ * @return the result of the comparison
+ */
+ public abstract boolean equals(Object other);
+
+ /**
+ * @return the hash code of this vector
+ */
+ public abstract int hashCode();
+
+ /**
+ * @return a human readable form of this vector
+ */
+ public abstract String toString();
+
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/util/Arrays.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/util/Arrays.java
new file mode 100644
index 0000000..731f303
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/util/Arrays.java
@@ -0,0 +1,628 @@
+package org.bc.util;
+
+import java.math.BigInteger;
+
+/**
+ * General array utilities.
+ */
+public final class Arrays
+{
+ private Arrays()
+ {
+ // static class, hide constructor
+ }
+
+ public static boolean areEqual(
+ boolean[] a,
+ boolean[] b)
+ {
+ if (a == b)
+ {
+ return true;
+ }
+
+ if (a == null || b == null)
+ {
+ return false;
+ }
+
+ if (a.length != b.length)
+ {
+ return false;
+ }
+
+ for (int i = 0; i != a.length; i++)
+ {
+ if (a[i] != b[i])
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public static boolean areEqual(
+ char[] a,
+ char[] b)
+ {
+ if (a == b)
+ {
+ return true;
+ }
+
+ if (a == null || b == null)
+ {
+ return false;
+ }
+
+ if (a.length != b.length)
+ {
+ return false;
+ }
+
+ for (int i = 0; i != a.length; i++)
+ {
+ if (a[i] != b[i])
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public static boolean areEqual(
+ byte[] a,
+ byte[] b)
+ {
+ if (a == b)
+ {
+ return true;
+ }
+
+ if (a == null || b == null)
+ {
+ return false;
+ }
+
+ if (a.length != b.length)
+ {
+ return false;
+ }
+
+ for (int i = 0; i != a.length; i++)
+ {
+ if (a[i] != b[i])
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * A constant time equals comparison - does not terminate early if
+ * test will fail.
+ *
+ * @param a first array
+ * @param b second array
+ * @return true if arrays equal, false otherwise.
+ */
+ public static boolean constantTimeAreEqual(
+ byte[] a,
+ byte[] b)
+ {
+ if (a == b)
+ {
+ return true;
+ }
+
+ if (a == null || b == null)
+ {
+ return false;
+ }
+
+ if (a.length != b.length)
+ {
+ return false;
+ }
+
+ int nonEqual = 0;
+
+ for (int i = 0; i != a.length; i++)
+ {
+ nonEqual |= (a[i] ^ b[i]);
+ }
+
+ return nonEqual == 0;
+ }
+
+ public static boolean areEqual(
+ int[] a,
+ int[] b)
+ {
+ if (a == b)
+ {
+ return true;
+ }
+
+ if (a == null || b == null)
+ {
+ return false;
+ }
+
+ if (a.length != b.length)
+ {
+ return false;
+ }
+
+ for (int i = 0; i != a.length; i++)
+ {
+ if (a[i] != b[i])
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public static boolean areEqual(
+ long[] a,
+ long[] b)
+ {
+ if (a == b)
+ {
+ return true;
+ }
+
+ if (a == null || b == null)
+ {
+ return false;
+ }
+
+ if (a.length != b.length)
+ {
+ return false;
+ }
+
+ for (int i = 0; i != a.length; i++)
+ {
+ if (a[i] != b[i])
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public static boolean areEqual(
+ BigInteger[] a,
+ BigInteger[] b)
+ {
+ if (a == b)
+ {
+ return true;
+ }
+
+ if (a == null || b == null)
+ {
+ return false;
+ }
+
+ if (a.length != b.length)
+ {
+ return false;
+ }
+
+ for (int i = 0; i != a.length; i++)
+ {
+ if (!a[i].equals(b[i]))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public static void fill(
+ byte[] array,
+ byte value)
+ {
+ for (int i = 0; i < array.length; i++)
+ {
+ array[i] = value;
+ }
+ }
+
+ public static void fill(
+ char[] array,
+ char value)
+ {
+ for (int i = 0; i < array.length; i++)
+ {
+ array[i] = value;
+ }
+ }
+
+ public static void fill(
+ long[] array,
+ long value)
+ {
+ for (int i = 0; i < array.length; i++)
+ {
+ array[i] = value;
+ }
+ }
+
+ public static void fill(
+ short[] array,
+ short value)
+ {
+ for (int i = 0; i < array.length; i++)
+ {
+ array[i] = value;
+ }
+ }
+
+ public static void fill(
+ int[] array,
+ int value)
+ {
+ for (int i = 0; i < array.length; i++)
+ {
+ array[i] = value;
+ }
+ }
+
+ public static int hashCode(byte[] data)
+ {
+ if (data == null)
+ {
+ return 0;
+ }
+
+ int i = data.length;
+ int hc = i + 1;
+
+ while (--i >= 0)
+ {
+ hc *= 257;
+ hc ^= data[i];
+ }
+
+ return hc;
+ }
+
+ public static int hashCode(char[] data)
+ {
+ if (data == null)
+ {
+ return 0;
+ }
+
+ int i = data.length;
+ int hc = i + 1;
+
+ while (--i >= 0)
+ {
+ hc *= 257;
+ hc ^= data[i];
+ }
+
+ return hc;
+ }
+
+ public static int hashCode(int[][] ints)
+ {
+ int hc = 0;
+
+ for (int i = 0; i != ints.length; i++)
+ {
+ hc = hc * 257 + hashCode(ints[i]);
+ }
+
+ return hc;
+ }
+
+ public static int hashCode(int[] data)
+ {
+ if (data == null)
+ {
+ return 0;
+ }
+
+ int i = data.length;
+ int hc = i + 1;
+
+ while (--i >= 0)
+ {
+ hc *= 257;
+ hc ^= data[i];
+ }
+
+ return hc;
+ }
+
+ public static int hashCode(short[][][] shorts)
+ {
+ int hc = 0;
+
+ for (int i = 0; i != shorts.length; i++)
+ {
+ hc = hc * 257 + hashCode(shorts[i]);
+ }
+
+ return hc;
+ }
+
+ public static int hashCode(short[][] shorts)
+ {
+ int hc = 0;
+
+ for (int i = 0; i != shorts.length; i++)
+ {
+ hc = hc * 257 + hashCode(shorts[i]);
+ }
+
+ return hc;
+ }
+
+ public static int hashCode(short[] data)
+ {
+ if (data == null)
+ {
+ return 0;
+ }
+
+ int i = data.length;
+ int hc = i + 1;
+
+ while (--i >= 0)
+ {
+ hc *= 257;
+ hc ^= (data[i] & 0xff);
+ }
+
+ return hc;
+ }
+
+ public static int hashCode(BigInteger[] data)
+ {
+ if (data == null)
+ {
+ return 0;
+ }
+
+ int i = data.length;
+ int hc = i + 1;
+
+ while (--i >= 0)
+ {
+ hc *= 257;
+ hc ^= data[i].hashCode();
+ }
+
+ return hc;
+ }
+
+ public static byte[] clone(byte[] data)
+ {
+ if (data == null)
+ {
+ return null;
+ }
+ byte[] copy = new byte[data.length];
+
+ System.arraycopy(data, 0, copy, 0, data.length);
+
+ return copy;
+ }
+
+ public static int[] clone(int[] data)
+ {
+ if (data == null)
+ {
+ return null;
+ }
+ int[] copy = new int[data.length];
+
+ System.arraycopy(data, 0, copy, 0, data.length);
+
+ return copy;
+ }
+
+ public static short[] clone(short[] data)
+ {
+ if (data == null)
+ {
+ return null;
+ }
+ short[] copy = new short[data.length];
+
+ System.arraycopy(data, 0, copy, 0, data.length);
+
+ return copy;
+ }
+
+ public static BigInteger[] clone(BigInteger[] data)
+ {
+ if (data == null)
+ {
+ return null;
+ }
+ BigInteger[] copy = new BigInteger[data.length];
+
+ System.arraycopy(data, 0, copy, 0, data.length);
+
+ return copy;
+ }
+
+ public static byte[] copyOf(byte[] data, int newLength)
+ {
+ byte[] tmp = new byte[newLength];
+
+ if (newLength < data.length)
+ {
+ System.arraycopy(data, 0, tmp, 0, newLength);
+ }
+ else
+ {
+ System.arraycopy(data, 0, tmp, 0, data.length);
+ }
+
+ return tmp;
+ }
+
+ public static char[] copyOf(char[] data, int newLength)
+ {
+ char[] tmp = new char[newLength];
+
+ if (newLength < data.length)
+ {
+ System.arraycopy(data, 0, tmp, 0, newLength);
+ }
+ else
+ {
+ System.arraycopy(data, 0, tmp, 0, data.length);
+ }
+
+ return tmp;
+ }
+
+ public static int[] copyOf(int[] data, int newLength)
+ {
+ int[] tmp = new int[newLength];
+
+ if (newLength < data.length)
+ {
+ System.arraycopy(data, 0, tmp, 0, newLength);
+ }
+ else
+ {
+ System.arraycopy(data, 0, tmp, 0, data.length);
+ }
+
+ return tmp;
+ }
+
+ public static long[] copyOf(long[] data, int newLength)
+ {
+ long[] tmp = new long[newLength];
+
+ if (newLength < data.length)
+ {
+ System.arraycopy(data, 0, tmp, 0, newLength);
+ }
+ else
+ {
+ System.arraycopy(data, 0, tmp, 0, data.length);
+ }
+
+ return tmp;
+ }
+
+ public static BigInteger[] copyOf(BigInteger[] data, int newLength)
+ {
+ BigInteger[] tmp = new BigInteger[newLength];
+
+ if (newLength < data.length)
+ {
+ System.arraycopy(data, 0, tmp, 0, newLength);
+ }
+ else
+ {
+ System.arraycopy(data, 0, tmp, 0, data.length);
+ }
+
+ return tmp;
+ }
+
+ public static byte[] copyOfRange(byte[] data, int from, int to)
+ {
+ int newLength = getLength(from, to);
+
+ byte[] tmp = new byte[newLength];
+
+ if (data.length - from < newLength)
+ {
+ System.arraycopy(data, from, tmp, 0, data.length - from);
+ }
+ else
+ {
+ System.arraycopy(data, from, tmp, 0, newLength);
+ }
+
+ return tmp;
+ }
+
+ public static int[] copyOfRange(int[] data, int from, int to)
+ {
+ int newLength = getLength(from, to);
+
+ int[] tmp = new int[newLength];
+
+ if (data.length - from < newLength)
+ {
+ System.arraycopy(data, from, tmp, 0, data.length - from);
+ }
+ else
+ {
+ System.arraycopy(data, from, tmp, 0, newLength);
+ }
+
+ return tmp;
+ }
+
+ public static long[] copyOfRange(long[] data, int from, int to)
+ {
+ int newLength = getLength(from, to);
+
+ long[] tmp = new long[newLength];
+
+ if (data.length - from < newLength)
+ {
+ System.arraycopy(data, from, tmp, 0, data.length - from);
+ }
+ else
+ {
+ System.arraycopy(data, from, tmp, 0, newLength);
+ }
+
+ return tmp;
+ }
+
+ public static BigInteger[] copyOfRange(BigInteger[] data, int from, int to)
+ {
+ int newLength = getLength(from, to);
+
+ BigInteger[] tmp = new BigInteger[newLength];
+
+ if (data.length - from < newLength)
+ {
+ System.arraycopy(data, from, tmp, 0, data.length - from);
+ }
+ else
+ {
+ System.arraycopy(data, from, tmp, 0, newLength);
+ }
+
+ return tmp;
+ }
+
+ private static int getLength(int from, int to)
+ {
+ int newLength = to - from;
+ if (newLength < 0)
+ {
+ StringBuffer sb = new StringBuffer(from);
+ sb.append(" > ").append(to);
+ throw new IllegalArgumentException(sb.toString());
+ }
+ return newLength;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/util/BigIntegers.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/util/BigIntegers.java
new file mode 100644
index 0000000..0d9626a
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/util/BigIntegers.java
@@ -0,0 +1,123 @@
+package org.bc.util;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
+/**
+ * BigInteger utilities.
+ */
+public final class BigIntegers
+{
+ private static final int MAX_ITERATIONS = 1000;
+ private static final BigInteger ZERO = BigInteger.valueOf(0);
+
+ /**
+ * Return the passed in value as an unsigned byte array.
+ *
+ * @param value value to be converted.
+ * @return a byte array without a leading zero byte if present in the signed encoding.
+ */
+ public static byte[] asUnsignedByteArray(
+ BigInteger value)
+ {
+ byte[] bytes = value.toByteArray();
+
+ if (bytes[0] == 0)
+ {
+ byte[] tmp = new byte[bytes.length - 1];
+
+ System.arraycopy(bytes, 1, tmp, 0, tmp.length);
+
+ return tmp;
+ }
+
+ return bytes;
+ }
+
+ /**
+ * Return the passed in value as an unsigned byte array.
+ *
+ * @param value value to be converted.
+ * @return a byte array without a leading zero byte if present in the signed encoding.
+ */
+ public static byte[] asUnsignedByteArray(
+ int length,
+ BigInteger value)
+ {
+ byte[] bytes = value.toByteArray();
+
+ if (bytes[0] == 0)
+ {
+ if (bytes.length - 1 > length)
+ {
+ throw new IllegalArgumentException("standard length exceeded for value");
+ }
+
+ byte[] tmp = new byte[length];
+
+ System.arraycopy(bytes, 1, tmp, tmp.length - (bytes.length - 1), bytes.length - 1);
+
+ return tmp;
+ }
+ else
+ {
+ if (bytes.length == length)
+ {
+ return bytes;
+ }
+
+ if (bytes.length > length)
+ {
+ throw new IllegalArgumentException("standard length exceeded for value");
+ }
+
+ byte[] tmp = new byte[length];
+
+ System.arraycopy(bytes, 0, tmp, tmp.length - bytes.length, bytes.length);
+
+ return tmp;
+ }
+ }
+
+ /**
+ * Return a random BigInteger not less than 'min' and not greater than 'max'
+ *
+ * @param min the least value that may be generated
+ * @param max the greatest value that may be generated
+ * @param random the source of randomness
+ * @return a random BigInteger value in the range [min,max]
+ */
+ public static BigInteger createRandomInRange(
+ BigInteger min,
+ BigInteger max,
+ SecureRandom random)
+ {
+ int cmp = min.compareTo(max);
+ if (cmp >= 0)
+ {
+ if (cmp > 0)
+ {
+ throw new IllegalArgumentException("'min' may not be greater than 'max'");
+ }
+
+ return min;
+ }
+
+ if (min.bitLength() > max.bitLength() / 2)
+ {
+ return createRandomInRange(ZERO, max.subtract(min), random).add(min);
+ }
+
+ for (int i = 0; i < MAX_ITERATIONS; ++i)
+ {
+ BigInteger x = new BigInteger(max.bitLength(), random);
+ if (x.compareTo(min) >= 0 && x.compareTo(max) <= 0)
+ {
+ return x;
+ }
+ }
+
+ // fall back to a faster (restricted) method
+ return new BigInteger(max.subtract(min).bitLength() - 1, random).add(min);
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/util/CollectionStore.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/util/CollectionStore.java
new file mode 100644
index 0000000..2d4d8eb
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/util/CollectionStore.java
@@ -0,0 +1,57 @@
+package org.bc.util;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * A simple collection backed store.
+ */
+public class CollectionStore
+ implements Store
+{
+ private Collection _local;
+
+ /**
+ * Basic constructor.
+ *
+ * @param collection - initial contents for the store, this is copied.
+ */
+ public CollectionStore(
+ Collection collection)
+ {
+ _local = new ArrayList(collection);
+ }
+
+ /**
+ * Return the matches in the collection for the passed in selector.
+ *
+ * @param selector the selector to match against.
+ * @return a possibly empty collection of matching objects.
+ */
+ public Collection getMatches(Selector selector)
+ {
+ if (selector == null)
+ {
+ return new ArrayList(_local);
+ }
+ else
+ {
+ List col = new ArrayList();
+ Iterator iter = _local.iterator();
+
+ while (iter.hasNext())
+ {
+ Object obj = iter.next();
+
+ if (selector.match(obj))
+ {
+ col.add(obj);
+ }
+ }
+
+ return col;
+ }
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/util/IPAddress.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/util/IPAddress.java
new file mode 100644
index 0000000..0dc8d80
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/util/IPAddress.java
@@ -0,0 +1,188 @@
+package org.bc.util;
+
+public class IPAddress
+{
+ /**
+ * Validate the given IPv4 or IPv6 address.
+ *
+ * @param address the IP address as a String.
+ *
+ * @return true if a valid address, false otherwise
+ */
+ public static boolean isValid(
+ String address)
+ {
+ return isValidIPv4(address) || isValidIPv6(address);
+ }
+
+ /**
+ * Validate the given IPv4 or IPv6 address and netmask.
+ *
+ * @param address the IP address as a String.
+ *
+ * @return true if a valid address with netmask, false otherwise
+ */
+ public static boolean isValidWithNetMask(
+ String address)
+ {
+ return isValidIPv4WithNetmask(address) || isValidIPv6WithNetmask(address);
+ }
+
+ /**
+ * Validate the given IPv4 address.
+ *
+ * @param address the IP address as a String.
+ *
+ * @return true if a valid IPv4 address, false otherwise
+ */
+ public static boolean isValidIPv4(
+ String address)
+ {
+ if (address.length() == 0)
+ {
+ return false;
+ }
+
+ int octet;
+ int octets = 0;
+
+ String temp = address+".";
+
+ int pos;
+ int start = 0;
+ while (start < temp.length()
+ && (pos = temp.indexOf('.', start)) > start)
+ {
+ if (octets == 4)
+ {
+ return false;
+ }
+ try
+ {
+ octet = Integer.parseInt(temp.substring(start, pos));
+ }
+ catch (NumberFormatException ex)
+ {
+ return false;
+ }
+ if (octet < 0 || octet > 255)
+ {
+ return false;
+ }
+ start = pos + 1;
+ octets++;
+ }
+
+ return octets == 4;
+ }
+
+ public static boolean isValidIPv4WithNetmask(
+ String address)
+ {
+ int index = address.indexOf("/");
+ String mask = address.substring(index + 1);
+
+ return (index > 0) && isValidIPv4(address.substring(0, index))
+ && (isValidIPv4(mask) || isMaskValue(mask, 32));
+ }
+
+ public static boolean isValidIPv6WithNetmask(
+ String address)
+ {
+ int index = address.indexOf("/");
+ String mask = address.substring(index + 1);
+
+ return (index > 0) && (isValidIPv6(address.substring(0, index))
+ && (isValidIPv6(mask) || isMaskValue(mask, 128)));
+ }
+
+ private static boolean isMaskValue(String component, int size)
+ {
+ try
+ {
+ int value = Integer.parseInt(component);
+
+ return value >= 0 && value <= size;
+ }
+ catch (NumberFormatException e)
+ {
+ return false;
+ }
+ }
+
+ /**
+ * Validate the given IPv6 address.
+ *
+ * @param address the IP address as a String.
+ *
+ * @return true if a valid IPv4 address, false otherwise
+ */
+ public static boolean isValidIPv6(
+ String address)
+ {
+ if (address.length() == 0)
+ {
+ return false;
+ }
+
+ int octet;
+ int octets = 0;
+
+ String temp = address + ":";
+ boolean doubleColonFound = false;
+ int pos;
+ int start = 0;
+ while (start < temp.length()
+ && (pos = temp.indexOf(':', start)) >= start)
+ {
+ if (octets == 8)
+ {
+ return false;
+ }
+
+ if (start != pos)
+ {
+ String value = temp.substring(start, pos);
+
+ if (pos == (temp.length() - 1) && value.indexOf('.') > 0)
+ {
+ if (!isValidIPv4(value))
+ {
+ return false;
+ }
+
+ octets++; // add an extra one as address covers 2 words.
+ }
+ else
+ {
+ try
+ {
+ octet = Integer.parseInt(temp.substring(start, pos), 16);
+ }
+ catch (NumberFormatException ex)
+ {
+ return false;
+ }
+ if (octet < 0 || octet > 0xffff)
+ {
+ return false;
+ }
+ }
+ }
+ else
+ {
+ if (pos != 1 && pos != temp.length() - 1 && doubleColonFound)
+ {
+ return false;
+ }
+ doubleColonFound = true;
+ }
+ start = pos + 1;
+ octets++;
+ }
+
+ return octets == 8 || doubleColonFound;
+ }
+}
+
+
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/util/Integers.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/util/Integers.java
new file mode 100644
index 0000000..a71a6e7
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/util/Integers.java
@@ -0,0 +1,9 @@
+package org.bc.util;
+
+public class Integers
+{
+ public static Integer valueOf(int value)
+ {
+ return Integer.valueOf(value);
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/util/Selector.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/util/Selector.java
new file mode 100644
index 0000000..f1f12a8
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/util/Selector.java
@@ -0,0 +1,9 @@
+package org.bc.util;
+
+public interface Selector
+ extends Cloneable
+{
+ boolean match(Object obj);
+
+ Object clone();
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/util/Store.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/util/Store.java
new file mode 100644
index 0000000..a0ab754
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/util/Store.java
@@ -0,0 +1,9 @@
+package org.bc.util;
+
+import java.util.Collection;
+
+public interface Store
+{
+ Collection getMatches(Selector selector)
+ throws StoreException;
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/util/StoreException.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/util/StoreException.java
new file mode 100644
index 0000000..474fa70
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/util/StoreException.java
@@ -0,0 +1,18 @@
+package org.bc.util;
+
+public class StoreException
+ extends RuntimeException
+{
+ private Throwable _e;
+
+ public StoreException(String s, Throwable e)
+ {
+ super(s);
+ _e = e;
+ }
+
+ public Throwable getCause()
+ {
+ return _e;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/util/StreamParser.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/util/StreamParser.java
new file mode 100644
index 0000000..95183f1
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/util/StreamParser.java
@@ -0,0 +1,10 @@
+package org.bc.util;
+
+import java.util.Collection;
+
+public interface StreamParser
+{
+ Object read() throws StreamParsingException;
+
+ Collection readAll() throws StreamParsingException;
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/util/StreamParsingException.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/util/StreamParsingException.java
new file mode 100644
index 0000000..f0bfe5b
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/util/StreamParsingException.java
@@ -0,0 +1,18 @@
+package org.bc.util;
+
+public class StreamParsingException
+ extends Exception
+{
+ Throwable _e;
+
+ public StreamParsingException(String message, Throwable e)
+ {
+ super(message);
+ _e = e;
+ }
+
+ public Throwable getCause()
+ {
+ return _e;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/util/Strings.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/util/Strings.java
new file mode 100644
index 0000000..3c0c515
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/util/Strings.java
@@ -0,0 +1,303 @@
+package org.bc.util;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Vector;
+
+public final class Strings
+{
+ public static String fromUTF8ByteArray(byte[] bytes)
+ {
+ int i = 0;
+ int length = 0;
+
+ while (i < bytes.length)
+ {
+ length++;
+ if ((bytes[i] & 0xf0) == 0xf0)
+ {
+ // surrogate pair
+ length++;
+ i += 4;
+ }
+ else if ((bytes[i] & 0xe0) == 0xe0)
+ {
+ i += 3;
+ }
+ else if ((bytes[i] & 0xc0) == 0xc0)
+ {
+ i += 2;
+ }
+ else
+ {
+ i += 1;
+ }
+ }
+
+ char[] cs = new char[length];
+
+ i = 0;
+ length = 0;
+
+ while (i < bytes.length)
+ {
+ char ch;
+
+ if ((bytes[i] & 0xf0) == 0xf0)
+ {
+ int codePoint = ((bytes[i] & 0x03) << 18) | ((bytes[i+1] & 0x3F) << 12) | ((bytes[i+2] & 0x3F) << 6) | (bytes[i+3] & 0x3F);
+ int U = codePoint - 0x10000;
+ char W1 = (char)(0xD800 | (U >> 10));
+ char W2 = (char)(0xDC00 | (U & 0x3FF));
+ cs[length++] = W1;
+ ch = W2;
+ i += 4;
+ }
+ else if ((bytes[i] & 0xe0) == 0xe0)
+ {
+ ch = (char)(((bytes[i] & 0x0f) << 12)
+ | ((bytes[i + 1] & 0x3f) << 6) | (bytes[i + 2] & 0x3f));
+ i += 3;
+ }
+ else if ((bytes[i] & 0xd0) == 0xd0)
+ {
+ ch = (char)(((bytes[i] & 0x1f) << 6) | (bytes[i + 1] & 0x3f));
+ i += 2;
+ }
+ else if ((bytes[i] & 0xc0) == 0xc0)
+ {
+ ch = (char)(((bytes[i] & 0x1f) << 6) | (bytes[i + 1] & 0x3f));
+ i += 2;
+ }
+ else
+ {
+ ch = (char)(bytes[i] & 0xff);
+ i += 1;
+ }
+
+ cs[length++] = ch;
+ }
+
+ return new String(cs);
+ }
+
+ public static byte[] toUTF8ByteArray(String string)
+ {
+ return toUTF8ByteArray(string.toCharArray());
+ }
+
+ public static byte[] toUTF8ByteArray(char[] string)
+ {
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ try
+ {
+ toUTF8ByteArray(string, bOut);
+ }
+ catch (IOException e)
+ {
+ throw new IllegalStateException("cannot encode string to byte array!");
+ }
+
+ return bOut.toByteArray();
+ }
+
+ public static void toUTF8ByteArray(char[] string, OutputStream sOut)
+ throws IOException
+ {
+ char[] c = string;
+ int i = 0;
+
+ while (i < c.length)
+ {
+ char ch = c[i];
+
+ if (ch < 0x0080)
+ {
+ sOut.write(ch);
+ }
+ else if (ch < 0x0800)
+ {
+ sOut.write(0xc0 | (ch >> 6));
+ sOut.write(0x80 | (ch & 0x3f));
+ }
+ // surrogate pair
+ else if (ch >= 0xD800 && ch <= 0xDFFF)
+ {
+ // in error - can only happen, if the Java String class has a
+ // bug.
+ if (i + 1 >= c.length)
+ {
+ throw new IllegalStateException("invalid UTF-16 codepoint");
+ }
+ char W1 = ch;
+ ch = c[++i];
+ char W2 = ch;
+ // in error - can only happen, if the Java String class has a
+ // bug.
+ if (W1 > 0xDBFF)
+ {
+ throw new IllegalStateException("invalid UTF-16 codepoint");
+ }
+ int codePoint = (((W1 & 0x03FF) << 10) | (W2 & 0x03FF)) + 0x10000;
+ sOut.write(0xf0 | (codePoint >> 18));
+ sOut.write(0x80 | ((codePoint >> 12) & 0x3F));
+ sOut.write(0x80 | ((codePoint >> 6) & 0x3F));
+ sOut.write(0x80 | (codePoint & 0x3F));
+ }
+ else
+ {
+ sOut.write(0xe0 | (ch >> 12));
+ sOut.write(0x80 | ((ch >> 6) & 0x3F));
+ sOut.write(0x80 | (ch & 0x3F));
+ }
+
+ i++;
+ }
+ }
+
+ /**
+ * A locale independent version of toUpperCase.
+ *
+ * @param string input to be converted
+ * @return a US Ascii uppercase version
+ */
+ public static String toUpperCase(String string)
+ {
+ boolean changed = false;
+ char[] chars = string.toCharArray();
+
+ for (int i = 0; i != chars.length; i++)
+ {
+ char ch = chars[i];
+ if ('a' <= ch && 'z' >= ch)
+ {
+ changed = true;
+ chars[i] = (char)(ch - 'a' + 'A');
+ }
+ }
+
+ if (changed)
+ {
+ return new String(chars);
+ }
+
+ return string;
+ }
+
+ /**
+ * A locale independent version of toLowerCase.
+ *
+ * @param string input to be converted
+ * @return a US ASCII lowercase version
+ */
+ public static String toLowerCase(String string)
+ {
+ boolean changed = false;
+ char[] chars = string.toCharArray();
+
+ for (int i = 0; i != chars.length; i++)
+ {
+ char ch = chars[i];
+ if ('A' <= ch && 'Z' >= ch)
+ {
+ changed = true;
+ chars[i] = (char)(ch - 'A' + 'a');
+ }
+ }
+
+ if (changed)
+ {
+ return new String(chars);
+ }
+
+ return string;
+ }
+
+ public static byte[] toByteArray(char[] chars)
+ {
+ byte[] bytes = new byte[chars.length];
+
+ for (int i = 0; i != bytes.length; i++)
+ {
+ bytes[i] = (byte)chars[i];
+ }
+
+ return bytes;
+ }
+
+ public static byte[] toByteArray(String string)
+ {
+ byte[] bytes = new byte[string.length()];
+
+ for (int i = 0; i != bytes.length; i++)
+ {
+ char ch = string.charAt(i);
+
+ bytes[i] = (byte)ch;
+ }
+
+ return bytes;
+ }
+
+ /**
+ * Convert an array of 8 bit characters into a string.
+ *
+ * @param bytes 8 bit characters.
+ * @return resulting String.
+ */
+ public static String fromByteArray(byte[] bytes)
+ {
+ return new String(asCharArray(bytes));
+ }
+
+ /**
+ * Do a simple conversion of an array of 8 bit characters into a string.
+ *
+ * @param bytes 8 bit characters.
+ * @return resulting String.
+ */
+ public static char[] asCharArray(byte[] bytes)
+ {
+ char[] chars = new char[bytes.length];
+
+ for (int i = 0; i != chars.length; i++)
+ {
+ chars[i] = (char)(bytes[i] & 0xff);
+ }
+
+ return chars;
+ }
+
+ public static String[] split(String input, char delimiter)
+ {
+ Vector v = new Vector();
+ boolean moreTokens = true;
+ String subString;
+
+ while (moreTokens)
+ {
+ int tokenLocation = input.indexOf(delimiter);
+ if (tokenLocation > 0)
+ {
+ subString = input.substring(0, tokenLocation);
+ v.addElement(subString);
+ input = input.substring(tokenLocation + 1);
+ }
+ else
+ {
+ moreTokens = false;
+ v.addElement(input);
+ }
+ }
+
+ String[] res = new String[v.size()];
+
+ for (int i = 0; i != res.length; i++)
+ {
+ res[i] = (String)v.elementAt(i);
+ }
+ return res;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/util/encoders/Base64.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/util/encoders/Base64.java
new file mode 100644
index 0000000..af22600
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/util/encoders/Base64.java
@@ -0,0 +1,121 @@
+package org.bc.util.encoders;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+public class Base64
+{
+ private static final Encoder encoder = new Base64Encoder();
+
+ /**
+ * encode the input data producing a base 64 encoded byte array.
+ *
+ * @return a byte array containing the base 64 encoded data.
+ */
+ public static byte[] encode(
+ byte[] data)
+ {
+ int len = (data.length + 2) / 3 * 4;
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream(len);
+
+ try
+ {
+ encoder.encode(data, 0, data.length, bOut);
+ }
+ catch (Exception e)
+ {
+ throw new EncoderException("exception encoding base64 string: " + e.getMessage(), e);
+ }
+
+ return bOut.toByteArray();
+ }
+
+ /**
+ * Encode the byte data to base 64 writing it to the given output stream.
+ *
+ * @return the number of bytes produced.
+ */
+ public static int encode(
+ byte[] data,
+ OutputStream out)
+ throws IOException
+ {
+ return encoder.encode(data, 0, data.length, out);
+ }
+
+ /**
+ * Encode the byte data to base 64 writing it to the given output stream.
+ *
+ * @return the number of bytes produced.
+ */
+ public static int encode(
+ byte[] data,
+ int off,
+ int length,
+ OutputStream out)
+ throws IOException
+ {
+ return encoder.encode(data, off, length, out);
+ }
+
+ /**
+ * decode the base 64 encoded input data. It is assumed the input data is valid.
+ *
+ * @return a byte array representing the decoded data.
+ */
+ public static byte[] decode(
+ byte[] data)
+ {
+ int len = data.length / 4 * 3;
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream(len);
+
+ try
+ {
+ encoder.decode(data, 0, data.length, bOut);
+ }
+ catch (Exception e)
+ {
+ throw new DecoderException("unable to decode base64 data: " + e.getMessage(), e);
+ }
+
+ return bOut.toByteArray();
+ }
+
+ /**
+ * decode the base 64 encoded String data - whitespace will be ignored.
+ *
+ * @return a byte array representing the decoded data.
+ */
+ public static byte[] decode(
+ String data)
+ {
+ int len = data.length() / 4 * 3;
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream(len);
+
+ try
+ {
+ encoder.decode(data, bOut);
+ }
+ catch (Exception e)
+ {
+ throw new DecoderException("unable to decode base64 string: " + e.getMessage(), e);
+ }
+
+ return bOut.toByteArray();
+ }
+
+ /**
+ * decode the base 64 encoded String data writing it to the given output stream,
+ * whitespace characters will be ignored.
+ *
+ * @return the number of bytes produced.
+ */
+ public static int decode(
+ String data,
+ OutputStream out)
+ throws IOException
+ {
+ return encoder.decode(data, out);
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/util/encoders/Base64Encoder.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/util/encoders/Base64Encoder.java
new file mode 100644
index 0000000..4aebe6b
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/util/encoders/Base64Encoder.java
@@ -0,0 +1,328 @@
+package org.bc.util.encoders;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+public class Base64Encoder
+ implements Encoder
+{
+ protected final byte[] encodingTable =
+ {
+ (byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F', (byte)'G',
+ (byte)'H', (byte)'I', (byte)'J', (byte)'K', (byte)'L', (byte)'M', (byte)'N',
+ (byte)'O', (byte)'P', (byte)'Q', (byte)'R', (byte)'S', (byte)'T', (byte)'U',
+ (byte)'V', (byte)'W', (byte)'X', (byte)'Y', (byte)'Z',
+ (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f', (byte)'g',
+ (byte)'h', (byte)'i', (byte)'j', (byte)'k', (byte)'l', (byte)'m', (byte)'n',
+ (byte)'o', (byte)'p', (byte)'q', (byte)'r', (byte)'s', (byte)'t', (byte)'u',
+ (byte)'v',
+ (byte)'w', (byte)'x', (byte)'y', (byte)'z',
+ (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5', (byte)'6',
+ (byte)'7', (byte)'8', (byte)'9',
+ (byte)'+', (byte)'/'
+ };
+
+ protected byte padding = (byte)'=';
+
+ /*
+ * set up the decoding table.
+ */
+ protected final byte[] decodingTable = new byte[128];
+
+ protected void initialiseDecodingTable()
+ {
+ for (int i = 0; i < decodingTable.length; i++)
+ {
+ decodingTable[i] = (byte)0xff;
+ }
+
+ for (int i = 0; i < encodingTable.length; i++)
+ {
+ decodingTable[encodingTable[i]] = (byte)i;
+ }
+ }
+
+ public Base64Encoder()
+ {
+ initialiseDecodingTable();
+ }
+
+ /**
+ * encode the input data producing a base 64 output stream.
+ *
+ * @return the number of bytes produced.
+ */
+ public int encode(
+ byte[] data,
+ int off,
+ int length,
+ OutputStream out)
+ throws IOException
+ {
+ int modulus = length % 3;
+ int dataLength = (length - modulus);
+ int a1, a2, a3;
+
+ for (int i = off; i < off + dataLength; i += 3)
+ {
+ a1 = data[i] & 0xff;
+ a2 = data[i + 1] & 0xff;
+ a3 = data[i + 2] & 0xff;
+
+ out.write(encodingTable[(a1 >>> 2) & 0x3f]);
+ out.write(encodingTable[((a1 << 4) | (a2 >>> 4)) & 0x3f]);
+ out.write(encodingTable[((a2 << 2) | (a3 >>> 6)) & 0x3f]);
+ out.write(encodingTable[a3 & 0x3f]);
+ }
+
+ /*
+ * process the tail end.
+ */
+ int b1, b2, b3;
+ int d1, d2;
+
+ switch (modulus)
+ {
+ case 0: /* nothing left to do */
+ break;
+ case 1:
+ d1 = data[off + dataLength] & 0xff;
+ b1 = (d1 >>> 2) & 0x3f;
+ b2 = (d1 << 4) & 0x3f;
+
+ out.write(encodingTable[b1]);
+ out.write(encodingTable[b2]);
+ out.write(padding);
+ out.write(padding);
+ break;
+ case 2:
+ d1 = data[off + dataLength] & 0xff;
+ d2 = data[off + dataLength + 1] & 0xff;
+
+ b1 = (d1 >>> 2) & 0x3f;
+ b2 = ((d1 << 4) | (d2 >>> 4)) & 0x3f;
+ b3 = (d2 << 2) & 0x3f;
+
+ out.write(encodingTable[b1]);
+ out.write(encodingTable[b2]);
+ out.write(encodingTable[b3]);
+ out.write(padding);
+ break;
+ }
+
+ return (dataLength / 3) * 4 + ((modulus == 0) ? 0 : 4);
+ }
+
+ private boolean ignore(
+ char c)
+ {
+ return (c == '\n' || c =='\r' || c == '\t' || c == ' ');
+ }
+
+ /**
+ * decode the base 64 encoded byte data writing it to the given output stream,
+ * whitespace characters will be ignored.
+ *
+ * @return the number of bytes produced.
+ */
+ public int decode(
+ byte[] data,
+ int off,
+ int length,
+ OutputStream out)
+ throws IOException
+ {
+ byte b1, b2, b3, b4;
+ int outLen = 0;
+
+ int end = off + length;
+
+ while (end > off)
+ {
+ if (!ignore((char)data[end - 1]))
+ {
+ break;
+ }
+
+ end--;
+ }
+
+ int i = off;
+ int finish = end - 4;
+
+ i = nextI(data, i, finish);
+
+ while (i < finish)
+ {
+ b1 = decodingTable[data[i++]];
+
+ i = nextI(data, i, finish);
+
+ b2 = decodingTable[data[i++]];
+
+ i = nextI(data, i, finish);
+
+ b3 = decodingTable[data[i++]];
+
+ i = nextI(data, i, finish);
+
+ b4 = decodingTable[data[i++]];
+
+ if ((b1 | b2 | b3 | b4) < 0)
+ {
+ throw new IOException("invalid characters encountered in base64 data");
+ }
+
+ out.write((b1 << 2) | (b2 >> 4));
+ out.write((b2 << 4) | (b3 >> 2));
+ out.write((b3 << 6) | b4);
+
+ outLen += 3;
+
+ i = nextI(data, i, finish);
+ }
+
+ outLen += decodeLastBlock(out, (char)data[end - 4], (char)data[end - 3], (char)data[end - 2], (char)data[end - 1]);
+
+ return outLen;
+ }
+
+ private int nextI(byte[] data, int i, int finish)
+ {
+ while ((i < finish) && ignore((char)data[i]))
+ {
+ i++;
+ }
+ return i;
+ }
+
+ /**
+ * decode the base 64 encoded String data writing it to the given output stream,
+ * whitespace characters will be ignored.
+ *
+ * @return the number of bytes produced.
+ */
+ public int decode(
+ String data,
+ OutputStream out)
+ throws IOException
+ {
+ byte b1, b2, b3, b4;
+ int length = 0;
+
+ int end = data.length();
+
+ while (end > 0)
+ {
+ if (!ignore(data.charAt(end - 1)))
+ {
+ break;
+ }
+
+ end--;
+ }
+
+ int i = 0;
+ int finish = end - 4;
+
+ i = nextI(data, i, finish);
+
+ while (i < finish)
+ {
+ b1 = decodingTable[data.charAt(i++)];
+
+ i = nextI(data, i, finish);
+
+ b2 = decodingTable[data.charAt(i++)];
+
+ i = nextI(data, i, finish);
+
+ b3 = decodingTable[data.charAt(i++)];
+
+ i = nextI(data, i, finish);
+
+ b4 = decodingTable[data.charAt(i++)];
+
+ if ((b1 | b2 | b3 | b4) < 0)
+ {
+ throw new IOException("invalid characters encountered in base64 data");
+ }
+
+ out.write((b1 << 2) | (b2 >> 4));
+ out.write((b2 << 4) | (b3 >> 2));
+ out.write((b3 << 6) | b4);
+
+ length += 3;
+
+ i = nextI(data, i, finish);
+ }
+
+ length += decodeLastBlock(out, data.charAt(end - 4), data.charAt(end - 3), data.charAt(end - 2), data.charAt(end - 1));
+
+ return length;
+ }
+
+ private int decodeLastBlock(OutputStream out, char c1, char c2, char c3, char c4)
+ throws IOException
+ {
+ byte b1, b2, b3, b4;
+
+ if (c3 == padding)
+ {
+ b1 = decodingTable[c1];
+ b2 = decodingTable[c2];
+
+ if ((b1 | b2) < 0)
+ {
+ throw new IOException("invalid characters encountered at end of base64 data");
+ }
+
+ out.write((b1 << 2) | (b2 >> 4));
+
+ return 1;
+ }
+ else if (c4 == padding)
+ {
+ b1 = decodingTable[c1];
+ b2 = decodingTable[c2];
+ b3 = decodingTable[c3];
+
+ if ((b1 | b2 | b3) < 0)
+ {
+ throw new IOException("invalid characters encountered at end of base64 data");
+ }
+
+ out.write((b1 << 2) | (b2 >> 4));
+ out.write((b2 << 4) | (b3 >> 2));
+
+ return 2;
+ }
+ else
+ {
+ b1 = decodingTable[c1];
+ b2 = decodingTable[c2];
+ b3 = decodingTable[c3];
+ b4 = decodingTable[c4];
+
+ if ((b1 | b2 | b3 | b4) < 0)
+ {
+ throw new IOException("invalid characters encountered at end of base64 data");
+ }
+
+ out.write((b1 << 2) | (b2 >> 4));
+ out.write((b2 << 4) | (b3 >> 2));
+ out.write((b3 << 6) | b4);
+
+ return 3;
+ }
+ }
+
+ private int nextI(String data, int i, int finish)
+ {
+ while ((i < finish) && ignore(data.charAt(i)))
+ {
+ i++;
+ }
+ return i;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/util/encoders/BufferedDecoder.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/util/encoders/BufferedDecoder.java
new file mode 100644
index 0000000..52d0fbd
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/util/encoders/BufferedDecoder.java
@@ -0,0 +1,96 @@
+package org.bc.util.encoders;
+
+
+/**
+ * a buffering class to allow translation from one format to another to
+ * be done in discrete chunks.
+ */
+public class BufferedDecoder
+{
+ protected byte[] buf;
+ protected int bufOff;
+
+ protected Translator translator;
+
+ /**
+ * @param translator the translator to use.
+ * @param bufSize amount of input to buffer for each chunk.
+ */
+ public BufferedDecoder(
+ Translator translator,
+ int bufSize)
+ {
+ this.translator = translator;
+
+ if ((bufSize % translator.getEncodedBlockSize()) != 0)
+ {
+ throw new IllegalArgumentException("buffer size not multiple of input block size");
+ }
+
+ buf = new byte[bufSize];
+ bufOff = 0;
+ }
+
+ public int processByte(
+ byte in,
+ byte[] out,
+ int outOff)
+ {
+ int resultLen = 0;
+
+ buf[bufOff++] = in;
+
+ if (bufOff == buf.length)
+ {
+ resultLen = translator.decode(buf, 0, buf.length, out, outOff);
+ bufOff = 0;
+ }
+
+ return resultLen;
+ }
+
+ public int processBytes(
+ byte[] in,
+ int inOff,
+ int len,
+ byte[] out,
+ int outOff)
+ {
+ if (len < 0)
+ {
+ throw new IllegalArgumentException("Can't have a negative input length!");
+ }
+
+ int resultLen = 0;
+ int gapLen = buf.length - bufOff;
+
+ if (len > gapLen)
+ {
+ System.arraycopy(in, inOff, buf, bufOff, gapLen);
+
+ resultLen += translator.decode(buf, 0, buf.length, out, outOff);
+
+ bufOff = 0;
+
+ len -= gapLen;
+ inOff += gapLen;
+ outOff += resultLen;
+
+ int chunkSize = len - (len % buf.length);
+
+ resultLen += translator.decode(in, inOff, chunkSize, out, outOff);
+
+ len -= chunkSize;
+ inOff += chunkSize;
+ }
+
+ if (len != 0)
+ {
+ System.arraycopy(in, inOff, buf, bufOff, len);
+
+ bufOff += len;
+ }
+
+ return resultLen;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/util/encoders/BufferedEncoder.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/util/encoders/BufferedEncoder.java
new file mode 100644
index 0000000..8e88c16
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/util/encoders/BufferedEncoder.java
@@ -0,0 +1,96 @@
+package org.bc.util.encoders;
+
+
+/**
+ * a buffering class to allow translation from one format to another to
+ * be done in discrete chunks.
+ */
+public class BufferedEncoder
+{
+ protected byte[] buf;
+ protected int bufOff;
+
+ protected Translator translator;
+
+ /**
+ * @param translator the translator to use.
+ * @param bufSize amount of input to buffer for each chunk.
+ */
+ public BufferedEncoder(
+ Translator translator,
+ int bufSize)
+ {
+ this.translator = translator;
+
+ if ((bufSize % translator.getEncodedBlockSize()) != 0)
+ {
+ throw new IllegalArgumentException("buffer size not multiple of input block size");
+ }
+
+ buf = new byte[bufSize];
+ bufOff = 0;
+ }
+
+ public int processByte(
+ byte in,
+ byte[] out,
+ int outOff)
+ {
+ int resultLen = 0;
+
+ buf[bufOff++] = in;
+
+ if (bufOff == buf.length)
+ {
+ resultLen = translator.encode(buf, 0, buf.length, out, outOff);
+ bufOff = 0;
+ }
+
+ return resultLen;
+ }
+
+ public int processBytes(
+ byte[] in,
+ int inOff,
+ int len,
+ byte[] out,
+ int outOff)
+ {
+ if (len < 0)
+ {
+ throw new IllegalArgumentException("Can't have a negative input length!");
+ }
+
+ int resultLen = 0;
+ int gapLen = buf.length - bufOff;
+
+ if (len > gapLen)
+ {
+ System.arraycopy(in, inOff, buf, bufOff, gapLen);
+
+ resultLen += translator.encode(buf, 0, buf.length, out, outOff);
+
+ bufOff = 0;
+
+ len -= gapLen;
+ inOff += gapLen;
+ outOff += resultLen;
+
+ int chunkSize = len - (len % buf.length);
+
+ resultLen += translator.encode(in, inOff, chunkSize, out, outOff);
+
+ len -= chunkSize;
+ inOff += chunkSize;
+ }
+
+ if (len != 0)
+ {
+ System.arraycopy(in, inOff, buf, bufOff, len);
+
+ bufOff += len;
+ }
+
+ return resultLen;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/util/encoders/DecoderException.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/util/encoders/DecoderException.java
new file mode 100644
index 0000000..f0b8501
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/util/encoders/DecoderException.java
@@ -0,0 +1,19 @@
+package org.bc.util.encoders;
+
+public class DecoderException
+ extends IllegalStateException
+{
+ private Throwable cause;
+
+ DecoderException(String msg, Throwable cause)
+ {
+ super(msg);
+
+ this.cause = cause;
+ }
+
+ public Throwable getCause()
+ {
+ return cause;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/util/encoders/Encoder.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/util/encoders/Encoder.java
new file mode 100644
index 0000000..6ee39ab
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/util/encoders/Encoder.java
@@ -0,0 +1,17 @@
+package org.bc.util.encoders;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * Encode and decode byte arrays (typically from binary to 7-bit ASCII
+ * encodings).
+ */
+public interface Encoder
+{
+ int encode(byte[] data, int off, int length, OutputStream out) throws IOException;
+
+ int decode(byte[] data, int off, int length, OutputStream out) throws IOException;
+
+ int decode(String data, OutputStream out) throws IOException;
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/util/encoders/EncoderException.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/util/encoders/EncoderException.java
new file mode 100644
index 0000000..240810a
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/util/encoders/EncoderException.java
@@ -0,0 +1,19 @@
+package org.bc.util.encoders;
+
+public class EncoderException
+ extends IllegalStateException
+{
+ private Throwable cause;
+
+ EncoderException(String msg, Throwable cause)
+ {
+ super(msg);
+
+ this.cause = cause;
+ }
+
+ public Throwable getCause()
+ {
+ return cause;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/util/encoders/Hex.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/util/encoders/Hex.java
new file mode 100644
index 0000000..44de994
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/util/encoders/Hex.java
@@ -0,0 +1,131 @@
+package org.bc.util.encoders;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+public class Hex
+{
+ private static final Encoder encoder = new HexEncoder();
+
+ /**
+ * encode the input data producing a Hex encoded byte array.
+ *
+ * @return a byte array containing the Hex encoded data.
+ */
+ public static byte[] encode(
+ byte[] data)
+ {
+ return encode(data, 0, data.length);
+ }
+
+ /**
+ * encode the input data producing a Hex encoded byte array.
+ *
+ * @return a byte array containing the Hex encoded data.
+ */
+ public static byte[] encode(
+ byte[] data,
+ int off,
+ int length)
+ {
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ try
+ {
+ encoder.encode(data, off, length, bOut);
+ }
+ catch (Exception e)
+ {
+ throw new EncoderException("exception encoding Hex string: " + e.getMessage(), e);
+ }
+
+ return bOut.toByteArray();
+ }
+
+ /**
+ * Hex encode the byte data writing it to the given output stream.
+ *
+ * @return the number of bytes produced.
+ */
+ public static int encode(
+ byte[] data,
+ OutputStream out)
+ throws IOException
+ {
+ return encoder.encode(data, 0, data.length, out);
+ }
+
+ /**
+ * Hex encode the byte data writing it to the given output stream.
+ *
+ * @return the number of bytes produced.
+ */
+ public static int encode(
+ byte[] data,
+ int off,
+ int length,
+ OutputStream out)
+ throws IOException
+ {
+ return encoder.encode(data, off, length, out);
+ }
+
+ /**
+ * decode the Hex encoded input data. It is assumed the input data is valid.
+ *
+ * @return a byte array representing the decoded data.
+ */
+ public static byte[] decode(
+ byte[] data)
+ {
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ try
+ {
+ encoder.decode(data, 0, data.length, bOut);
+ }
+ catch (Exception e)
+ {
+ throw new DecoderException("exception decoding Hex data: " + e.getMessage(), e);
+ }
+
+ return bOut.toByteArray();
+ }
+
+ /**
+ * decode the Hex encoded String data - whitespace will be ignored.
+ *
+ * @return a byte array representing the decoded data.
+ */
+ public static byte[] decode(
+ String data)
+ {
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ try
+ {
+ encoder.decode(data, bOut);
+ }
+ catch (Exception e)
+ {
+ throw new DecoderException("exception decoding Hex string: " + e.getMessage(), e);
+ }
+
+ return bOut.toByteArray();
+ }
+
+ /**
+ * decode the Hex encoded String data writing it to the given output stream,
+ * whitespace characters will be ignored.
+ *
+ * @return the number of bytes produced.
+ */
+ public static int decode(
+ String data,
+ OutputStream out)
+ throws IOException
+ {
+ return encoder.decode(data, out);
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/util/encoders/HexEncoder.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/util/encoders/HexEncoder.java
new file mode 100644
index 0000000..c00b9a7
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/util/encoders/HexEncoder.java
@@ -0,0 +1,187 @@
+package org.bc.util.encoders;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+public class HexEncoder
+ implements Encoder
+{
+ protected final byte[] encodingTable =
+ {
+ (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5', (byte)'6', (byte)'7',
+ (byte)'8', (byte)'9', (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f'
+ };
+
+ /*
+ * set up the decoding table.
+ */
+ protected final byte[] decodingTable = new byte[128];
+
+ protected void initialiseDecodingTable()
+ {
+ for (int i = 0; i < decodingTable.length; i++)
+ {
+ decodingTable[i] = (byte)0xff;
+ }
+
+ for (int i = 0; i < encodingTable.length; i++)
+ {
+ decodingTable[encodingTable[i]] = (byte)i;
+ }
+
+ decodingTable['A'] = decodingTable['a'];
+ decodingTable['B'] = decodingTable['b'];
+ decodingTable['C'] = decodingTable['c'];
+ decodingTable['D'] = decodingTable['d'];
+ decodingTable['E'] = decodingTable['e'];
+ decodingTable['F'] = decodingTable['f'];
+ }
+
+ public HexEncoder()
+ {
+ initialiseDecodingTable();
+ }
+
+ /**
+ * encode the input data producing a Hex output stream.
+ *
+ * @return the number of bytes produced.
+ */
+ public int encode(
+ byte[] data,
+ int off,
+ int length,
+ OutputStream out)
+ throws IOException
+ {
+ for (int i = off; i < (off + length); i++)
+ {
+ int v = data[i] & 0xff;
+
+ out.write(encodingTable[(v >>> 4)]);
+ out.write(encodingTable[v & 0xf]);
+ }
+
+ return length * 2;
+ }
+
+ private static boolean ignore(
+ char c)
+ {
+ return c == '\n' || c =='\r' || c == '\t' || c == ' ';
+ }
+
+ /**
+ * decode the Hex encoded byte data writing it to the given output stream,
+ * whitespace characters will be ignored.
+ *
+ * @return the number of bytes produced.
+ */
+ public int decode(
+ byte[] data,
+ int off,
+ int length,
+ OutputStream out)
+ throws IOException
+ {
+ byte b1, b2;
+ int outLen = 0;
+
+ int end = off + length;
+
+ while (end > off)
+ {
+ if (!ignore((char)data[end - 1]))
+ {
+ break;
+ }
+
+ end--;
+ }
+
+ int i = off;
+ while (i < end)
+ {
+ while (i < end && ignore((char)data[i]))
+ {
+ i++;
+ }
+
+ b1 = decodingTable[data[i++]];
+
+ while (i < end && ignore((char)data[i]))
+ {
+ i++;
+ }
+
+ b2 = decodingTable[data[i++]];
+
+ if ((b1 | b2) < 0)
+ {
+ throw new IOException("invalid characters encountered in Hex data");
+ }
+
+ out.write((b1 << 4) | b2);
+
+ outLen++;
+ }
+
+ return outLen;
+ }
+
+ /**
+ * decode the Hex encoded String data writing it to the given output stream,
+ * whitespace characters will be ignored.
+ *
+ * @return the number of bytes produced.
+ */
+ public int decode(
+ String data,
+ OutputStream out)
+ throws IOException
+ {
+ byte b1, b2;
+ int length = 0;
+
+ int end = data.length();
+
+ while (end > 0)
+ {
+ if (!ignore(data.charAt(end - 1)))
+ {
+ break;
+ }
+
+ end--;
+ }
+
+ int i = 0;
+ while (i < end)
+ {
+ while (i < end && ignore(data.charAt(i)))
+ {
+ i++;
+ }
+
+ b1 = decodingTable[data.charAt(i++)];
+
+ while (i < end && ignore(data.charAt(i)))
+ {
+ i++;
+ }
+
+ b2 = decodingTable[data.charAt(i++)];
+
+ if ((b1 | b2) < 0)
+ {
+ throw new IOException("invalid characters encountered in Hex string");
+ }
+
+ out.write((b1 << 4) | b2);
+
+ length++;
+ }
+
+ return length;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/util/encoders/HexTranslator.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/util/encoders/HexTranslator.java
new file mode 100644
index 0000000..29c03a2
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/util/encoders/HexTranslator.java
@@ -0,0 +1,87 @@
+package org.bc.util.encoders;
+
+/**
+ * Converters for going from hex to binary and back. Note: this class assumes ASCII processing.
+ */
+public class HexTranslator
+ implements Translator
+{
+ private static final byte[] hexTable =
+ {
+ (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5', (byte)'6', (byte)'7',
+ (byte)'8', (byte)'9', (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f'
+ };
+
+ /**
+ * size of the output block on encoding produced by getDecodedBlockSize()
+ * bytes.
+ */
+ public int getEncodedBlockSize()
+ {
+ return 2;
+ }
+
+ public int encode(
+ byte[] in,
+ int inOff,
+ int length,
+ byte[] out,
+ int outOff)
+ {
+ for (int i = 0, j = 0; i < length; i++, j += 2)
+ {
+ out[outOff + j] = hexTable[(in[inOff] >> 4) & 0x0f];
+ out[outOff + j + 1] = hexTable[in[inOff] & 0x0f];
+
+ inOff++;
+ }
+
+ return length * 2;
+ }
+
+ /**
+ * size of the output block on decoding produced by getEncodedBlockSize()
+ * bytes.
+ */
+ public int getDecodedBlockSize()
+ {
+ return 1;
+ }
+
+ public int decode(
+ byte[] in,
+ int inOff,
+ int length,
+ byte[] out,
+ int outOff)
+ {
+ int halfLength = length / 2;
+ byte left, right;
+ for (int i = 0; i < halfLength; i++)
+ {
+ left = in[inOff + i * 2];
+ right = in[inOff + i * 2 + 1];
+
+ if (left < (byte)'a')
+ {
+ out[outOff] = (byte)((left - '0') << 4);
+ }
+ else
+ {
+ out[outOff] = (byte)((left - 'a' + 10) << 4);
+ }
+ if (right < (byte)'a')
+ {
+ out[outOff] += (byte)(right - '0');
+ }
+ else
+ {
+ out[outOff] += (byte)(right - 'a' + 10);
+ }
+
+ outOff++;
+ }
+
+ return halfLength;
+ }
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/util/encoders/Translator.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/util/encoders/Translator.java
new file mode 100644
index 0000000..4616db3
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/util/encoders/Translator.java
@@ -0,0 +1,23 @@
+package org.bc.util.encoders;
+
+/**
+ * general interface for an translator.
+ */
+public interface Translator
+{
+ /**
+ * size of the output block on encoding produced by getDecodedBlockSize()
+ * bytes.
+ */
+ public int getEncodedBlockSize();
+
+ public int encode(byte[] in, int inOff, int length, byte[] out, int outOff);
+
+ /**
+ * size of the output block on decoding produced by getEncodedBlockSize()
+ * bytes.
+ */
+ public int getDecodedBlockSize();
+
+ public int decode(byte[] in, int inOff, int length, byte[] out, int outOff);
+}
diff --git a/java/ext/lcrypto-jdk15on-148/src/org/bc/util/encoders/UrlBase64.java b/java/ext/lcrypto-jdk15on-148/src/org/bc/util/encoders/UrlBase64.java
new file mode 100644
index 0000000..db6b6c2
--- /dev/null
+++ b/java/ext/lcrypto-jdk15on-148/src/org/bc/util/encoders/UrlBase64.java
@@ -0,0 +1,129 @@
+package org.bc.util.encoders;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * Convert binary data to and from UrlBase64 encoding. This is identical to
+ * Base64 encoding, except that the padding character is "." and the other
+ * non-alphanumeric characters are "-" and "_" instead of "+" and "/".
+ *