Skip to content

Commit 819f9ab

Browse files
- Addressing PR Feedback
- Bumping Java version to v1.8
1 parent ce29e4d commit 819f9ab

26 files changed

+411
-627
lines changed

pom.xml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
<groupId>com.mastercard.developer</groupId>
88
<artifactId>client-encryption</artifactId>
9-
<version>1.5.1-SNAPSHOT</version>
9+
<version>1.6.0-SNAPSHOT</version>
1010
<packaging>jar</packaging>
1111
<description>Library for Mastercard API compliant payload encryption/decryption</description>
1212
<url>https://github.com/Mastercard/client-encryption-java</url>
@@ -140,6 +140,7 @@
140140
<groupId>net.minidev</groupId>
141141
<artifactId>json-smart</artifactId>
142142
<version>2.3</version>
143+
<scope>test</scope>
143144
</dependency>
144145

145146
<dependency>
@@ -189,8 +190,8 @@
189190
<artifactId>maven-compiler-plugin</artifactId>
190191
<version>3.8.1</version>
191192
<configuration>
192-
<source>1.7</source>
193-
<target>1.7</target>
193+
<source>1.8</source>
194+
<target>1.8</target>
194195
</configuration>
195196
</plugin>
196197
</plugins>

src/main/java/com/mastercard/developer/encryption/FieldLevelEncryption.java

Lines changed: 4 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@
33
import com.jayway.jsonpath.DocumentContext;
44
import com.jayway.jsonpath.JsonPath;
55
import com.jayway.jsonpath.spi.json.JsonProvider;
6+
import com.mastercard.developer.encryption.aes.AESCBC;
7+
68
import javax.crypto.Cipher;
79
import java.io.UnsupportedEncodingException;
810
import java.nio.charset.StandardCharsets;
911
import java.security.GeneralSecurityException;
10-
import java.security.Key;
11-
import java.security.spec.AlgorithmParameterSpec;
1212
import java.util.ArrayList;
1313
import java.util.Collection;
1414
import java.util.Map.Entry;
@@ -23,8 +23,6 @@
2323
*/
2424
public class FieldLevelEncryption {
2525

26-
private static final String SYMMETRIC_CYPHER = "AES/CBC/PKCS5Padding";
27-
2826
public static String encryptPayload(String payload, FieldLevelEncryptionConfig config) throws EncryptionException {
2927
return encryptPayload(payload, config, null);
3028
}
@@ -93,7 +91,7 @@ private static void encryptPayloadPath(DocumentContext payloadContext, String js
9391
} catch (UnsupportedEncodingException e) {
9492
// Should not happen
9593
}
96-
byte[] encryptedValueBytes = encryptBytes(params.getSecretKey(), params.getIvSpec(), inJsonBytes);
94+
byte[] encryptedValueBytes = AESCBC.cipher(params.getSecretKey(), params.getIvSpec(), inJsonBytes, Cipher.ENCRYPT_MODE);
9795
String encryptedValue = encodeBytes(encryptedValueBytes, config.fieldValueEncoding);
9896

9997
// Delete data in clear
@@ -161,7 +159,7 @@ private static void decryptPayloadPath(DocumentContext payloadContext, String js
161159

162160
// Decrypt data
163161
byte[] encryptedValueBytes = decodeValue(JsonParser.jsonEngine.toJsonString(encryptedValueJsonElement), config.fieldValueEncoding);
164-
byte[] decryptedValueBytes = decryptBytes(params.getSecretKey(), params.getIvSpec(), encryptedValueBytes);
162+
byte[] decryptedValueBytes = AESCBC.cipher(params.getSecretKey(), params.getIvSpec(), encryptedValueBytes, Cipher.DECRYPT_MODE);
165163

166164
// Add decrypted data at the given JSON path
167165
String decryptedValue = new String(decryptedValueBytes, StandardCharsets.UTF_8);
@@ -176,18 +174,6 @@ private static void decryptPayloadPath(DocumentContext payloadContext, String js
176174
}
177175
}
178176

179-
static byte[] encryptBytes(Key key, AlgorithmParameterSpec iv, byte[] bytes) throws GeneralSecurityException {
180-
Cipher cipher = Cipher.getInstance(SYMMETRIC_CYPHER);
181-
cipher.init(Cipher.ENCRYPT_MODE, key, iv);
182-
return cipher.doFinal(bytes);
183-
}
184-
185-
static byte[] decryptBytes(Key key, AlgorithmParameterSpec iv, byte[] bytes) throws GeneralSecurityException {
186-
Cipher cipher = Cipher.getInstance(SYMMETRIC_CYPHER);
187-
cipher.init(Cipher.DECRYPT_MODE, key, iv);
188-
return cipher.doFinal(bytes);
189-
}
190-
191177
private static Object readAndDeleteJsonKey(DocumentContext context, String objectPath, Object object, String key) {
192178
if (null == key) {
193179
// Do nothing

src/main/java/com/mastercard/developer/encryption/FieldLevelEncryptionParams.java

Lines changed: 9 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,24 @@
11
package com.mastercard.developer.encryption;
22

3-
import javax.crypto.Cipher;
43
import javax.crypto.KeyGenerator;
54
import javax.crypto.SecretKey;
65
import javax.crypto.spec.IvParameterSpec;
7-
import javax.crypto.spec.OAEPParameterSpec;
8-
import javax.crypto.spec.PSource;
96
import java.security.GeneralSecurityException;
107
import java.security.Key;
11-
import java.security.spec.MGF1ParameterSpec;
8+
9+
import com.mastercard.developer.encryption.aes.AESEncryption;
10+
import com.mastercard.developer.encryption.rsa.RSA;
1211

1312
import static com.mastercard.developer.utils.EncodingUtils.decodeValue;
1413
import static com.mastercard.developer.utils.EncodingUtils.encodeBytes;
15-
import static com.mastercard.developer.utils.EncryptionUtils.generateIv;
1614

1715
/**
1816
* Encryption parameters for computing field level encryption/decryption.
1917
*/
2018
public final class FieldLevelEncryptionParams {
2119

2220
private static final Integer SYMMETRIC_KEY_SIZE = 128;
23-
protected static final String SYMMETRIC_KEY_TYPE = "AES";
24-
private static final String ASYMMETRIC_CYPHER = "RSA/ECB/OAEPWith{ALG}AndMGF1Padding";
21+
static final String SYMMETRIC_KEY_TYPE = "AES";
2522

2623
private final String ivValue;
2724
private final String encryptedKeyValue;
@@ -46,14 +43,14 @@ public FieldLevelEncryptionParams(String ivValue, String encryptedKeyValue, Stri
4643
public static FieldLevelEncryptionParams generate(FieldLevelEncryptionConfig config) throws EncryptionException {
4744

4845
// Generate a random IV
49-
IvParameterSpec ivParameterSpec = generateIv();
46+
IvParameterSpec ivParameterSpec = AESEncryption.generateIv();
5047
String ivSpecValue = encodeBytes(ivParameterSpec.getIV(), config.fieldValueEncoding);
5148

5249
// Generate an AES secret key
5350
SecretKey secretKey = generateSecretKey();
5451

5552
// Encrypt the secret key
56-
byte[] encryptedSecretKeyBytes = wrapSecretKey(config, secretKey);
53+
byte[] encryptedSecretKeyBytes = RSA.wrapSecretKey(config.encryptionCertificate.getPublicKey(), secretKey, config.oaepPaddingDigestAlgorithm);
5754
String encryptedKeyValue = encodeBytes(encryptedSecretKeyBytes, config.fieldValueEncoding);
5855

5956
// Compute the OAEP padding digest algorithm
@@ -79,14 +76,14 @@ public String getOaepPaddingDigestAlgorithmValue() {
7976
return oaepPaddingDigestAlgorithmValue;
8077
}
8178

82-
public Key getSecretKey() throws EncryptionException {
79+
Key getSecretKey() throws EncryptionException {
8380
try {
8481
if (secretKey != null) {
8582
return secretKey;
8683
}
8784
// Decrypt the AES secret key
8885
byte[] encryptedSecretKeyBytes = decodeValue(encryptedKeyValue, config.fieldValueEncoding);
89-
secretKey = FieldLevelEncryptionParams.unwrapSecretKey(config, encryptedSecretKeyBytes, oaepPaddingDigestAlgorithmValue);
86+
secretKey = RSA.unwrapSecretKey(config.decryptionKey, encryptedSecretKeyBytes, oaepPaddingDigestAlgorithmValue);
9087
return secretKey;
9188
} catch (EncryptionException e) {
9289
throw e;
@@ -95,7 +92,7 @@ public Key getSecretKey() throws EncryptionException {
9592
}
9693
}
9794

98-
public IvParameterSpec getIvSpec() throws EncryptionException {
95+
IvParameterSpec getIvSpec() throws EncryptionException {
9996
try {
10097
if (ivParameterSpec != null) {
10198
return ivParameterSpec;
@@ -118,37 +115,4 @@ private static SecretKey generateSecretKey() throws EncryptionException {
118115
throw new EncryptionException("Failed to generate a secret key!", e);
119116
}
120117
}
121-
122-
protected static byte[] wrapSecretKey(FieldLevelEncryptionConfig config, Key key) throws EncryptionException {
123-
try {
124-
Key publicEncryptionKey = config.encryptionCertificate.getPublicKey();
125-
MGF1ParameterSpec mgf1ParameterSpec = new MGF1ParameterSpec(config.oaepPaddingDigestAlgorithm);
126-
String asymmetricCipher = ASYMMETRIC_CYPHER.replace("{ALG}", mgf1ParameterSpec.getDigestAlgorithm());
127-
Cipher cipher = Cipher.getInstance(asymmetricCipher);
128-
cipher.init(Cipher.WRAP_MODE, publicEncryptionKey, getOaepParameterSpec(mgf1ParameterSpec));
129-
return cipher.wrap(key);
130-
} catch (GeneralSecurityException e) {
131-
throw new EncryptionException("Failed to wrap secret key!", e);
132-
}
133-
}
134-
135-
protected static Key unwrapSecretKey(EncryptionConfig config, byte[] keyBytes, String oaepDigestAlgorithm) throws EncryptionException {
136-
if (!oaepDigestAlgorithm.contains("-")) {
137-
oaepDigestAlgorithm = oaepDigestAlgorithm.replace("SHA", "SHA-");
138-
}
139-
try {
140-
MGF1ParameterSpec mgf1ParameterSpec = new MGF1ParameterSpec(oaepDigestAlgorithm);
141-
Key key = config.decryptionKey;
142-
String asymmetricCipher = ASYMMETRIC_CYPHER.replace("{ALG}", mgf1ParameterSpec.getDigestAlgorithm());
143-
Cipher cipher = Cipher.getInstance(asymmetricCipher);
144-
cipher.init(Cipher.UNWRAP_MODE, key, getOaepParameterSpec(mgf1ParameterSpec));
145-
return cipher.unwrap(keyBytes, SYMMETRIC_KEY_TYPE, Cipher.SECRET_KEY);
146-
} catch (GeneralSecurityException e) {
147-
throw new EncryptionException("Failed to unwrap secret key!", e);
148-
}
149-
}
150-
151-
private static OAEPParameterSpec getOaepParameterSpec(MGF1ParameterSpec mgf1ParameterSpec) {
152-
return new OAEPParameterSpec(mgf1ParameterSpec.getDigestAlgorithm(), "MGF1", mgf1ParameterSpec, PSource.PSpecified.DEFAULT);
153-
}
154118
}

src/main/java/com/mastercard/developer/encryption/JweConfigBuilder.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ public static JweConfigBuilder aJweEncryptionConfig() {
1414
}
1515

1616
/**
17-
* Build a {@link com.mastercard.developer.encryption.JweConfig}.
17+
* Build a {@link JweConfig}.
1818
*
1919
* @throws EncryptionException
2020
*/
@@ -35,39 +35,39 @@ public JweConfig build() throws EncryptionException {
3535
}
3636

3737
/**
38-
* See: {@link com.mastercard.developer.encryption.EncryptionConfig#encryptionCertificate}.
38+
* See: {@link EncryptionConfig#encryptionCertificate}.
3939
*/
4040
public JweConfigBuilder withEncryptionCertificate(Certificate encryptionCertificate) {
4141
this.encryptionCertificate = encryptionCertificate;
4242
return this;
4343
}
4444

4545
/**
46-
* See: {@link com.mastercard.developer.encryption.EncryptionConfig#decryptionKey}.
46+
* See: {@link EncryptionConfig#decryptionKey}.
4747
*/
4848
public JweConfigBuilder withDecryptionKey(PrivateKey decryptionKey) {
4949
this.decryptionKey = decryptionKey;
5050
return this;
5151
}
5252

5353
/**
54-
* See: {@link com.mastercard.developer.encryption.EncryptionConfig#encryptionPaths}.
54+
* See: {@link EncryptionConfig#encryptionPaths}.
5555
*/
5656
public JweConfigBuilder withEncryptionPath(String jsonPathIn, String jsonPathOut) {
5757
this.encryptionPaths.put(jsonPathIn, jsonPathOut);
5858
return this;
5959
}
6060

6161
/**
62-
* See: {@link com.mastercard.developer.encryption.EncryptionConfig#decryptionPaths}.
62+
* See: {@link EncryptionConfig#decryptionPaths}.
6363
*/
6464
public JweConfigBuilder withDecryptionPath(String jsonPathIn, String jsonPathOut) {
6565
this.decryptionPaths.put(jsonPathIn, jsonPathOut);
6666
return this;
6767
}
6868

6969
/**
70-
* See: {@link com.mastercard.developer.encryption.EncryptionConfig#encryptedValueFieldName}.
70+
* See: {@link EncryptionConfig#encryptedValueFieldName}.
7171
*/
7272
public JweConfigBuilder withEncryptedValueFieldName(String encryptedValueFieldName) {
7373
this.encryptedValueFieldName = encryptedValueFieldName;

src/main/java/com/mastercard/developer/encryption/JweEncryption.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import com.mastercard.developer.encryption.jwe.JWEHeader;
66
import com.mastercard.developer.encryption.jwe.JWEObject;
77

8-
import java.security.interfaces.RSAPublicKey;
8+
import java.security.GeneralSecurityException;
99
import java.util.ArrayList;
1010
import java.util.Collection;
1111
import java.util.Map;
@@ -57,7 +57,7 @@ public static String decryptPayload(String payload, JweConfig config) throws Enc
5757
}
5858
}
5959

60-
private static void encryptPayloadPath(DocumentContext payloadContext, String jsonPathIn, String jsonPathOut, JweConfig config) throws EncryptionException {
60+
private static void encryptPayloadPath(DocumentContext payloadContext, String jsonPathIn, String jsonPathOut, JweConfig config) throws EncryptionException, GeneralSecurityException {
6161
Object inJsonElement = readJsonElement(payloadContext, jsonPathIn);
6262
if (inJsonElement == null) {
6363
// Nothing to encrypt
@@ -84,7 +84,7 @@ private static void encryptPayloadPath(DocumentContext payloadContext, String js
8484
payloadContext.put(jsonPathOut, config.encryptedValueFieldName, payload);
8585
}
8686

87-
private static void decryptPayloadPath(DocumentContext payloadContext, String jsonPathIn, String jsonPathOut, JweConfig config) throws EncryptionException {
87+
private static void decryptPayloadPath(DocumentContext payloadContext, String jsonPathIn, String jsonPathOut, JweConfig config) throws EncryptionException, GeneralSecurityException {
8888

8989
Object inJsonObject = readJsonObject(payloadContext, jsonPathIn);
9090
if (inJsonObject == null) {
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package com.mastercard.developer.encryption.aes;
2+
3+
import com.mastercard.developer.encryption.jwe.JWEObject;
4+
import com.mastercard.developer.utils.EncodingUtils;
5+
6+
import javax.crypto.Cipher;
7+
import javax.crypto.spec.IvParameterSpec;
8+
import javax.crypto.spec.SecretKeySpec;
9+
import java.security.GeneralSecurityException;
10+
import java.security.Key;
11+
import java.security.spec.AlgorithmParameterSpec;
12+
13+
public class AESCBC {
14+
15+
private AESCBC() {
16+
}
17+
18+
private static final String CYPHER = "AES/CBC/PKCS5Padding";
19+
20+
public static byte[] decrypt(Key secretKey, JWEObject object) throws GeneralSecurityException {
21+
SecretKeySpec aesKey = new SecretKeySpec(secretKey.getEncoded(), 16, 16, "AES");
22+
23+
byte[] cipherText = EncodingUtils.base64Decode(object.getCipherText());
24+
byte[] iv = EncodingUtils.base64Decode(object.getIv());
25+
SecretKeySpec keyspec = new SecretKeySpec(aesKey.getEncoded(), "AES");
26+
27+
return cipher(keyspec, new IvParameterSpec(iv), cipherText, Cipher.DECRYPT_MODE);
28+
}
29+
30+
public static byte[] cipher(Key key, AlgorithmParameterSpec iv, byte[] bytes, int mode) throws GeneralSecurityException {
31+
Cipher cipher = Cipher.getInstance(CYPHER);
32+
cipher.init(mode, key, iv);
33+
return cipher.doFinal(bytes);
34+
}
35+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package com.mastercard.developer.encryption.aes;
2+
3+
import com.mastercard.developer.encryption.EncryptionException;
4+
import com.mastercard.developer.utils.ByteUtils;
5+
6+
import javax.crypto.spec.IvParameterSpec;
7+
import javax.crypto.spec.SecretKeySpec;
8+
import java.security.GeneralSecurityException;
9+
import java.security.SecureRandom;
10+
11+
public class AESEncryption {
12+
13+
public static IvParameterSpec generateIv() throws EncryptionException {
14+
try {
15+
SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
16+
byte[] ivBytes = new byte[16];
17+
secureRandom.nextBytes(ivBytes);
18+
return new IvParameterSpec(ivBytes);
19+
} catch (GeneralSecurityException e) {
20+
throw new EncryptionException("Failed to generate an IV value!", e);
21+
}
22+
}
23+
24+
public static SecretKeySpec generateCek(int bitLength) {
25+
SecureRandom random = new SecureRandom();
26+
byte[] cekMaterial = new byte[ByteUtils.byteLength(bitLength)];
27+
random.nextBytes(cekMaterial);
28+
return new SecretKeySpec(cekMaterial, "AES");
29+
}
30+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package com.mastercard.developer.encryption.aes;
2+
3+
import com.mastercard.developer.encryption.jwe.JWEObject;
4+
import com.mastercard.developer.utils.ByteUtils;
5+
import com.mastercard.developer.utils.EncodingUtils;
6+
7+
import javax.crypto.Cipher;
8+
import javax.crypto.SecretKey;
9+
import javax.crypto.spec.GCMParameterSpec;
10+
import javax.crypto.spec.SecretKeySpec;
11+
import java.nio.charset.StandardCharsets;
12+
import java.security.GeneralSecurityException;
13+
import java.security.Key;
14+
15+
public class AESGCM {
16+
17+
private AESGCM() {
18+
}
19+
20+
private static final String CYPHER = "AES/GCM/NoPadding";
21+
22+
public static byte[] decrypt(Key cek, JWEObject object) throws GeneralSecurityException {
23+
byte[] aad = object.getRawHeader().getBytes(StandardCharsets.US_ASCII);
24+
SecretKey aesKey = new SecretKeySpec(cek.getEncoded(), "AES");
25+
GCMParameterSpec gcmSpec = new GCMParameterSpec(128, EncodingUtils.base64Decode(object.getIv()));
26+
byte[] bytes = ByteUtils.concat(EncodingUtils.base64Decode(object.getCipherText()), EncodingUtils.base64Decode(object.getAuthTag()));
27+
return cipher(aesKey, gcmSpec, bytes, aad, Cipher.DECRYPT_MODE);
28+
}
29+
30+
public static byte[] cipher(Key key, GCMParameterSpec gcpSpec, byte[] bytes, byte[] aad, int mode) throws GeneralSecurityException {
31+
Cipher cipher = Cipher.getInstance(CYPHER);
32+
cipher.init(mode, key, gcpSpec);
33+
cipher.updateAAD(aad);
34+
return cipher.doFinal(bytes);
35+
}
36+
}

0 commit comments

Comments
 (0)