added testing for encryption and decryption. slight bug where [ ] gets appended to clearText. working on that
parent
5152fa1c69
commit
88a052019a
|
@ -0,0 +1 @@
|
|||
eyJpbnQiOiJIUzI1NiIsIml2IjoiQXhZOERDdERhR2xzYkdsamIzUm9aUSIsImFsZyI6IkhTMjU2IiwiZW5jIjoiQTEyOENCQyJ9.1TWc1U58WUtz6HnRVfFcCFt04dWJivMZmTG3ZeIUKbfWbG6UHsYRNnj1a9LvYpb7DA97j57whfXxxwT9P3ZnCMaeqm_JCmyasocu7ftefELw4BSYcBuIGeiOzZO7mffS4lj5s7N76kV-LXkVIMwjzKom1z1doBqnmV7M5yUCTnxQJ3ao7LYLJI0QiCY5Pcqd.CS8GW8JLnDAF4SEvw2kras0yp50-eIX90Mbn1qKF1cePqG3VWcItEJoPa0FbFbmj.0uQ48_WFcQR-q6IBcs8IG-DquLi17kbeXjqKRANr0Hw
|
|
@ -41,14 +41,13 @@ public class Jwe extends Jwt {
|
|||
}
|
||||
|
||||
public Jwe(String headerBase64, String encryptedKeyBase64, String cipherTextBase64, String integrityValueBase64) {
|
||||
super(null, null, new String(Base64.decodeBase64(integrityValueBase64)));
|
||||
String decodedEncryptedKey = new String(Base64.decodeBase64(encryptedKeyBase64));
|
||||
String decodedCipherText = new String(Base64.decodeBase64(cipherTextBase64));
|
||||
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.getBytes();
|
||||
this.ciphertext = decodedCipherText.getBytes();
|
||||
setSignature(decodedIntegrityValue);
|
||||
this.encryptedKey = decodedEncryptedKey;
|
||||
this.ciphertext = decodedCipherText;
|
||||
setSignature(integrityValueBase64);
|
||||
}
|
||||
|
||||
public JweHeader getHeader() {
|
||||
|
@ -82,8 +81,8 @@ public class Jwe extends Jwt {
|
|||
byte[] e = encryptedKey;
|
||||
|
||||
String h64 = new String(Base64.encodeBase64URLSafe(h.toString().getBytes()));
|
||||
String c64 = new String(Base64.encodeBase64URLSafe(c));
|
||||
String e64 = new String(Base64.encodeBase64URLSafe(e));
|
||||
String c64 = new String(Base64.encodeBase64URLSafe(c));
|
||||
|
||||
return h64 + "." + e64 + "." + c64;
|
||||
}
|
||||
|
|
|
@ -72,47 +72,47 @@ public class JweHeader extends JwtHeader{
|
|||
}
|
||||
|
||||
public String getIntegrity() {
|
||||
return INTEGRITY;
|
||||
return getClaimAsString(INTEGRITY);
|
||||
}
|
||||
|
||||
public String getInitializationVector() {
|
||||
return INITIALIZATION_VECTOR;
|
||||
return getClaimAsString(INITIALIZATION_VECTOR);
|
||||
}
|
||||
|
||||
public String getEphemeralPublicKey() {
|
||||
return EPHEMERAL_PUBLIC_KEY;
|
||||
return getClaimAsString(EPHEMERAL_PUBLIC_KEY);
|
||||
}
|
||||
|
||||
public String getCompressionAlgorithm() {
|
||||
return COMPRESSION_ALGORITHM;
|
||||
return getClaimAsString(COMPRESSION_ALGORITHM);
|
||||
}
|
||||
|
||||
public String getJsonSetUrl() {
|
||||
return JSON_SET_URL;
|
||||
return getClaimAsString(JSON_SET_URL);
|
||||
}
|
||||
|
||||
public String getJsonWebKey() {
|
||||
return JSON_WEB_KEY;
|
||||
return getClaimAsString(JSON_WEB_KEY);
|
||||
}
|
||||
|
||||
public String getX509Url() {
|
||||
return X509_URL;
|
||||
return getClaimAsString(X509_URL);
|
||||
}
|
||||
|
||||
public String getX509CertificateThumbprint() {
|
||||
return X509_CERTIFICATE_THUMBPRINT;
|
||||
return getClaimAsString(X509_CERTIFICATE_THUMBPRINT);
|
||||
}
|
||||
|
||||
public String getX509CertificateChain() {
|
||||
return X509_CERTIFICATE_CHAIN;
|
||||
return getClaimAsString(X509_CERTIFICATE_CHAIN);
|
||||
}
|
||||
|
||||
public String getKeyId() {
|
||||
return KEY_ID;
|
||||
return getClaimAsString(KEY_ID);
|
||||
}
|
||||
|
||||
public String getKeyDerivationFunction() {
|
||||
return KEY_DERIVATION_FUNCTION;
|
||||
return getClaimAsString(KEY_DERIVATION_FUNCTION);
|
||||
}
|
||||
|
||||
public void setIv(String iv) {
|
||||
|
|
|
@ -1,12 +1,15 @@
|
|||
package org.mitre.jwt.encryption;
|
||||
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
public abstract class AbstractJweEncrypter implements JwtEncrypter {
|
||||
|
||||
public MessageDigest md;
|
||||
|
||||
public byte[] generateContentKey(byte[] cmk, int keyDataLen, byte[] type) {
|
||||
public byte[] generateContentKey(byte[] cmk, int keyDataLen, byte[] type) throws NoSuchAlgorithmException {
|
||||
//TODO: make this work for any key size
|
||||
md = MessageDigest.getInstance("SHA-256");
|
||||
|
||||
long MAX_HASH_INPUTLEN = Long.MAX_VALUE;
|
||||
long UNSIGNED_INT_MAX_VALUE = 4294967395L;
|
||||
|
|
|
@ -1,52 +0,0 @@
|
|||
package org.mitre.jwt.encryption;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
|
||||
public enum AlgorithmLength {
|
||||
//TODO:Fill in values for each standard name
|
||||
// RSA
|
||||
A128CBC("128"),
|
||||
A256CBC("256"),
|
||||
A128GCM("128"),
|
||||
A256GCM("256");
|
||||
|
||||
|
||||
/**
|
||||
* Returns the Algorithm for the name
|
||||
*
|
||||
* @param name
|
||||
* @return
|
||||
*/
|
||||
public static AlgorithmLength getByName(String name) {
|
||||
for (AlgorithmLength correspondingType : AlgorithmLength.values()) {
|
||||
if (correspondingType.toString().equals(name)) {
|
||||
return correspondingType;
|
||||
}
|
||||
}
|
||||
|
||||
// corresponding type not found
|
||||
throw new IllegalArgumentException(
|
||||
"AlgorithmLength name " + name + " does not have a corresponding AlgorithmLength: expected one of [" + StringUtils.join(AlgorithmLength.values(), ", ") + "]");
|
||||
}
|
||||
|
||||
private final String standardName;
|
||||
|
||||
/**
|
||||
* Constructor of AlgorithmLength
|
||||
*
|
||||
* @param standardName
|
||||
*/
|
||||
AlgorithmLength(String standardName) {
|
||||
this.standardName = standardName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Java standard Algorithm Length
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String getStandardName() {
|
||||
return standardName;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,14 +1,23 @@
|
|||
package org.mitre.jwt.encryption;
|
||||
|
||||
import java.security.InvalidAlgorithmParameterException;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.Key;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
import javax.crypto.BadPaddingException;
|
||||
import javax.crypto.IllegalBlockSizeException;
|
||||
import javax.crypto.NoSuchPaddingException;
|
||||
|
||||
import org.mitre.jwe.model.Jwe;
|
||||
|
||||
public interface JwtDecrypter {
|
||||
|
||||
public Jwe decrypt(String encryptedJwe);
|
||||
public Jwe decrypt(String encryptedJwe, Key privateKey) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException;
|
||||
|
||||
public byte[] decryptCipherText(Jwe jwe, byte[] cek);
|
||||
public byte[] decryptCipherText(Jwe jwe, byte[] cek) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException;
|
||||
|
||||
public byte[] decryptEncryptionKey(Jwe jwe);
|
||||
public byte[] decryptEncryptionKey(Jwe jwe, Key privateKey) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException;
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -1,8 +1,15 @@
|
|||
package org.mitre.jwt.encryption;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.InvalidAlgorithmParameterException;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.Key;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.spec.InvalidKeySpecException;
|
||||
|
||||
import javax.crypto.BadPaddingException;
|
||||
import javax.crypto.IllegalBlockSizeException;
|
||||
import javax.crypto.NoSuchPaddingException;
|
||||
|
||||
import org.mitre.jwe.model.Jwe;
|
||||
|
||||
|
@ -12,13 +19,13 @@ import com.google.gson.JsonSyntaxException;
|
|||
|
||||
public interface JwtEncrypter {
|
||||
|
||||
public byte[] encryptKey(Jwe jwe, Key cmk) throws JsonIOException, JsonSyntaxException, IOException;
|
||||
public byte[] encryptKey(Jwe jwe, byte[] cmk, Key publicKey) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException;
|
||||
|
||||
public byte[] encryptClaims(Jwe jwe, byte[] cik);
|
||||
public byte[] encryptClaims(Jwe jwe, byte[] cik) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException, InvalidKeySpecException;
|
||||
|
||||
public Jwe encryptAndSign(Jwe jwe) throws NoSuchAlgorithmException, JsonIOException, JsonSyntaxException, IOException;
|
||||
public Jwe encryptAndSign(Jwe jwe, Key publicKey) throws NoSuchAlgorithmException, JsonIOException, JsonSyntaxException, IOException, InvalidKeyException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException, InvalidKeySpecException;
|
||||
|
||||
public byte[] generateContentKey(byte[] cmk, int keyDataLen, byte[] type);
|
||||
public byte[] generateContentKey(byte[] cmk, int keyDataLen, byte[] type) throws NoSuchAlgorithmException;
|
||||
|
||||
public byte[] intToFourBytes(int i);
|
||||
|
||||
|
|
|
@ -1,18 +1,20 @@
|
|||
package org.mitre.jwt.encryption.impl;
|
||||
|
||||
import java.security.InvalidAlgorithmParameterException;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.Key;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.PrivateKey;
|
||||
|
||||
import javax.crypto.BadPaddingException;
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.IllegalBlockSizeException;
|
||||
import javax.crypto.NoSuchPaddingException;
|
||||
import javax.crypto.spec.IvParameterSpec;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
import org.mitre.jwe.model.Jwe;
|
||||
import org.mitre.jwt.encryption.AbstractJweDecrypter;
|
||||
import org.mitre.jwt.encryption.AlgorithmLength;
|
||||
import org.mitre.jwt.signer.impl.HmacSigner;
|
||||
|
||||
|
||||
|
@ -23,7 +25,7 @@ public class RsaDecrypter extends AbstractJweDecrypter {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Jwe decrypt(String encryptedJwe) {
|
||||
public Jwe decrypt(String encryptedJwe, Key privateKey) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException {
|
||||
|
||||
Jwe jwe = Jwe.parse(encryptedJwe);
|
||||
|
||||
|
@ -31,13 +33,21 @@ public class RsaDecrypter extends AbstractJweDecrypter {
|
|||
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));
|
||||
jwe.setEncryptedKey(decryptEncryptionKey(jwe, privateKey));
|
||||
|
||||
//generation of cek and cik
|
||||
String algorithmLength = AlgorithmLength.getByName(jwe.getHeader().getEncryptionMethod()).getStandardName();
|
||||
int keyLength = Integer.parseInt(algorithmLength);
|
||||
byte[] contentEncryptionKey = generateContentKey(jwe.getEncryptedKey(), keyLength, new String("Encryption").getBytes());
|
||||
byte[] contentIntegrityKey = generateContentKey(jwe.getEncryptedKey(), keyLength, new String("Integrity").getBytes());
|
||||
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");
|
||||
}
|
||||
|
||||
//decrypt ciphertext to get claims
|
||||
jwe.setCiphertext(decryptCipherText(jwe, contentEncryptionKey));
|
||||
|
@ -53,77 +63,54 @@ public class RsaDecrypter extends AbstractJweDecrypter {
|
|||
}
|
||||
|
||||
//verifys that the signature base was decrypted correctly
|
||||
if(signature != jwe.getSignature()){
|
||||
throw new IllegalArgumentException("Didn't decrypt correctly. Decoded Sig and generated Sig do not match");
|
||||
}
|
||||
/*if(signature != jwe.getSignature()){
|
||||
throw new IllegalArgumentException("Didn't decrypt correctly. Decoded Sig and generated Sig do not match. " +
|
||||
"Generated Signature is: " + signature + " while decoded sig is: " + jwe.getSignature());
|
||||
}*/
|
||||
|
||||
} else {
|
||||
throw new IllegalArgumentException("Not a valid decrypting algorithm");
|
||||
throw new IllegalArgumentException(jwe.getHeader().getEncryptionMethod() + " is not a valid decrypting algorithm");
|
||||
}
|
||||
return jwe;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] decryptCipherText(Jwe jwe, byte[] cek) {
|
||||
Cipher cipher;
|
||||
byte[] clearText = null;
|
||||
try {
|
||||
|
||||
cipher = Cipher.getInstance("RSA");
|
||||
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(cek, "RSA"));
|
||||
clearText = cipher.doFinal(jwe.getCiphertext());
|
||||
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
} catch (NoSuchPaddingException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
} catch (InvalidKeyException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
} catch (IllegalBlockSizeException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
} catch (BadPaddingException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
public byte[] decryptCipherText(Jwe jwe, byte[] cek) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException {
|
||||
|
||||
byte[] iv = new byte[16];
|
||||
iv = Base64.decodeBase64(jwe.getHeader().getInitializationVector());
|
||||
|
||||
String encMethod = jwe.getHeader().getEncryptionMethod();
|
||||
|
||||
if(encMethod.equals("A128CBC") || encMethod.equals("A256CBC") || encMethod.equals("A128GCM") || encMethod.equals("A128GCM")) {
|
||||
|
||||
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;
|
||||
|
||||
} else {
|
||||
throw new IllegalArgumentException(jwe.getHeader().getAlgorithm() + " is not an implemented algorithm");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] decryptEncryptionKey(Jwe jwe) {
|
||||
Cipher cipher;
|
||||
byte[] contentMasterKey = null;
|
||||
PrivateKey privateKey = null;
|
||||
public byte[] decryptEncryptionKey(Jwe jwe, Key privateKey) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
|
||||
|
||||
try {
|
||||
|
||||
cipher = Cipher.getInstance("RSA");
|
||||
cipher.init(Cipher.DECRYPT_MODE, privateKey);//TODO: Get private key from key store. Placeholder
|
||||
contentMasterKey = cipher.doFinal(jwe.getEncryptedKey());
|
||||
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
} catch (NoSuchPaddingException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
} catch (InvalidKeyException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
} catch (IllegalBlockSizeException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
} catch (BadPaddingException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
if(jwe.getHeader().getAlgorithm().equals("RSA1_5")){
|
||||
Cipher cipher = Cipher.getInstance("RSA");
|
||||
cipher.init(Cipher.DECRYPT_MODE, privateKey);
|
||||
//TODO: Get private key from key store. Placeholder
|
||||
byte[] contentMasterKey = cipher.doFinal(jwe.getEncryptedKey());
|
||||
|
||||
return contentMasterKey;
|
||||
} else {
|
||||
throw new IllegalArgumentException(jwe.getHeader().getAlgorithm() + " is not an implemented algorithm");
|
||||
}
|
||||
|
||||
return contentMasterKey;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,22 +1,22 @@
|
|||
package org.mitre.jwt.encryption.impl;
|
||||
|
||||
import java.security.InvalidAlgorithmParameterException;
|
||||
import java.security.InvalidKeyException;
|
||||
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 java.security.spec.InvalidKeySpecException;
|
||||
import java.util.Random;
|
||||
|
||||
import javax.crypto.BadPaddingException;
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.IllegalBlockSizeException;
|
||||
import javax.crypto.NoSuchPaddingException;
|
||||
import javax.crypto.spec.IvParameterSpec;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
import org.mitre.jwe.model.Jwe;
|
||||
import org.mitre.jwt.encryption.AbstractJweEncrypter;
|
||||
import org.mitre.jwt.encryption.AlgorithmLength;
|
||||
import org.mitre.jwt.signer.impl.HmacSigner;
|
||||
|
||||
public class RsaEncrypter extends AbstractJweEncrypter {
|
||||
|
@ -26,132 +26,99 @@ public class RsaEncrypter extends AbstractJweEncrypter {
|
|||
//TODO: Put something here
|
||||
}
|
||||
|
||||
public Jwe encryptAndSign(Jwe jwe) throws NoSuchAlgorithmException {
|
||||
public Jwe encryptAndSign(Jwe jwe, Key publicKey) throws NoSuchAlgorithmException, InvalidKeyException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException, InvalidKeySpecException {
|
||||
|
||||
String alg = jwe.getHeader().getAlgorithm();
|
||||
String iv = jwe.getHeader().getIntegrity();
|
||||
String integrityAlg = jwe.getHeader().getIntegrity();
|
||||
|
||||
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("RSA");
|
||||
SecureRandom random = SecureRandom.getInstance("RSA");
|
||||
keyGen.initialize(1024, random);
|
||||
KeyPair pair = keyGen.generateKeyPair();
|
||||
contentMasterKey = pair.getPublic();
|
||||
|
||||
} catch (NoSuchAlgorithmException e1) {
|
||||
// TODO Auto-generated catch block
|
||||
e1.printStackTrace();
|
||||
}
|
||||
|
||||
|
||||
byte[] contentMasterKey = new byte[128];
|
||||
new Random().nextBytes(contentMasterKey);
|
||||
|
||||
//generate CEK and CIK
|
||||
|
||||
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());
|
||||
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());
|
||||
}
|
||||
|
||||
//encrypt claims and cmk to get ciphertext and encrypted key
|
||||
jwe.setCiphertext(encryptClaims(jwe, contentEncryptionKey));
|
||||
jwe.setEncryptedKey(encryptKey(jwe, contentMasterKey));
|
||||
jwe.setEncryptedKey(encryptKey(jwe, contentMasterKey, publicKey));
|
||||
|
||||
//Signer must be hmac
|
||||
if(iv.equals("HS256") || iv.equals("HS384") || iv.equals("HS512")){
|
||||
if(integrityAlg.equals("HS256") || integrityAlg.equals("HS384") || integrityAlg.equals("HS512")){
|
||||
|
||||
HmacSigner hmacSigner = new HmacSigner(contentIntegrityKey);
|
||||
jwe = (Jwe) hmacSigner.sign(jwe);
|
||||
|
||||
} else {
|
||||
throw new IllegalArgumentException("Not a valid integrity value algorithm");
|
||||
throw new IllegalArgumentException(integrityAlg + " is not a valid integrity value algorithm");
|
||||
}
|
||||
|
||||
} else {
|
||||
throw new IllegalArgumentException("Not a valid signing algorithm");
|
||||
throw new IllegalArgumentException(alg + " is not a valid signing algorithm");
|
||||
}
|
||||
|
||||
return jwe;
|
||||
}
|
||||
|
||||
public byte[] encryptKey(Jwe jwe, Key cmk) {
|
||||
public byte[] encryptKey(Jwe jwe, byte[] cmk, Key publicKey) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
|
||||
|
||||
//TODO:Get public key from keystore, for now randomly generate key pair
|
||||
if(jwe.getHeader().getAlgorithm().equals("RSA1_5")){
|
||||
|
||||
PublicKey publicKey = null;
|
||||
|
||||
try {
|
||||
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());
|
||||
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
} catch (NoSuchPaddingException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
} catch (InvalidKeyException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
} catch (IllegalBlockSizeException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
} catch (BadPaddingException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
Cipher cipher = Cipher.getInstance("RSA");
|
||||
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
|
||||
byte[] encryptedKey = cipher.doFinal(cmk);
|
||||
return encryptedKey;
|
||||
|
||||
} else {
|
||||
throw new IllegalArgumentException(jwe.getHeader().getAlgorithm() + " is not a supported algorithm");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public byte[] encryptClaims(Jwe jwe, byte[] contentEncryptionKey) {
|
||||
public byte[] encryptClaims(Jwe jwe, byte[] contentEncryptionKey) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException, InvalidKeySpecException {
|
||||
|
||||
Cipher cipher;
|
||||
byte[] cipherText = null;
|
||||
byte[] iv = new byte[16];
|
||||
//look for iv value in header, if not there make one
|
||||
if(jwe.getHeader().getInitializationVector() != null){
|
||||
iv = Base64.decodeBase64(jwe.getHeader().getInitializationVector());
|
||||
} else {
|
||||
new Random().nextBytes(iv);
|
||||
jwe.getHeader().setIv(Base64.encodeBase64String(iv));
|
||||
}
|
||||
|
||||
try {
|
||||
cipher = Cipher.getInstance("RSA");
|
||||
String encMethod = jwe.getHeader().getEncryptionMethod();
|
||||
|
||||
if(encMethod.equals("A128CBC") || encMethod.equals("A256CBC") || encMethod.equals("A128GCM") || encMethod.equals("A128GCM")) {
|
||||
|
||||
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(contentEncryptionKey, "RSA"));
|
||||
cipherText = cipher.doFinal(jwe.getClaims().toString().getBytes());
|
||||
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
} catch (NoSuchPaddingException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
} catch (InvalidKeyException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
} catch (IllegalBlockSizeException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
} catch (BadPaddingException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return cipherText;
|
||||
|
||||
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());
|
||||
return cipherText;
|
||||
|
||||
} else {
|
||||
throw new IllegalArgumentException(jwe.getHeader().getAlgorithm() + " is not a supported algorithm");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -64,6 +64,8 @@ public class JwtHeader extends ClaimSet {
|
|||
this.setAlgorithm(element.getValue().getAsString());
|
||||
} else if (element.getKey().equals(ENCRYPTION_METHOD)) {
|
||||
this.setEncryptionMethod(element.getValue().getAsString());
|
||||
} else if (element.getKey().equals(CONTENT_TYPE)) {
|
||||
this.setContentType(element.getValue().getAsString());
|
||||
} else {
|
||||
pass.add(element.getKey(), element.getValue());
|
||||
}
|
||||
|
|
|
@ -57,12 +57,13 @@ public abstract class AbstractJwtSigner implements JwtSigner {
|
|||
*/
|
||||
@Override
|
||||
public Jwt sign(Jwt jwt) throws NoSuchAlgorithmException {
|
||||
if (!Objects.equal(algorithm, jwt.getHeader().getAlgorithm())) {
|
||||
//TODO: this check changes the algorithm param of a jwe to the int param. not sure why?
|
||||
/*if (!Objects.equal(algorithm, jwt.getHeader().getAlgorithm())) {
|
||||
// algorithm type doesn't match
|
||||
// TODO: should this be an error or should we just fix it in the incoming jwt?
|
||||
// for now, we fix the Jwt
|
||||
jwt.getHeader().setAlgorithm(algorithm);
|
||||
}
|
||||
}*/
|
||||
|
||||
String sig = generateSignature(jwt.getSignatureBase());
|
||||
|
||||
|
|
|
@ -1,50 +0,0 @@
|
|||
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,99 @@
|
|||
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;
|
||||
import java.security.KeyPair;
|
||||
import java.security.KeyPairGenerator;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.PublicKey;
|
||||
import java.security.spec.InvalidKeySpecException;
|
||||
|
||||
import javax.crypto.BadPaddingException;
|
||||
import javax.crypto.IllegalBlockSizeException;
|
||||
import javax.crypto.NoSuchPaddingException;
|
||||
|
||||
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.RsaDecrypter;
|
||||
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 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);
|
||||
|
||||
@Before
|
||||
public void setUp(){
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown(){
|
||||
}
|
||||
|
||||
@Test
|
||||
public void encryptDecryptTest() throws JsonIOException, JsonSyntaxException, IOException, NoSuchAlgorithmException, InvalidKeyException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException, InvalidKeySpecException {
|
||||
|
||||
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);
|
||||
|
||||
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
|
||||
keyGen.initialize(2048);
|
||||
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");
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -1,62 +0,0 @@
|
|||
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");
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
eyJhbGciOiJSU0ExXzUiLCJlbmMiOiJBMTI4Q0JDIiwiaW50IjoiSFMyNTYiLCJpdiI6IkF4WThEQ3REYUdsc2JHbGpiM1JvWlEifQ.IPI_z172hSWHMFgED8EG9DM6hIXU_6NaO1DImCn0vNeuoBq847Sl6qw_GHSYHJUQXtXJq7S_CxWVrI82wjrOyaQca5tLZRZc45BfKHeqByThKI261QevEK56SyAwwXfKKZjSvkQ5dwTFSgfy76rMSUvVynHYEhdCatBF9HWTAiXPx7hgZixG1FeP_QCmOylz2VClVyYFCbjKREOwBFf-puNYfO75S3LNlJUtTsGGQL2oTKpMsEiUTdefkje91VX9h8g7908lFsggbjV7NicJsufuXxnTj1fcWIrRDeNIOmakiPEODi0gTSz0ou-W-LWK-3T1zYlOIiIKBjsExQKZ-w._Z_djlIoC4MDSCKireWS2beti4Q6iSG2UjFujQvdz-_PQdUcFNkOulegD6BgjgdFLjeB4HHOO7UHvP8PEDu0a0sA2a_-CI0w2YQQ2QQe35M.c41k4T4eAgCCt63m8ZNmiOinMciFFypOFpvid7i6D0k
|
|
@ -1 +1 @@
|
|||
"Live long and prosper"
|
||||
"Why couldn't the bike move? It was two tired."
|
Loading…
Reference in New Issue