Skip to content

Define an enum for the RSA padding scheme #162

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Mar 10, 2020
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
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import com.amazonaws.encryptionsdk.DecryptRequest;
import com.amazonaws.encryptionsdk.EncryptRequest;
import com.amazonaws.encryptionsdk.keyrings.Keyring;
import com.amazonaws.encryptionsdk.keyrings.RawRsaKeyringBuilder.RsaPaddingScheme;
import com.amazonaws.encryptionsdk.keyrings.StandardKeyrings;
import com.amazonaws.encryptionsdk.kms.AwsKmsCmkId;

Expand Down Expand Up @@ -94,7 +95,7 @@ private static byte[] standardEncrypt(final AwsKmsCmkId kmsArn, final PublicKey
.keyNamespace("Escrow")
.keyName("Escrow")
.publicKey(publicEscrowKey)
.wrappingAlgorithm("RSA/ECB/OAEPWithSHA-512AndMGF1Padding")
.paddingScheme(RsaPaddingScheme.OAEP_SHA512_MGF1)
.build();

// 4. Combine the providers into a single MultiKeyring
Expand Down Expand Up @@ -138,7 +139,7 @@ private static byte[] escrowDecrypt(final byte[] cipherText, final PrivateKey pr
.keyNamespace("Escrow")
.keyName("Escrow")
.privateKey(privateEscrowKey)
.wrappingAlgorithm("RSA/ECB/OAEPWithSHA-512AndMGF1Padding")
.paddingScheme(RsaPaddingScheme.OAEP_SHA512_MGF1)
.build();

// 3. Decrypt the data with the keyring
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import com.amazonaws.encryptionsdk.AwsCryptoResult;
import com.amazonaws.encryptionsdk.DecryptRequest;
import com.amazonaws.encryptionsdk.keyrings.Keyring;
import com.amazonaws.encryptionsdk.keyrings.RawRsaKeyringBuilder.RsaPaddingScheme;
import com.amazonaws.encryptionsdk.keyrings.StandardKeyrings;

import java.security.KeyPair;
Expand All @@ -35,7 +36,7 @@ public static byte[] decrypt(byte[] ciphertext, KeyPair keyPair) {
final Keyring keyring = StandardKeyrings.rawRsaBuilder()
.keyNamespace("ExampleKeyNamespace")
.keyName("ExampleKeyName")
.wrappingAlgorithm("RSA/ECB/OAEPWithSHA-512AndMGF1Padding")
.paddingScheme(RsaPaddingScheme.OAEP_SHA512_MGF1)
.privateKey(keyPair.getPrivate()).build();

// 3. Decrypt the ciphertext with the keyring
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import com.amazonaws.encryptionsdk.AwsCryptoResult;
import com.amazonaws.encryptionsdk.EncryptRequest;
import com.amazonaws.encryptionsdk.keyrings.Keyring;
import com.amazonaws.encryptionsdk.keyrings.RawRsaKeyringBuilder.RsaPaddingScheme;
import com.amazonaws.encryptionsdk.keyrings.StandardKeyrings;

import java.nio.charset.StandardCharsets;
Expand All @@ -39,7 +40,7 @@ public static byte[] encrypt(PublicKey publicKey) {
final Keyring keyring = StandardKeyrings.rawRsaBuilder()
.keyNamespace("ExampleKeyNamespace")
.keyName("ExampleKeyName")
.wrappingAlgorithm("RSA/ECB/OAEPWithSHA-512AndMGF1Padding")
.paddingScheme(RsaPaddingScheme.OAEP_SHA512_MGF1)
.publicKey(publicKey).build();

// 3. Create an encryption context
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

import com.amazonaws.encryptionsdk.EncryptedDataKey;
import com.amazonaws.encryptionsdk.internal.JceKeyCipher;
import com.amazonaws.encryptionsdk.keyrings.RawRsaKeyringBuilder.RsaPaddingScheme;

import java.security.PrivateKey;
import java.security.PublicKey;
Expand All @@ -28,8 +29,8 @@
*/
class RawRsaKeyring extends RawKeyring {

RawRsaKeyring(String keyNamespace, String keyName, PublicKey publicKey, PrivateKey privateKey, String transformation) {
super(keyNamespace, keyName, JceKeyCipher.rsa(publicKey, privateKey, transformation));
RawRsaKeyring(String keyNamespace, String keyName, PublicKey publicKey, PrivateKey privateKey, RsaPaddingScheme rsaPaddingScheme) {
super(keyNamespace, keyName, JceKeyCipher.rsa(publicKey, privateKey, rsaPaddingScheme.getTransformation()));
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public class RawRsaKeyringBuilder {
private String keyName;
private PublicKey publicKey;
private PrivateKey privateKey;
private String wrappingAlgorithm;
private RsaPaddingScheme paddingScheme;

private RawRsaKeyringBuilder() {
// Use RawRsaKeyringBuilder.standard() or StandardKeyrings.rawRsa() to instantiate
Expand Down Expand Up @@ -81,13 +81,13 @@ public RawRsaKeyringBuilder privateKey(PrivateKey privateKey) {
}

/**
* The RSA algorithm to use with this keyring (required).
* The RSA padding scheme to use with this keyring (required).
*
* @param wrappingAlgorithm The algorithm
* @param paddingScheme The RSA padding scheme
* @return The RawRsaKeyringBuilder, for method chaining
*/
public RawRsaKeyringBuilder wrappingAlgorithm(String wrappingAlgorithm) {
this.wrappingAlgorithm = wrappingAlgorithm;
public RawRsaKeyringBuilder paddingScheme(RsaPaddingScheme paddingScheme) {
this.paddingScheme = paddingScheme;
return this;
}

Expand All @@ -97,6 +97,33 @@ public RawRsaKeyringBuilder wrappingAlgorithm(String wrappingAlgorithm) {
* @return The {@link Keyring} instance
*/
public Keyring build() {
return new RawRsaKeyring(keyNamespace, keyName, publicKey, privateKey, wrappingAlgorithm);
return new RawRsaKeyring(keyNamespace, keyName, publicKey, privateKey, paddingScheme);
}

public enum RsaPaddingScheme {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NitPick: For ease of use, calculate the correct OAEPParameterSpec instances for each of these (they are immutable) and just pull them from the enum.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll hold off on this until Master Keys are deleted


PKCS1("RSA/ECB/PKCS1Padding"),
OAEP_SHA1_MGF1("RSA/ECB/OAEPWithSHA-1AndMGF1Padding"),
OAEP_SHA256_MGF1("RSA/ECB/OAEPWithSHA-256AndMGF1Padding"),
OAEP_SHA384_MGF1("RSA/ECB/OAEPWithSHA-384AndMGF1Padding"),
OAEP_SHA512_MGF1("RSA/ECB/OAEPWithSHA-512AndMGF1Padding");

private final String transformation;

RsaPaddingScheme(String transformation) {
this.transformation = transformation;
}

/**
* The Cipher transformation standard name as specified in
* https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#Cipher
Comment on lines +118 to +119
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is almost correct. Please clarify that in all cases the hash function used with MGF1 is the same as the hash function used directly with the message.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated

* Note: In all cases the hash function used with MGF1 is the
* same as the hash function used directly with the message.
*
* @return The transformation name
*/
public String getTransformation() {
return transformation;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import com.amazonaws.encryptionsdk.AwsCrypto;
import com.amazonaws.encryptionsdk.DecryptRequest;
import com.amazonaws.encryptionsdk.keyrings.Keyring;
import com.amazonaws.encryptionsdk.keyrings.RawRsaKeyringBuilder.RsaPaddingScheme;
import com.amazonaws.encryptionsdk.keyrings.StandardKeyrings;
import org.junit.jupiter.api.Test;

Expand All @@ -38,7 +39,7 @@ void testEncrypt() throws Exception {
.keyNamespace("ExampleKeyNamespace")
.keyName("ExampleKeyName")
.privateKey(keyPair.getPrivate())
.wrappingAlgorithm("RSA/ECB/OAEPWithSHA-512AndMGF1Padding")
.paddingScheme(RsaPaddingScheme.OAEP_SHA512_MGF1)
.build();


Expand Down
29 changes: 21 additions & 8 deletions src/test/java/com/amazonaws/encryptionsdk/TestVectorRunner.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import com.amazonaws.auth.DefaultAWSCredentialsProviderChain;
import com.amazonaws.encryptionsdk.jce.JceMasterKey;
import com.amazonaws.encryptionsdk.keyrings.Keyring;
import com.amazonaws.encryptionsdk.keyrings.RawRsaKeyringBuilder.RsaPaddingScheme;
import com.amazonaws.encryptionsdk.keyrings.StandardKeyrings;
import com.amazonaws.encryptionsdk.kms.AwsKmsClientSupplier;
import com.amazonaws.encryptionsdk.kms.AwsKmsCmkId;
Expand Down Expand Up @@ -171,15 +172,27 @@ private static TestCase parseTest(String testName, Map<String, Object> data, Map
.wrappingKey((SecretKey) key.key).build());
mks.add(JceMasterKey.getInstance((SecretKey) key.key, provId, key.keyId, "AES/GCM/NoPadding"));
} else if ("rsa".equals(algorithm)) {
String transformation = "RSA/ECB/";
final RsaPaddingScheme paddingScheme;
final String padding = mkEntry.get("padding-algorithm");
if ("pkcs1".equals(padding)) {
transformation += "PKCS1Padding";
paddingScheme = RsaPaddingScheme.PKCS1;
} else if ("oaep-mgf1".equals(padding)) {
final String hashName = mkEntry.get("padding-hash")
.replace("sha", "sha-")
.toUpperCase();
transformation += "OAEPWith" + hashName + "AndMGF1Padding";
switch(mkEntry.get("padding-hash")) {
case "sha1":
paddingScheme = RsaPaddingScheme.OAEP_SHA1_MGF1;
break;
case "sha256":
paddingScheme = RsaPaddingScheme.OAEP_SHA256_MGF1;
break;
case "sha384":
paddingScheme = RsaPaddingScheme.OAEP_SHA384_MGF1;
break;
case "sha512":
paddingScheme = RsaPaddingScheme.OAEP_SHA512_MGF1;
break;
default:
throw new IllegalArgumentException("Unsupported padding hash:" + mkEntry.get("padding-hash"));
}
} else {
throw new IllegalArgumentException("Unsupported padding:" + padding);
}
Expand All @@ -197,8 +210,8 @@ private static TestCase parseTest(String testName, Map<String, Object> data, Map
.privateKey(unwrappingKey)
.keyNamespace(provId)
.keyName(key.keyId)
.wrappingAlgorithm(transformation).build());
mks.add(JceMasterKey.getInstance(wrappingKey, unwrappingKey, provId, key.keyId, transformation));
.paddingScheme(paddingScheme).build());
mks.add(JceMasterKey.getInstance(wrappingKey, unwrappingKey, provId, key.keyId, paddingScheme.getTransformation()));
} else {
throw new IllegalArgumentException("Unsupported algorithm: " + algorithm);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import com.amazonaws.encryptionsdk.internal.RandomBytesGenerator;
import com.amazonaws.encryptionsdk.internal.Utils;
import com.amazonaws.encryptionsdk.jce.JceMasterKey;
import com.amazonaws.encryptionsdk.keyrings.RawRsaKeyringBuilder.RsaPaddingScheme;
import com.amazonaws.encryptionsdk.kms.AwsKmsCmkId;
import com.amazonaws.encryptionsdk.kms.KMSTestFixtures;
import com.amazonaws.encryptionsdk.kms.KmsMasterKey;
Expand Down Expand Up @@ -74,19 +75,19 @@ void testRawAesKeyringCompatibility() {

@Test
void testRawRsaKeyringCompatibility() throws Exception {
final String wrappingAlgorithm = "RSA/ECB/OAEPWithSHA-512AndMGF1Padding";
final RsaPaddingScheme paddingScheme = RsaPaddingScheme.OAEP_SHA512_MGF1;
final KeyPairGenerator kg = KeyPairGenerator.getInstance("RSA");
kg.initialize(4096);
KeyPair keyPair = kg.generateKeyPair();

JceMasterKey mkp = JceMasterKey.getInstance(keyPair.getPublic(), keyPair.getPrivate(), KEY_NAMESPACE, KEY_NAME,
wrappingAlgorithm);
paddingScheme.getTransformation());
Keyring keyring = StandardKeyrings.rawRsaBuilder()
.keyNamespace(KEY_NAMESPACE)
.keyName(KEY_NAME)
.publicKey(keyPair.getPublic())
.privateKey(keyPair.getPrivate())
.wrappingAlgorithm(wrappingAlgorithm)
.paddingScheme(paddingScheme)
.build();

testCompatibility(keyring, mkp);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
package com.amazonaws.encryptionsdk.keyrings;

import com.amazonaws.encryptionsdk.EncryptedDataKey;
import com.amazonaws.encryptionsdk.keyrings.RawRsaKeyringBuilder.RsaPaddingScheme;
import com.amazonaws.encryptionsdk.model.DecryptionMaterials;
import com.amazonaws.encryptionsdk.model.EncryptionMaterials;
import com.amazonaws.encryptionsdk.model.KeyBlob;
Expand All @@ -37,15 +38,15 @@

class RawRsaKeyringTest {

private static final String TRANSFORMATION = "RSA/ECB/PKCS1Padding";
private static final RsaPaddingScheme PADDING_SCHEME = RsaPaddingScheme.PKCS1;
private static RawRsaKeyring keyring;

@BeforeAll
static void setup() throws Exception {
final KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(2048);
final KeyPair keyPair = keyPairGenerator.generateKeyPair();
keyring = new RawRsaKeyring(KEYNAMESPACE, KEYNAME, keyPair.getPublic(), keyPair.getPrivate(), TRANSFORMATION);
keyring = new RawRsaKeyring(KEYNAMESPACE, KEYNAME, keyPair.getPublic(), keyPair.getPrivate(), PADDING_SCHEME);
}

@Test
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except
* in compliance with the License. A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/

package com.amazonaws.encryptionsdk.model;

import com.amazonaws.encryptionsdk.keyrings.RawRsaKeyringBuilder.RsaPaddingScheme;
import org.junit.jupiter.api.Test;

import javax.crypto.Cipher;

import static org.junit.jupiter.api.Assertions.assertNotNull;

class RsaPaddingSchemeTest {

@Test
void testCipherInitialization() throws Exception {
for (RsaPaddingScheme paddingScheme : RsaPaddingScheme.values()) {
assertNotNull(Cipher.getInstance(paddingScheme.getTransformation()));
}
}
}