Skip to content

Commit ad7fdce

Browse files
author
gefeili
committed
Extract BeAEADUtil.processAEADData,and processAeadKeyData functions.
1 parent d24c6be commit ad7fdce

File tree

5 files changed

+81
-151
lines changed

5 files changed

+81
-151
lines changed

pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcAEADSecretKeyEncryptorBuilder.java

Lines changed: 19 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -7,24 +7,16 @@
77
import org.bouncycastle.bcpg.PacketTags;
88
import org.bouncycastle.bcpg.PublicKeyPacket;
99
import org.bouncycastle.bcpg.S2K;
10-
import org.bouncycastle.bcpg.SymmetricKeyUtils;
11-
import org.bouncycastle.crypto.InvalidCipherTextException;
12-
import org.bouncycastle.crypto.digests.SHA256Digest;
13-
import org.bouncycastle.crypto.generators.HKDFBytesGenerator;
14-
import org.bouncycastle.crypto.modes.AEADBlockCipher;
15-
import org.bouncycastle.crypto.params.AEADParameters;
16-
import org.bouncycastle.crypto.params.HKDFParameters;
17-
import org.bouncycastle.crypto.params.KeyParameter;
1810
import org.bouncycastle.openpgp.PGPException;
1911
import org.bouncycastle.openpgp.operator.PBESecretKeyEncryptor;
20-
import org.bouncycastle.util.Arrays;
2112

2213
public class BcAEADSecretKeyEncryptorBuilder
2314
{
2415

2516
private int aeadAlgorithm;
2617
private int symmetricAlgorithm;
2718
private S2K.Argon2Params argon2Params;
19+
private SecureRandom random = new SecureRandom();
2820

2921
public BcAEADSecretKeyEncryptorBuilder(int aeadAlgorithm, int symmetricAlgorithm, S2K.Argon2Params argon2Params)
3022
{
@@ -33,9 +25,15 @@ public BcAEADSecretKeyEncryptorBuilder(int aeadAlgorithm, int symmetricAlgorithm
3325
this.argon2Params = argon2Params;
3426
}
3527

36-
public PBESecretKeyEncryptor build(char[] passphrase, final PublicKeyPacket pubKey)
28+
public BcAEADSecretKeyEncryptorBuilder setSecureRandom(SecureRandom random)
3729
{
38-
return new PBESecretKeyEncryptor(symmetricAlgorithm, aeadAlgorithm, argon2Params, new SecureRandom(), passphrase)
30+
this.random = random;
31+
return this;
32+
}
33+
34+
public PBESecretKeyEncryptor build(char[] passphrase, PublicKeyPacket pubKey)
35+
{
36+
return new PBESecretKeyEncryptor(symmetricAlgorithm, aeadAlgorithm, argon2Params, random, passphrase)
3937
{
4038
private byte[] iv;
4139

@@ -48,49 +46,24 @@ public PBESecretKeyEncryptor build(char[] passphrase, final PublicKeyPacket pubK
4846
public byte[] encryptKeyData(byte[] key, byte[] keyData, int keyOff, int keyLen)
4947
throws PGPException
5048
{
51-
int packetTag = pubKey.getPacketTag() == PacketTags.PUBLIC_KEY ? PacketTags.SECRET_KEY : PacketTags.SECRET_SUBKEY;
52-
byte[] hkdfInfo = new byte[] {
53-
(byte) (0xC0 | packetTag),
54-
(byte) pubKey.getVersion(),
55-
(byte) symmetricAlgorithm,
56-
(byte) aeadAlgorithm
57-
};
58-
59-
HKDFParameters hkdfParameters = new HKDFParameters(
60-
getKey(),
61-
null,
62-
hkdfInfo);
63-
64-
HKDFBytesGenerator hkdfGen = new HKDFBytesGenerator(new SHA256Digest());
65-
hkdfGen.init(hkdfParameters);
66-
key = new byte[SymmetricKeyUtils.getKeyLengthInOctets(encAlgorithm)];
67-
hkdfGen.generateBytes(key, 0, key.length);
68-
6949
try
7050
{
71-
byte[] aad = Arrays.prepend(pubKey.getEncodedContents(), (byte) (0xC0 | packetTag));
72-
AEADBlockCipher cipher = BcAEADUtil.createAEADCipher(encAlgorithm, aeadAlgorithm);
73-
cipher.init(true, new AEADParameters(
74-
new KeyParameter(key),
75-
128,
51+
return BcAEADUtil.processAeadKeyData(true,
52+
encAlgorithm,
53+
aeadAlgorithm,
54+
getKey(),
7655
getCipherIV(),
77-
aad
78-
));
79-
int dataLen = cipher.getOutputSize(keyData.length);
80-
byte[] encKey = new byte[dataLen];
81-
dataLen = cipher.processBytes(keyData, 0, keyData.length, encKey, 0);
82-
83-
cipher.doFinal(encKey, dataLen);
84-
return encKey;
56+
pubKey.getPacketTag() == PacketTags.PUBLIC_KEY ? PacketTags.SECRET_KEY : PacketTags.SECRET_SUBKEY,
57+
pubKey.getVersion(),
58+
keyData,
59+
keyOff,
60+
keyLen,
61+
pubKey.getEncodedContents());
8562
}
8663
catch (IOException e)
8764
{
8865
throw new PGPException("Exception AEAD protecting private key material", e);
8966
}
90-
catch (InvalidCipherTextException e)
91-
{
92-
throw new PGPException("Exception AEAD protecting private key material", e);
93-
}
9467
}
9568

9669
@Override

pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcAEADUtil.java

Lines changed: 48 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@
3434

3535
public class BcAEADUtil
3636
{
37+
final static String RecoverAEADEncryptedSessionDataErrorMessage = "Exception recovering session info";
38+
private final static String ProcessAeadKeyDataErrorMessage = "Exception recovering AEAD protected private key material";
39+
final static String GetEskAndTagErrorMessage = "cannot encrypt session info";
3740
/**
3841
* Generate a nonce by xor-ing the given iv with the chunk index.
3942
*
@@ -275,6 +278,45 @@ public PGPDigestCalculator getIntegrityCalculator()
275278
};
276279
}
277280

281+
static byte[] processAEADData(boolean forEncryption, int encAlgorithm, int aeadAlgorithm, byte[] key, byte[] iv, byte[] aad, byte[] msg, int off, int len, String errorMessage)
282+
throws PGPException
283+
{
284+
AEADBlockCipher cipher = createAEADCipher(encAlgorithm, aeadAlgorithm);
285+
try
286+
{
287+
return processAEADData(forEncryption, cipher, new KeyParameter(key), iv, aad, msg, off, len);
288+
}
289+
catch (InvalidCipherTextException e)
290+
{
291+
throw new PGPException(errorMessage, e);
292+
}
293+
}
294+
295+
static byte[] processAEADData(boolean forEncryption, AEADBlockCipher cipher, KeyParameter key, byte[] iv, byte[] aad, byte[] msg, int off, int msgLen)
296+
throws InvalidCipherTextException
297+
{
298+
cipher.init(forEncryption, new AEADParameters(key, 128, iv, aad));
299+
int dataLen = cipher.getOutputSize(msgLen);
300+
byte[] data = new byte[dataLen];
301+
dataLen = cipher.processBytes(msg, off, msgLen, data, 0);
302+
cipher.doFinal(data, dataLen);
303+
return data;
304+
}
305+
306+
static byte[] processAeadKeyData(boolean forEncryption, int encAlgorithm, int aeadAlgorithm, byte[] s2kKey, byte[] iv,
307+
int packetTag, int keyVersion, byte[] keyData, int keyOff, int keyLen, byte[] pubkeyData)
308+
throws PGPException
309+
{
310+
byte[] key = generateHKDFBytes(s2kKey,
311+
null,
312+
new byte[]{
313+
(byte)(0xC0 | packetTag), (byte)keyVersion, (byte)encAlgorithm, (byte)aeadAlgorithm
314+
},
315+
SymmetricKeyUtils.getKeyLengthInOctets(encAlgorithm));
316+
byte[] aad = Arrays.prepend(pubkeyData, (byte)(0xC0 | packetTag));
317+
return processAEADData(forEncryption, encAlgorithm, aeadAlgorithm, key, iv, aad, keyData, keyOff, keyLen, ProcessAeadKeyDataErrorMessage);
318+
}
319+
278320
protected static class PGPAeadInputStream
279321
extends InputStream
280322
{
@@ -422,16 +464,10 @@ private byte[] readBlock()
422464
xorChunkId(adata, chunkIndex);
423465
}
424466

425-
byte[] decData = new byte[dataLen];
467+
byte[] decData;
426468
try
427469
{
428-
c.init(false, new AEADParameters(secretKey, 128, getNonce(iv, chunkIndex))); // always full tag.
429-
430-
c.processAADBytes(adata, 0, adata.length);
431-
432-
int len = c.processBytes(buf, 0, dataLen + tagLen, decData, 0);
433-
434-
c.doFinal(decData, len);
470+
decData = processAEADData(false, c, secretKey, getNonce(iv, chunkIndex), adata, buf, 0, dataLen + tagLen);
435471
}
436472
catch (InvalidCipherTextException e)
437473
{
@@ -449,9 +485,8 @@ private byte[] readBlock()
449485

450486
try
451487
{
452-
c.init(false, new AEADParameters(secretKey, 128, getNonce(iv, chunkIndex))); // always full tag.
488+
c.init(false, new AEADParameters(secretKey, 128, getNonce(iv, chunkIndex), adata)); // always full tag.
453489

454-
c.processAADBytes(adata, 0, adata.length);
455490
if (isV5StyleAEAD)
456491
{
457492
c.processAADBytes(Pack.longToBigEndian(totalBytes), 0, 8);
@@ -625,8 +660,7 @@ private void writeBlock()
625660

626661
try
627662
{
628-
c.init(true, new AEADParameters(secretKey, 128, getNonce(iv, chunkIndex))); // always full tag.
629-
c.processAADBytes(adata, 0, adata.length);
663+
c.init(true, new AEADParameters(secretKey, 128, getNonce(iv, chunkIndex), adata)); // always full tag.
630664

631665
int len = c.processBytes(data, 0, dataOff, data, 0);
632666
out.write(data, 0, len);
@@ -655,8 +689,8 @@ private void finish()
655689
byte[] adata = PGPAeadInputStream.getAdata(v5StyleAEAD, aaData, chunkIndex, totalBytes);
656690
try
657691
{
658-
c.init(true, new AEADParameters(secretKey, 128, getNonce(iv, chunkIndex))); // always full tag.
659-
c.processAADBytes(adata, 0, adata.length);
692+
c.init(true, new AEADParameters(secretKey, 128, getNonce(iv, chunkIndex), adata)); // always full tag.
693+
660694
if (v5StyleAEAD)
661695
{
662696
c.processAADBytes(Pack.longToBigEndian(totalBytes), 0, 8);

pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPBEDataDecryptorFactory.java

Lines changed: 9 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,11 @@
88
import org.bouncycastle.bcpg.UnsupportedPacketVersionException;
99
import org.bouncycastle.crypto.BlockCipher;
1010
import org.bouncycastle.crypto.BufferedBlockCipher;
11-
import org.bouncycastle.crypto.InvalidCipherTextException;
12-
import org.bouncycastle.crypto.modes.AEADBlockCipher;
13-
import org.bouncycastle.crypto.params.AEADParameters;
14-
import org.bouncycastle.crypto.params.KeyParameter;
1511
import org.bouncycastle.openpgp.PGPException;
1612
import org.bouncycastle.openpgp.PGPSessionKey;
1713
import org.bouncycastle.openpgp.operator.PBEDataDecryptorFactory;
1814
import org.bouncycastle.openpgp.operator.PGPDataDecryptor;
19-
import org.bouncycastle.openpgp.operator.PGPDigestCalculatorProvider;
15+
import org.bouncycastle.util.Arrays;
2016

2117
/**
2218
* A {@link PBEDataDecryptorFactory} for handling PBE decryption operations using the Bouncy Castle
@@ -31,7 +27,7 @@ public class BcPBEDataDecryptorFactory
3127
* @param pass the passphrase to use as the primary source of key material.
3228
* @param calculatorProvider a digest calculator provider to provide calculators to support the key generation calculation required.
3329
*/
34-
public BcPBEDataDecryptorFactory(char[] pass, PGPDigestCalculatorProvider calculatorProvider)
30+
public BcPBEDataDecryptorFactory(char[] pass, BcPGPDigestCalculatorProvider calculatorProvider)
3531
{
3632
super(pass, calculatorProvider);
3733
}
@@ -92,50 +88,29 @@ public byte[] recoverAEADEncryptedSessionData(SymmetricKeyEncSessionPacket keyDa
9288

9389
byte[] hkdfInfo = keyData.getAAData(); // Between v5 and v6, these bytes differ
9490

95-
KeyParameter secretKey;
91+
byte[] kek;
9692
if (keyData.getVersion() == SymmetricKeyEncSessionPacket.VERSION_5)
9793
{
98-
secretKey = new KeyParameter(ikm);
94+
kek = ikm;
9995
}
10096
else if (keyData.getVersion() == SymmetricKeyEncSessionPacket.VERSION_6)
10197
{
10298
// HKDF
10399
// secretKey := HKDF_sha256(ikm, hkdfInfo).generate()
104100
int kekLen = SymmetricKeyUtils.getKeyLengthInOctets(keyData.getEncAlgorithm());
105-
byte[] kek = BcAEADUtil.generateHKDFBytes(ikm, null, hkdfInfo, kekLen);
106-
secretKey = new KeyParameter(kek);
101+
kek = BcAEADUtil.generateHKDFBytes(ikm, null, hkdfInfo, kekLen);
107102
}
108103
else
109104
{
110105
throw new UnsupportedPacketVersionException("Unsupported SKESK packet version encountered: " + keyData.getVersion());
111106
}
112107

113108
// AEAD
114-
AEADBlockCipher aead = BcAEADUtil.createAEADCipher(keyData.getEncAlgorithm(), keyData.getAeadAlgorithm());
115-
int aeadMacLen = 128;
116-
byte[] authTag = keyData.getAuthTag();
117-
byte[] aeadIv = keyData.getIv();
118-
byte[] encSessionKey = keyData.getSecKeyData();
119-
120109
// sessionData := AEAD(secretKey).decrypt(encSessionKey || authTag)
121-
AEADParameters parameters = new AEADParameters(secretKey,
122-
aeadMacLen, aeadIv, keyData.getAAData());
123-
aead.init(false, parameters);
124-
int sessionKeyLen = aead.getOutputSize(encSessionKey.length + authTag.length);
125-
byte[] sessionData = new byte[sessionKeyLen];
126-
int dataLen = aead.processBytes(encSessionKey, 0, encSessionKey.length, sessionData, 0);
127-
dataLen += aead.processBytes(authTag, 0, authTag.length, sessionData, dataLen);
128-
129-
try
130-
{
131-
aead.doFinal(sessionData, dataLen);
132-
}
133-
catch (InvalidCipherTextException e)
134-
{
135-
throw new PGPException("Exception recovering session info", e);
136-
}
137-
138-
return sessionData;
110+
byte[] data = Arrays.concatenate(keyData.getSecKeyData(), keyData.getAuthTag());
111+
return BcAEADUtil.processAEADData(false, keyData.getEncAlgorithm(), keyData.getAeadAlgorithm(), kek,
112+
keyData.getIv(), keyData.getAAData(), data, 0, data.length,
113+
BcAEADUtil.RecoverAEADEncryptedSessionDataErrorMessage);
139114
}
140115

141116
// OpenPGP v4

pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPBEKeyEncryptionMethodGenerator.java

Lines changed: 4 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,6 @@
77
import org.bouncycastle.crypto.BlockCipher;
88
import org.bouncycastle.crypto.BufferedBlockCipher;
99
import org.bouncycastle.crypto.InvalidCipherTextException;
10-
import org.bouncycastle.crypto.modes.AEADCipher;
11-
import org.bouncycastle.crypto.params.AEADParameters;
12-
import org.bouncycastle.crypto.params.KeyParameter;
1310
import org.bouncycastle.openpgp.PGPException;
1411
import org.bouncycastle.openpgp.operator.PBEKeyEncryptionMethodGenerator;
1512
import org.bouncycastle.openpgp.operator.PGPDigestCalculator;
@@ -113,22 +110,11 @@ protected byte[] generateV6KEK(int kekAlgorithm, byte[] ikm, byte[] info)
113110
return BcAEADUtil.generateHKDFBytes(ikm, null, info, SymmetricKeyUtils.getKeyLengthInOctets(kekAlgorithm));
114111
}
115112

116-
protected byte[] getEskAndTag(int kekAlgorithm, int aeadAlgorithm, byte[] sessionKey, byte[] key, byte[] iv, byte[] info)
113+
protected byte[] getEskAndTag(int kekAlgorithm, int aeadAlgorithm, byte[] sessionInfo, byte[] key, byte[] iv, byte[] info)
117114
throws PGPException
118115
{
119-
AEADCipher aeadCipher = BcAEADUtil.createAEADCipher(kekAlgorithm, aeadAlgorithm);
120-
aeadCipher.init(true, new AEADParameters(new KeyParameter(key), 128, iv, info));
121-
int outLen = aeadCipher.getOutputSize(sessionKey.length);
122-
byte[] eskAndTag = new byte[outLen];
123-
int len = aeadCipher.processBytes(sessionKey, 0, sessionKey.length, eskAndTag, 0);
124-
try
125-
{
126-
len += aeadCipher.doFinal(eskAndTag, len);
127-
}
128-
catch (InvalidCipherTextException e)
129-
{
130-
throw new PGPException("cannot encrypt session info", e);
131-
}
132-
return eskAndTag;
116+
byte[] sessionKey = new byte[sessionInfo.length - 3];
117+
System.arraycopy(sessionInfo, 1, sessionKey, 0, sessionKey.length);
118+
return BcAEADUtil.processAEADData(true, kekAlgorithm, aeadAlgorithm, key, iv, info, sessionKey, 0, sessionKey.length, BcAEADUtil.GetEskAndTagErrorMessage);
133119
}
134120
}

pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPBESecretKeyDecryptorBuilder.java

Lines changed: 1 addition & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,10 @@
11
package org.bouncycastle.openpgp.operator.bc;
22

3-
import org.bouncycastle.bcpg.SymmetricKeyUtils;
43
import org.bouncycastle.crypto.BufferedBlockCipher;
54
import org.bouncycastle.crypto.InvalidCipherTextException;
6-
import org.bouncycastle.crypto.digests.SHA256Digest;
7-
import org.bouncycastle.crypto.generators.HKDFBytesGenerator;
8-
import org.bouncycastle.crypto.modes.AEADBlockCipher;
9-
import org.bouncycastle.crypto.params.AEADParameters;
10-
import org.bouncycastle.crypto.params.HKDFParameters;
11-
import org.bouncycastle.crypto.params.KeyParameter;
125
import org.bouncycastle.openpgp.PGPException;
136
import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptor;
147
import org.bouncycastle.openpgp.operator.PGPDigestCalculatorProvider;
15-
import org.bouncycastle.util.Arrays;
168

179
public class BcPBESecretKeyDecryptorBuilder
1810
{
@@ -50,37 +42,7 @@ public byte[] recoverKeyData(int encAlgorithm, byte[] key, byte[] iv, byte[] key
5042
@Override
5143
public byte[] recoverKeyData(int encAlgorithm, int aeadAlgorithm, byte[] s2kKey, byte[] iv, int packetTag, int keyVersion, byte[] keyData, byte[] pubkeyData) throws PGPException
5244
{
53-
byte[] hkdfInfo = new byte[] {
54-
(byte) (0xC0 | packetTag), (byte) keyVersion, (byte) encAlgorithm, (byte) aeadAlgorithm
55-
};
56-
57-
HKDFParameters hkdfParameters = new HKDFParameters(s2kKey, null, hkdfInfo);
58-
HKDFBytesGenerator hkdfGen = new HKDFBytesGenerator(new SHA256Digest());
59-
hkdfGen.init(hkdfParameters);
60-
byte[] key = new byte[SymmetricKeyUtils.getKeyLengthInOctets(encAlgorithm)];
61-
hkdfGen.generateBytes(key, 0, key.length);
62-
63-
byte[] aad = Arrays.prepend(pubkeyData, (byte) (0xC0 | packetTag));
64-
AEADBlockCipher cipher = BcAEADUtil.createAEADCipher(encAlgorithm, aeadAlgorithm);
65-
cipher.init(false, new AEADParameters(
66-
new KeyParameter(key),
67-
128,
68-
iv,
69-
aad
70-
));
71-
int dataLen = cipher.getOutputSize(keyData.length);
72-
byte[] data = new byte[dataLen];
73-
dataLen = cipher.processBytes(keyData, 0, keyData.length, data, 0);
74-
75-
try
76-
{
77-
cipher.doFinal(data, dataLen);
78-
return data;
79-
}
80-
catch (InvalidCipherTextException e)
81-
{
82-
throw new PGPException("Exception recovering AEAD protected private key material", e);
83-
}
45+
return BcAEADUtil.processAeadKeyData(false, encAlgorithm, aeadAlgorithm, s2kKey, iv, packetTag, keyVersion, keyData, 0, keyData.length, pubkeyData);
8446
}
8547
};
8648
}

0 commit comments

Comments
 (0)