updated encrypter and decrypter to use enum class rather than fragile parsing
parent
5f80ebc89a
commit
61c7231d9a
|
@ -1,5 +1,7 @@
|
||||||
package org.mitre.jwt.encryption;
|
package org.mitre.jwt.encryption;
|
||||||
|
|
||||||
|
import org.apache.commons.lang.StringUtils;
|
||||||
|
|
||||||
public enum JweAlgorithms {
|
public enum JweAlgorithms {
|
||||||
|
|
||||||
//Key Derivation Function Values
|
//Key Derivation Function Values
|
||||||
|
@ -20,4 +22,18 @@ public enum JweAlgorithms {
|
||||||
this.value = value;
|
this.value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String getByName(String name) {
|
||||||
|
for (JweAlgorithms correspondingType : JweAlgorithms.values()) {
|
||||||
|
if (correspondingType.toString().equals(name)) {
|
||||||
|
return correspondingType.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"JweAlgorithm name " + name + " does not have a corresponding JweAlgorithm: expected one of [" + StringUtils.join(JweAlgorithms.values(), ", ") + "]");
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@ import javax.crypto.spec.SecretKeySpec;
|
||||||
import org.apache.commons.codec.binary.Base64;
|
import org.apache.commons.codec.binary.Base64;
|
||||||
import org.mitre.jwe.model.Jwe;
|
import org.mitre.jwe.model.Jwe;
|
||||||
import org.mitre.jwt.encryption.AbstractJweDecrypter;
|
import org.mitre.jwt.encryption.AbstractJweDecrypter;
|
||||||
import org.mitre.jwt.signer.impl.HmacSigner;
|
import org.mitre.jwt.encryption.JweAlgorithms;
|
||||||
|
|
||||||
|
|
||||||
public class RsaDecrypter extends AbstractJweDecrypter {
|
public class RsaDecrypter extends AbstractJweDecrypter {
|
||||||
|
@ -33,35 +33,16 @@ public class RsaDecrypter extends AbstractJweDecrypter {
|
||||||
|
|
||||||
//generation of cek and cik
|
//generation of cek and cik
|
||||||
byte[] contentEncryptionKey = null;
|
byte[] contentEncryptionKey = null;
|
||||||
byte[] contentIntegrityKey = null;
|
|
||||||
//check what the key length is
|
//check what the key length is
|
||||||
String encMethod = jwe.getHeader().getKeyDerivationFunction();
|
String kdf = jwe.getHeader().getKeyDerivationFunction();
|
||||||
char[] array = encMethod.toCharArray();
|
String keyLength = JweAlgorithms.getByName(kdf);
|
||||||
String keyBitLengthString = new String("" + array[2] + array[3] + array[4]);
|
int keyBitLength = Integer.parseInt(keyLength);
|
||||||
int keyBitLength = Integer.parseInt(keyBitLengthString);
|
|
||||||
//generate cek and cik
|
//generate cek and cik
|
||||||
contentEncryptionKey = generateContentKey(jwe.getEncryptedKey(), keyBitLength, "Encryption".getBytes());
|
contentEncryptionKey = generateContentKey(jwe.getEncryptedKey(), keyBitLength, "Encryption".getBytes());
|
||||||
contentIntegrityKey = generateContentKey(jwe.getEncryptedKey(), keyBitLength, "Integrity".getBytes());
|
|
||||||
|
|
||||||
//decrypt ciphertext to get claims
|
//decrypt ciphertext to get claims
|
||||||
jwe.setCiphertext(decryptCipherText(jwe, contentEncryptionKey));
|
jwe.setCiphertext(decryptCipherText(jwe, contentEncryptionKey));
|
||||||
|
|
||||||
//generate signature for decrypted signature base in order to verify that decryption worked
|
|
||||||
/*String signature = null;
|
|
||||||
try {
|
|
||||||
HmacSigner hmacSigner = new HmacSigner(contentIntegrityKey);
|
|
||||||
signature = hmacSigner.generateSignature(jwe.getSignatureBase());
|
|
||||||
} catch (NoSuchAlgorithmException e) {
|
|
||||||
// TODO Auto-generated catch block
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
//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. " +
|
|
||||||
"Generated Signature is: " + signature + " while decoded sig is: " + jwe.getSignature());
|
|
||||||
}*/
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalArgumentException(jwe.getHeader().getEncryptionMethod() + " is not a valid decrypting algorithm");
|
throw new IllegalArgumentException(jwe.getHeader().getEncryptionMethod() + " is not a valid decrypting algorithm");
|
||||||
}
|
}
|
||||||
|
@ -78,10 +59,9 @@ public class RsaDecrypter extends AbstractJweDecrypter {
|
||||||
//TODO: should also check for A128GCM and A256GCM, but Cipher.getInstance() does not support the GCM mode. For now, don't use them
|
//TODO: should also check for A128GCM and A256GCM, but Cipher.getInstance() does not support the GCM mode. For now, don't use them
|
||||||
if(encMethod.equals("A128CBC") || encMethod.equals("A256CBC")) {
|
if(encMethod.equals("A128CBC") || encMethod.equals("A256CBC")) {
|
||||||
|
|
||||||
String delims = "[8,6]+";
|
String mode = JweAlgorithms.getByName(encMethod);
|
||||||
String[] mode = encMethod.split(delims);
|
|
||||||
|
|
||||||
Cipher cipher = Cipher.getInstance("AES/" + mode[1] + "/PKCS5Padding");
|
Cipher cipher = Cipher.getInstance("AES/" + mode + "/PKCS5Padding");
|
||||||
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(contentEncryptionKey, "AES"), new IvParameterSpec(iv));
|
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(contentEncryptionKey, "AES"), new IvParameterSpec(iv));
|
||||||
byte[] clearText = cipher.doFinal(jwe.getCiphertext());
|
byte[] clearText = cipher.doFinal(jwe.getCiphertext());
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,7 @@ import javax.crypto.spec.SecretKeySpec;
|
||||||
import org.apache.commons.codec.binary.Base64;
|
import org.apache.commons.codec.binary.Base64;
|
||||||
import org.mitre.jwe.model.Jwe;
|
import org.mitre.jwe.model.Jwe;
|
||||||
import org.mitre.jwt.encryption.AbstractJweEncrypter;
|
import org.mitre.jwt.encryption.AbstractJweEncrypter;
|
||||||
|
import org.mitre.jwt.encryption.JweAlgorithms;
|
||||||
import org.mitre.jwt.signer.impl.HmacSigner;
|
import org.mitre.jwt.signer.impl.HmacSigner;
|
||||||
|
|
||||||
public class RsaEncrypter extends AbstractJweEncrypter {
|
public class RsaEncrypter extends AbstractJweEncrypter {
|
||||||
|
@ -31,10 +32,9 @@ public class RsaEncrypter extends AbstractJweEncrypter {
|
||||||
//generate random content master key
|
//generate random content master key
|
||||||
|
|
||||||
//check what the key length is
|
//check what the key length is
|
||||||
String encMethod = jwe.getHeader().getKeyDerivationFunction();
|
String kdf = jwe.getHeader().getKeyDerivationFunction();
|
||||||
char[] array = encMethod.toCharArray();
|
String keyLength = JweAlgorithms.getByName(kdf);
|
||||||
String keyBitLengthString = new String("" + array[2] + array[3] + array[4]);
|
int keyBitLength = Integer.parseInt(keyLength);
|
||||||
int keyBitLength = Integer.parseInt(keyBitLengthString);
|
|
||||||
|
|
||||||
byte[] contentMasterKey = new byte[keyBitLength];
|
byte[] contentMasterKey = new byte[keyBitLength];
|
||||||
new Random().nextBytes(contentMasterKey);
|
new Random().nextBytes(contentMasterKey);
|
||||||
|
@ -96,11 +96,10 @@ public class RsaEncrypter extends AbstractJweEncrypter {
|
||||||
String encMethod = jwe.getHeader().getEncryptionMethod();
|
String encMethod = jwe.getHeader().getEncryptionMethod();
|
||||||
//TODO: should also check for A128GCM and A256GCM, but Cipher.getInstance() does not support the GCM mode. For now, don't use them
|
//TODO: should also check for A128GCM and A256GCM, but Cipher.getInstance() does not support the GCM mode. For now, don't use them
|
||||||
if(encMethod.equals("A128CBC") || encMethod.equals("A256CBC")) {
|
if(encMethod.equals("A128CBC") || encMethod.equals("A256CBC")) {
|
||||||
// FIXME: this is fragile
|
|
||||||
String delims = "[8,6]+";
|
|
||||||
String[] mode = encMethod.split(delims);
|
|
||||||
|
|
||||||
Cipher cipher = Cipher.getInstance("AES/" + mode[1] + "/PKCS5Padding");
|
String mode = JweAlgorithms.getByName(encMethod);
|
||||||
|
|
||||||
|
Cipher cipher = Cipher.getInstance("AES/" + mode + "/PKCS5Padding");
|
||||||
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(contentEncryptionKey, "AES"), new IvParameterSpec(iv));
|
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(contentEncryptionKey, "AES"), new IvParameterSpec(iv));
|
||||||
byte[] cipherText = cipher.doFinal(jwe.getCiphertext());
|
byte[] cipherText = cipher.doFinal(jwe.getCiphertext());
|
||||||
return cipherText;
|
return cipherText;
|
||||||
|
|
|
@ -20,7 +20,6 @@ import javax.crypto.Cipher;
|
||||||
import javax.crypto.IllegalBlockSizeException;
|
import javax.crypto.IllegalBlockSizeException;
|
||||||
import javax.crypto.NoSuchPaddingException;
|
import javax.crypto.NoSuchPaddingException;
|
||||||
|
|
||||||
import org.easymock.internal.matchers.GreaterThan;
|
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Assume;
|
import org.junit.Assume;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
|
@ -64,14 +63,14 @@ public class RsaEncrypterDecrypterTest {
|
||||||
//read in header and plaintext from files
|
//read in header and plaintext from files
|
||||||
JsonParser parser = new JsonParser();
|
JsonParser parser = new JsonParser();
|
||||||
JsonObject jweHeaderObject = parser.parse(new BufferedReader(new InputStreamReader(jweHeaderUrl.openStream()))).getAsJsonObject();
|
JsonObject jweHeaderObject = parser.parse(new BufferedReader(new InputStreamReader(jweHeaderUrl.openStream()))).getAsJsonObject();
|
||||||
//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
|
//generate key pair. this will be passed in from the user
|
||||||
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
|
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
|
||||||
keyGen.initialize(4096);
|
keyGen.initialize(4096);
|
||||||
KeyPair pair = keyGen.generateKeyPair();
|
KeyPair pair = keyGen.generateKeyPair();
|
||||||
PublicKey publicKey = pair.getPublic();
|
PublicKey publicKey = pair.getPublic();
|
||||||
PrivateKey privateKey = pair.getPrivate();
|
PrivateKey privateKey = pair.getPrivate();
|
||||||
|
//create jwe based on header and plaintext
|
||||||
|
Jwe jwe = new Jwe(new JweHeader(jweHeaderObject), null, jwePlaintextString.getBytes(), null);
|
||||||
//encrypt
|
//encrypt
|
||||||
RsaEncrypter rsaEncrypter = new RsaEncrypter();
|
RsaEncrypter rsaEncrypter = new RsaEncrypter();
|
||||||
jwe = rsaEncrypter.encryptAndSign(jwe, publicKey);
|
jwe = rsaEncrypter.encryptAndSign(jwe, publicKey);
|
||||||
|
|
Loading…
Reference in New Issue