diff --git a/openid-connect-common/src/main/java/org/mitre/jwe/model/Jwe.java b/openid-connect-common/src/main/java/org/mitre/jwe/model/Jwe.java index 9d5043f63..e240cd3a4 100644 --- a/openid-connect-common/src/main/java/org/mitre/jwe/model/Jwe.java +++ b/openid-connect-common/src/main/java/org/mitre/jwe/model/Jwe.java @@ -43,7 +43,6 @@ public class Jwe extends Jwt { public Jwe(String headerBase64, String encryptedKeyBase64, String cipherTextBase64, String integrityValueBase64) { byte[] decodedEncryptedKey = Base64.decodeBase64(encryptedKeyBase64.getBytes()); byte[] decodedCipherText = Base64.decodeBase64(cipherTextBase64.getBytes()); - String decodedIntegrityValue = new String(Base64.decodeBase64(integrityValueBase64)); this.header = new JweHeader(headerBase64); this.encryptedKey = decodedEncryptedKey; this.ciphertext = decodedCipherText; diff --git a/openid-connect-common/src/main/java/org/mitre/jwt/encryption/AbstractJweDecrypter.java b/openid-connect-common/src/main/java/org/mitre/jwt/encryption/AbstractJweDecrypter.java index e5d3ffc4a..6507c3101 100644 --- a/openid-connect-common/src/main/java/org/mitre/jwt/encryption/AbstractJweDecrypter.java +++ b/openid-connect-common/src/main/java/org/mitre/jwt/encryption/AbstractJweDecrypter.java @@ -8,16 +8,14 @@ public abstract class AbstractJweDecrypter implements JwtDecrypter { long MAX_HASH_INPUTLEN = Long.MAX_VALUE; long UNSIGNED_INT_MAX_VALUE = 4294967395L; - public byte[] generateContentKey(byte[] cmk, int keyDataLen, byte[] type) { + public byte[] generateContentKey(byte[] cmk, int keyDataLen, byte[] type) throws NoSuchAlgorithmException { MessageDigest md = null; - try { - md = MessageDigest.getInstance("SHA-256"); //TODO: should figure out this getInstance itself, not always 256 - } catch (NoSuchAlgorithmException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - + //HUGE DISCLAIMER: this won't work on windows machines that don't have jce unlimited security files installed. + //without it, keys can't be over 128 bit in length, and SHA-128 doesn't work for message digest. + + //this is what it should be + md = MessageDigest.getInstance("SHA-" + Integer.toString(keyDataLen)); keyDataLen = keyDataLen / 8; byte[] key = new byte[keyDataLen]; diff --git a/openid-connect-common/src/main/java/org/mitre/jwt/encryption/AbstractJweEncrypter.java b/openid-connect-common/src/main/java/org/mitre/jwt/encryption/AbstractJweEncrypter.java index 6a9227fce..4275d392e 100644 --- a/openid-connect-common/src/main/java/org/mitre/jwt/encryption/AbstractJweEncrypter.java +++ b/openid-connect-common/src/main/java/org/mitre/jwt/encryption/AbstractJweEncrypter.java @@ -8,9 +8,12 @@ public abstract class AbstractJweEncrypter implements JwtEncrypter { public MessageDigest md; public byte[] generateContentKey(byte[] cmk, int keyDataLen, byte[] type) throws NoSuchAlgorithmException { - //TODO: make this work for any key size - md = MessageDigest.getInstance("SHA-256"); - + //HUGE DISCLAIMER: this won't work on windows machines that don't have jce unlimited security files installed. + //without it, keys can't be over 128 bit in length, and SHA-128 doesn't work for message digest. + + //this is what it should be + md = MessageDigest.getInstance("SHA-" + Integer.toString(keyDataLen)); + long MAX_HASH_INPUTLEN = Long.MAX_VALUE; long UNSIGNED_INT_MAX_VALUE = 4294967395L; diff --git a/openid-connect-common/src/main/java/org/mitre/jwt/encryption/impl/RsaDecrypter.java b/openid-connect-common/src/main/java/org/mitre/jwt/encryption/impl/RsaDecrypter.java index 9b01d9342..69ddd508a 100644 --- a/openid-connect-common/src/main/java/org/mitre/jwt/encryption/impl/RsaDecrypter.java +++ b/openid-connect-common/src/main/java/org/mitre/jwt/encryption/impl/RsaDecrypter.java @@ -38,16 +38,14 @@ public class RsaDecrypter extends AbstractJweDecrypter { //generation of cek and cik byte[] contentEncryptionKey = null; byte[] contentIntegrityKey = null; - //check whether the key length is 128 or 256 - if(jwe.getHeader().getEncryptionMethod().equals("A128CBC") || jwe.getHeader().getEncryptionMethod().equals("A128GCM")){ - contentEncryptionKey = generateContentKey(jwe.getEncryptedKey(), 128, new String("Encryption").getBytes()); - contentIntegrityKey = generateContentKey(jwe.getEncryptedKey(), 128, new String("Integrity").getBytes()); - } else if(jwe.getHeader().getEncryptionMethod().equals("A256CBC") || jwe.getHeader().getEncryptionMethod().equals("A256GCM")){ - contentEncryptionKey = generateContentKey(jwe.getEncryptedKey(), 256, new String("Encryption").getBytes()); - contentIntegrityKey = generateContentKey(jwe.getEncryptedKey(), 256, new String("Integrity").getBytes()); - } else { - throw new IllegalArgumentException(jwe.getHeader().getEncryptionMethod() + " is not a valid encryption method"); - } + //check what the key length is + String encMethod = jwe.getHeader().getEncryptionMethod(); + char[] array = encMethod.toCharArray(); + String keyBitLengthString = String.copyValueOf(array, 1, 3); + int keyBitLength = Integer.parseInt(keyBitLengthString); + //generate cek and cik + contentEncryptionKey = generateContentKey(jwe.getEncryptedKey(), keyBitLength, "Encryption".getBytes()); + contentIntegrityKey = generateContentKey(jwe.getEncryptedKey(), keyBitLength, "Integrity".getBytes()); //decrypt ciphertext to get claims jwe.setCiphertext(decryptCipherText(jwe, contentEncryptionKey)); @@ -83,12 +81,12 @@ public class RsaDecrypter extends AbstractJweDecrypter { String encMethod = jwe.getHeader().getEncryptionMethod(); if(encMethod.equals("A128CBC") || encMethod.equals("A256CBC") || encMethod.equals("A128GCM") || encMethod.equals("A128GCM")) { + + Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); + cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(cek, "AES"), new IvParameterSpec(iv)); + byte[] clearText = cipher.doFinal(jwe.getCiphertext()); - Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding"); - cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(cek, "AES"), new IvParameterSpec(iv)); - byte[] clearText = cipher.doFinal(jwe.getCiphertext()); - - return clearText; + return clearText; } else { throw new IllegalArgumentException(jwe.getHeader().getAlgorithm() + " is not an implemented algorithm"); diff --git a/openid-connect-common/src/main/java/org/mitre/jwt/encryption/impl/RsaEncrypter.java b/openid-connect-common/src/main/java/org/mitre/jwt/encryption/impl/RsaEncrypter.java index b013fdc9c..b9bc810ad 100644 --- a/openid-connect-common/src/main/java/org/mitre/jwt/encryption/impl/RsaEncrypter.java +++ b/openid-connect-common/src/main/java/org/mitre/jwt/encryption/impl/RsaEncrypter.java @@ -35,28 +35,22 @@ public class RsaEncrypter extends AbstractJweEncrypter { //generate random content master key - byte[] contentMasterKey = new byte[128]; + //check what the key length is + String encMethod = jwe.getHeader().getEncryptionMethod(); + char[] array = encMethod.toCharArray(); + String keyBitLengthString = String.copyValueOf(array, 1, 3); + int keyBitLength = Integer.parseInt(keyBitLengthString); + + byte[] contentMasterKey = new byte[keyBitLength]; new Random().nextBytes(contentMasterKey); - //generate CEK and CIK - byte[] contentEncryptionKey = null; byte[] contentIntegrityKey = null; - //check what the key length is - if(jwe.getHeader().getEncryptionMethod().equals("A128CBC") || jwe.getHeader().getEncryptionMethod().equals("A128GCM")){ - contentEncryptionKey = generateContentKey(contentMasterKey, 128, "Encryption".getBytes()); - contentIntegrityKey = generateContentKey(contentMasterKey, 128, "Integrity".getBytes()); - } else if(jwe.getHeader().getEncryptionMethod().equals("A256CBC") || jwe.getHeader().getEncryptionMethod().equals("A256GCM")){ - contentEncryptionKey = generateContentKey(contentMasterKey, 256, new String("Encryption").getBytes()); - contentIntegrityKey = generateContentKey(contentMasterKey, 256, new String("Integrity").getBytes()); - } else if(jwe.getHeader().getEncryptionMethod().equals("A384CBC") || jwe.getHeader().getEncryptionMethod().equals("A384GCM")){ - contentEncryptionKey = generateContentKey(contentMasterKey, 384, new String("Encryption").getBytes()); - contentIntegrityKey = generateContentKey(contentMasterKey, 384, new String("Integrity").getBytes()); - } else if(jwe.getHeader().getEncryptionMethod().equals("A512CBC") || jwe.getHeader().getEncryptionMethod().equals("A512GCM")){ - contentEncryptionKey = generateContentKey(contentMasterKey, 512, new String("Encryption").getBytes()); - contentIntegrityKey = generateContentKey(contentMasterKey, 512, new String("Integrity").getBytes()); - } + + //generate cek and cik + contentEncryptionKey = generateContentKey(contentMasterKey, keyBitLength, "Encryption".getBytes()); + contentIntegrityKey = generateContentKey(contentMasterKey, keyBitLength, "Integrity".getBytes()); //encrypt claims and cmk to get ciphertext and encrypted key jwe.setCiphertext(encryptClaims(jwe, contentEncryptionKey)); @@ -109,7 +103,7 @@ public class RsaEncrypter extends AbstractJweEncrypter { String encMethod = jwe.getHeader().getEncryptionMethod(); if(encMethod.equals("A128CBC") || encMethod.equals("A256CBC") || encMethod.equals("A128GCM") || encMethod.equals("A128GCM")) { - + Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(contentEncryptionKey, "AES"), new IvParameterSpec(iv)); byte[] cipherText = cipher.doFinal(jwe.getCiphertext()); diff --git a/openid-connect-common/src/test/java/org/mitre/jwe/encryption/impl/RsaEncrypterDecrypterTest.java b/openid-connect-common/src/test/java/org/mitre/jwe/encryption/impl/RsaEncrypterDecrypterTest.java index 9644d3c08..0ec79840a 100644 --- a/openid-connect-common/src/test/java/org/mitre/jwe/encryption/impl/RsaEncrypterDecrypterTest.java +++ b/openid-connect-common/src/test/java/org/mitre/jwe/encryption/impl/RsaEncrypterDecrypterTest.java @@ -3,12 +3,8 @@ package org.mitre.jwe.encryption.impl; import static org.junit.Assert.assertEquals; import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileWriter; import java.io.IOException; import java.io.InputStreamReader; -import java.io.PrintWriter; import java.net.URL; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; @@ -44,10 +40,7 @@ import com.google.gson.JsonSyntaxException; public class RsaEncrypterDecrypterTest { URL jweHeaderUrl = this.getClass().getResource("/jwe/jweHeader"); - URL jwePlaintextUrl = this.getClass().getResource("/jwe/jwePlaintext"); - URL jweEncryptedUrl = this.getClass().getResource("/jwe/encryptedJwe"); - String jweEncryptedUrlString = jweEncryptedUrl.toString(); - File jweEncryptedFile = new File(jweEncryptedUrlString); + String jwePlaintextString = new String("Why couldn't the bike move? It was two tired."); @Before public void setUp(){ @@ -59,40 +52,33 @@ public class RsaEncrypterDecrypterTest { @Test public void encryptDecryptTest() throws JsonIOException, JsonSyntaxException, IOException, NoSuchAlgorithmException, InvalidKeyException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException, InvalidKeySpecException { - + //read in header and plaintext from files JsonParser parser = new JsonParser(); JsonObject jweHeaderObject = parser.parse(new BufferedReader(new InputStreamReader(jweHeaderUrl.openStream()))).getAsJsonObject(); - String jwePlaintextString = parser.parse(new BufferedReader(new InputStreamReader(jwePlaintextUrl.openStream()))).toString(); - + //create jwe based on header and plaintext Jwe jwe = new Jwe(new JweHeader(jweHeaderObject), null, jwePlaintextString.getBytes(), null); - + //generate key pair. this will be passed in from the user KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA"); - keyGen.initialize(2048); + keyGen.initialize(4096); KeyPair pair = keyGen.generateKeyPair(); PublicKey publicKey = pair.getPublic(); PrivateKey privateKey = pair.getPrivate(); //encrypt RsaEncrypter rsaEncrypter = new RsaEncrypter(); jwe = rsaEncrypter.encryptAndSign(jwe, publicKey); - //put encrypted jwe in text file to then be decrypted - PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter("C:/Users/derryberry/projects/OpenID-Connect-Java-Spring-Server-2/openid-connect-common/target/test-classes/jwe/encryptedJwe"))); - out.println(jwe.toString()); - out.close(); - - String jweEncryptedString = parser.parse(new BufferedReader(new InputStreamReader(jweEncryptedUrl.openStream()))).toString(); - jweEncryptedString = jweEncryptedString.replaceAll("^\"|\"$", ""); - - assertEquals(jwe.toString(), jweEncryptedString); + //decrypt RsaDecrypter rsaDecrypter = new RsaDecrypter(); String encryptedJweString = jwe.toString(); jwe = rsaDecrypter.decrypt(encryptedJweString, privateKey); - assertEquals(new String(jwe.getCiphertext()), jwePlaintextString); - assertEquals(jwe.getHeader().getAlgorithm(), "RSA1_5"); - assertEquals(jwe.getHeader().getEncryptionMethod(), "A128CBC"); - assertEquals(jwe.getHeader().getIntegrity(), "HS256"); - assertEquals(jwe.getHeader().getInitializationVector(), "AxY8DCtDaGlsbGljb3RoZQ"); + String jweDecryptedCleartext = new String(jwe.getCiphertext()); + //test ALL THE THINGS + assertEquals(jweDecryptedCleartext, jwePlaintextString); + assertEquals(jwe.getHeader().getAlgorithm(), jweHeaderObject.get("alg").getAsString()); + assertEquals(jwe.getHeader().getEncryptionMethod(), jweHeaderObject.get("enc").getAsString()); + assertEquals(jwe.getHeader().getIntegrity(), jweHeaderObject.get("int").getAsString()); + assertEquals(jwe.getHeader().getInitializationVector(), jweHeaderObject.get("iv").getAsString()); } diff --git a/openid-connect-common/src/test/resources/jwe/encryptedJwe b/openid-connect-common/src/test/resources/jwe/encryptedJwe deleted file mode 100644 index e69de29bb..000000000 diff --git a/openid-connect-common/src/test/resources/jwe/jweHeader b/openid-connect-common/src/test/resources/jwe/jweHeader index 9e69f162e..296669820 100644 --- a/openid-connect-common/src/test/resources/jwe/jweHeader +++ b/openid-connect-common/src/test/resources/jwe/jweHeader @@ -1 +1 @@ -{"alg":"RSA1_5","enc":"A128CBC","int":"HS256","iv":"AxY8DCtDaGlsbGljb3RoZQ"} \ No newline at end of file +{"alg":"RSA1_5","enc":"A256CBC","int":"HS256","iv":"AxY8DCtDaGlsbGljb3RoZQ"} \ No newline at end of file diff --git a/openid-connect-common/src/test/resources/jwe/jwePlaintext b/openid-connect-common/src/test/resources/jwe/jwePlaintext deleted file mode 100644 index d46a4fa11..000000000 --- a/openid-connect-common/src/test/resources/jwe/jwePlaintext +++ /dev/null @@ -1 +0,0 @@ -"Why couldn't the bike move? It was two tired." \ No newline at end of file