Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@ JweConfig config = JweConfigBuilder.aJweEncryptionConfig()
.withEncryptionPath("$.path.to.foo", "$.path.to.encryptedFoo")
.withDecryptionPath("$.path.to.encryptedFoo.encryptedValue", "$.path.to.foo")
.withEncryptedValueFieldName("encryptedValue")
.withIVSize(16) // available values are 12 or 16. If not specified, default value is 16.
.build();
```

Expand Down
3 changes: 1 addition & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<groupId>com.mastercard.developer</groupId>
<artifactId>client-encryption</artifactId>
<version>1.7.13-SNAPSHOT</version>
<version>1.8.0</version>
<packaging>jar</packaging>
<description>Library for Mastercard API compliant payload encryption/decryption</description>
<url>https://github.com/Mastercard/client-encryption-java</url>
Expand Down Expand Up @@ -96,7 +96,6 @@
<version>4.13.1</version>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,13 @@ public enum Scheme {
*/
PrivateKey decryptionKey;


/**
* IV size in bytes
*/

Integer ivSize = 16;

/**
* A list of JSON paths to encrypt in request payloads.
* Example:
Expand Down Expand Up @@ -107,4 +114,6 @@ Map<String, String> getDecryptionPaths() {
String getEncryptedValueFieldName() {
return encryptedValueFieldName;
}

public Integer getIVSize() { return ivSize; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ abstract class EncryptionConfigBuilder {
protected Map<String, String> decryptionPaths = new HashMap<>();
protected String encryptedValueFieldName;

protected Integer ivSize = 16;

void computeEncryptionKeyFingerprintWhenNeeded() throws EncryptionException {
try {
if ((encryptionCertificate == null && encryptionKey == null) || !isNullOrEmpty(encryptionKeyFingerprint)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,16 @@ public FieldLevelEncryptionConfigBuilder withEncryptionKeyFingerprintHeaderName(
return this;
}

/**
* See: {@link EncryptionConfig#ivSize}.
*/
public FieldLevelEncryptionConfigBuilder withEncryptionIVSize(Integer ivSize) {
if (ivSize == 12 || ivSize == 16) {
this.ivSize = ivSize;
return this;
}
throw new IllegalArgumentException("Supported IV Sizes are either 12 or 16!");
}
/**
* Build a {@link com.mastercard.developer.encryption.FieldLevelEncryptionConfig}.
* @throws EncryptionException
Expand All @@ -209,6 +219,7 @@ public FieldLevelEncryptionConfig build() throws EncryptionException {
config.encryptionCertificate = this.encryptionCertificate;
config.oaepPaddingDigestAlgorithm = this.oaepPaddingDigestAlgorithm;
config.ivFieldName = this.ivFieldName;
config.ivSize = this.ivSize;
config.oaepPaddingDigestAlgorithmFieldName = this.oaepPaddingDigestAlgorithmFieldName;
config.decryptionPaths = this.decryptionPaths;
config.encryptedKeyFieldName = this.encryptedKeyFieldName;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public FieldLevelEncryptionParams(String ivValue, String encryptedKeyValue, Stri
public static FieldLevelEncryptionParams generate(FieldLevelEncryptionConfig config) throws EncryptionException {

// Generate a random IV
IvParameterSpec ivParameterSpec = AESEncryption.generateIv();
IvParameterSpec ivParameterSpec = AESEncryption.generateIv(config.getIVSize());
String ivSpecValue = encodeBytes(ivParameterSpec.getIV(), config.fieldValueEncoding);

// Generate an AES secret key
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ public JweConfig build() throws EncryptionException {
config.decryptionPaths = this.decryptionPaths.isEmpty() ? Collections.singletonMap("$.encryptedData", "$") : this.decryptionPaths;
config.encryptedValueFieldName = this.encryptedValueFieldName == null ? "encryptedData" : this.encryptedValueFieldName;
config.scheme = EncryptionConfig.Scheme.JWE;
config.ivSize = ivSize;
return config;
}

Expand Down Expand Up @@ -82,9 +83,8 @@ public JweConfigBuilder withDecryptionPath(String jsonPathIn, String jsonPathOut
return this;
}

/**
* See: {@link EncryptionConfig#encryptedValueFieldName}.
*/


public JweConfigBuilder withEncryptedValueFieldName(String encryptedValueFieldName) {
this.encryptedValueFieldName = encryptedValueFieldName;
return this;
Expand All @@ -95,9 +95,21 @@ public JweConfigBuilder withEncryptionKeyFingerprint(String encryptionKeyFingerp
return this;
}

/**
* See: {@link EncryptionConfig#ivSize}.
*/
public JweConfigBuilder withEncryptionIVSize(Integer ivSize) {
if (ivSize == 12 || ivSize == 16) {
this.ivSize = ivSize;
return this;
}
throw new IllegalArgumentException("Supported IV Sizes are either 12 or 16!");
}

private void checkParameterValues() {
if (decryptionKey == null && encryptionCertificate == null && encryptionKey == null) {
throw new IllegalArgumentException("You must include at least an encryption key/certificate or a decryption key");
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ private AESEncryption() {
// Nothing to do here
}

public static IvParameterSpec generateIv() throws EncryptionException {
public static IvParameterSpec generateIv(Integer ivSize) throws EncryptionException {
try {
SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
byte[] ivBytes = new byte[16];
byte[] ivBytes = new byte[ivSize];
secureRandom.nextBytes(ivBytes);
return new IvParameterSpec(ivBytes);
} catch (GeneralSecurityException e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ public static String encrypt(JweConfig config, String payload, JweHeader header)
byte[] encryptedSecretKeyBytes = RSA.wrapSecretKey(config.getEncryptionKey(), cek, "SHA-256");
String encryptedKey = EncodingUtils.base64UrlEncode(encryptedSecretKeyBytes);

byte[] iv = AESEncryption.generateIv().getIV();
byte[] iv = AESEncryption.generateIv(config.getIVSize()).getIV();
byte[] payloadBytes = payload.getBytes();
GCMParameterSpec gcmSpec = new GCMParameterSpec(128, iv);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,17 @@
import org.junit.rules.ExpectedException;

import static com.mastercard.developer.encryption.FieldLevelEncryptionConfig.FieldValueEncoding.HEX;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.core.IsEqual.equalTo;
import static org.junit.Assert.assertFalse;

public class FieldLevelEncryptionConfigBuilderTest {

@Rule
public ExpectedException expectedException = ExpectedException.none();

@Test
public void testBuild_Nominal() throws Exception {
public void testBuild_Nominal_iv12() throws Exception {
FieldLevelEncryptionConfig config = FieldLevelEncryptionConfigBuilder.aFieldLevelEncryptionConfig()
.withEncryptionPath("$.payload", "$.encryptedPayload")
.withEncryptionCertificate(TestUtils.getTestEncryptionCertificate())
Expand All @@ -35,6 +38,7 @@ public void testBuild_Nominal() throws Exception {
.withIvFieldName("iv")
.withIvHeaderName("x-iv")
.withFieldValueEncoding(HEX)
.withEncryptionIVSize(12)
.build();
Assert.assertNotNull(config);
Assert.assertEquals(1, config.encryptionPaths.size());
Expand All @@ -56,6 +60,85 @@ public void testBuild_Nominal() throws Exception {
Assert.assertEquals("oaepPaddingDigestAlgorithm", config.oaepPaddingDigestAlgorithmFieldName);
Assert.assertEquals("x-oaep-padding-digest-algorithm", config.oaepPaddingDigestAlgorithmHeaderName);
Assert.assertEquals(HEX, config.fieldValueEncoding);
assertThat(config.getIVSize().intValue(),equalTo(12));
}

@Test
public void testBuild_Nominal_iv16() throws Exception {
FieldLevelEncryptionConfig config = FieldLevelEncryptionConfigBuilder.aFieldLevelEncryptionConfig()
.withEncryptionPath("$.payload", "$.encryptedPayload")
.withEncryptionCertificate(TestUtils.getTestEncryptionCertificate())
.withEncryptionCertificateFingerprint("97A2FFE9F0D48960EF31E87FCD7A55BF7843FB4A9EEEF01BDB6032AD6FEF146B")
.withEncryptionKeyFingerprint("F806B26BC4870E26986C70B6590AF87BAF4C2B56BB50622C51B12212DAFF2810")
.withEncryptionCertificateFingerprintFieldName("publicCertificateFingerprint")
.withEncryptionCertificateFingerprintHeaderName("x-public-certificate-fingerprint")
.withEncryptionKeyFingerprintFieldName("publicKeyFingerprint")
.withEncryptionKeyFingerprintHeaderName("x-public-key-fingerprint")
.withDecryptionPath("$.encryptedPayload", "$.payload")
.withDecryptionKey(TestUtils.getTestDecryptionKey())
.withOaepPaddingDigestAlgorithm("SHA-512")
.withOaepPaddingDigestAlgorithmFieldName("oaepPaddingDigestAlgorithm")
.withOaepPaddingDigestAlgorithmHeaderName("x-oaep-padding-digest-algorithm")
.withEncryptedValueFieldName("encryptedValue")
.withEncryptedKeyFieldName("encryptedKey")
.withEncryptedKeyHeaderName("x-encrypted-key")
.withIvFieldName("iv")
.withIvHeaderName("x-iv")
.withFieldValueEncoding(HEX)
.withEncryptionIVSize(16)
.build();
Assert.assertNotNull(config);
Assert.assertEquals(1, config.encryptionPaths.size());
Assert.assertNotNull(config.encryptionCertificate);
Assert.assertEquals("97A2FFE9F0D48960EF31E87FCD7A55BF7843FB4A9EEEF01BDB6032AD6FEF146B", config.encryptionCertificateFingerprint);
Assert.assertEquals("F806B26BC4870E26986C70B6590AF87BAF4C2B56BB50622C51B12212DAFF2810", config.encryptionKeyFingerprint);
Assert.assertEquals("publicCertificateFingerprint", config.encryptionCertificateFingerprintFieldName);
Assert.assertEquals("x-public-certificate-fingerprint", config.encryptionCertificateFingerprintHeaderName);
Assert.assertEquals("publicKeyFingerprint", config.encryptionKeyFingerprintFieldName);
Assert.assertEquals("x-public-key-fingerprint", config.encryptionKeyFingerprintHeaderName);
Assert.assertEquals(1, config.decryptionPaths.size());
Assert.assertNotNull(config.decryptionKey);
Assert.assertEquals("SHA-512", config.oaepPaddingDigestAlgorithm);
Assert.assertEquals("encryptedValue", config.encryptedValueFieldName);
Assert.assertEquals("encryptedKey", config.encryptedKeyFieldName);
Assert.assertEquals("x-encrypted-key", config.encryptedKeyHeaderName);
Assert.assertEquals("iv", config.ivFieldName);
Assert.assertEquals("x-iv", config.ivHeaderName);
Assert.assertEquals("oaepPaddingDigestAlgorithm", config.oaepPaddingDigestAlgorithmFieldName);
Assert.assertEquals("x-oaep-padding-digest-algorithm", config.oaepPaddingDigestAlgorithmHeaderName);
Assert.assertEquals(HEX, config.fieldValueEncoding);
assertThat(config.getIVSize().intValue(),equalTo(16));
}

@Test
public void testBuild_FailedIV() throws Exception {
try {
FieldLevelEncryptionConfig config = FieldLevelEncryptionConfigBuilder.aFieldLevelEncryptionConfig()
.withEncryptionPath("$.payload", "$.encryptedPayload")
.withEncryptionCertificate(TestUtils.getTestEncryptionCertificate())
.withEncryptionCertificateFingerprint("97A2FFE9F0D48960EF31E87FCD7A55BF7843FB4A9EEEF01BDB6032AD6FEF146B")
.withEncryptionKeyFingerprint("F806B26BC4870E26986C70B6590AF87BAF4C2B56BB50622C51B12212DAFF2810")
.withEncryptionCertificateFingerprintFieldName("publicCertificateFingerprint")
.withEncryptionCertificateFingerprintHeaderName("x-public-certificate-fingerprint")
.withEncryptionKeyFingerprintFieldName("publicKeyFingerprint")
.withEncryptionKeyFingerprintHeaderName("x-public-key-fingerprint")
.withDecryptionPath("$.encryptedPayload", "$.payload")
.withDecryptionKey(TestUtils.getTestDecryptionKey())
.withOaepPaddingDigestAlgorithm("SHA-512")
.withOaepPaddingDigestAlgorithmFieldName("oaepPaddingDigestAlgorithm")
.withOaepPaddingDigestAlgorithmHeaderName("x-oaep-padding-digest-algorithm")
.withEncryptedValueFieldName("encryptedValue")
.withEncryptedKeyFieldName("encryptedKey")
.withEncryptedKeyHeaderName("x-encrypted-key")
.withIvFieldName("iv")
.withIvHeaderName("x-iv")
.withFieldValueEncoding(HEX)
.withEncryptionIVSize(23)
.build();
assertFalse("It should raise an exception, but it didn't", true);
} catch ( IllegalArgumentException e) {
assertThat(e.getMessage(), equalTo("Supported IV Sizes are either 12 or 16!"));
}
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,44 @@

import java.util.Collections;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.core.IsEqual.equalTo;
import static org.junit.Assert.assertFalse;

public class JweConfigBuilderTest {

@Rule
public ExpectedException expectedException = ExpectedException.none();

@Test
public void testBuild_Nominal() throws Exception {
public void testBuild_Nominal_iv12() throws Exception {
JweConfig config = JweConfigBuilder.aJweEncryptionConfig()
.withEncryptionCertificate(TestUtils.getTestEncryptionCertificate())
.withDecryptionKey(TestUtils.getTestDecryptionKey())
.withEncryptionPath("$", "$")
.withDecryptionPath("$.encryptedPayload", "$")
.withEncryptedValueFieldName("encryptedPayload")
.withEncryptionIVSize(12)
.build();
Assert.assertNotNull(config);
Assert.assertEquals(EncryptionConfig.Scheme.JWE, config.getScheme());
Assert.assertEquals(TestUtils.getTestDecryptionKey(), config.getDecryptionKey());
Assert.assertEquals(TestUtils.getTestEncryptionCertificate(), config.getEncryptionCertificate());
Assert.assertEquals("encryptedPayload", config.getEncryptedValueFieldName());
Assert.assertEquals(Collections.singletonMap("$.encryptedPayload", "$"), config.getDecryptionPaths());
Assert.assertEquals(Collections.singletonMap("$", "$"), config.getEncryptionPaths());
assertThat(config.getIVSize().intValue(),equalTo(12));
}

@Test
public void testBuild_Nominal_iv16() throws Exception {
JweConfig config = JweConfigBuilder.aJweEncryptionConfig()
.withEncryptionCertificate(TestUtils.getTestEncryptionCertificate())
.withDecryptionKey(TestUtils.getTestDecryptionKey())
.withEncryptionPath("$", "$")
.withDecryptionPath("$.encryptedPayload", "$")
.withEncryptedValueFieldName("encryptedPayload")
.withEncryptionIVSize(16)
.build();
Assert.assertNotNull(config);
Assert.assertEquals(EncryptionConfig.Scheme.JWE, config.getScheme());
Expand All @@ -29,8 +54,25 @@ public void testBuild_Nominal() throws Exception {
Assert.assertEquals("encryptedPayload", config.getEncryptedValueFieldName());
Assert.assertEquals(Collections.singletonMap("$.encryptedPayload", "$"), config.getDecryptionPaths());
Assert.assertEquals(Collections.singletonMap("$", "$"), config.getEncryptionPaths());
assertThat(config.getIVSize().intValue(),equalTo(16));
}

@Test
public void testBuild_FailedIV() throws Exception {
try {
JweConfig config = JweConfigBuilder.aJweEncryptionConfig()
.withEncryptionCertificate(TestUtils.getTestEncryptionCertificate())
.withDecryptionKey(TestUtils.getTestDecryptionKey())
.withEncryptionPath("$", "$")
.withDecryptionPath("$.encryptedPayload", "$")
.withEncryptedValueFieldName("encryptedPayload")
.withEncryptionIVSize(24)
.build();
assertFalse("It should raise an exception, but it didn't", true);
} catch ( IllegalArgumentException e) {
assertThat(e.getMessage(), equalTo("Supported IV Sizes are either 12 or 16!"));
}
}
@Test
public void testBuild_EncryptionKeyNoDecryptionKey() throws Exception {
JweConfig config = JweConfigBuilder.aJweEncryptionConfig()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ public void testDecryptPayload_ShouldDecryptRootArrays() throws Exception {
" \"encryptedData\": \"eyJraWQiOiI3NjFiMDAzYzFlYWRlM2E1NDkwZTUwMDBkMzc4ODdiYWE1ZTZlYzBlMjI2YzA3NzA2ZTU5OTQ1MWZjMDMyYTc5IiwiY3R5IjoiYXBwbGljYXRpb24vanNvbiIsImVuYyI6IkEyNTZHQ00iLCJhbGciOiJSU0EtT0FFUC0yNTYifQ.IcTIce59pgtjODJn4PhR7oK3F-gxcd7dishTrT7T9y5VC0U5ZS_JdMoRe59_UTkJMY8Nykb2rv3Oh_jSDYRmGB_CWMIciXYMLHQptLTF5xI1ZauDPnooDMWoOCBD_d3I0wTJNcM7I658rK0ZWSByVK9YqhEo8UaIf4e6egRHQdZ2_IGKgICwmglv_uXQrYewOWFTKR1uMpya1N50MDnWax2NtnW3SljP3mARUBLBnRmOyubQCg-Mgn8fsOWWXm-KL9RrQq9AF_HJceoJl1rRgzPW7g6SLK6EjiGW_ArTmrLaOHg9bYOY_LrbyokK_M1pMo9qup70DHvjHkMZqIL3aQ.vtma3jBIo2STkquxTUX9PQ.9ZoQG0sFvQ.ms4bW3OFd03neRlex-zZ8w\"" +
"}";
JweConfig config = getTestJweConfigBuilder()
.withEncryptedValueFieldName("encryptedResponse")
.withDecryptionPath("$.encryptedData", "$")
.build();

Expand Down
8 changes: 8 additions & 0 deletions src/test/resources/log4j.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Root logger option
log4j.rootLogger=INFO, stdout

# Direct log messages to stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n