Added integration test defined in RFC 7516 Appendix A3

This commit is contained in:
Les Hazlewood 2021-10-02 11:01:53 -07:00
parent bfdaa754ac
commit 34bb74488b
1 changed files with 125 additions and 0 deletions

View File

@ -0,0 +1,125 @@
package io.jsonwebtoken.impl.security
import io.jsonwebtoken.Jwe
import io.jsonwebtoken.Jwts
import io.jsonwebtoken.io.Decoders
import io.jsonwebtoken.io.Encoders
import io.jsonwebtoken.security.*
import org.junit.Test
import javax.crypto.SecretKey
import javax.crypto.spec.SecretKeySpec
import java.nio.charset.StandardCharsets
import static org.junit.Assert.assertArrayEquals
import static org.junit.Assert.assertEquals
class RFC7516AppendixA3Test {
static String encode(byte[] b) {
return Encoders.BASE64URL.encode(b)
}
static byte[] decode(String val) {
return Decoders.BASE64URL.decode(val)
}
// defined in https://datatracker.ietf.org/doc/html/rfc7516#appendix-A.3 :
final static String PLAINTEXT = 'Live long and prosper.' as String
final static byte[] PLAINTEXT_BYTES = [76, 105, 118, 101, 32, 108, 111, 110, 103, 32, 97, 110, 100, 32,
112, 114, 111, 115, 112, 101, 114, 46] as byte[]
// defined in https://datatracker.ietf.org/doc/html/rfc7516#appendix-A.3.1 :
final static String PROT_HEADER_STRING = '{"alg":"A128KW","enc":"A128CBC-HS256"}' as String
final static String encodedHeader = 'eyJhbGciOiJBMTI4S1ciLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0' as String
// defined in https://datatracker.ietf.org/doc/html/rfc7516#appendix-A.2.2
final static byte[] CEK_BYTES = [4, 211, 31, 197, 84, 157, 252, 254, 11, 100, 157, 250, 63, 170, 106,
206, 107, 124, 212, 45, 111, 107, 9, 219, 200, 177, 0, 240, 143, 156,
44, 207] as byte[]
final static SecretKey CEK = new SecretKeySpec(CEK_BYTES, "AES")
// defined in https://datatracker.ietf.org/doc/html/rfc7516#appendix-A.3.3
final static Map<String, String> KEK_VALUES = [
"kty": "oct",
"k" : "GawgguFyGrWKav7AX4VKUg"
]
final static byte[] ENCRYPTED_CEK_BYTES = [232, 160, 123, 211, 183, 76, 245, 132, 200, 128, 123, 75, 190, 216,
22, 67, 201, 138, 193, 186, 9, 91, 122, 31, 246, 90, 28, 139, 57, 3,
76, 124, 193, 11, 98, 37, 173, 61, 104, 57] as byte[]
final static String encodedEncryptedCek = '6KB707dM9YTIgHtLvtgWQ8mKwboJW3of9locizkDTHzBC2IlrT1oOQ' as String
// https://datatracker.ietf.org/doc/html/rfc7516#appendix-A.3.4
final static byte[] IV = [3, 22, 60, 12, 43, 67, 104, 105, 108, 108, 105, 99, 111, 116, 104, 101] as byte[]
final static String encodedIv = 'AxY8DCtDaGlsbGljb3RoZQ' as String
// defined in https://datatracker.ietf.org/doc/html/rfc7516#appendix-A.3.5
final static byte[] AAD_BYTES = [101, 121, 74, 104, 98, 71, 99, 105, 79, 105, 74, 66, 77, 84, 73, 52,
83, 49, 99, 105, 76, 67, 74, 108, 98, 109, 77, 105, 79, 105, 74, 66,
77, 84, 73, 52, 81, 48, 74, 68, 76, 85, 104, 84, 77, 106, 85, 50, 73,
110, 48] as byte[]
// defined in https://datatracker.ietf.org/doc/html/rfc7516#appendix-A.3.6
final static byte[] CIPHERTEXT = [40, 57, 83, 181, 119, 33, 133, 148, 198, 185, 243, 24, 152, 230, 6,
75, 129, 223, 127, 19, 210, 82, 183, 230, 168, 33, 215, 104, 143,
112, 56, 102] as byte[]
final static String encodedCiphertext = 'KDlTtXchhZTGufMYmOYGS4HffxPSUrfmqCHXaI9wOGY' as String
final static byte[] TAG = [83, 73, 191, 98, 104, 205, 211, 128, 201, 189, 199, 133, 32, 38, 194, 85] as byte[]
final static String encodedTag = 'U0m_YmjN04DJvceFICbCVQ'
// defined in https://datatracker.ietf.org/doc/html/rfc7516#appendix-A.3.7
final static String COMPLETE_JWE =
'eyJhbGciOiJBMTI4S1ciLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0.' +
'6KB707dM9YTIgHtLvtgWQ8mKwboJW3of9locizkDTHzBC2IlrT1oOQ.' +
'AxY8DCtDaGlsbGljb3RoZQ.' +
'KDlTtXchhZTGufMYmOYGS4HffxPSUrfmqCHXaI9wOGY.' +
'U0m_YmjN04DJvceFICbCVQ' as String
@Test
void test() {
//ensure our test constants are correctly copied and match the RFC values:
assertEquals PLAINTEXT, new String(PLAINTEXT_BYTES, StandardCharsets.UTF_8)
assertEquals PROT_HEADER_STRING, new String(decode(encodedHeader), StandardCharsets.UTF_8)
assertEquals encodedEncryptedCek, encode(ENCRYPTED_CEK_BYTES)
assertEquals encodedIv, encode(IV)
assertArrayEquals AAD_BYTES, encodedHeader.getBytes(StandardCharsets.US_ASCII)
assertArrayEquals CIPHERTEXT, decode(encodedCiphertext)
assertArrayEquals TAG, decode(encodedTag)
//read the RFC Test JWK to get the private key for decrypting
SecretJwk jwk = Jwks.builder().putAll(KEK_VALUES).build() as SecretJwk
SecretKey kek = jwk.toKey()
// test decryption per the RFC
Jwe<String> jwe = Jwts.parserBuilder().decryptWith(kek).build().parsePlaintextJwe(COMPLETE_JWE)
assertEquals PLAINTEXT, jwe.getBody()
// now ensure that when JJWT does the encryption (i.e. a compact value is produced from JJWT, not from the RFC text),
// that the resulting compact string is identical to the RFC as described in
// https://datatracker.ietf.org/doc/html/rfc7516#appendix-A.3.8 :
//ensure that the algorithm reflects the test harness values:
SymmetricAeadAlgorithm enc = new HmacAesAeadAlgorithm(128) {
@Override
protected byte[] ensureInitializationVector(SecurityRequest request) {
return IV;
}
@Override
SecretKey generateKey() {
return CEK;
}
}
String compact = Jwts.jweBuilder()
.setPayload(PLAINTEXT)
.encryptWith(enc)
.withKeyFrom(kek, KeyAlgorithms.A128KW)
.compact()
assertEquals COMPLETE_JWE, compact
}
}