Skip to content

Commit c6cfe18

Browse files
author
gefeili
committed
Extract BcUtil.processBufferedBlockCipher function
1 parent decbe39 commit c6cfe18

File tree

6 files changed

+82
-144
lines changed

6 files changed

+82
-144
lines changed

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: 10 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,11 @@
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;
19-
import org.bouncycastle.openpgp.operator.PGPDigestCalculatorProvider;
14+
import org.bouncycastle.util.Arrays;
2015

2116
/**
2217
* A {@link PBEDataDecryptorFactory} for handling PBE decryption operations using the Bouncy Castle
@@ -31,7 +26,7 @@ public class BcPBEDataDecryptorFactory
3126
* @param pass the passphrase to use as the primary source of key material.
3227
* @param calculatorProvider a digest calculator provider to provide calculators to support the key generation calculation required.
3328
*/
34-
public BcPBEDataDecryptorFactory(char[] pass, PGPDigestCalculatorProvider calculatorProvider)
29+
public BcPBEDataDecryptorFactory(char[] pass, BcPGPDigestCalculatorProvider calculatorProvider)
3530
{
3631
super(pass, calculatorProvider);
3732
}
@@ -55,15 +50,7 @@ public byte[] recoverSessionData(int keyAlgorithm, byte[] key, byte[] secKeyData
5550
if (secKeyData != null && secKeyData.length > 0)
5651
{
5752
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;
53+
return BcUtil.processBufferedBlockCipher(false, engine, key, new byte[engine.getBlockSize()], secKeyData, 0, secKeyData.length);
6754
}
6855
else
6956
{
@@ -92,50 +79,29 @@ public byte[] recoverAEADEncryptedSessionData(SymmetricKeyEncSessionPacket keyDa
9279

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

95-
KeyParameter secretKey;
82+
byte[] kek;
9683
if (keyData.getVersion() == SymmetricKeyEncSessionPacket.VERSION_5)
9784
{
98-
secretKey = new KeyParameter(ikm);
85+
kek = ikm;
9986
}
10087
else if (keyData.getVersion() == SymmetricKeyEncSessionPacket.VERSION_6)
10188
{
10289
// HKDF
10390
// secretKey := HKDF_sha256(ikm, hkdfInfo).generate()
10491
int kekLen = SymmetricKeyUtils.getKeyLengthInOctets(keyData.getEncAlgorithm());
105-
byte[] kek = BcAEADUtil.generateHKDFBytes(ikm, null, hkdfInfo, kekLen);
106-
secretKey = new KeyParameter(kek);
92+
kek = BcAEADUtil.generateHKDFBytes(ikm, null, hkdfInfo, kekLen);
10793
}
10894
else
10995
{
11096
throw new UnsupportedPacketVersionException("Unsupported SKESK packet version encountered: " + keyData.getVersion());
11197
}
11298

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

141107
// OpenPGP v4

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

Lines changed: 5 additions & 28 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
{
@@ -113,22 +101,11 @@ protected byte[] generateV6KEK(int kekAlgorithm, byte[] ikm, byte[] info)
113101
return BcAEADUtil.generateHKDFBytes(ikm, null, info, SymmetricKeyUtils.getKeyLengthInOctets(kekAlgorithm));
114102
}
115103

116-
protected byte[] getEskAndTag(int kekAlgorithm, int aeadAlgorithm, byte[] sessionKey, byte[] key, byte[] iv, byte[] info)
104+
protected byte[] getEskAndTag(int kekAlgorithm, int aeadAlgorithm, byte[] sessionInfo, 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+
byte[] sessionKey = new byte[sessionInfo.length - 3];
108+
System.arraycopy(sessionInfo, 1, sessionKey, 0, sessionKey.length);
109+
return BcAEADUtil.processAEADData(true, kekAlgorithm, aeadAlgorithm, key, iv, info, sessionKey, 0, sessionKey.length, BcAEADUtil.GetEskAndTagErrorMessage);
133110
}
134111
}

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

Lines changed: 2 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,9 @@
11
package org.bouncycastle.openpgp.operator.bc;
22

3-
import org.bouncycastle.bcpg.SymmetricKeyUtils;
4-
import org.bouncycastle.crypto.BufferedBlockCipher;
53
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;
124
import org.bouncycastle.openpgp.PGPException;
135
import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptor;
146
import org.bouncycastle.openpgp.operator.PGPDigestCalculatorProvider;
15-
import org.bouncycastle.util.Arrays;
167

178
public class BcPBESecretKeyDecryptorBuilder
189
{
@@ -32,14 +23,7 @@ public byte[] recoverKeyData(int encAlgorithm, byte[] key, byte[] iv, byte[] key
3223
{
3324
try
3425
{
35-
BufferedBlockCipher c = BcUtil.createSymmetricKeyWrapper(false, BcImplProvider.createBlockCipher(encAlgorithm), key, iv);
36-
37-
byte[] out = new byte[keyLen];
38-
int outLen = c.processBytes(keyData, keyOff, keyLen, out, 0);
39-
40-
outLen += c.doFinal(out, outLen);
41-
42-
return out;
26+
return BcUtil.processBufferedBlockCipher(false, BcImplProvider.createBlockCipher(encAlgorithm), key, iv, keyData, keyOff, keyLen);
4327
}
4428
catch (InvalidCipherTextException e)
4529
{
@@ -50,37 +34,7 @@ public byte[] recoverKeyData(int encAlgorithm, byte[] key, byte[] iv, byte[] key
5034
@Override
5135
public byte[] recoverKeyData(int encAlgorithm, int aeadAlgorithm, byte[] s2kKey, byte[] iv, int packetTag, int keyVersion, byte[] keyData, byte[] pubkeyData) throws PGPException
5236
{
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-
}
37+
return BcAEADUtil.processAeadKeyData(false, encAlgorithm, aeadAlgorithm, s2kKey, iv, packetTag, keyVersion, keyData, 0, keyData.length, pubkeyData);
8438
}
8539
};
8640
}

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

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
import java.security.SecureRandom;
44

55
import org.bouncycastle.crypto.BlockCipher;
6-
import org.bouncycastle.crypto.BufferedBlockCipher;
76
import org.bouncycastle.crypto.InvalidCipherTextException;
87
import org.bouncycastle.openpgp.PGPException;
98
import org.bouncycastle.openpgp.operator.PBESecretKeyEncryptor;
@@ -117,15 +116,7 @@ public byte[] encryptKeyData(byte[] key, byte[] iv, byte[] keyData, int keyOff,
117116

118117
this.random.nextBytes(iv);
119118
}
120-
121-
BufferedBlockCipher c = BcUtil.createSymmetricKeyWrapper(true, engine, key, iv);
122-
123-
byte[] out = new byte[keyLen];
124-
int outLen = c.processBytes(keyData, keyOff, keyLen, out, 0);
125-
126-
outLen += c.doFinal(out, outLen);
127-
128-
return out;
119+
return BcUtil.processBufferedBlockCipher(true, engine, key, iv, keyData, keyOff, keyLen);
129120
}
130121
catch (InvalidCipherTextException e)
131122
{

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

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import org.bouncycastle.crypto.BlockCipher;
1414
import org.bouncycastle.crypto.BufferedBlockCipher;
1515
import org.bouncycastle.crypto.DefaultBufferedBlockCipher;
16+
import org.bouncycastle.crypto.InvalidCipherTextException;
1617
import org.bouncycastle.crypto.RawAgreement;
1718
import org.bouncycastle.crypto.ec.CustomNamedCurves;
1819
import org.bouncycastle.crypto.io.CipherInputStream;
@@ -102,6 +103,21 @@ public static BufferedBlockCipher createSymmetricKeyWrapper(boolean forEncryptio
102103
return c;
103104
}
104105

106+
static byte[] processBufferedBlockCipher(boolean forEncryption, BlockCipher engine, byte[] key, byte[] iv, byte[] msg, int msgOff, int msgLen)
107+
throws InvalidCipherTextException
108+
109+
{
110+
BufferedBlockCipher cipher = BcUtil.createSymmetricKeyWrapper(forEncryption, engine, key, iv);
111+
112+
byte[] out = new byte[msgLen];
113+
114+
int len = cipher.processBytes(msg, msgOff, msgLen, out, 0);
115+
116+
len += cipher.doFinal(out, len);
117+
118+
return out;
119+
}
120+
105121
static X9ECParameters getX9Parameters(ASN1ObjectIdentifier curveOID)
106122
{
107123
X9ECParameters x9 = CustomNamedCurves.getByOID(curveOID);

0 commit comments

Comments
 (0)