added tests for encryption and decryption. WIP

pull/105/head
Mike Derryberry 2012-07-11 10:34:31 -04:00
parent 26792d2fba
commit 5152fa1c69
11 changed files with 162 additions and 70 deletions

View File

@ -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);

View File

@ -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];

View File

@ -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;

View File

@ -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);

View File

@ -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 {

View File

@ -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());

View File

@ -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.");
}
}

View File

@ -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");
}
}

View File

@ -0,0 +1 @@
eyJhbGciOiJSU0ExXzUiLCJlbmMiOiJBMTI4Q0JDIiwiaW50IjoiSFMyNTYiLCJpdiI6IkF4WThEQ3REYUdsc2JHbGpiM1JvWlEifQ.IPI_z172hSWHMFgED8EG9DM6hIXU_6NaO1DImCn0vNeuoBq847Sl6qw_GHSYHJUQXtXJq7S_CxWVrI82wjrOyaQca5tLZRZc45BfKHeqByThKI261QevEK56SyAwwXfKKZjSvkQ5dwTFSgfy76rMSUvVynHYEhdCatBF9HWTAiXPx7hgZixG1FeP_QCmOylz2VClVyYFCbjKREOwBFf-puNYfO75S3LNlJUtTsGGQL2oTKpMsEiUTdefkje91VX9h8g7908lFsggbjV7NicJsufuXxnTj1fcWIrRDeNIOmakiPEODi0gTSz0ou-W-LWK-3T1zYlOIiIKBjsExQKZ-w._Z_djlIoC4MDSCKireWS2beti4Q6iSG2UjFujQvdz-_PQdUcFNkOulegD6BgjgdFLjeB4HHOO7UHvP8PEDu0a0sA2a_-CI0w2YQQ2QQe35M.c41k4T4eAgCCt63m8ZNmiOinMciFFypOFpvid7i6D0k

View File

@ -0,0 +1 @@
{"alg":"RSA1_5","enc":"A128CBC","int":"HS256","iv":"AxY8DCtDaGlsbGljb3RoZQ"}

View File

@ -0,0 +1 @@
"Live long and prosper"