/extern/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/dh/IESCipher.java

https://gitlab.com/vizilo/fdroidclient · Java · 507 lines · 424 code · 70 blank · 13 comment · 76 complexity · 5e8495b304d60f793c0f0a58720f2a67 MD5 · raw file

  1. package org.spongycastle.jcajce.provider.asymmetric.dh;
  2. import java.io.ByteArrayOutputStream;
  3. import java.security.AlgorithmParameters;
  4. import java.security.InvalidAlgorithmParameterException;
  5. import java.security.InvalidKeyException;
  6. import java.security.Key;
  7. import java.security.NoSuchAlgorithmException;
  8. import java.security.PrivateKey;
  9. import java.security.PublicKey;
  10. import java.security.SecureRandom;
  11. import java.security.spec.AlgorithmParameterSpec;
  12. import javax.crypto.BadPaddingException;
  13. import javax.crypto.Cipher;
  14. import javax.crypto.CipherSpi;
  15. import javax.crypto.IllegalBlockSizeException;
  16. import javax.crypto.NoSuchPaddingException;
  17. import javax.crypto.ShortBufferException;
  18. import javax.crypto.interfaces.DHKey;
  19. import javax.crypto.interfaces.DHPrivateKey;
  20. import javax.crypto.interfaces.DHPublicKey;
  21. import org.spongycastle.crypto.InvalidCipherTextException;
  22. import org.spongycastle.crypto.KeyEncoder;
  23. import org.spongycastle.crypto.agreement.DHBasicAgreement;
  24. import org.spongycastle.crypto.digests.SHA1Digest;
  25. import org.spongycastle.crypto.engines.AESEngine;
  26. import org.spongycastle.crypto.engines.DESedeEngine;
  27. import org.spongycastle.crypto.engines.IESEngine;
  28. import org.spongycastle.crypto.generators.DHKeyPairGenerator;
  29. import org.spongycastle.crypto.generators.EphemeralKeyPairGenerator;
  30. import org.spongycastle.crypto.generators.KDF2BytesGenerator;
  31. import org.spongycastle.crypto.macs.HMac;
  32. import org.spongycastle.crypto.paddings.PaddedBufferedBlockCipher;
  33. import org.spongycastle.crypto.params.AsymmetricKeyParameter;
  34. import org.spongycastle.crypto.params.DHKeyGenerationParameters;
  35. import org.spongycastle.crypto.params.DHKeyParameters;
  36. import org.spongycastle.crypto.params.DHParameters;
  37. import org.spongycastle.crypto.params.DHPublicKeyParameters;
  38. import org.spongycastle.crypto.params.IESParameters;
  39. import org.spongycastle.crypto.params.IESWithCipherParameters;
  40. import org.spongycastle.crypto.parsers.DHIESPublicKeyParser;
  41. import org.spongycastle.jcajce.provider.asymmetric.util.DHUtil;
  42. import org.spongycastle.jcajce.provider.asymmetric.util.IESUtil;
  43. import org.spongycastle.jce.interfaces.IESKey;
  44. import org.spongycastle.jce.provider.BouncyCastleProvider;
  45. import org.spongycastle.jce.spec.IESParameterSpec;
  46. import org.spongycastle.util.BigIntegers;
  47. import org.spongycastle.util.Strings;
  48. public class IESCipher
  49. extends CipherSpi
  50. {
  51. private IESEngine engine;
  52. private int state = -1;
  53. private ByteArrayOutputStream buffer = new ByteArrayOutputStream();
  54. private AlgorithmParameters engineParam = null;
  55. private IESParameterSpec engineSpec = null;
  56. private AsymmetricKeyParameter key;
  57. private SecureRandom random;
  58. private boolean dhaesMode = false;
  59. private AsymmetricKeyParameter otherKeyParameter = null;
  60. public IESCipher(IESEngine engine)
  61. {
  62. this.engine = engine;
  63. }
  64. public int engineGetBlockSize()
  65. {
  66. if (engine.getCipher() != null)
  67. {
  68. return engine.getCipher().getBlockSize();
  69. }
  70. else
  71. {
  72. return 0;
  73. }
  74. }
  75. public int engineGetKeySize(Key key)
  76. {
  77. if (key instanceof DHKey)
  78. {
  79. return ((DHKey)key).getParams().getP().bitLength();
  80. }
  81. else
  82. {
  83. throw new IllegalArgumentException("not a DH key");
  84. }
  85. }
  86. public byte[] engineGetIV()
  87. {
  88. return null;
  89. }
  90. public AlgorithmParameters engineGetParameters()
  91. {
  92. if (engineParam == null && engineSpec != null)
  93. {
  94. try
  95. {
  96. engineParam = AlgorithmParameters.getInstance("IES", BouncyCastleProvider.PROVIDER_NAME);
  97. engineParam.init(engineSpec);
  98. }
  99. catch (Exception e)
  100. {
  101. throw new RuntimeException(e.toString());
  102. }
  103. }
  104. return engineParam;
  105. }
  106. public void engineSetMode(String mode)
  107. throws NoSuchAlgorithmException
  108. {
  109. String modeName = Strings.toUpperCase(mode);
  110. if (modeName.equals("NONE"))
  111. {
  112. dhaesMode = false;
  113. }
  114. else if (modeName.equals("DHAES"))
  115. {
  116. dhaesMode = true;
  117. }
  118. else
  119. {
  120. throw new IllegalArgumentException("can't support mode " + mode);
  121. }
  122. }
  123. public int engineGetOutputSize(int inputLen)
  124. {
  125. int len1, len2, len3;
  126. len1 = engine.getMac().getMacSize();
  127. if (key != null)
  128. {
  129. len2 = ((DHKey)key).getParams().getP().bitLength() / 8 + 1;
  130. }
  131. else
  132. {
  133. throw new IllegalStateException("cipher not initialised");
  134. }
  135. if (engine.getCipher() == null)
  136. {
  137. len3 = inputLen;
  138. }
  139. else if (state == Cipher.ENCRYPT_MODE || state == Cipher.WRAP_MODE)
  140. {
  141. len3 = engine.getCipher().getOutputSize(inputLen);
  142. }
  143. else if (state == Cipher.DECRYPT_MODE || state == Cipher.UNWRAP_MODE)
  144. {
  145. len3 = engine.getCipher().getOutputSize(inputLen - len1 - len2);
  146. }
  147. else
  148. {
  149. throw new IllegalStateException("cipher not initialised");
  150. }
  151. if (state == Cipher.ENCRYPT_MODE || state == Cipher.WRAP_MODE)
  152. {
  153. return buffer.size() + len1 + len2 + len3;
  154. }
  155. else if (state == Cipher.DECRYPT_MODE || state == Cipher.UNWRAP_MODE)
  156. {
  157. return buffer.size() - len1 - len2 + len3;
  158. }
  159. else
  160. {
  161. throw new IllegalStateException("IESCipher not initialised");
  162. }
  163. }
  164. public void engineSetPadding(String padding)
  165. throws NoSuchPaddingException
  166. {
  167. String paddingName = Strings.toUpperCase(padding);
  168. // TDOD: make this meaningful...
  169. if (paddingName.equals("NOPADDING"))
  170. {
  171. }
  172. else if (paddingName.equals("PKCS5PADDING") || paddingName.equals("PKCS7PADDING"))
  173. {
  174. }
  175. else
  176. {
  177. throw new NoSuchPaddingException("padding not available with IESCipher");
  178. }
  179. }
  180. // Initialisation methods
  181. public void engineInit(
  182. int opmode,
  183. Key key,
  184. AlgorithmParameters params,
  185. SecureRandom random)
  186. throws InvalidKeyException, InvalidAlgorithmParameterException
  187. {
  188. AlgorithmParameterSpec paramSpec = null;
  189. if (params != null)
  190. {
  191. try
  192. {
  193. paramSpec = params.getParameterSpec(IESParameterSpec.class);
  194. }
  195. catch (Exception e)
  196. {
  197. throw new InvalidAlgorithmParameterException("cannot recognise parameters: " + e.toString());
  198. }
  199. }
  200. engineParam = params;
  201. engineInit(opmode, key, paramSpec, random);
  202. }
  203. public void engineInit(
  204. int opmode,
  205. Key key,
  206. AlgorithmParameterSpec engineSpec,
  207. SecureRandom random)
  208. throws InvalidAlgorithmParameterException, InvalidKeyException
  209. {
  210. // Use default parameters (including cipher key size) if none are specified
  211. if (engineSpec == null)
  212. {
  213. this.engineSpec = IESUtil.guessParameterSpec(engine);
  214. }
  215. else if (engineSpec instanceof IESParameterSpec)
  216. {
  217. this.engineSpec = (IESParameterSpec)engineSpec;
  218. }
  219. else
  220. {
  221. throw new InvalidAlgorithmParameterException("must be passed IES parameters");
  222. }
  223. // Parse the recipient's key
  224. if (opmode == Cipher.ENCRYPT_MODE || opmode == Cipher.WRAP_MODE)
  225. {
  226. if (key instanceof DHPublicKey)
  227. {
  228. this.key = DHUtil.generatePublicKeyParameter((PublicKey)key);
  229. }
  230. else if (key instanceof IESKey)
  231. {
  232. IESKey ieKey = (IESKey)key;
  233. this.key = DHUtil.generatePublicKeyParameter(ieKey.getPublic());
  234. this.otherKeyParameter = DHUtil.generatePrivateKeyParameter(ieKey.getPrivate());
  235. }
  236. else
  237. {
  238. throw new InvalidKeyException("must be passed recipient's public DH key for encryption");
  239. }
  240. }
  241. else if (opmode == Cipher.DECRYPT_MODE || opmode == Cipher.UNWRAP_MODE)
  242. {
  243. if (key instanceof DHPrivateKey)
  244. {
  245. this.key = DHUtil.generatePrivateKeyParameter((PrivateKey)key);
  246. }
  247. else if (key instanceof IESKey)
  248. {
  249. IESKey ieKey = (IESKey)key;
  250. this.otherKeyParameter = DHUtil.generatePublicKeyParameter(ieKey.getPublic());
  251. this.key = DHUtil.generatePrivateKeyParameter(ieKey.getPrivate());
  252. }
  253. else
  254. {
  255. throw new InvalidKeyException("must be passed recipient's private DH key for decryption");
  256. }
  257. }
  258. else
  259. {
  260. throw new InvalidKeyException("must be passed EC key");
  261. }
  262. this.random = random;
  263. this.state = opmode;
  264. buffer.reset();
  265. }
  266. public void engineInit(
  267. int opmode,
  268. Key key,
  269. SecureRandom random)
  270. throws InvalidKeyException
  271. {
  272. try
  273. {
  274. engineInit(opmode, key, (AlgorithmParameterSpec)null, random);
  275. }
  276. catch (InvalidAlgorithmParameterException e)
  277. {
  278. throw new IllegalArgumentException("can't handle supplied parameter spec");
  279. }
  280. }
  281. // Update methods - buffer the input
  282. public byte[] engineUpdate(
  283. byte[] input,
  284. int inputOffset,
  285. int inputLen)
  286. {
  287. buffer.write(input, inputOffset, inputLen);
  288. return null;
  289. }
  290. public int engineUpdate(
  291. byte[] input,
  292. int inputOffset,
  293. int inputLen,
  294. byte[] output,
  295. int outputOffset)
  296. {
  297. buffer.write(input, inputOffset, inputLen);
  298. return 0;
  299. }
  300. // Finalisation methods
  301. public byte[] engineDoFinal(
  302. byte[] input,
  303. int inputOffset,
  304. int inputLen)
  305. throws IllegalBlockSizeException, BadPaddingException
  306. {
  307. if (inputLen != 0)
  308. {
  309. buffer.write(input, inputOffset, inputLen);
  310. }
  311. byte[] in = buffer.toByteArray();
  312. buffer.reset();
  313. // Convert parameters for use in IESEngine
  314. IESParameters params = new IESWithCipherParameters(engineSpec.getDerivationV(),
  315. engineSpec.getEncodingV(),
  316. engineSpec.getMacKeySize(),
  317. engineSpec.getCipherKeySize());
  318. DHParameters dhParams = ((DHKeyParameters)key).getParameters();
  319. byte[] V;
  320. if (otherKeyParameter != null)
  321. {
  322. try
  323. {
  324. if (state == Cipher.ENCRYPT_MODE || state == Cipher.WRAP_MODE)
  325. {
  326. engine.init(true, otherKeyParameter, key, params);
  327. }
  328. else
  329. {
  330. engine.init(false, key, otherKeyParameter, params);
  331. }
  332. return engine.processBlock(in, 0, in.length);
  333. }
  334. catch (Exception e)
  335. {
  336. throw new BadPaddingException(e.getMessage());
  337. }
  338. }
  339. if (state == Cipher.ENCRYPT_MODE || state == Cipher.WRAP_MODE)
  340. {
  341. // Generate the ephemeral key pair
  342. DHKeyPairGenerator gen = new DHKeyPairGenerator();
  343. gen.init(new DHKeyGenerationParameters(random, dhParams));
  344. EphemeralKeyPairGenerator kGen = new EphemeralKeyPairGenerator(gen, new KeyEncoder()
  345. {
  346. public byte[] getEncoded(AsymmetricKeyParameter keyParameter)
  347. {
  348. byte[] Vloc = new byte[(((DHKeyParameters)keyParameter).getParameters().getP().bitLength() + 7) / 8];
  349. byte[] Vtmp = BigIntegers.asUnsignedByteArray(((DHPublicKeyParameters)keyParameter).getY());
  350. if (Vtmp.length > Vloc.length)
  351. {
  352. throw new IllegalArgumentException("Senders's public key longer than expected.");
  353. }
  354. else
  355. {
  356. System.arraycopy(Vtmp, 0, Vloc, Vloc.length - Vtmp.length, Vtmp.length);
  357. }
  358. return Vloc;
  359. }
  360. });
  361. // Encrypt the buffer
  362. try
  363. {
  364. engine.init(key, params, kGen);
  365. return engine.processBlock(in, 0, in.length);
  366. }
  367. catch (Exception e)
  368. {
  369. throw new BadPaddingException(e.getMessage());
  370. }
  371. }
  372. else if (state == Cipher.DECRYPT_MODE || state == Cipher.UNWRAP_MODE)
  373. {
  374. // Decrypt the buffer
  375. try
  376. {
  377. engine.init(key, params, new DHIESPublicKeyParser(((DHKeyParameters)key).getParameters()));
  378. return engine.processBlock(in, 0, in.length);
  379. }
  380. catch (InvalidCipherTextException e)
  381. {
  382. throw new BadPaddingException(e.getMessage());
  383. }
  384. }
  385. else
  386. {
  387. throw new IllegalStateException("IESCipher not initialised");
  388. }
  389. }
  390. public int engineDoFinal(
  391. byte[] input,
  392. int inputOffset,
  393. int inputLength,
  394. byte[] output,
  395. int outputOffset)
  396. throws ShortBufferException, IllegalBlockSizeException, BadPaddingException
  397. {
  398. byte[] buf = engineDoFinal(input, inputOffset, inputLength);
  399. System.arraycopy(buf, 0, output, outputOffset, buf.length);
  400. return buf.length;
  401. }
  402. /**
  403. * Classes that inherit from us
  404. */
  405. static public class IES
  406. extends IESCipher
  407. {
  408. public IES()
  409. {
  410. super(new IESEngine(new DHBasicAgreement(),
  411. new KDF2BytesGenerator(new SHA1Digest()),
  412. new HMac(new SHA1Digest())));
  413. }
  414. }
  415. static public class IESwithDESede
  416. extends IESCipher
  417. {
  418. public IESwithDESede()
  419. {
  420. super(new IESEngine(new DHBasicAgreement(),
  421. new KDF2BytesGenerator(new SHA1Digest()),
  422. new HMac(new SHA1Digest()),
  423. new PaddedBufferedBlockCipher(new DESedeEngine())));
  424. }
  425. }
  426. static public class IESwithAES
  427. extends IESCipher
  428. {
  429. public IESwithAES()
  430. {
  431. super(new IESEngine(new DHBasicAgreement(),
  432. new KDF2BytesGenerator(new SHA1Digest()),
  433. new HMac(new SHA1Digest()),
  434. new PaddedBufferedBlockCipher(new AESEngine())));
  435. }
  436. }
  437. }