Skip to content

Commit 33cbad1

Browse files
committed
Merge branch 'pg-refactor-BcAEADUtil' into 'main'
Refactor around BcAEADUtil See merge request root/bc-java!52
2 parents d95afbf + f68a305 commit 33cbad1

File tree

8 files changed

+138
-189
lines changed

8 files changed

+138
-189
lines changed

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

Lines changed: 18 additions & 45 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

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

@@ -48,46 +46,21 @@ 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)
87-
{
88-
throw new PGPException("Exception AEAD protecting private key material", e);
89-
}
90-
catch (InvalidCipherTextException e)
9164
{
9265
throw new PGPException("Exception AEAD protecting private key material", e);
9366
}

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 & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,12 @@
77
import org.bouncycastle.bcpg.SymmetricKeyUtils;
88
import org.bouncycastle.bcpg.UnsupportedPacketVersionException;
99
import org.bouncycastle.crypto.BlockCipher;
10-
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;
1510
import org.bouncycastle.openpgp.PGPException;
1611
import org.bouncycastle.openpgp.PGPSessionKey;
1712
import org.bouncycastle.openpgp.operator.PBEDataDecryptorFactory;
1813
import org.bouncycastle.openpgp.operator.PGPDataDecryptor;
1914
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
@@ -55,15 +51,7 @@ public byte[] recoverSessionData(int keyAlgorithm, byte[] key, byte[] secKeyData
5551
if (secKeyData != null && secKeyData.length > 0)
5652
{
5753
BlockCipher engine = BcImplProvider.createBlockCipher(keyAlgorithm);
58-
BufferedBlockCipher cipher = BcUtil.createSymmetricKeyWrapper(false, engine, key, new byte[engine.getBlockSize()]);
59-
60-
byte[] out = new byte[secKeyData.length];
61-
62-
int len = cipher.processBytes(secKeyData, 0, secKeyData.length, out, 0);
63-
64-
len += cipher.doFinal(out, len);
65-
66-
return out;
54+
return BcUtil.processBufferedBlockCipher(false, engine, key, new byte[engine.getBlockSize()], secKeyData, 0, secKeyData.length);
6755
}
6856
else
6957
{
@@ -92,50 +80,29 @@ public byte[] recoverAEADEncryptedSessionData(SymmetricKeyEncSessionPacket keyDa
9280

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

95-
KeyParameter secretKey;
83+
byte[] kek;
9684
if (keyData.getVersion() == SymmetricKeyEncSessionPacket.VERSION_5)
9785
{
98-
secretKey = new KeyParameter(ikm);
86+
kek = ikm;
9987
}
10088
else if (keyData.getVersion() == SymmetricKeyEncSessionPacket.VERSION_6)
10189
{
10290
// HKDF
10391
// secretKey := HKDF_sha256(ikm, hkdfInfo).generate()
10492
int kekLen = SymmetricKeyUtils.getKeyLengthInOctets(keyData.getEncAlgorithm());
105-
byte[] kek = BcAEADUtil.generateHKDFBytes(ikm, null, hkdfInfo, kekLen);
106-
secretKey = new KeyParameter(kek);
93+
kek = BcAEADUtil.generateHKDFBytes(ikm, null, hkdfInfo, kekLen);
10794
}
10895
else
10996
{
11097
throw new UnsupportedPacketVersionException("Unsupported SKESK packet version encountered: " + keyData.getVersion());
11198
}
11299

113100
// 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-
120101
// 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;
102+
byte[] data = Arrays.concatenate(keyData.getSecKeyData(), keyData.getAuthTag());
103+
return BcAEADUtil.processAEADData(false, keyData.getEncAlgorithm(), keyData.getAeadAlgorithm(), kek,
104+
keyData.getIv(), keyData.getAAData(), data, 0, data.length,
105+
BcAEADUtil.RecoverAEADEncryptedSessionDataErrorMessage);
139106
}
140107

141108
// OpenPGP v4

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

Lines changed: 2 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,7 @@
55
import org.bouncycastle.bcpg.S2K;
66
import org.bouncycastle.bcpg.SymmetricKeyUtils;
77
import org.bouncycastle.crypto.BlockCipher;
8-
import org.bouncycastle.crypto.BufferedBlockCipher;
98
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;
139
import org.bouncycastle.openpgp.PGPException;
1410
import org.bouncycastle.openpgp.operator.PBEKeyEncryptionMethodGenerator;
1511
import org.bouncycastle.openpgp.operator.PGPDigestCalculator;
@@ -92,15 +88,7 @@ protected byte[] encryptSessionInfo(int encAlgorithm, byte[] key, byte[] session
9288
try
9389
{
9490
BlockCipher engine = BcImplProvider.createBlockCipher(encAlgorithm);
95-
BufferedBlockCipher cipher = BcUtil.createSymmetricKeyWrapper(true, engine, key, new byte[engine.getBlockSize()]);
96-
97-
byte[] out = new byte[sessionInfo.length];
98-
99-
int len = cipher.processBytes(sessionInfo, 0, sessionInfo.length, out, 0);
100-
101-
len += cipher.doFinal(out, len);
102-
103-
return out;
91+
return BcUtil.processBufferedBlockCipher(true, engine, key, new byte[engine.getBlockSize()], sessionInfo, 0, sessionInfo.length);
10492
}
10593
catch (InvalidCipherTextException e)
10694
{
@@ -116,19 +104,6 @@ protected byte[] generateV6KEK(int kekAlgorithm, byte[] ikm, byte[] info)
116104
protected byte[] getEskAndTag(int kekAlgorithm, int aeadAlgorithm, byte[] sessionKey, byte[] key, byte[] iv, byte[] info)
117105
throws PGPException
118106
{
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;
107+
return BcAEADUtil.processAEADData(true, kekAlgorithm, aeadAlgorithm, key, iv, info, sessionKey, 0, sessionKey.length, BcAEADUtil.GetEskAndTagErrorMessage);
133108
}
134109
}

0 commit comments

Comments
 (0)