Skip to content

Commit ee9a871

Browse files
committed
Merge branch 'pg-refactor-JceAEADUtil' into 'main'
Pg refactor jce aead util See merge request root/bc-java!54
2 parents f0474a0 + 6647e01 commit ee9a871

File tree

5 files changed

+85
-122
lines changed

5 files changed

+85
-122
lines changed

pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcaAEADSecretKeyEncryptorBuilder.java

Lines changed: 13 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -4,24 +4,16 @@
44
import java.security.SecureRandom;
55

66
import javax.crypto.Cipher;
7-
import javax.crypto.SecretKey;
8-
import javax.crypto.spec.SecretKeySpec;
97

108
import org.bouncycastle.bcpg.AEADUtils;
119
import org.bouncycastle.bcpg.PacketTags;
1210
import org.bouncycastle.bcpg.PublicKeyPacket;
1311
import org.bouncycastle.bcpg.S2K;
14-
import org.bouncycastle.bcpg.SymmetricKeyUtils;
15-
import org.bouncycastle.crypto.digests.SHA256Digest;
16-
import org.bouncycastle.crypto.generators.HKDFBytesGenerator;
17-
import org.bouncycastle.crypto.params.HKDFParameters;
1812
import org.bouncycastle.jcajce.util.DefaultJcaJceHelper;
1913
import org.bouncycastle.jcajce.util.NamedJcaJceHelper;
2014
import org.bouncycastle.jcajce.util.ProviderJcaJceHelper;
2115
import org.bouncycastle.openpgp.PGPException;
22-
import org.bouncycastle.openpgp.PGPUtil;
2316
import org.bouncycastle.openpgp.operator.PBESecretKeyEncryptor;
24-
import org.bouncycastle.util.Arrays;
2517

2618
public class JcaAEADSecretKeyEncryptorBuilder
2719
{
@@ -70,33 +62,21 @@ public PBESecretKeyEncryptor build(char[] passphrase, final PublicKeyPacket pubK
7062
public byte[] encryptKeyData(byte[] key, byte[] keyData, int keyOff, int keyLen)
7163
throws PGPException
7264
{
73-
int packetTag = pubKey.getPacketTag() == PacketTags.PUBLIC_KEY ? PacketTags.SECRET_KEY : PacketTags.SECRET_SUBKEY;
74-
byte[] hkdfInfo = new byte[] {
75-
(byte) (0xC0 | packetTag),
76-
(byte) pubKey.getVersion(),
77-
(byte) symmetricAlgorithm,
78-
(byte) aeadAlgorithm
79-
};
80-
81-
HKDFParameters hkdfParameters = new HKDFParameters(
82-
getKey(),
83-
null,
84-
hkdfInfo);
85-
86-
HKDFBytesGenerator hkdfGen = new HKDFBytesGenerator(new SHA256Digest());
87-
hkdfGen.init(hkdfParameters);
88-
key = new byte[SymmetricKeyUtils.getKeyLengthInOctets(encAlgorithm)];
89-
hkdfGen.generateBytes(key, 0, key.length);
90-
9165
try
9266
{
93-
byte[] aad = Arrays.prepend(pubKey.getEncodedContents(), (byte) (0xC0 | packetTag));
94-
SecretKey secretKey = new SecretKeySpec(key, PGPUtil.getSymmetricCipherName(encAlgorithm));
95-
final Cipher c = aeadUtil.createAEADCipher(encAlgorithm, aeadAlgorithm);
96-
97-
JceAEADCipherUtil.setUpAeadCipher(c, secretKey, Cipher.ENCRYPT_MODE, iv, 128, aad);
98-
byte[] data = c.doFinal(keyData, keyOff, keyLen);
99-
return data;
67+
return JceAEADUtil.processAeadKeyData(
68+
aeadUtil,
69+
Cipher.ENCRYPT_MODE,
70+
encAlgorithm,
71+
aeadAlgorithm,
72+
getKey(),
73+
iv,
74+
pubKey.getPacketTag() == PacketTags.PUBLIC_KEY ? PacketTags.SECRET_KEY : PacketTags.SECRET_SUBKEY,
75+
pubKey.getVersion(),
76+
keyData,
77+
keyOff,
78+
keyLen,
79+
pubKey.getEncodedContents());
10080
}
10181
catch (Exception e)
10282
{

pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JceAEADUtil.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,12 @@
44
import java.io.InputStream;
55
import java.io.OutputStream;
66
import java.security.GeneralSecurityException;
7+
import java.security.InvalidAlgorithmParameterException;
8+
import java.security.InvalidKeyException;
79

10+
import javax.crypto.BadPaddingException;
811
import javax.crypto.Cipher;
12+
import javax.crypto.IllegalBlockSizeException;
913
import javax.crypto.SecretKey;
1014
import javax.crypto.spec.SecretKeySpec;
1115

@@ -276,6 +280,30 @@ Cipher createAEADCipher(int encAlgorithm, int aeadAlgorithm)
276280
return helper.createCipher(cName);
277281
}
278282

283+
static byte[] processAeadKeyData(JceAEADUtil aeadUtil, int mode, int encAlgorithm, int aeadAlgorithm, byte[] s2kKey, byte[] iv, int packetTag, int keyVersion, byte[] keyData, int keyOff, int keyLen, byte[] pubkeyData)
284+
throws PGPException
285+
{
286+
// TODO: Replace HDKF code with JCE based implementation
287+
byte[] key = generateHKDFBytes(s2kKey, null,
288+
new byte[]{(byte)(0xC0 | packetTag), (byte)keyVersion, (byte)encAlgorithm, (byte)aeadAlgorithm},
289+
SymmetricKeyUtils.getKeyLengthInOctets(encAlgorithm));
290+
291+
try
292+
{
293+
byte[] aad = Arrays.prepend(pubkeyData, (byte)(0xC0 | packetTag));
294+
SecretKey secretKey = new SecretKeySpec(key, PGPUtil.getSymmetricCipherName(encAlgorithm));
295+
final Cipher c = aeadUtil.createAEADCipher(encAlgorithm, aeadAlgorithm);
296+
297+
JceAEADCipherUtil.setUpAeadCipher(c, secretKey, mode, iv, 128, aad);
298+
return c.doFinal(keyData, keyOff, keyLen);
299+
}
300+
catch (InvalidAlgorithmParameterException | InvalidKeyException |
301+
IllegalBlockSizeException | BadPaddingException e)
302+
{
303+
throw new PGPException("Exception recovering AEAD protected private key material", e);
304+
}
305+
}
306+
279307
static class PGPAeadInputStream
280308
extends InputStream
281309
{

pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePBEProtectionRemoverFactory.java

Lines changed: 2 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,14 @@
11
package org.bouncycastle.openpgp.operator.jcajce;
22

3-
import java.security.GeneralSecurityException;
43
import java.security.InvalidAlgorithmParameterException;
54
import java.security.InvalidKeyException;
65
import java.security.Provider;
76

87
import javax.crypto.BadPaddingException;
98
import javax.crypto.Cipher;
109
import javax.crypto.IllegalBlockSizeException;
11-
import javax.crypto.SecretKey;
1210
import javax.crypto.spec.IvParameterSpec;
13-
import javax.crypto.spec.SecretKeySpec;
1411

15-
import org.bouncycastle.bcpg.SymmetricKeyUtils;
16-
import org.bouncycastle.crypto.digests.SHA256Digest;
17-
import org.bouncycastle.crypto.generators.HKDFBytesGenerator;
18-
import org.bouncycastle.crypto.params.HKDFParameters;
1912
import org.bouncycastle.jcajce.spec.AEADParameterSpec;
2013
import org.bouncycastle.jcajce.util.DefaultJcaJceHelper;
2114
import org.bouncycastle.jcajce.util.NamedJcaJceHelper;
@@ -26,7 +19,6 @@
2619
import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptor;
2720
import org.bouncycastle.openpgp.operator.PGPDigestCalculatorProvider;
2821
import org.bouncycastle.openpgp.operator.PGPSecretKeyDecryptorWithAAD;
29-
import org.bouncycastle.util.Arrays;
3022

3123
public class JcePBEProtectionRemoverFactory
3224
implements PBEProtectionRemoverFactory
@@ -121,30 +113,7 @@ public byte[] recoverKeyData(int encAlgorithm, byte[] key, byte[] iv, byte[] aad
121113
public byte[] recoverKeyData(int encAlgorithm, int aeadAlgorithm, byte[] s2kKey, byte[] iv, int packetTag, int keyVersion, byte[] keyData, byte[] pubkeyData)
122114
throws PGPException
123115
{
124-
byte[] hkdfInfo = new byte[] {
125-
(byte) (0xC0 | packetTag), (byte) keyVersion, (byte) encAlgorithm, (byte) aeadAlgorithm
126-
};
127-
// TODO: Replace HDKF code with JCE based implementation
128-
HKDFParameters hkdfParameters = new HKDFParameters(s2kKey, null, hkdfInfo);
129-
HKDFBytesGenerator hkdfGen = new HKDFBytesGenerator(new SHA256Digest());
130-
hkdfGen.init(hkdfParameters);
131-
byte[] key = new byte[SymmetricKeyUtils.getKeyLengthInOctets(encAlgorithm)];
132-
hkdfGen.generateBytes(key, 0, key.length);
133-
134-
byte[] aad = Arrays.prepend(pubkeyData, (byte) (0xC0 | packetTag));
135-
136-
SecretKey secretKey = new SecretKeySpec(key, PGPUtil.getSymmetricCipherName(encAlgorithm));
137-
final Cipher c = aeadUtil.createAEADCipher(encAlgorithm, aeadAlgorithm);
138-
try
139-
{
140-
JceAEADCipherUtil.setUpAeadCipher(c, secretKey, Cipher.DECRYPT_MODE, iv, 128, aad);
141-
byte[] data = c.doFinal(keyData);
142-
return data;
143-
}
144-
catch (GeneralSecurityException e)
145-
{
146-
throw new PGPException("Cannot extract AEAD protected secret key material", e);
147-
}
116+
return JceAEADUtil.processAeadKeyData(aeadUtil, Cipher.DECRYPT_MODE, encAlgorithm, aeadAlgorithm, s2kKey, iv, packetTag, keyVersion, keyData, 0, keyData.length, pubkeyData);
148117
}
149118
};
150119
}
@@ -184,30 +153,7 @@ public byte[] recoverKeyData(int encAlgorithm, byte[] key, byte[] iv, byte[] key
184153
public byte[] recoverKeyData(int encAlgorithm, int aeadAlgorithm, byte[] s2kKey, byte[] iv, int packetTag, int keyVersion, byte[] keyData, byte[] pubkeyData)
185154
throws PGPException
186155
{
187-
byte[] hkdfInfo = new byte[] {
188-
(byte) (0xC0 | packetTag), (byte) keyVersion, (byte) encAlgorithm, (byte) aeadAlgorithm
189-
};
190-
// TODO: Replace HDKF code with JCE based implementation
191-
HKDFParameters hkdfParameters = new HKDFParameters(s2kKey, null, hkdfInfo);
192-
HKDFBytesGenerator hkdfGen = new HKDFBytesGenerator(new SHA256Digest());
193-
hkdfGen.init(hkdfParameters);
194-
byte[] key = new byte[SymmetricKeyUtils.getKeyLengthInOctets(encAlgorithm)];
195-
hkdfGen.generateBytes(key, 0, key.length);
196-
197-
byte[] aad = Arrays.prepend(pubkeyData, (byte) (0xC0 | packetTag));
198-
199-
SecretKey secretKey = new SecretKeySpec(key, PGPUtil.getSymmetricCipherName(encAlgorithm));
200-
final Cipher c = aeadUtil.createAEADCipher(encAlgorithm, aeadAlgorithm);
201-
try
202-
{
203-
JceAEADCipherUtil.setUpAeadCipher(c, secretKey, Cipher.DECRYPT_MODE, iv, 128, aad);
204-
byte[] data = c.doFinal(keyData);
205-
return data;
206-
}
207-
catch (GeneralSecurityException e)
208-
{
209-
throw new PGPException("Cannot extract AEAD protected secret key material", e);
210-
}
156+
return JceAEADUtil.processAeadKeyData(aeadUtil, Cipher.DECRYPT_MODE, encAlgorithm, aeadAlgorithm, s2kKey, iv, packetTag, keyVersion, keyData, 0, keyData.length, pubkeyData);
211157
}
212158
};
213159

pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePBESecretKeyDecryptorBuilder.java

Lines changed: 1 addition & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,21 @@
11
package org.bouncycastle.openpgp.operator.jcajce;
22

3-
import java.security.GeneralSecurityException;
43
import java.security.InvalidAlgorithmParameterException;
54
import java.security.InvalidKeyException;
65
import java.security.Provider;
76

87
import javax.crypto.BadPaddingException;
98
import javax.crypto.Cipher;
109
import javax.crypto.IllegalBlockSizeException;
11-
import javax.crypto.SecretKey;
1210
import javax.crypto.spec.IvParameterSpec;
13-
import javax.crypto.spec.SecretKeySpec;
1411

15-
import org.bouncycastle.bcpg.SymmetricKeyUtils;
16-
import org.bouncycastle.crypto.digests.SHA256Digest;
17-
import org.bouncycastle.crypto.generators.HKDFBytesGenerator;
18-
import org.bouncycastle.crypto.params.HKDFParameters;
1912
import org.bouncycastle.jcajce.util.DefaultJcaJceHelper;
2013
import org.bouncycastle.jcajce.util.NamedJcaJceHelper;
2114
import org.bouncycastle.jcajce.util.ProviderJcaJceHelper;
2215
import org.bouncycastle.openpgp.PGPException;
2316
import org.bouncycastle.openpgp.PGPUtil;
2417
import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptor;
2518
import org.bouncycastle.openpgp.operator.PGPDigestCalculatorProvider;
26-
import org.bouncycastle.util.Arrays;
2719

2820
public class JcePBESecretKeyDecryptorBuilder
2921
{
@@ -112,30 +104,7 @@ public byte[] recoverKeyData(int encAlgorithm, byte[] key, byte[] iv, byte[] key
112104
public byte[] recoverKeyData(int encAlgorithm, int aeadAlgorithm, byte[] s2kKey, byte[] iv, int packetTag, int keyVersion, byte[] keyData, byte[] pubkeyData)
113105
throws PGPException
114106
{
115-
byte[] hkdfInfo = new byte[] {
116-
(byte) (0xC0 | packetTag), (byte) keyVersion, (byte) encAlgorithm, (byte) aeadAlgorithm
117-
};
118-
// TODO: Replace HDKF code with JCE based implementation
119-
HKDFParameters hkdfParameters = new HKDFParameters(s2kKey, null, hkdfInfo);
120-
HKDFBytesGenerator hkdfGen = new HKDFBytesGenerator(new SHA256Digest());
121-
hkdfGen.init(hkdfParameters);
122-
byte[] key = new byte[SymmetricKeyUtils.getKeyLengthInOctets(encAlgorithm)];
123-
hkdfGen.generateBytes(key, 0, key.length);
124-
125-
byte[] aad = Arrays.prepend(pubkeyData, (byte) (0xC0 | packetTag));
126-
127-
SecretKey secretKey = new SecretKeySpec(key, PGPUtil.getSymmetricCipherName(encAlgorithm));
128-
final Cipher c = aeadUtil.createAEADCipher(encAlgorithm, aeadAlgorithm);
129-
try
130-
{
131-
JceAEADCipherUtil.setUpAeadCipher(c, secretKey, Cipher.DECRYPT_MODE, iv, 128, aad);
132-
byte[] data = c.doFinal(keyData);
133-
return data;
134-
}
135-
catch (GeneralSecurityException e)
136-
{
137-
throw new PGPException("Cannot extract AEAD protected secret key material", e);
138-
}
107+
return JceAEADUtil.processAeadKeyData(aeadUtil, Cipher.DECRYPT_MODE, encAlgorithm, aeadAlgorithm, s2kKey, iv, packetTag, keyVersion, keyData, 0, keyData.length, pubkeyData);
139108
}
140109
};
141110
}

pg/src/test/java/org/bouncycastle/openpgp/test/OperatorJcajceTest.java

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import java.security.PrivateKey;
1010
import java.security.Provider;
1111
import java.security.PublicKey;
12+
import java.security.SecureRandom;
1213
import java.security.Security;
1314
import java.security.spec.PKCS8EncodedKeySpec;
1415
import java.security.spec.X509EncodedKeySpec;
@@ -21,6 +22,7 @@
2122
import org.bouncycastle.bcpg.HashAlgorithmTags;
2223
import org.bouncycastle.bcpg.PublicKeyAlgorithmTags;
2324
import org.bouncycastle.bcpg.PublicKeyPacket;
25+
import org.bouncycastle.bcpg.S2K;
2426
import org.bouncycastle.bcpg.SymmetricKeyAlgorithmTags;
2527
import org.bouncycastle.crypto.digests.SHA256Digest;
2628
import org.bouncycastle.crypto.params.X25519PrivateKeyParameters;
@@ -30,21 +32,27 @@
3032
import org.bouncycastle.jcajce.spec.HybridValueParameterSpec;
3133
import org.bouncycastle.jcajce.spec.UserKeyingMaterialSpec;
3234
import org.bouncycastle.jce.provider.BouncyCastleProvider;
35+
import org.bouncycastle.jce.spec.ECNamedCurveGenParameterSpec;
3336
import org.bouncycastle.openpgp.PGPEncryptedData;
37+
import org.bouncycastle.openpgp.PGPKeyPair;
3438
import org.bouncycastle.openpgp.PGPPublicKey;
39+
import org.bouncycastle.openpgp.operator.PBESecretKeyEncryptor;
3540
import org.bouncycastle.openpgp.operator.PGPContentVerifier;
3641
import org.bouncycastle.openpgp.operator.PGPDigestCalculator;
3742
import org.bouncycastle.openpgp.operator.PGPDigestCalculatorProvider;
43+
import org.bouncycastle.openpgp.operator.jcajce.JcaAEADSecretKeyEncryptorBuilder;
3844
import org.bouncycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator;
3945
import org.bouncycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider;
4046
import org.bouncycastle.openpgp.operator.jcajce.JcaPGPDigestCalculatorProviderBuilder;
4147
import org.bouncycastle.openpgp.operator.jcajce.JcaPGPKeyConverter;
48+
import org.bouncycastle.openpgp.operator.jcajce.JcaPGPKeyPair;
4249
import org.bouncycastle.openpgp.operator.jcajce.JcePBESecretKeyEncryptorBuilder;
4350
import org.bouncycastle.openpgp.operator.jcajce.JcePGPDataEncryptorBuilder;
4451
import org.bouncycastle.util.Arrays;
4552
import org.bouncycastle.util.Strings;
4653
import org.bouncycastle.util.encoders.Hex;
4754
import org.bouncycastle.util.test.SimpleTest;
55+
import org.junit.Assert;
4856

4957
public class OperatorJcajceTest
5058
extends SimpleTest
@@ -66,6 +74,7 @@ public String getName()
6674
public void performTest()
6775
throws Exception
6876
{
77+
testJcaAEADSecretKeyEncryptorBuilder();
6978
testCreateDigest();
7079
testX25519HKDF();
7180
testJcePBESecretKeyEncryptorBuilder();
@@ -316,12 +325,43 @@ public void testX25519HKDF()
316325
//isTrue(Arrays.areEqual(output, expectedDecryptedSessionKey));
317326
}
318327

328+
public void testJcaAEADSecretKeyEncryptorBuilder()
329+
throws Exception
330+
{
331+
BouncyCastleProvider prov = new BouncyCastleProvider();
332+
KeyPairGenerator eddsaGen = KeyPairGenerator.getInstance("EdDSA", prov);
333+
Date creationTime = new Date();
334+
eddsaGen.initialize(new ECNamedCurveGenParameterSpec("ed25519"));
335+
KeyPair kp = eddsaGen.generateKeyPair();
336+
SecureRandom random = new SecureRandom();
337+
for (int version : new int[]{PublicKeyPacket.VERSION_4, PublicKeyPacket.VERSION_6})
338+
{
339+
PGPKeyPair keyPair = new JcaPGPKeyPair(version, PublicKeyAlgorithmTags.Ed25519, kp, creationTime);
340+
JcaAEADSecretKeyEncryptorBuilder jcaEncBuilder = new JcaAEADSecretKeyEncryptorBuilder(
341+
AEADAlgorithmTags.OCB, SymmetricKeyAlgorithmTags.AES_256,
342+
S2K.Argon2Params.memoryConstrainedParameters())
343+
.setProvider(new BouncyCastleProvider());
344+
PBESecretKeyEncryptor encryptor = jcaEncBuilder.build(
345+
"Yin".toCharArray(),
346+
keyPair.getPublicKey().getPublicKeyPacket());
347+
byte[] key = new byte[16];
348+
random.nextBytes(key);
349+
byte[] input1 = new byte[64];
350+
random.nextBytes(input1);
351+
352+
byte[] input2 = Arrays.copyOfRange(input1, 32, 64);
353+
byte[] output1 = encryptor.encryptKeyData(key, input1, 32, 32);
354+
byte[] output2 = encryptor.encryptKeyData(key, input2, 0, 32);
355+
Assert.assertTrue(Arrays.areEqual(output1, output2));
356+
}
357+
}
358+
319359
private class NullProvider
320360
extends Provider
321361
{
322362
NullProvider()
323363
{
324-
super("NULL", 0.0, "Null Provider");
364+
super("NULL", 0.0, "Null Provider");
325365
}
326366
}
327367

0 commit comments

Comments
 (0)