package com.nimbusds.jose.crypto;
import java.util.Arrays;
import java.util.HashSet;
import com.nimbusds.jose.*;
import com.nimbusds.jose.jwk.OctetSequenceKey;
import junit.framework.TestCase;
/**
* Tests direct JWE encryption and decryption.
*
* @author Vladimir Dzhuvinov
* @version $version$ (2014-04-22)
*/
public class DirectCryptoTest extends TestCase {
// 128-bit shared symmetric key
private final static byte[] key128 = {
(byte)177, (byte)119, (byte) 33, (byte) 13, (byte)164, (byte) 30, (byte)108, (byte)121,
(byte)207, (byte)136, (byte)107, (byte)242, (byte) 12, (byte)224, (byte) 19, (byte)226 };
// 192-bit shared symmetric key
private final static byte[] key192 = {
(byte)177, (byte)119, (byte) 33, (byte) 13, (byte)164, (byte) 30, (byte)108, (byte)121,
(byte)207, (byte)136, (byte)107, (byte)242, (byte) 12, (byte)224, (byte) 19, (byte)226,
(byte)198, (byte)134, (byte) 17, (byte) 71, (byte)173, (byte) 75, (byte) 42, (byte) 61 };
// 256-bit shared symmetric key
private final static byte[] key256 = {
(byte)177, (byte)119, (byte) 33, (byte) 13, (byte)164, (byte) 30, (byte)108, (byte)121,
(byte)207, (byte)136, (byte)107, (byte)242, (byte) 12, (byte)224, (byte) 19, (byte)226,
(byte)198, (byte)134, (byte) 17, (byte) 71, (byte)173, (byte) 75, (byte) 42, (byte) 61,
(byte) 48, (byte)162, (byte)206, (byte)161, (byte) 97, (byte)108, (byte)185, (byte)234 };
// 384-bit shared symmetric key
private final static byte[] key384 = {
(byte)177, (byte)119, (byte) 33, (byte) 13, (byte)164, (byte) 30, (byte)108, (byte)121,
(byte)207, (byte)136, (byte)107, (byte)242, (byte) 12, (byte)224, (byte) 19, (byte)226,
(byte)198, (byte)134, (byte) 17, (byte) 71, (byte)173, (byte) 75, (byte) 42, (byte) 61,
(byte) 48, (byte)162, (byte)206, (byte)161, (byte) 97, (byte)108, (byte)185, (byte)234,
(byte) 60, (byte)181, (byte) 90, (byte) 85, (byte) 51, (byte)123, (byte) 6, (byte)224,
(byte) 4, (byte)122, (byte) 29, (byte)230, (byte)151, (byte) 12, (byte)244, (byte)127 };
// 512-bit shared symmetric key
private final static byte[] key512 = {
(byte)177, (byte)119, (byte) 33, (byte) 13, (byte)164, (byte) 30, (byte)108, (byte)121,
(byte)207, (byte)136, (byte)107, (byte)242, (byte) 12, (byte)224, (byte) 19, (byte)226,
(byte)198, (byte)134, (byte) 17, (byte) 71, (byte)173, (byte) 75, (byte) 42, (byte) 61,
(byte) 48, (byte)162, (byte)206, (byte)161, (byte) 97, (byte)108, (byte)185, (byte)234,
(byte) 60, (byte)181, (byte) 90, (byte) 85, (byte) 51, (byte)123, (byte) 6, (byte)224,
(byte) 4, (byte)122, (byte) 29, (byte)230, (byte)151, (byte) 12, (byte)244, (byte)127,
(byte)121, (byte) 25, (byte) 4, (byte) 85, (byte)220, (byte)144, (byte)215, (byte)110,
(byte)130, (byte) 17, (byte) 68, (byte)228, (byte)129, (byte)138, (byte) 7, (byte)130 };
public void testKeyLengths() {
assertEquals(128, key128.length * 8);
assertEquals(192, key192.length * 8);
assertEquals(256, key256.length * 8);
assertEquals(384, key384.length * 8);
assertEquals(512, key512.length * 8);
}
public void testSupportedAlgorithms()
throws Exception {
JWEEncrypter encrypter = new DirectEncrypter(key128);
assertEquals(1, encrypter.supportedAlgorithms().size());
assertTrue(encrypter.supportedAlgorithms().contains(JWEAlgorithm.DIR));
JWEDecrypter decrypter = new DirectDecrypter(key128);
assertEquals(1, decrypter.supportedAlgorithms().size());
assertTrue(decrypter.supportedAlgorithms().contains(JWEAlgorithm.DIR));
}
public void testSupportedEncryptionMethods()
throws Exception {
JWEEncrypter encrypter = new DirectEncrypter(key128);
assertEquals(6, encrypter.supportedEncryptionMethods().size());
assertTrue(encrypter.supportedEncryptionMethods().contains(EncryptionMethod.A128CBC_HS256));
assertTrue(encrypter.supportedEncryptionMethods().contains(EncryptionMethod.A192CBC_HS384));
assertTrue(encrypter.supportedEncryptionMethods().contains(EncryptionMethod.A256CBC_HS512));
assertTrue(encrypter.supportedEncryptionMethods().contains(EncryptionMethod.A128GCM));
assertTrue(encrypter.supportedEncryptionMethods().contains(EncryptionMethod.A192GCM));
assertTrue(encrypter.supportedEncryptionMethods().contains(EncryptionMethod.A256GCM));
JWEDecrypter decrypter = new DirectDecrypter(key128);
assertEquals(6, decrypter.supportedEncryptionMethods().size());
assertTrue(decrypter.supportedEncryptionMethods().contains(EncryptionMethod.A128CBC_HS256));
assertTrue(decrypter.supportedEncryptionMethods().contains(EncryptionMethod.A192CBC_HS384));
assertTrue(decrypter.supportedEncryptionMethods().contains(EncryptionMethod.A256CBC_HS512));
assertTrue(decrypter.supportedEncryptionMethods().contains(EncryptionMethod.A128GCM));
assertTrue(decrypter.supportedEncryptionMethods().contains(EncryptionMethod.A192GCM));
assertTrue(decrypter.supportedEncryptionMethods().contains(EncryptionMethod.A256GCM));
}
public void testGetAcceptedAlgorithms()
throws Exception {
JWEDecrypter decrypter = new DirectDecrypter(key128);
assertEquals(1, decrypter.getAcceptedAlgorithms().size());
assertTrue(decrypter.getAcceptedAlgorithms().contains(JWEAlgorithm.DIR));
}
public void testGetAcceptedEncryptionMethods()
throws Exception {
JWEDecrypter decrypter = new DirectDecrypter(key128);
assertEquals(6, decrypter.getAcceptedEncryptionMethods().size());
assertTrue(decrypter.getAcceptedEncryptionMethods().contains(EncryptionMethod.A128CBC_HS256));
assertTrue(decrypter.getAcceptedEncryptionMethods().contains(EncryptionMethod.A192CBC_HS384));
assertTrue(decrypter.getAcceptedEncryptionMethods().contains(EncryptionMethod.A256CBC_HS512));
assertTrue(decrypter.getAcceptedEncryptionMethods().contains(EncryptionMethod.A128GCM));
assertTrue(decrypter.getAcceptedEncryptionMethods().contains(EncryptionMethod.A192GCM));
assertTrue(decrypter.getAcceptedEncryptionMethods().contains(EncryptionMethod.A256GCM));
}
public void testSetAcceptedAlgorithms()
throws Exception {
JWEDecrypter decrypter = new DirectDecrypter(key128);
try {
decrypter.setAcceptedAlgorithms(null);
fail();
} catch (IllegalArgumentException e) {
// ok
}
try {
decrypter.setAcceptedAlgorithms(new HashSet<JWEAlgorithm>(Arrays.asList(JWEAlgorithm.A128KW)));
fail();
} catch (IllegalArgumentException e) {
// ok
}
decrypter.setAcceptedAlgorithms(new HashSet<JWEAlgorithm>());
assertTrue(decrypter.getAcceptedAlgorithms().isEmpty());
}
public void testSetAcceptedEncryptionMethods()
throws Exception {
JWEDecrypter decrypter = new DirectDecrypter(key128);
try {
decrypter.setAcceptedEncryptionMethods(null);
fail();
} catch (IllegalArgumentException e) {
// ok
}
try {
decrypter.setAcceptedEncryptionMethods(new HashSet<EncryptionMethod>(Arrays.asList(new EncryptionMethod("unsupported"))));
fail();
} catch (IllegalArgumentException e) {
// ok
}
decrypter.setAcceptedEncryptionMethods(new HashSet<EncryptionMethod>(Arrays.asList(EncryptionMethod.A128GCM)));
assertTrue(decrypter.getAcceptedEncryptionMethods().contains(EncryptionMethod.A128GCM));
assertEquals(1, decrypter.getAcceptedAlgorithms().size());
}
public void testWithA128CBC_HS256()
throws Exception {
JWEHeader header = new JWEHeader(JWEAlgorithm.DIR, EncryptionMethod.A128CBC_HS256);
Payload payload = new Payload("Hello world!");
JWEObject jweObject = new JWEObject(header, payload);
assertEquals("State check", JWEObject.State.UNENCRYPTED, jweObject.getState());
JWEEncrypter encrypter = new DirectEncrypter(key256);
jweObject.encrypt(encrypter);
assertEquals("State check", JWEObject.State.ENCRYPTED, jweObject.getState());
String jweString = jweObject.serialize();
jweObject = JWEObject.parse(jweString);
assertEquals("State check", JWEObject.State.ENCRYPTED, jweObject.getState());
JWEDecrypter decrypter = new DirectDecrypter(key256);
jweObject.decrypt(decrypter);
assertEquals("State check", JWEObject.State.DECRYPTED, jweObject.getState());
payload = jweObject.getPayload();
assertEquals("Hello world!", payload.toString());
}
public void testWithA192CBC_HS384()
throws Exception {
JWEHeader header = new JWEHeader(JWEAlgorithm.DIR, EncryptionMethod.A192CBC_HS384);
Payload payload = new Payload("Hello world!");
JWEObject jweObject = new JWEObject(header, payload);
assertEquals("State check", JWEObject.State.UNENCRYPTED, jweObject.getState());
JWEEncrypter encrypter = new DirectEncrypter(key384);
jweObject.encrypt(encrypter);
assertEquals("State check", JWEObject.State.ENCRYPTED, jweObject.getState());
String jweString = jweObject.serialize();
jweObject = JWEObject.parse(jweString);
assertEquals("State check", JWEObject.State.ENCRYPTED, jweObject.getState());
JWEDecrypter decrypter = new DirectDecrypter(key384);
jweObject.decrypt(decrypter);
assertEquals("State check", JWEObject.State.DECRYPTED, jweObject.getState());
payload = jweObject.getPayload();
assertEquals("Hello world!", payload.toString());
}
public void testWithA256CBC_HS512()
throws Exception {
JWEHeader header = new JWEHeader(JWEAlgorithm.DIR, EncryptionMethod.A256CBC_HS512);
Payload payload = new Payload("Hello world!");
JWEObject jweObject = new JWEObject(header, payload);
assertEquals("State check", JWEObject.State.UNENCRYPTED, jweObject.getState());
JWEEncrypter encrypter = new DirectEncrypter(key512);
jweObject.encrypt(encrypter);
assertEquals("State check", JWEObject.State.ENCRYPTED, jweObject.getState());
String jweString = jweObject.serialize();
jweObject = JWEObject.parse(jweString);
assertEquals("State check", JWEObject.State.ENCRYPTED, jweObject.getState());
JWEDecrypter decrypter = new DirectDecrypter(key512);
jweObject.decrypt(decrypter);
assertEquals("State check", JWEObject.State.DECRYPTED, jweObject.getState());
payload = jweObject.getPayload();
assertEquals("Hello world!", payload.toString());
}
public void testWithA128GCM()
throws Exception {
JWEHeader header = new JWEHeader(JWEAlgorithm.DIR, EncryptionMethod.A128GCM);
Payload payload = new Payload("Hello world!");
JWEObject jweObject = new JWEObject(header, payload);
assertEquals("State check", JWEObject.State.UNENCRYPTED, jweObject.getState());
JWEEncrypter encrypter = new DirectEncrypter(key128);
jweObject.encrypt(encrypter);
assertEquals("State check", JWEObject.State.ENCRYPTED, jweObject.getState());
String jweString = jweObject.serialize();
jweObject = JWEObject.parse(jweString);
assertEquals("State check", JWEObject.State.ENCRYPTED, jweObject.getState());
JWEDecrypter decrypter = new DirectDecrypter(key128);
jweObject.decrypt(decrypter);
assertEquals("State check", JWEObject.State.DECRYPTED, jweObject.getState());
payload = jweObject.getPayload();
assertEquals("Hello world!", payload.toString());
}
public void testWithA192GCM()
throws Exception {
JWEHeader header = new JWEHeader(JWEAlgorithm.DIR, EncryptionMethod.A192GCM);
Payload payload = new Payload("Hello world!");
JWEObject jweObject = new JWEObject(header, payload);
assertEquals("State check", JWEObject.State.UNENCRYPTED, jweObject.getState());
JWEEncrypter encrypter = new DirectEncrypter(key192);
jweObject.encrypt(encrypter);
assertEquals("State check", JWEObject.State.ENCRYPTED, jweObject.getState());
String jweString = jweObject.serialize();
jweObject = JWEObject.parse(jweString);
assertEquals("State check", JWEObject.State.ENCRYPTED, jweObject.getState());
JWEDecrypter decrypter = new DirectDecrypter(key192);
jweObject.decrypt(decrypter);
assertEquals("State check", JWEObject.State.DECRYPTED, jweObject.getState());
payload = jweObject.getPayload();
assertEquals("Hello world!", payload.toString());
}
public void testWithA256GCM()
throws Exception {
JWEHeader header = new JWEHeader(JWEAlgorithm.DIR, EncryptionMethod.A256GCM);
Payload payload = new Payload("I think therefore I am.");
JWEObject jweObject = new JWEObject(header, payload);
assertEquals("State check", JWEObject.State.UNENCRYPTED, jweObject.getState());
JWEEncrypter encrypter = new DirectEncrypter(key256);
jweObject.encrypt(encrypter);
assertEquals("State check", JWEObject.State.ENCRYPTED, jweObject.getState());
String jweString = jweObject.serialize();
jweObject = JWEObject.parse(jweString);
assertEquals("State check", JWEObject.State.ENCRYPTED, jweObject.getState());
JWEDecrypter decrypter = new DirectDecrypter(key256);
jweObject.decrypt(decrypter);
assertEquals("State check", JWEObject.State.DECRYPTED, jweObject.getState());
payload = jweObject.getPayload();
assertEquals("I think therefore I am.", payload.toString());
}
public void testWithCompression()
throws Exception {
JWEHeader header = new JWEHeader(JWEAlgorithm.DIR, EncryptionMethod.A128CBC_HS256);
header.setCompressionAlgorithm(CompressionAlgorithm.DEF);
Payload payload = new Payload("Hello world!");
JWEObject jweObject = new JWEObject(header, payload);
assertEquals("State check", JWEObject.State.UNENCRYPTED, jweObject.getState());
JWEEncrypter encrypter = new DirectEncrypter(key256);
jweObject.encrypt(encrypter);
assertEquals("State check", JWEObject.State.ENCRYPTED, jweObject.getState());
String jweString = jweObject.serialize();
jweObject = JWEObject.parse(jweString);
assertEquals("State check", JWEObject.State.ENCRYPTED, jweObject.getState());
JWEDecrypter decrypter = new DirectDecrypter(key256);
jweObject.decrypt(decrypter);
assertEquals("State check", JWEObject.State.DECRYPTED, jweObject.getState());
payload = jweObject.getPayload();
assertEquals("Hello world!", payload.toString());
}
public void testCookbookExample()
throws Exception {
String json ="{"+
"\"kty\":\"oct\","+
"\"kid\":\"77c7e2b8-6e13-45cf-8672-617b5b45243a\","+
"\"use\":\"enc\","+
"\"alg\":\"A128GCM\","+
"\"k\":\"XctOhJAkA-pD9Lh7ZgW_2A\""+
"}";
OctetSequenceKey jwk = OctetSequenceKey.parse(json);
String jwe = "eyJhbGciOiJkaXIiLCJraWQiOiI3N2M3ZTJiOC02ZTEzLTQ1Y2YtODY3Mi02MT"+
"diNWI0NTI0M2EiLCJlbmMiOiJBMTI4R0NNIn0"+
"."+
"."+
"refa467QzzKx6QAB"+
"."+
"JW_i_f52hww_ELQPGaYyeAB6HYGcR559l9TYnSovc23XJoBcW29rHP8yZOZG7Y"+
"hLpT1bjFuvZPjQS-m0IFtVcXkZXdH_lr_FrdYt9HRUYkshtrMmIUAyGmUnd9zM"+
"DB2n0cRDIHAzFVeJUDxkUwVAE7_YGRPdcqMyiBoCO-FBdE-Nceb4h3-FtBP-c_"+
"BIwCPTjb9o0SbdcdREEMJMyZBH8ySWMVi1gPD9yxi-aQpGbSv_F9N4IZAxscj5"+
"g-NJsUPbjk29-s7LJAGb15wEBtXphVCgyy53CoIKLHHeJHXex45Uz9aKZSRSIn"+
"ZI-wjsY0yu3cT4_aQ3i1o-tiE-F8Ios61EKgyIQ4CWao8PFMj8TTnp"+
"."+
"vbb32Xvllea2OtmHAdccRQ";
JWEObject jweObject = JWEObject.parse(jwe);
assertEquals(JWEAlgorithm.DIR, jweObject.getHeader().getAlgorithm());
assertEquals(EncryptionMethod.A128GCM, jweObject.getHeader().getEncryptionMethod());
assertEquals("77c7e2b8-6e13-45cf-8672-617b5b45243a", jweObject.getHeader().getKeyID());
JWEDecrypter decrypter = new DirectDecrypter(jwk.toByteArray());
jweObject.decrypt(decrypter);
assertEquals(JWEObject.State.DECRYPTED, jweObject.getState());
}
public void testCritHeaderParamIgnore()
throws Exception {
JWEHeader header = new JWEHeader(JWEAlgorithm.DIR, EncryptionMethod.A128CBC_HS256);
header.setCustomParameter("exp", "2014-04-24");
header.setCriticalHeaders(new HashSet<String>(Arrays.asList("exp")));
Payload payload = new Payload("Hello world!");
JWEObject jweObject = new JWEObject(header, payload);
JWEEncrypter encrypter = new DirectEncrypter(key256);
jweObject.encrypt(encrypter);
String jweString = jweObject.serialize();
jweObject = JWEObject.parse(jweString);
JWEDecrypter decrypter = new DirectDecrypter(key256);
decrypter.getIgnoredCriticalHeaderParameters().add("exp");
jweObject.decrypt(decrypter);
assertEquals("State check", JWEObject.State.DECRYPTED, jweObject.getState());
payload = jweObject.getPayload();
assertEquals("Hello world!", payload.toString());
}
public void testCritHeaderParamReject()
throws Exception {
JWEHeader header = new JWEHeader(JWEAlgorithm.DIR, EncryptionMethod.A128CBC_HS256);
header.setCustomParameter("exp", "2014-04-24");
header.setCriticalHeaders(new HashSet<String>(Arrays.asList("exp")));
Payload payload = new Payload("Hello world!");
JWEObject jweObject = new JWEObject(header, payload);
JWEEncrypter encrypter = new DirectEncrypter(key256);
jweObject.encrypt(encrypter);
String jweString = jweObject.serialize();
jweObject = JWEObject.parse(jweString);
JWEDecrypter decrypter = new DirectDecrypter(key256);
try {
jweObject.decrypt(decrypter);
fail();
} catch (JOSEException e) {
// ok
assertEquals("Unsupported critical header parameter", e.getMessage());
}
}
}