/projects/azureus-4.7.0.2/org/bouncycastle/openssl/PEMUtilities.java
Java | 185 lines | 163 code | 15 blank | 7 comment | 27 complexity | cc7efb74ed55347e229bed884d94d7a4 MD5 | raw file
1package org.bouncycastle.openssl;
2
3import org.bouncycastle.crypto.PBEParametersGenerator;
4import org.bouncycastle.crypto.generators.OpenSSLPBEParametersGenerator;
5import org.bouncycastle.crypto.params.KeyParameter;
6
7import javax.crypto.Cipher;
8import javax.crypto.SecretKey;
9import javax.crypto.spec.IvParameterSpec;
10import javax.crypto.spec.RC2ParameterSpec;
11import java.io.IOException;
12import java.security.Key;
13import java.security.spec.AlgorithmParameterSpec;
14
15final class PEMUtilities
16{
17 static byte[] crypt(
18 boolean encrypt,
19 String provider,
20 byte[] bytes,
21 char[] password,
22 String dekAlgName,
23 byte[] iv)
24 throws IOException
25 {
26 AlgorithmParameterSpec paramSpec = new IvParameterSpec(iv);
27 String alg;
28 String blockMode = "CBC";
29 String padding = "PKCS5Padding";
30 Key sKey;
31
32
33 // Figure out block mode and padding.
34 if (dekAlgName.endsWith("-CFB"))
35 {
36 blockMode = "CFB";
37 padding = "NoPadding";
38 }
39 if (dekAlgName.endsWith("-ECB") ||
40 "DES-EDE".equals(dekAlgName) ||
41 "DES-EDE3".equals(dekAlgName))
42 {
43 // ECB is actually the default (though seldom used) when OpenSSL
44 // uses DES-EDE (des2) or DES-EDE3 (des3).
45 blockMode = "ECB";
46 paramSpec = null;
47 }
48 if (dekAlgName.endsWith("-OFB"))
49 {
50 blockMode = "OFB";
51 padding = "NoPadding";
52 }
53
54
55 // Figure out algorithm and key size.
56 if (dekAlgName.startsWith("DES-EDE"))
57 {
58 alg = "DESede";
59 // "DES-EDE" is actually des2 in OpenSSL-speak!
60 // "DES-EDE3" is des3.
61 boolean des2 = !dekAlgName.startsWith("DES-EDE3");
62 sKey = getKey(password, alg, 24, iv, des2);
63 }
64 else if (dekAlgName.startsWith("DES-"))
65 {
66 alg = "DES";
67 sKey = getKey(password, alg, 8, iv);
68 }
69 else if (dekAlgName.startsWith("BF-"))
70 {
71 alg = "Blowfish";
72 sKey = getKey(password, alg, 16, iv);
73 }
74 else if (dekAlgName.startsWith("RC2-"))
75 {
76 alg = "RC2";
77 int keyBits = 128;
78 if (dekAlgName.startsWith("RC2-40-"))
79 {
80 keyBits = 40;
81 }
82 else if (dekAlgName.startsWith("RC2-64-"))
83 {
84 keyBits = 64;
85 }
86 sKey = getKey(password, alg, keyBits / 8, iv);
87 if (paramSpec == null) // ECB block mode
88 {
89 paramSpec = new RC2ParameterSpec(keyBits);
90 }
91 else
92 {
93 paramSpec = new RC2ParameterSpec(keyBits, iv);
94 }
95 }
96 else if (dekAlgName.startsWith("AES-"))
97 {
98 alg = "AES";
99 byte[] salt = iv;
100 if (salt.length > 8)
101 {
102 salt = new byte[8];
103 System.arraycopy(iv, 0, salt, 0, 8);
104 }
105
106 int keyBits;
107 if (dekAlgName.startsWith("AES-128-"))
108 {
109 keyBits = 128;
110 }
111 else if (dekAlgName.startsWith("AES-192-"))
112 {
113 keyBits = 192;
114 }
115 else if (dekAlgName.startsWith("AES-256-"))
116 {
117 keyBits = 256;
118 }
119 else
120 {
121 throw new IOException("unknown AES encryption with private key");
122 }
123 sKey = getKey(password, "AES", keyBits / 8, salt);
124 }
125 else
126 {
127 throw new IOException("unknown encryption with private key");
128 }
129
130 String transformation = alg + "/" + blockMode + "/" + padding;
131
132 try
133 {
134 Cipher c = Cipher.getInstance(transformation, provider);
135 int mode = encrypt ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE;
136
137 if (paramSpec == null) // ECB block mode
138 {
139 c.init(mode, sKey);
140 }
141 else
142 {
143 c.init(mode, sKey, paramSpec);
144 }
145 return c.doFinal(bytes);
146 }
147 catch (Exception e)
148 {
149 throw new IOException("exception using cipher: " + e.toString());
150 }
151 }
152
153 private static SecretKey getKey(
154 char[] password,
155 String algorithm,
156 int keyLength,
157 byte[] salt)
158 throws IOException
159 {
160 return getKey(password, algorithm, keyLength, salt, false);
161 }
162
163 private static SecretKey getKey(
164 char[] password,
165 String algorithm,
166 int keyLength,
167 byte[] salt,
168 boolean des2)
169 throws IOException
170 {
171 OpenSSLPBEParametersGenerator pGen = new OpenSSLPBEParametersGenerator();
172
173 pGen.init(PBEParametersGenerator.PKCS5PasswordToBytes(password), salt);
174
175 KeyParameter keyParam;
176 keyParam = (KeyParameter) pGen.generateDerivedParameters(keyLength * 8);
177 byte[] key = keyParam.getKey();
178 if (des2 && key.length >= 24)
179 {
180 // For DES2, we must copy first 8 bytes into the last 8 bytes.
181 System.arraycopy(key, 0, key, 16, 8);
182 }
183 return new javax.crypto.spec.SecretKeySpec(key, algorithm);
184 }
185}