update to encryption/decryption. added cmk, cek, and cik use
parent
bc1ff0d964
commit
7e7cd4f480
|
@ -20,7 +20,6 @@ public class JweHeader extends JwtHeader{
|
|||
public static final String X509_CERTIFICATE_CHAIN = "x5c";
|
||||
public static final String KEY_ID = "kid";
|
||||
public static final String KEY_DERIVATION_FUNCTION = "kdf";
|
||||
public static final String CONTENT_TYPE = "cty";
|
||||
|
||||
public JweHeader(){
|
||||
super();
|
||||
|
@ -112,14 +111,10 @@ public class JweHeader extends JwtHeader{
|
|||
return KEY_ID;
|
||||
}
|
||||
|
||||
public static String getKeyDerivationFunction() {
|
||||
public String getKeyDerivationFunction() {
|
||||
return KEY_DERIVATION_FUNCTION;
|
||||
}
|
||||
|
||||
public static String getContentType() {
|
||||
return CONTENT_TYPE;
|
||||
}
|
||||
|
||||
public void setIv(String iv) {
|
||||
setClaim(INITIALIZATION_VECTOR, iv);
|
||||
}
|
||||
|
@ -163,8 +158,4 @@ public class JweHeader extends JwtHeader{
|
|||
public void setKeyDerivationFunction(String kdf) {
|
||||
setClaim(KEY_DERIVATION_FUNCTION, kdf);
|
||||
}
|
||||
|
||||
public void setContentType(String cty) {
|
||||
setClaim(CONTENT_TYPE, cty);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package org.mitre.jwt.encryption;
|
||||
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.Key;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.PublicKey;
|
||||
|
@ -39,13 +40,13 @@ public abstract class AbstractJweDecrypter implements JwtDecrypter {
|
|||
|
||||
|
||||
@Override
|
||||
public String decryptCipherText(Jwe jwe) {
|
||||
public String decryptCipherText(Jwe jwe, Key cek) {
|
||||
Cipher cipher;
|
||||
String clearTextString = null;
|
||||
try {
|
||||
|
||||
cipher = Cipher.getInstance("RSA");
|
||||
cipher.init(Cipher.DECRYPT_MODE, privateKey);
|
||||
cipher.init(Cipher.DECRYPT_MODE, cek);
|
||||
byte[] clearText = cipher.doFinal(jwe.getCiphertext());
|
||||
clearTextString = new String(clearText);
|
||||
|
||||
|
@ -73,13 +74,13 @@ public abstract class AbstractJweDecrypter implements JwtDecrypter {
|
|||
@Override
|
||||
public byte[] decryptEncryptionKey(Jwe jwe) {
|
||||
Cipher cipher;
|
||||
byte[] unencryptedKey = null;
|
||||
byte[] contentMasterKey = null;
|
||||
|
||||
try {
|
||||
|
||||
cipher = Cipher.getInstance("RSA");
|
||||
cipher.init(Cipher.DECRYPT_MODE, privateKey);//TODO: Keys are null, get them from keystore. Placeholder
|
||||
unencryptedKey = cipher.doFinal(jwe.getEncryptedKey());
|
||||
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
|
||||
|
@ -98,6 +99,6 @@ public abstract class AbstractJweDecrypter implements JwtDecrypter {
|
|||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return unencryptedKey;
|
||||
return contentMasterKey;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,16 +1,23 @@
|
|||
package org.mitre.jwt.encryption;
|
||||
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.Key;
|
||||
import java.security.KeyPair;
|
||||
import java.security.KeyPairGenerator;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.interfaces.RSAPrivateKey;
|
||||
import java.security.PublicKey;
|
||||
import java.security.SecureRandom;
|
||||
import java.security.interfaces.RSAPublicKey;
|
||||
import java.security.spec.InvalidParameterSpecException;
|
||||
|
||||
import javax.crypto.BadPaddingException;
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.IllegalBlockSizeException;
|
||||
import javax.crypto.NoSuchPaddingException;
|
||||
import javax.crypto.spec.IvParameterSpec;
|
||||
|
||||
import org.mitre.jwe.model.Jwe;
|
||||
import org.springframework.security.crypto.codec.Base64;
|
||||
|
||||
|
||||
public abstract class AbstractJweEncrypter implements JwtEncrypter {
|
||||
|
@ -21,10 +28,6 @@ public abstract class AbstractJweEncrypter implements JwtEncrypter {
|
|||
|
||||
private RSAPublicKey publicKey;
|
||||
|
||||
private RSAPrivateKey privateKey;
|
||||
|
||||
|
||||
|
||||
public byte[] getEncryptecKey() {
|
||||
return encryptedKey;
|
||||
}
|
||||
|
@ -44,13 +47,29 @@ public abstract class AbstractJweEncrypter implements JwtEncrypter {
|
|||
|
||||
public byte[] encryptKey(Jwe jwe){
|
||||
|
||||
//generate random content master key
|
||||
PublicKey contentMasterKey = null;
|
||||
|
||||
//TODO:Get keys from keystore, currently null
|
||||
try {
|
||||
|
||||
KeyPairGenerator keyGen = KeyPairGenerator.getInstance(jwe.getHeader().getAlgorithm());
|
||||
SecureRandom random = SecureRandom.getInstance(jwe.getHeader().getAlgorithm());
|
||||
keyGen.initialize(1024, random);
|
||||
KeyPair pair = keyGen.generateKeyPair();
|
||||
contentMasterKey = pair.getPublic();
|
||||
|
||||
} catch (NoSuchAlgorithmException e1) {
|
||||
// TODO Auto-generated catch block
|
||||
e1.printStackTrace();
|
||||
}
|
||||
|
||||
|
||||
//TODO:Get public key from keystore, currently null
|
||||
Cipher cipher;
|
||||
try {
|
||||
cipher = Cipher.getInstance("RSA");
|
||||
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
|
||||
encryptedKey = cipher.doFinal(privateKey.getEncoded());
|
||||
encryptedKey = cipher.doFinal(contentMasterKey.getEncoded());
|
||||
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
// TODO Auto-generated catch block
|
||||
|
@ -73,14 +92,17 @@ public abstract class AbstractJweEncrypter implements JwtEncrypter {
|
|||
|
||||
}
|
||||
|
||||
public byte[] encryptClaims(Jwe jwe) {
|
||||
public byte[] encryptClaims(Jwe jwe, Key cek) {
|
||||
|
||||
|
||||
//TODO:Get keys from keystore, currently null
|
||||
Cipher cipher;
|
||||
try {
|
||||
cipher = Cipher.getInstance("RSA");
|
||||
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
|
||||
|
||||
//TODO: generated the iv, but not sure how to use it to encrypt?
|
||||
IvParameterSpec spec = cipher.getParameters().getParameterSpec(IvParameterSpec.class);
|
||||
byte[] iv = spec.getIV();
|
||||
|
||||
cipher.init(Cipher.ENCRYPT_MODE, cek);
|
||||
cipherText = cipher.doFinal(jwe.getClaims().toString().getBytes());
|
||||
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
|
@ -98,13 +120,16 @@ public abstract class AbstractJweEncrypter implements JwtEncrypter {
|
|||
} catch (BadPaddingException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
} catch (InvalidParameterSpecException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return cipherText;
|
||||
|
||||
}
|
||||
|
||||
public abstract Jwe encryptAndSign(Jwe jwe);
|
||||
public abstract Jwe encryptAndSign(Jwe jwe) throws NoSuchAlgorithmException;
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
package org.mitre.jwt.encryption;
|
||||
|
||||
import java.security.Key;
|
||||
|
||||
import org.mitre.jwe.model.Jwe;
|
||||
|
||||
public interface JwtDecrypter {
|
||||
|
||||
public Jwe decrypt(String encryptedJwe);
|
||||
|
||||
public String decryptCipherText(Jwe jwe);
|
||||
public String decryptCipherText(Jwe jwe, Key cek);
|
||||
|
||||
public byte[] decryptEncryptionKey(Jwe jwe);
|
||||
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
package org.mitre.jwt.encryption;
|
||||
|
||||
import java.security.Key;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
import org.mitre.jwe.model.Jwe;
|
||||
|
||||
|
||||
|
@ -7,8 +10,8 @@ public interface JwtEncrypter {
|
|||
|
||||
public byte[] encryptKey(Jwe jwe);
|
||||
|
||||
public byte[] encryptClaims(Jwe jwe);
|
||||
public byte[] encryptClaims(Jwe jwe, Key cik);
|
||||
|
||||
public Jwe encryptAndSign(Jwe jwe);
|
||||
public Jwe encryptAndSign(Jwe jwe) throws NoSuchAlgorithmException;
|
||||
|
||||
}
|
||||
|
|
|
@ -1,9 +1,16 @@
|
|||
package org.mitre.jwt.encryption.impl;
|
||||
|
||||
import java.security.KeyPair;
|
||||
import java.security.KeyPairGenerator;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.PublicKey;
|
||||
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
import org.mitre.jwe.model.Jwe;
|
||||
import org.mitre.jwe.model.JweHeader;
|
||||
import org.mitre.jwt.encryption.AbstractJweDecrypter;
|
||||
import org.mitre.jwt.signer.impl.HmacSigner;
|
||||
|
||||
|
||||
public class Decrypter extends AbstractJweDecrypter {
|
||||
|
@ -33,6 +40,7 @@ public class Decrypter extends AbstractJweDecrypter {
|
|||
//Base 64 decode each part of the jwe
|
||||
String decodedHeader = new String(Base64.decodeBase64(jwe.getHeader().toString()));
|
||||
JweHeader unencryptedHeader = new JweHeader(decodedHeader);
|
||||
jwe.setHeader(unencryptedHeader);
|
||||
|
||||
String decodedEncryptionKey = new String(Base64.decodeBase64(jwe.getEncryptedKey().toString()));
|
||||
//sets decoded key on jwe so that it can be decrypted
|
||||
|
@ -42,12 +50,43 @@ public class Decrypter extends AbstractJweDecrypter {
|
|||
//sets decoded ciphertext on jwe so that it can be decrypted
|
||||
jwe.setCiphertext(decodedCiphertext.getBytes());
|
||||
|
||||
//decode signature, but don't set it on jwe yet. first has to be verified (see below)
|
||||
String decodedSig = new String(Base64.decodeBase64(jwe.getSignature()));
|
||||
|
||||
//create new jwe using the decoded header and signature, and decrypt the ciphertext and key
|
||||
jwe.setHeader(unencryptedHeader);
|
||||
jwe.setCiphertext(decryptCipherText(jwe).getBytes());
|
||||
|
||||
PrivateKey contentEncryptionKey = null;
|
||||
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));
|
||||
|
||||
//generate signature for decrypted signature base in order to verify that decryption worked
|
||||
String signature = null;
|
||||
try {
|
||||
HmacSigner hmacSigner = new HmacSigner(contentIntegrityKey.getEncoded());
|
||||
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 != decodedSig){
|
||||
throw new IllegalArgumentException("Didn't decrypt correctly. Decoded Sig and generated Sig do not match");
|
||||
}
|
||||
|
||||
jwe.setSignature(decodedSig);
|
||||
|
||||
} else if(alg.equals("HS256") || alg.equals("HS384") || alg.equals("HS512")){
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
package org.mitre.jwt.encryption.impl;
|
||||
|
||||
import java.security.KeyPair;
|
||||
import java.security.KeyPairGenerator;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.PublicKey;
|
||||
|
||||
import org.mitre.jwe.model.Jwe;
|
||||
import org.mitre.jwe.model.JweHeader;
|
||||
|
@ -59,25 +63,38 @@ public class Encrypter extends AbstractJweEncrypter {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Jwe encryptAndSign(Jwe jwe) {
|
||||
public Jwe encryptAndSign(Jwe jwe) throws NoSuchAlgorithmException {
|
||||
|
||||
String alg = jwe.getHeader().getAlgorithm();
|
||||
String iv = jwe.getHeader().getIntegrity();
|
||||
|
||||
if(alg.equals("RS256") || alg.equals("RS384") || alg.equals("RS512")) {
|
||||
|
||||
jwe.setCiphertext(encryptClaims(jwe));
|
||||
//generate CEK and CIK
|
||||
|
||||
PrivateKey contentEncryptionKey = null;
|
||||
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(encryptClaims(jwe, contentEncryptionKey));
|
||||
jwe.setEncryptedKey(encryptKey(jwe));
|
||||
|
||||
if(iv.equals("HS256") || iv.equals("HS384") || iv.equals("HS512")){
|
||||
|
||||
HmacSigner hmacSigner = new HmacSigner(); //TODO: Add parameters to RsaSigner. ie: keys from keystore (null at the moment)
|
||||
try {
|
||||
jwe = (Jwe) hmacSigner.sign(jwe);
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
HmacSigner hmacSigner = new HmacSigner(contentIntegrityKey.getEncoded());
|
||||
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 {
|
||||
|
@ -85,9 +102,7 @@ public class Encrypter extends AbstractJweEncrypter {
|
|||
}
|
||||
|
||||
} 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");
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue