added tests for encryption and decryption. WIP
parent
26792d2fba
commit
5152fa1c69
|
@ -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);
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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.");
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -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");
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
eyJhbGciOiJSU0ExXzUiLCJlbmMiOiJBMTI4Q0JDIiwiaW50IjoiSFMyNTYiLCJpdiI6IkF4WThEQ3REYUdsc2JHbGpiM1JvWlEifQ.IPI_z172hSWHMFgED8EG9DM6hIXU_6NaO1DImCn0vNeuoBq847Sl6qw_GHSYHJUQXtXJq7S_CxWVrI82wjrOyaQca5tLZRZc45BfKHeqByThKI261QevEK56SyAwwXfKKZjSvkQ5dwTFSgfy76rMSUvVynHYEhdCatBF9HWTAiXPx7hgZixG1FeP_QCmOylz2VClVyYFCbjKREOwBFf-puNYfO75S3LNlJUtTsGGQL2oTKpMsEiUTdefkje91VX9h8g7908lFsggbjV7NicJsufuXxnTj1fcWIrRDeNIOmakiPEODi0gTSz0ou-W-LWK-3T1zYlOIiIKBjsExQKZ-w._Z_djlIoC4MDSCKireWS2beti4Q6iSG2UjFujQvdz-_PQdUcFNkOulegD6BgjgdFLjeB4HHOO7UHvP8PEDu0a0sA2a_-CI0w2YQQ2QQe35M.c41k4T4eAgCCt63m8ZNmiOinMciFFypOFpvid7i6D0k
|
|
@ -0,0 +1 @@
|
|||
{"alg":"RSA1_5","enc":"A128CBC","int":"HS256","iv":"AxY8DCtDaGlsbGljb3RoZQ"}
|
|
@ -0,0 +1 @@
|
|||
"Live long and prosper"
|
Loading…
Reference in New Issue