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 dd8dcf8a6..032dcde4b 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 @@ -42,11 +42,10 @@ public class Jwe extends Jwt { public Jwe(String headerBase64, String encryptedKeyBase64, String cipherTextBase64, String integrityValueBase64) { super(null, null, new String(Base64.decodeBase64(integrityValueBase64))); - String decodedHeader = new String(Base64.decodeBase64(headerBase64)); String decodedEncryptedKey = new String(Base64.decodeBase64(encryptedKeyBase64)); String decodedCipherText = new String(Base64.decodeBase64(cipherTextBase64)); String decodedIntegrityValue = new String(Base64.decodeBase64(integrityValueBase64)); - this.header = new JweHeader(decodedHeader); + this.header = new JweHeader(headerBase64); this.encryptedKey = decodedEncryptedKey.getBytes(); this.ciphertext = decodedCipherText.getBytes(); setSignature(decodedIntegrityValue); 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 711c23590..e5d3ffc4a 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 @@ -1,37 +1,23 @@ package org.mitre.jwt.encryption; import java.security.MessageDigest; -import java.security.PrivateKey; -import java.security.PublicKey; +import java.security.NoSuchAlgorithmException; public abstract class AbstractJweDecrypter implements JwtDecrypter { - protected PrivateKey privateKey; - - private PublicKey publicKey; - - public MessageDigest md; - - public PrivateKey getPrivateKey() { - return privateKey; - } - - public void setPrivateKey(PrivateKey privateKey) { - this.privateKey = privateKey; - } - - public PublicKey getPublicKey() { - return publicKey; - } - - public void setPublicKey(PublicKey publicKey) { - this.publicKey = publicKey; - } + long MAX_HASH_INPUTLEN = Long.MAX_VALUE; + long UNSIGNED_INT_MAX_VALUE = 4294967395L; public byte[] generateContentKey(byte[] cmk, int keyDataLen, byte[] type) { + + 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(); + } - long MAX_HASH_INPUTLEN = Long.MAX_VALUE; - long UNSIGNED_INT_MAX_VALUE = 4294967395L; 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 f5dc0ee94..4f93bd3d1 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 @@ -1,34 +1,11 @@ package org.mitre.jwt.encryption; import java.security.MessageDigest; -import java.security.PublicKey; public abstract class AbstractJweEncrypter implements JwtEncrypter { - protected byte[] encryptedKey; - - protected byte[] cipherText; - - protected PublicKey publicKey; - public MessageDigest md; - public byte[] getEncryptecKey() { - return encryptedKey; - } - - public void setEncryptedKey(byte[] encryptedKey) { - this.encryptedKey = encryptedKey; - } - - public byte[] getCipherText() { - return cipherText; - } - - public void setCipherText(byte[] cipherText) { - this.cipherText = cipherText; - } - public byte[] generateContentKey(byte[] cmk, int keyDataLen, byte[] type) { long MAX_HASH_INPUTLEN = Long.MAX_VALUE; diff --git a/openid-connect-common/src/main/java/org/mitre/jwt/encryption/JwtEncrypter.java b/openid-connect-common/src/main/java/org/mitre/jwt/encryption/JwtEncrypter.java index 10de1610e..1e74348bc 100644 --- a/openid-connect-common/src/main/java/org/mitre/jwt/encryption/JwtEncrypter.java +++ b/openid-connect-common/src/main/java/org/mitre/jwt/encryption/JwtEncrypter.java @@ -1,18 +1,22 @@ package org.mitre.jwt.encryption; +import java.io.IOException; import java.security.Key; import java.security.NoSuchAlgorithmException; import org.mitre.jwe.model.Jwe; +import com.google.gson.JsonIOException; +import com.google.gson.JsonSyntaxException; + public interface JwtEncrypter { - public byte[] encryptKey(Jwe jwe, Key cmk); + public byte[] encryptKey(Jwe jwe, Key cmk) throws JsonIOException, JsonSyntaxException, IOException; public byte[] encryptClaims(Jwe jwe, byte[] cik); - public Jwe encryptAndSign(Jwe jwe) throws NoSuchAlgorithmException; + public Jwe encryptAndSign(Jwe jwe) throws NoSuchAlgorithmException, JsonIOException, JsonSyntaxException, IOException; public byte[] generateContentKey(byte[] cmk, int keyDataLen, byte[] type); 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 48cbf8112..7e2b46448 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 @@ -2,6 +2,7 @@ package org.mitre.jwt.encryption.impl; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; import javax.crypto.BadPaddingException; import javax.crypto.Cipher; @@ -27,7 +28,7 @@ public class RsaDecrypter extends AbstractJweDecrypter { Jwe jwe = Jwe.parse(encryptedJwe); String alg = jwe.getHeader().getAlgorithm(); - if(alg.equals("RS256") || alg.equals("RS384") || alg.equals("RS512")) { + if(alg.equals("RSA1_5") || alg.equals("RSA-OAEP") || alg.equals("ECDH-ES") || alg.equals("A128KW") || alg.equals("A256KW")) { //decrypt to get cmk to be used for cek and cik jwe.setEncryptedKey(decryptEncryptionKey(jwe)); @@ -56,10 +57,6 @@ public class RsaDecrypter extends AbstractJweDecrypter { throw new IllegalArgumentException("Didn't decrypt correctly. Decoded Sig and generated Sig do not match"); } - } else if(alg.equals("HS256") || alg.equals("HS384") || alg.equals("HS512")){ - - throw new IllegalArgumentException("Cannot use Hmac for decryption"); - } else { throw new IllegalArgumentException("Not a valid decrypting algorithm"); } @@ -101,6 +98,7 @@ public class RsaDecrypter extends AbstractJweDecrypter { public byte[] decryptEncryptionKey(Jwe jwe) { Cipher cipher; byte[] contentMasterKey = null; + PrivateKey privateKey = null; try { 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 4334ad174..09549eef6 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 @@ -5,6 +5,7 @@ import java.security.Key; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.NoSuchAlgorithmException; +import java.security.PublicKey; import java.security.SecureRandom; import javax.crypto.BadPaddingException; @@ -16,7 +17,6 @@ import javax.crypto.spec.SecretKeySpec; import org.mitre.jwe.model.Jwe; import org.mitre.jwt.encryption.AbstractJweEncrypter; import org.mitre.jwt.encryption.AlgorithmLength; -import org.mitre.jwt.encryption.JwtAlgorithm; import org.mitre.jwt.signer.impl.HmacSigner; public class RsaEncrypter extends AbstractJweEncrypter { @@ -31,15 +31,15 @@ public class RsaEncrypter extends AbstractJweEncrypter { String alg = jwe.getHeader().getAlgorithm(); String iv = jwe.getHeader().getIntegrity(); - if(alg.equals("RS256") || alg.equals("RS384") || alg.equals("RS512")) { + if(alg.equals("RSA1_5") || alg.equals("RSA-OAEP") || alg.equals("ECDH-ES") || alg.equals("A128KW") || alg.equals("A256KW")) { //generate random content master key Key contentMasterKey = null; try { - KeyPairGenerator keyGen = KeyPairGenerator.getInstance(jwe.getHeader().getAlgorithm()); - SecureRandom random = SecureRandom.getInstance(jwe.getHeader().getAlgorithm()); + KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA"); + SecureRandom random = SecureRandom.getInstance("RSA"); keyGen.initialize(1024, random); KeyPair pair = keyGen.generateKeyPair(); contentMasterKey = pair.getPublic(); @@ -51,7 +51,7 @@ public class RsaEncrypter extends AbstractJweEncrypter { //generate CEK and CIK - String algorithmLength = AlgorithmLength.getByName(jwe.getHeader().getEncryptionMethod()).getStandardName(); + String algorithmLength = AlgorithmLength.getByName(jwe.getHeader().getEncryptionMethod()).toString(); int keyLength = Integer.parseInt(algorithmLength); byte[] contentEncryptionKey = generateContentKey(contentMasterKey.getEncoded(), keyLength, new String("Encryption").getBytes()); byte[] contentIntegrityKey = generateContentKey(contentMasterKey.getEncoded(), keyLength, new String("Integrity").getBytes()); @@ -66,14 +66,10 @@ public class RsaEncrypter extends AbstractJweEncrypter { HmacSigner hmacSigner = new HmacSigner(contentIntegrityKey); jwe = (Jwe) hmacSigner.sign(jwe); - } else if(iv.equals("RS256") || iv.equals("RS384") || iv.equals("RS512")) { - throw new IllegalArgumentException("Integrity Value must use Hmac signing"); } else { throw new IllegalArgumentException("Not a valid integrity value algorithm"); } - } else if(alg.equals("HS256") || alg.equals("HS384") || alg.equals("HS512")){ - throw new IllegalArgumentException("Cannot use Hmac for encryption"); } else { throw new IllegalArgumentException("Not a valid signing algorithm"); } @@ -83,10 +79,25 @@ public class RsaEncrypter extends AbstractJweEncrypter { public byte[] encryptKey(Jwe jwe, Key cmk) { - //TODO:Get public key from keystore, currently null - Cipher cipher; + //TODO:Get public key from keystore, for now randomly generate key pair + + PublicKey publicKey = null; + try { - cipher = Cipher.getInstance(JwtAlgorithm.getByName(jwe.getHeader().getAlgorithm()).getStandardName()); + KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA"); + keyGen.initialize(1024); + KeyPair pair = keyGen.generateKeyPair(); + publicKey = pair.getPublic(); + } catch (NoSuchAlgorithmException e1) { + // TODO Auto-generated catch block + e1.printStackTrace(); + } + + Cipher cipher; + byte[] encryptedKey = null; + + try { + cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.ENCRYPT_MODE, publicKey); encryptedKey = cipher.doFinal(cmk.getEncoded()); @@ -114,8 +125,10 @@ public class RsaEncrypter extends AbstractJweEncrypter { public byte[] encryptClaims(Jwe jwe, byte[] contentEncryptionKey) { Cipher cipher; + byte[] cipherText = null; + try { - cipher = Cipher.getInstance(JwtAlgorithm.getByName(jwe.getHeader().getEncryptionMethod()).getStandardName()); + cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(contentEncryptionKey, "RSA")); cipherText = cipher.doFinal(jwe.getClaims().toString().getBytes()); diff --git a/openid-connect-common/src/test/java/org/mitre/jwe/encryption/impl/RsaDecrypterTest.java b/openid-connect-common/src/test/java/org/mitre/jwe/encryption/impl/RsaDecrypterTest.java new file mode 100644 index 000000000..b86fd0ff8 --- /dev/null +++ b/openid-connect-common/src/test/java/org/mitre/jwe/encryption/impl/RsaDecrypterTest.java @@ -0,0 +1,50 @@ +package org.mitre.jwe.encryption.impl; + +import static org.junit.Assert.assertEquals; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.URL; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mitre.jwe.model.Jwe; +import org.mitre.jwt.encryption.impl.RsaDecrypter; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import com.google.gson.JsonIOException; +import com.google.gson.JsonParser; +import com.google.gson.JsonSyntaxException; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = { "classpath:test-context.xml" }) +public class RsaDecrypterTest { + + URL jweUrl = this.getClass().getResource("/jwe/encryptedJwe"); + + @Before + public void setUp(){ + } + + @After + public void tearDown(){ + } + + @Test + public void decryptTest() throws JsonIOException, JsonSyntaxException, IOException { + + JsonParser parser = new JsonParser(); + String jweString = parser.parse(new BufferedReader(new InputStreamReader(jweUrl.openStream()))).toString(); + + RsaDecrypter rsaDecrypter = new RsaDecrypter(); + Jwe jwe = rsaDecrypter.decrypt(jweString); + + assertEquals(jwe.getCiphertext().toString(), "Now is the time for all good men to come to the aid of their country."); + + } + +} diff --git a/openid-connect-common/src/test/java/org/mitre/jwe/encryption/impl/RsaEncrypterTest.java b/openid-connect-common/src/test/java/org/mitre/jwe/encryption/impl/RsaEncrypterTest.java new file mode 100644 index 000000000..dda682157 --- /dev/null +++ b/openid-connect-common/src/test/java/org/mitre/jwe/encryption/impl/RsaEncrypterTest.java @@ -0,0 +1,62 @@ +package org.mitre.jwe.encryption.impl; + +import static org.junit.Assert.assertEquals; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.URL; +import java.security.NoSuchAlgorithmException; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mitre.jwe.model.Jwe; +import org.mitre.jwe.model.JweHeader; +import org.mitre.jwt.encryption.impl.RsaEncrypter; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import com.google.gson.JsonIOException; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.google.gson.JsonSyntaxException; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = { "classpath:test-context.xml" }) +public class RsaEncrypterTest { + + URL jweHeaderUrl = this.getClass().getResource("/jwe/jweHeader"); + URL jwePlaintextUrl = this.getClass().getResource("/jwe/jwePlaintext"); + + @Before + public void setUp(){ + } + + @After + public void tearDown(){ + } + + @Test + public void encryptTest() throws JsonIOException, JsonSyntaxException, IOException { + + 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(); + + Jwe jwe = new Jwe(new JweHeader(jweHeaderObject), null, jwePlaintextString.getBytes(), null); + + RsaEncrypter rsaEncrypter = new RsaEncrypter(); + try { + jwe = rsaEncrypter.encryptAndSign(jwe); + } catch (NoSuchAlgorithmException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + assertEquals(jwe.toString(), "yooooo"); + + } + +} diff --git a/openid-connect-common/src/test/resources/jwe/encryptedJwe b/openid-connect-common/src/test/resources/jwe/encryptedJwe new file mode 100644 index 000000000..fdde1a1b5 --- /dev/null +++ b/openid-connect-common/src/test/resources/jwe/encryptedJwe @@ -0,0 +1 @@ +eyJhbGciOiJSU0ExXzUiLCJlbmMiOiJBMTI4Q0JDIiwiaW50IjoiSFMyNTYiLCJpdiI6IkF4WThEQ3REYUdsc2JHbGpiM1JvWlEifQ.IPI_z172hSWHMFgED8EG9DM6hIXU_6NaO1DImCn0vNeuoBq847Sl6qw_GHSYHJUQXtXJq7S_CxWVrI82wjrOyaQca5tLZRZc45BfKHeqByThKI261QevEK56SyAwwXfKKZjSvkQ5dwTFSgfy76rMSUvVynHYEhdCatBF9HWTAiXPx7hgZixG1FeP_QCmOylz2VClVyYFCbjKREOwBFf-puNYfO75S3LNlJUtTsGGQL2oTKpMsEiUTdefkje91VX9h8g7908lFsggbjV7NicJsufuXxnTj1fcWIrRDeNIOmakiPEODi0gTSz0ou-W-LWK-3T1zYlOIiIKBjsExQKZ-w._Z_djlIoC4MDSCKireWS2beti4Q6iSG2UjFujQvdz-_PQdUcFNkOulegD6BgjgdFLjeB4HHOO7UHvP8PEDu0a0sA2a_-CI0w2YQQ2QQe35M.c41k4T4eAgCCt63m8ZNmiOinMciFFypOFpvid7i6D0k \ No newline at end of file diff --git a/openid-connect-common/src/test/resources/jwe/jweHeader b/openid-connect-common/src/test/resources/jwe/jweHeader new file mode 100644 index 000000000..9e69f162e --- /dev/null +++ b/openid-connect-common/src/test/resources/jwe/jweHeader @@ -0,0 +1 @@ +{"alg":"RSA1_5","enc":"A128CBC","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 new file mode 100644 index 000000000..43fe94f9d --- /dev/null +++ b/openid-connect-common/src/test/resources/jwe/jwePlaintext @@ -0,0 +1 @@ +"Live long and prosper" \ No newline at end of file