diff options
Diffstat (limited to 'core/src/main/java/org/spongycastle/crypto/generators/PKCS12ParametersGenerator.java')
-rw-r--r-- | core/src/main/java/org/spongycastle/crypto/generators/PKCS12ParametersGenerator.java | 220 |
1 files changed, 220 insertions, 0 deletions
diff --git a/core/src/main/java/org/spongycastle/crypto/generators/PKCS12ParametersGenerator.java b/core/src/main/java/org/spongycastle/crypto/generators/PKCS12ParametersGenerator.java new file mode 100644 index 00000000..ee40465e --- /dev/null +++ b/core/src/main/java/org/spongycastle/crypto/generators/PKCS12ParametersGenerator.java @@ -0,0 +1,220 @@ +package org.spongycastle.crypto.generators; + +import org.spongycastle.crypto.CipherParameters; +import org.spongycastle.crypto.Digest; +import org.spongycastle.crypto.ExtendedDigest; +import org.spongycastle.crypto.PBEParametersGenerator; +import org.spongycastle.crypto.params.KeyParameter; +import org.spongycastle.crypto.params.ParametersWithIV; + +/** + * Generator for PBE derived keys and ivs as defined by PKCS 12 V1.0. + * <p> + * The document this implementation is based on can be found at + * <a href=http://www.rsasecurity.com/rsalabs/pkcs/pkcs-12/index.html> + * RSA's PKCS12 Page</a> + */ +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; + byte[] A = new byte[u]; + + for (int i = 1; i <= c; i++) + { + 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); + } +} |