updated decryption to generate cik and cek based off of key derivation
parent
d86ee2329b
commit
26792d2fba
|
@ -1,5 +1,6 @@
|
||||||
package org.mitre.jwt.encryption;
|
package org.mitre.jwt.encryption;
|
||||||
|
|
||||||
|
import java.security.MessageDigest;
|
||||||
import java.security.PrivateKey;
|
import java.security.PrivateKey;
|
||||||
import java.security.PublicKey;
|
import java.security.PublicKey;
|
||||||
|
|
||||||
|
@ -9,6 +10,8 @@ public abstract class AbstractJweDecrypter implements JwtDecrypter {
|
||||||
|
|
||||||
private PublicKey publicKey;
|
private PublicKey publicKey;
|
||||||
|
|
||||||
|
public MessageDigest md;
|
||||||
|
|
||||||
public PrivateKey getPrivateKey() {
|
public PrivateKey getPrivateKey() {
|
||||||
return privateKey;
|
return privateKey;
|
||||||
}
|
}
|
||||||
|
@ -24,4 +27,46 @@ public abstract class AbstractJweDecrypter implements JwtDecrypter {
|
||||||
public void setPublicKey(PublicKey publicKey) {
|
public void setPublicKey(PublicKey publicKey) {
|
||||||
this.publicKey = publicKey;
|
this.publicKey = publicKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public byte[] generateContentKey(byte[] cmk, int keyDataLen, byte[] type) {
|
||||||
|
|
||||||
|
long MAX_HASH_INPUTLEN = Long.MAX_VALUE;
|
||||||
|
long UNSIGNED_INT_MAX_VALUE = 4294967395L;
|
||||||
|
|
||||||
|
keyDataLen = keyDataLen / 8;
|
||||||
|
byte[] key = new byte[keyDataLen];
|
||||||
|
int hashLen = md.getDigestLength();
|
||||||
|
int reps = keyDataLen / hashLen;
|
||||||
|
if (reps > UNSIGNED_INT_MAX_VALUE) {
|
||||||
|
throw new IllegalArgumentException("Key derivation failed");
|
||||||
|
}
|
||||||
|
int counter = 1;
|
||||||
|
byte[] counterInBytes = intToFourBytes(counter);
|
||||||
|
if ((counterInBytes.length + cmk.length + type.length) * 8 > MAX_HASH_INPUTLEN) {
|
||||||
|
throw new IllegalArgumentException("Key derivation failed");
|
||||||
|
}
|
||||||
|
for (int i = 0; i <= reps; i++) {
|
||||||
|
md.reset();
|
||||||
|
md.update(intToFourBytes(i + 1));
|
||||||
|
md.update(cmk);
|
||||||
|
md.update(type);
|
||||||
|
byte[] hash = md.digest();
|
||||||
|
if (i < reps) {
|
||||||
|
System.arraycopy(hash, 0, key, hashLen * i, hashLen);
|
||||||
|
} else {
|
||||||
|
System.arraycopy(hash, 0, key, hashLen * i, keyDataLen % hashLen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return key;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] intToFourBytes(int i) {
|
||||||
|
byte[] res = new byte[4];
|
||||||
|
res[0] = (byte) (i >>> 24);
|
||||||
|
res[1] = (byte) ((i >>> 16) & 0xFF);
|
||||||
|
res[2] = (byte) ((i >>> 8) & 0xFF);
|
||||||
|
res[3] = (byte) (i & 0xFF);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,15 +6,18 @@ public enum JwtAlgorithm {
|
||||||
|
|
||||||
//TODO:Fill in values for each standard name
|
//TODO:Fill in values for each standard name
|
||||||
// RSA
|
// RSA
|
||||||
RSA1_5(""),
|
RSA1_5("RSA"),
|
||||||
RSA_OAEP(""),
|
RSA_OAEP("RSA"),
|
||||||
//EC
|
//EC
|
||||||
ECDH_ES(""),
|
ECDH_ES("EC"),
|
||||||
//AES
|
//AES
|
||||||
A128KW(""),
|
A128KW("AES"),
|
||||||
A256KW(""),
|
A256KW("AES"),
|
||||||
A128GCM(""),
|
A128CBC("AES"),
|
||||||
A256GCM("");
|
A256CBC("AES"),
|
||||||
|
A128GCM("AES"),
|
||||||
|
A256GCM("AES");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,14 +1,12 @@
|
||||||
package org.mitre.jwt.encryption;
|
package org.mitre.jwt.encryption;
|
||||||
|
|
||||||
import java.security.Key;
|
|
||||||
|
|
||||||
import org.mitre.jwe.model.Jwe;
|
import org.mitre.jwe.model.Jwe;
|
||||||
|
|
||||||
public interface JwtDecrypter {
|
public interface JwtDecrypter {
|
||||||
|
|
||||||
public Jwe decrypt(String encryptedJwe);
|
public Jwe decrypt(String encryptedJwe);
|
||||||
|
|
||||||
public String decryptCipherText(Jwe jwe, Key cek);
|
public byte[] decryptCipherText(Jwe jwe, byte[] cek);
|
||||||
|
|
||||||
public byte[] decryptEncryptionKey(Jwe jwe);
|
public byte[] decryptEncryptionKey(Jwe jwe);
|
||||||
|
|
||||||
|
|
|
@ -1,20 +1,17 @@
|
||||||
package org.mitre.jwt.encryption.impl;
|
package org.mitre.jwt.encryption.impl;
|
||||||
|
|
||||||
import java.security.InvalidKeyException;
|
import java.security.InvalidKeyException;
|
||||||
import java.security.Key;
|
|
||||||
import java.security.KeyPair;
|
|
||||||
import java.security.KeyPairGenerator;
|
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.security.PrivateKey;
|
|
||||||
import java.security.PublicKey;
|
|
||||||
|
|
||||||
import javax.crypto.BadPaddingException;
|
import javax.crypto.BadPaddingException;
|
||||||
import javax.crypto.Cipher;
|
import javax.crypto.Cipher;
|
||||||
import javax.crypto.IllegalBlockSizeException;
|
import javax.crypto.IllegalBlockSizeException;
|
||||||
import javax.crypto.NoSuchPaddingException;
|
import javax.crypto.NoSuchPaddingException;
|
||||||
|
import javax.crypto.spec.SecretKeySpec;
|
||||||
|
|
||||||
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.encryption.AlgorithmLength;
|
||||||
import org.mitre.jwt.signer.impl.HmacSigner;
|
import org.mitre.jwt.signer.impl.HmacSigner;
|
||||||
|
|
||||||
|
|
||||||
|
@ -32,28 +29,22 @@ public class RsaDecrypter extends AbstractJweDecrypter {
|
||||||
String alg = jwe.getHeader().getAlgorithm();
|
String alg = jwe.getHeader().getAlgorithm();
|
||||||
if(alg.equals("RS256") || alg.equals("RS384") || alg.equals("RS512")) {
|
if(alg.equals("RS256") || alg.equals("RS384") || alg.equals("RS512")) {
|
||||||
|
|
||||||
PrivateKey contentEncryptionKey = null;
|
//decrypt to get cmk to be used for cek and cik
|
||||||
PublicKey contentIntegrityKey = null;
|
|
||||||
|
|
||||||
try {
|
|
||||||
|
|
||||||
KeyPairGenerator keyGen = KeyPairGenerator.getInstance(jwe.getHeader().getKeyDerivationFunction());
|
|
||||||
KeyPair keyPair = keyGen.genKeyPair();
|
|
||||||
contentEncryptionKey = keyPair.getPrivate();
|
|
||||||
contentIntegrityKey = keyPair.getPublic();
|
|
||||||
|
|
||||||
} catch (NoSuchAlgorithmException e1) {
|
|
||||||
// TODO Auto-generated catch block
|
|
||||||
e1.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
jwe.setCiphertext(decryptCipherText(jwe, contentEncryptionKey).getBytes());
|
|
||||||
jwe.setEncryptedKey(decryptEncryptionKey(jwe));
|
jwe.setEncryptedKey(decryptEncryptionKey(jwe));
|
||||||
|
|
||||||
|
//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());
|
||||||
|
|
||||||
|
//decrypt ciphertext to get claims
|
||||||
|
jwe.setCiphertext(decryptCipherText(jwe, contentEncryptionKey));
|
||||||
|
|
||||||
//generate signature for decrypted signature base in order to verify that decryption worked
|
//generate signature for decrypted signature base in order to verify that decryption worked
|
||||||
String signature = null;
|
String signature = null;
|
||||||
try {
|
try {
|
||||||
HmacSigner hmacSigner = new HmacSigner(contentIntegrityKey.getEncoded());
|
HmacSigner hmacSigner = new HmacSigner(contentIntegrityKey);
|
||||||
signature = hmacSigner.generateSignature(jwe.getSignatureBase());
|
signature = hmacSigner.generateSignature(jwe.getSignatureBase());
|
||||||
} catch (NoSuchAlgorithmException e) {
|
} catch (NoSuchAlgorithmException e) {
|
||||||
// TODO Auto-generated catch block
|
// TODO Auto-generated catch block
|
||||||
|
@ -76,15 +67,14 @@ public class RsaDecrypter extends AbstractJweDecrypter {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String decryptCipherText(Jwe jwe, Key cek) {
|
public byte[] decryptCipherText(Jwe jwe, byte[] cek) {
|
||||||
Cipher cipher;
|
Cipher cipher;
|
||||||
String clearTextString = null;
|
byte[] clearText = null;
|
||||||
try {
|
try {
|
||||||
|
|
||||||
cipher = Cipher.getInstance("RSA");
|
cipher = Cipher.getInstance("RSA");
|
||||||
cipher.init(Cipher.DECRYPT_MODE, cek);
|
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(cek, "RSA"));
|
||||||
byte[] clearText = cipher.doFinal(jwe.getCiphertext());
|
clearText = cipher.doFinal(jwe.getCiphertext());
|
||||||
clearTextString = new String(clearText);
|
|
||||||
|
|
||||||
} catch (NoSuchAlgorithmException e) {
|
} catch (NoSuchAlgorithmException e) {
|
||||||
// TODO Auto-generated catch block
|
// TODO Auto-generated catch block
|
||||||
|
@ -103,7 +93,7 @@ public class RsaDecrypter extends AbstractJweDecrypter {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|
||||||
return clearTextString;
|
return clearText;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -115,9 +115,9 @@ public class RsaEncrypter extends AbstractJweEncrypter {
|
||||||
|
|
||||||
Cipher cipher;
|
Cipher cipher;
|
||||||
try {
|
try {
|
||||||
cipher = Cipher.getInstance(JwtAlgorithm.getByName(jwe.getHeader().getAlgorithm()).getStandardName());
|
cipher = Cipher.getInstance(JwtAlgorithm.getByName(jwe.getHeader().getEncryptionMethod()).getStandardName());
|
||||||
|
|
||||||
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(contentEncryptionKey, 0, contentEncryptionKey.length, "RSA"));
|
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(contentEncryptionKey, "RSA"));
|
||||||
cipherText = cipher.doFinal(jwe.getClaims().toString().getBytes());
|
cipherText = cipher.doFinal(jwe.getClaims().toString().getBytes());
|
||||||
|
|
||||||
} catch (NoSuchAlgorithmException e) {
|
} catch (NoSuchAlgorithmException e) {
|
||||||
|
|
Loading…
Reference in New Issue