001: package org.bouncycastle.openssl;
002:
003: import org.bouncycastle.crypto.PBEParametersGenerator;
004: import org.bouncycastle.crypto.generators.OpenSSLPBEParametersGenerator;
005: import org.bouncycastle.crypto.params.KeyParameter;
006:
007: import javax.crypto.Cipher;
008: import javax.crypto.SecretKey;
009: import javax.crypto.spec.IvParameterSpec;
010: import javax.crypto.spec.RC2ParameterSpec;
011: import java.io.IOException;
012: import java.security.Key;
013: import java.security.spec.AlgorithmParameterSpec;
014:
015: final class PEMUtilities {
016: static byte[] crypt(boolean encrypt, String provider, byte[] bytes,
017: char[] password, String dekAlgName, byte[] iv)
018: throws IOException {
019: AlgorithmParameterSpec paramSpec = new IvParameterSpec(iv);
020: String alg;
021: String blockMode = "CBC";
022: String padding = "PKCS5Padding";
023: Key sKey;
024:
025: // Figure out block mode and padding.
026: if (dekAlgName.endsWith("-CFB")) {
027: blockMode = "CFB";
028: padding = "NoPadding";
029: }
030: if (dekAlgName.endsWith("-ECB") || "DES-EDE".equals(dekAlgName)
031: || "DES-EDE3".equals(dekAlgName)) {
032: // ECB is actually the default (though seldom used) when OpenSSL
033: // uses DES-EDE (des2) or DES-EDE3 (des3).
034: blockMode = "ECB";
035: paramSpec = null;
036: }
037: if (dekAlgName.endsWith("-OFB")) {
038: blockMode = "OFB";
039: padding = "NoPadding";
040: }
041:
042: // Figure out algorithm and key size.
043: if (dekAlgName.startsWith("DES-EDE")) {
044: alg = "DESede";
045: // "DES-EDE" is actually des2 in OpenSSL-speak!
046: // "DES-EDE3" is des3.
047: boolean des2 = !dekAlgName.startsWith("DES-EDE3");
048: sKey = getKey(password, alg, 24, iv, des2);
049: } else if (dekAlgName.startsWith("DES-")) {
050: alg = "DES";
051: sKey = getKey(password, alg, 8, iv);
052: } else if (dekAlgName.startsWith("BF-")) {
053: alg = "Blowfish";
054: sKey = getKey(password, alg, 16, iv);
055: } else if (dekAlgName.startsWith("RC2-")) {
056: alg = "RC2";
057: int keyBits = 128;
058: if (dekAlgName.startsWith("RC2-40-")) {
059: keyBits = 40;
060: } else if (dekAlgName.startsWith("RC2-64-")) {
061: keyBits = 64;
062: }
063: sKey = getKey(password, alg, keyBits / 8, iv);
064: if (paramSpec == null) // ECB block mode
065: {
066: paramSpec = new RC2ParameterSpec(keyBits);
067: } else {
068: paramSpec = new RC2ParameterSpec(keyBits, iv);
069: }
070: } else if (dekAlgName.startsWith("AES-")) {
071: alg = "AES";
072: byte[] salt = iv;
073: if (salt.length > 8) {
074: salt = new byte[8];
075: System.arraycopy(iv, 0, salt, 0, 8);
076: }
077:
078: int keyBits;
079: if (dekAlgName.startsWith("AES-128-")) {
080: keyBits = 128;
081: } else if (dekAlgName.startsWith("AES-192-")) {
082: keyBits = 192;
083: } else if (dekAlgName.startsWith("AES-256-")) {
084: keyBits = 256;
085: } else {
086: throw new IOException(
087: "unknown AES encryption with private key");
088: }
089: sKey = getKey(password, "AES", keyBits / 8, salt);
090: } else {
091: throw new IOException("unknown encryption with private key");
092: }
093:
094: String transformation = alg + "/" + blockMode + "/" + padding;
095:
096: try {
097: Cipher c = Cipher.getInstance(transformation, provider);
098: int mode = encrypt ? Cipher.ENCRYPT_MODE
099: : Cipher.DECRYPT_MODE;
100:
101: if (paramSpec == null) // ECB block mode
102: {
103: c.init(mode, sKey);
104: } else {
105: c.init(mode, sKey, paramSpec);
106: }
107: return c.doFinal(bytes);
108: } catch (Exception e) {
109: throw new IOException("exception using cipher: "
110: + e.toString());
111: }
112: }
113:
114: private static SecretKey getKey(char[] password, String algorithm,
115: int keyLength, byte[] salt) throws IOException {
116: return getKey(password, algorithm, keyLength, salt, false);
117: }
118:
119: private static SecretKey getKey(char[] password, String algorithm,
120: int keyLength, byte[] salt, boolean des2)
121: throws IOException {
122: OpenSSLPBEParametersGenerator pGen = new OpenSSLPBEParametersGenerator();
123:
124: pGen.init(
125: PBEParametersGenerator.PKCS5PasswordToBytes(password),
126: salt);
127:
128: KeyParameter keyParam;
129: keyParam = (KeyParameter) pGen
130: .generateDerivedParameters(keyLength * 8);
131: byte[] key = keyParam.getKey();
132: if (des2 && key.length >= 24) {
133: // For DES2, we must copy first 8 bytes into the last 8 bytes.
134: System.arraycopy(key, 0, key, 16, 8);
135: }
136: return new javax.crypto.spec.SecretKeySpec(key, algorithm);
137: }
138: }
|