PageRenderTime 9153ms CodeModel.GetById 28ms RepoModel.GetById 0ms app.codeStats 0ms

/pkix/src/main/java/org/bouncycastle/openssl/jcajce/PEMUtilities.java

https://gitlab.com/edgardo001/bc-java
Java | 272 lines | 238 code | 27 blank | 7 comment | 28 complexity | 2c0a7d42046a65e010c82d365431a4c4 MD5 | raw file
  1. package org.bouncycastle.openssl.jcajce;
  2. import java.security.GeneralSecurityException;
  3. import java.security.Key;
  4. import java.security.NoSuchAlgorithmException;
  5. import java.security.NoSuchProviderException;
  6. import java.security.spec.AlgorithmParameterSpec;
  7. import java.security.spec.InvalidKeySpecException;
  8. import java.util.HashMap;
  9. import java.util.HashSet;
  10. import java.util.Map;
  11. import java.util.Set;
  12. import javax.crypto.Cipher;
  13. import javax.crypto.SecretKey;
  14. import javax.crypto.SecretKeyFactory;
  15. import javax.crypto.spec.IvParameterSpec;
  16. import javax.crypto.spec.PBEKeySpec;
  17. import javax.crypto.spec.RC2ParameterSpec;
  18. import javax.crypto.spec.SecretKeySpec;
  19. import org.bouncycastle.asn1.ASN1ObjectIdentifier;
  20. import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
  21. import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
  22. import org.bouncycastle.jcajce.util.JcaJceHelper;
  23. import org.bouncycastle.openssl.EncryptionException;
  24. import org.bouncycastle.openssl.PEMException;
  25. import org.bouncycastle.util.Integers;
  26. class PEMUtilities
  27. {
  28. private static final Map KEYSIZES = new HashMap();
  29. private static final Set PKCS5_SCHEME_1 = new HashSet();
  30. private static final Set PKCS5_SCHEME_2 = new HashSet();
  31. static
  32. {
  33. PKCS5_SCHEME_1.add(PKCSObjectIdentifiers.pbeWithMD2AndDES_CBC);
  34. PKCS5_SCHEME_1.add(PKCSObjectIdentifiers.pbeWithMD2AndRC2_CBC);
  35. PKCS5_SCHEME_1.add(PKCSObjectIdentifiers.pbeWithMD5AndDES_CBC);
  36. PKCS5_SCHEME_1.add(PKCSObjectIdentifiers.pbeWithMD5AndRC2_CBC);
  37. PKCS5_SCHEME_1.add(PKCSObjectIdentifiers.pbeWithSHA1AndDES_CBC);
  38. PKCS5_SCHEME_1.add(PKCSObjectIdentifiers.pbeWithSHA1AndRC2_CBC);
  39. PKCS5_SCHEME_2.add(PKCSObjectIdentifiers.id_PBES2);
  40. PKCS5_SCHEME_2.add(PKCSObjectIdentifiers.des_EDE3_CBC);
  41. PKCS5_SCHEME_2.add(NISTObjectIdentifiers.id_aes128_CBC);
  42. PKCS5_SCHEME_2.add(NISTObjectIdentifiers.id_aes192_CBC);
  43. PKCS5_SCHEME_2.add(NISTObjectIdentifiers.id_aes256_CBC);
  44. KEYSIZES.put(PKCSObjectIdentifiers.des_EDE3_CBC.getId(), Integers.valueOf(192));
  45. KEYSIZES.put(NISTObjectIdentifiers.id_aes128_CBC.getId(), Integers.valueOf(128));
  46. KEYSIZES.put(NISTObjectIdentifiers.id_aes192_CBC.getId(), Integers.valueOf(192));
  47. KEYSIZES.put(NISTObjectIdentifiers.id_aes256_CBC.getId(), Integers.valueOf(256));
  48. KEYSIZES.put(PKCSObjectIdentifiers.pbeWithSHAAnd128BitRC4.getId(), Integers.valueOf(128));
  49. KEYSIZES.put(PKCSObjectIdentifiers.pbeWithSHAAnd40BitRC4, Integers.valueOf(40));
  50. KEYSIZES.put(PKCSObjectIdentifiers.pbeWithSHAAnd2_KeyTripleDES_CBC, Integers.valueOf(128));
  51. KEYSIZES.put(PKCSObjectIdentifiers.pbeWithSHAAnd3_KeyTripleDES_CBC, Integers.valueOf(192));
  52. KEYSIZES.put(PKCSObjectIdentifiers.pbeWithSHAAnd128BitRC2_CBC, Integers.valueOf(128));
  53. KEYSIZES.put(PKCSObjectIdentifiers.pbeWithSHAAnd40BitRC2_CBC, Integers.valueOf(40));
  54. }
  55. static int getKeySize(String algorithm)
  56. {
  57. if (!KEYSIZES.containsKey(algorithm))
  58. {
  59. throw new IllegalStateException("no key size for algorithm: " + algorithm);
  60. }
  61. return ((Integer)KEYSIZES.get(algorithm)).intValue();
  62. }
  63. static boolean isPKCS5Scheme1(ASN1ObjectIdentifier algOid)
  64. {
  65. return PKCS5_SCHEME_1.contains(algOid);
  66. }
  67. static boolean isPKCS5Scheme2(ASN1ObjectIdentifier algOid)
  68. {
  69. return PKCS5_SCHEME_2.contains(algOid);
  70. }
  71. public static boolean isPKCS12(ASN1ObjectIdentifier algOid)
  72. {
  73. return algOid.getId().startsWith(PKCSObjectIdentifiers.pkcs_12PbeIds.getId());
  74. }
  75. public static SecretKey generateSecretKeyForPKCS5Scheme2(JcaJceHelper helper, String algorithm, char[] password, byte[] salt, int iterationCount)
  76. throws NoSuchProviderException, NoSuchAlgorithmException, InvalidKeySpecException
  77. {
  78. SecretKeyFactory keyGen = helper.createSecretKeyFactory("PBKDF2with8BIT");
  79. SecretKey sKey = keyGen.generateSecret(new PBEKeySpec(password, salt, iterationCount, PEMUtilities.getKeySize(algorithm)));
  80. return new SecretKeySpec(sKey.getEncoded(), algorithm);
  81. }
  82. static byte[] crypt(
  83. boolean encrypt,
  84. JcaJceHelper helper,
  85. byte[] bytes,
  86. char[] password,
  87. String dekAlgName,
  88. byte[] iv)
  89. throws PEMException
  90. {
  91. AlgorithmParameterSpec paramSpec = new IvParameterSpec(iv);
  92. String alg;
  93. String blockMode = "CBC";
  94. String padding = "PKCS5Padding";
  95. Key sKey;
  96. // Figure out block mode and padding.
  97. if (dekAlgName.endsWith("-CFB"))
  98. {
  99. blockMode = "CFB";
  100. padding = "NoPadding";
  101. }
  102. if (dekAlgName.endsWith("-ECB") ||
  103. "DES-EDE".equals(dekAlgName) ||
  104. "DES-EDE3".equals(dekAlgName))
  105. {
  106. // ECB is actually the default (though seldom used) when OpenSSL
  107. // uses DES-EDE (des2) or DES-EDE3 (des3).
  108. blockMode = "ECB";
  109. paramSpec = null;
  110. }
  111. if (dekAlgName.endsWith("-OFB"))
  112. {
  113. blockMode = "OFB";
  114. padding = "NoPadding";
  115. }
  116. // Figure out algorithm and key size.
  117. if (dekAlgName.startsWith("DES-EDE"))
  118. {
  119. alg = "DESede";
  120. // "DES-EDE" is actually des2 in OpenSSL-speak!
  121. // "DES-EDE3" is des3.
  122. boolean des2 = !dekAlgName.startsWith("DES-EDE3");
  123. sKey = getKey(helper, password, alg, 24, iv, des2);
  124. }
  125. else if (dekAlgName.startsWith("DES-"))
  126. {
  127. alg = "DES";
  128. sKey = getKey(helper, password, alg, 8, iv);
  129. }
  130. else if (dekAlgName.startsWith("BF-"))
  131. {
  132. alg = "Blowfish";
  133. sKey = getKey(helper, password, alg, 16, iv);
  134. }
  135. else if (dekAlgName.startsWith("RC2-"))
  136. {
  137. alg = "RC2";
  138. int keyBits = 128;
  139. if (dekAlgName.startsWith("RC2-40-"))
  140. {
  141. keyBits = 40;
  142. }
  143. else if (dekAlgName.startsWith("RC2-64-"))
  144. {
  145. keyBits = 64;
  146. }
  147. sKey = getKey(helper, password, alg, keyBits / 8, iv);
  148. if (paramSpec == null) // ECB block mode
  149. {
  150. paramSpec = new RC2ParameterSpec(keyBits);
  151. }
  152. else
  153. {
  154. paramSpec = new RC2ParameterSpec(keyBits, iv);
  155. }
  156. }
  157. else if (dekAlgName.startsWith("AES-"))
  158. {
  159. alg = "AES";
  160. byte[] salt = iv;
  161. if (salt.length > 8)
  162. {
  163. salt = new byte[8];
  164. System.arraycopy(iv, 0, salt, 0, 8);
  165. }
  166. int keyBits;
  167. if (dekAlgName.startsWith("AES-128-"))
  168. {
  169. keyBits = 128;
  170. }
  171. else if (dekAlgName.startsWith("AES-192-"))
  172. {
  173. keyBits = 192;
  174. }
  175. else if (dekAlgName.startsWith("AES-256-"))
  176. {
  177. keyBits = 256;
  178. }
  179. else
  180. {
  181. throw new EncryptionException("unknown AES encryption with private key");
  182. }
  183. sKey = getKey(helper, password, "AES", keyBits / 8, salt);
  184. }
  185. else
  186. {
  187. throw new EncryptionException("unknown encryption with private key");
  188. }
  189. String transformation = alg + "/" + blockMode + "/" + padding;
  190. try
  191. {
  192. Cipher c = helper.createCipher(transformation);
  193. int mode = encrypt ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE;
  194. if (paramSpec == null) // ECB block mode
  195. {
  196. c.init(mode, sKey);
  197. }
  198. else
  199. {
  200. c.init(mode, sKey, paramSpec);
  201. }
  202. return c.doFinal(bytes);
  203. }
  204. catch (Exception e)
  205. {
  206. throw new EncryptionException("exception using cipher - please check password and data.", e);
  207. }
  208. }
  209. private static SecretKey getKey(
  210. JcaJceHelper helper,
  211. char[] password,
  212. String algorithm,
  213. int keyLength,
  214. byte[] salt)
  215. throws PEMException
  216. {
  217. return getKey(helper, password, algorithm, keyLength, salt, false);
  218. }
  219. private static SecretKey getKey(
  220. JcaJceHelper helper,
  221. char[] password,
  222. String algorithm,
  223. int keyLength,
  224. byte[] salt,
  225. boolean des2)
  226. throws PEMException
  227. {
  228. try
  229. {
  230. PBEKeySpec spec = new PBEKeySpec(password, salt, 1, keyLength * 8);
  231. SecretKeyFactory keyFactory = helper.createSecretKeyFactory("PBKDF-OpenSSL");
  232. byte[] key = keyFactory.generateSecret(spec).getEncoded();
  233. if (des2 && key.length >= 24)
  234. {
  235. // For DES2, we must copy first 8 bytes into the last 8 bytes.
  236. System.arraycopy(key, 0, key, 16, 8);
  237. }
  238. return new SecretKeySpec(key, algorithm);
  239. }
  240. catch (GeneralSecurityException e)
  241. {
  242. throw new PEMException("Unable to create OpenSSL PBDKF: " + e.getMessage(), e);
  243. }
  244. }
  245. }