package com.auth0.jwt.algorithms;
import com.auth0.jwt.JWT;
import com.auth0.jwt.exceptions.SignatureGenerationException;
import com.auth0.jwt.exceptions.SignatureVerificationException;
import com.auth0.jwt.interfaces.DecodedJWT;
import org.apache.commons.codec.binary.Base64;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
public class HMACAlgorithmTest {
@Rule
public ExpectedException exception = ExpectedException.none();
// Verify
@Test
public void shouldGetStringBytes() throws Exception {
String text = "abcdef123456!@#$%^";
byte[] expectedBytes = text.getBytes("UTF-8");
assertTrue(Arrays.equals(expectedBytes, HMACAlgorithm.getSecretBytes(text)));
}
@Test
public void shouldPassHMAC256Verification() throws Exception {
String jwt = "eyJhbGciOiJIUzI1NiIsImN0eSI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.mZ0m_N1J4PgeqWmi903JuUoDRZDBPB7HwkS4nVyWH1M";
Algorithm algorithmString = Algorithm.HMAC256("secret");
Algorithm algorithmBytes = Algorithm.HMAC256("secret".getBytes(StandardCharsets.UTF_8));
DecodedJWT decoded = JWT.decode(jwt);
algorithmString.verify(decoded);
algorithmBytes.verify(decoded);
}
@Test
public void shouldFailHMAC256VerificationWithInvalidSecretString() throws Exception {
exception.expect(SignatureVerificationException.class);
exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: HmacSHA256");
String jwt = "eyJhbGciOiJIUzI1NiIsImN0eSI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.mZ0m_N1J4PgeqWmi903JuUoDRZDBPB7HwkS4nVyWH1M";
Algorithm algorithm = Algorithm.HMAC256("not_real_secret");
algorithm.verify(JWT.decode(jwt));
}
@Test
public void shouldFailHMAC256VerificationWithInvalidSecretBytes() throws Exception {
exception.expect(SignatureVerificationException.class);
exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: HmacSHA256");
String jwt = "eyJhbGciOiJIUzI1NiIsImN0eSI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.mZ0m_N1J4PgeqWmi903JuUoDRZDBPB7HwkS4nVyWH1M";
Algorithm algorithm = Algorithm.HMAC256("not_real_secret".getBytes(StandardCharsets.UTF_8));
algorithm.verify(JWT.decode(jwt));
}
@Test
public void shouldPassHMAC384Verification() throws Exception {
String jwt = "eyJhbGciOiJIUzM4NCIsImN0eSI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.uztpK_wUMYJhrRv8SV-1LU4aPnwl-EM1q-wJnqgyb5DHoDteP6lN_gE1xnZJH5vw";
Algorithm algorithmString = Algorithm.HMAC384("secret");
Algorithm algorithmBytes = Algorithm.HMAC384("secret".getBytes(StandardCharsets.UTF_8));
DecodedJWT decoded = JWT.decode(jwt);
algorithmString.verify(decoded);
algorithmBytes.verify(decoded);
}
@Test
public void shouldFailHMAC384VerificationWithInvalidSecretString() throws Exception {
exception.expect(SignatureVerificationException.class);
exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: HmacSHA384");
String jwt = "eyJhbGciOiJIUzM4NCIsImN0eSI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.uztpK_wUMYJhrRv8SV-1LU4aPnwl-EM1q-wJnqgyb5DHoDteP6lN_gE1xnZJH5vw";
Algorithm algorithm = Algorithm.HMAC384("not_real_secret");
algorithm.verify(JWT.decode(jwt));
}
@Test
public void shouldFailHMAC384VerificationWithInvalidSecretBytes() throws Exception {
exception.expect(SignatureVerificationException.class);
exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: HmacSHA384");
String jwt = "eyJhbGciOiJIUzM4NCIsImN0eSI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.uztpK_wUMYJhrRv8SV-1LU4aPnwl-EM1q-wJnqgyb5DHoDteP6lN_gE1xnZJH5vw";
Algorithm algorithm = Algorithm.HMAC384("not_real_secret".getBytes(StandardCharsets.UTF_8));
algorithm.verify(JWT.decode(jwt));
}
@Test
public void shouldPassHMAC512Verification() throws Exception {
String jwt = "eyJhbGciOiJIUzUxMiIsImN0eSI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.VUo2Z9SWDV-XcOc_Hr6Lff3vl7L9e5Vb8ThXpmGDFjHxe3Dr1ZBmUChYF-xVA7cAdX1P_D4ZCUcsv3IefpVaJw";
Algorithm algorithmString = Algorithm.HMAC512("secret");
Algorithm algorithmBytes = Algorithm.HMAC512("secret".getBytes(StandardCharsets.UTF_8));
DecodedJWT decoded = JWT.decode(jwt);
algorithmString.verify(decoded);
algorithmBytes.verify(decoded);
}
@Test
public void shouldFailHMAC512VerificationWithInvalidSecretString() throws Exception {
exception.expect(SignatureVerificationException.class);
exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: HmacSHA512");
String jwt = "eyJhbGciOiJIUzUxMiIsImN0eSI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.VUo2Z9SWDV-XcOc_Hr6Lff3vl7L9e5Vb8ThXpmGDFjHxe3Dr1ZBmUChYF-xVA7cAdX1P_D4ZCUcsv3IefpVaJw";
Algorithm algorithm = Algorithm.HMAC512("not_real_secret");
algorithm.verify(JWT.decode(jwt));
}
@Test
public void shouldFailHMAC512VerificationWithInvalidSecretBytes() throws Exception {
exception.expect(SignatureVerificationException.class);
exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: HmacSHA512");
String jwt = "eyJhbGciOiJIUzUxMiIsImN0eSI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.VUo2Z9SWDV-XcOc_Hr6Lff3vl7L9e5Vb8ThXpmGDFjHxe3Dr1ZBmUChYF-xVA7cAdX1P_D4ZCUcsv3IefpVaJw";
Algorithm algorithm = Algorithm.HMAC512("not_real_secret".getBytes(StandardCharsets.UTF_8));
algorithm.verify(JWT.decode(jwt));
}
@Test
public void shouldThrowOnVerifyWhenSignatureAlgorithmDoesNotExists() throws Exception {
exception.expect(SignatureVerificationException.class);
exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: some-alg");
exception.expectCause(isA(NoSuchAlgorithmException.class));
CryptoHelper crypto = mock(CryptoHelper.class);
when(crypto.verifySignatureFor(anyString(), any(byte[].class), any(byte[].class), any(byte[].class)))
.thenThrow(NoSuchAlgorithmException.class);
Algorithm algorithm = new HMACAlgorithm(crypto, "some-alg", "some-algorithm", "secret".getBytes(StandardCharsets.UTF_8));
String jwt = "eyJhbGciOiJIUzI1NiIsImN0eSI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.mZ0m_N1J4PgeqWmi903JuUoDRZDBPB7HwkS4nVyWH1M";
algorithm.verify(JWT.decode(jwt));
}
@Test
public void shouldThrowOnVerifyWhenTheSecretIsInvalid() throws Exception {
exception.expect(SignatureVerificationException.class);
exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: some-alg");
exception.expectCause(isA(InvalidKeyException.class));
CryptoHelper crypto = mock(CryptoHelper.class);
when(crypto.verifySignatureFor(anyString(), any(byte[].class), any(byte[].class), any(byte[].class)))
.thenThrow(InvalidKeyException.class);
Algorithm algorithm = new HMACAlgorithm(crypto, "some-alg", "some-algorithm", "secret".getBytes(StandardCharsets.UTF_8));
String jwt = "eyJhbGciOiJIUzI1NiIsImN0eSI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.mZ0m_N1J4PgeqWmi903JuUoDRZDBPB7HwkS4nVyWH1M";
algorithm.verify(JWT.decode(jwt));
}
// Sign
private static final String HS256Header = "eyJhbGciOiJIUzI1NiJ9";
private static final String HS384Header = "eyJhbGciOiJIUzM4NCJ9";
private static final String HS512Header = "eyJhbGciOiJIUzUxMiJ9";
private static final String auth0IssPayload = "eyJpc3MiOiJhdXRoMCJ9";
@Test
public void shouldDoHMAC256SigningWithBytes() throws Exception {
Algorithm algorithm = Algorithm.HMAC256("secret".getBytes(StandardCharsets.UTF_8));
String jwtContent = String.format("%s.%s", HS256Header, auth0IssPayload);
byte[] contentBytes = jwtContent.getBytes(StandardCharsets.UTF_8);
byte[] signatureBytes = algorithm.sign(contentBytes);
String jwtSignature = Base64.encodeBase64URLSafeString(signatureBytes);
String jwt = String.format("%s.%s", jwtContent, jwtSignature);
String expectedSignature = "s69x7Mmu4JqwmdxiK6sesALO7tcedbFsKEEITUxw9ho";
assertThat(signatureBytes, is(notNullValue()));
assertThat(jwtSignature, is(expectedSignature));
algorithm.verify(JWT.decode(jwt));
}
@Test
public void shouldDoHMAC384SigningWithBytes() throws Exception {
Algorithm algorithm = Algorithm.HMAC384("secret".getBytes(StandardCharsets.UTF_8));
String jwtContent = String.format("%s.%s", HS384Header, auth0IssPayload);
byte[] contentBytes = jwtContent.getBytes(StandardCharsets.UTF_8);
byte[] signatureBytes = algorithm.sign(contentBytes);
String jwtSignature = Base64.encodeBase64URLSafeString(signatureBytes);
String jwt = String.format("%s.%s", jwtContent, jwtSignature);
String expectedSignature = "4-y2Gxz_foN0jAOFimmBPF7DWxf4AsjM20zxNkHg8Zah5Q64G42P9GfjmUp4Hldt";
assertThat(signatureBytes, is(notNullValue()));
assertThat(jwtSignature, is(expectedSignature));
algorithm.verify(JWT.decode(jwt));
}
@Test
public void shouldDoHMAC512SigningWithBytes() throws Exception {
Algorithm algorithm = Algorithm.HMAC512("secret".getBytes(StandardCharsets.UTF_8));
String jwtContent = String.format("%s.%s", HS512Header, auth0IssPayload);
byte[] contentBytes = jwtContent.getBytes(StandardCharsets.UTF_8);
byte[] signatureBytes = algorithm.sign(contentBytes);
String jwtSignature = Base64.encodeBase64URLSafeString(signatureBytes);
String jwt = String.format("%s.%s", jwtContent, jwtSignature);
String expectedSignature = "OXWyxmf-VcVo8viOiTFfLaEy6mrQqLEos5R82Xsx8mtFxQadJAQ1aVniIWN8qT2GNE_pMQPcdzk4x7Cqxsp1dw";
assertThat(signatureBytes, is(notNullValue()));
assertThat(jwtSignature, is(expectedSignature));
algorithm.verify(JWT.decode(jwt));
}
@Test
public void shouldDoHMAC256SigningWithString() throws Exception {
Algorithm algorithm = Algorithm.HMAC256("secret");
String jwtContent = String.format("%s.%s", HS256Header, auth0IssPayload);
byte[] contentBytes = jwtContent.getBytes(StandardCharsets.UTF_8);
byte[] signatureBytes = algorithm.sign(contentBytes);
String jwtSignature = Base64.encodeBase64URLSafeString(signatureBytes);
String jwt = String.format("%s.%s", jwtContent, jwtSignature);
String expectedSignature = "s69x7Mmu4JqwmdxiK6sesALO7tcedbFsKEEITUxw9ho";
assertThat(signatureBytes, is(notNullValue()));
assertThat(jwtSignature, is(expectedSignature));
algorithm.verify(JWT.decode(jwt));
}
@Test
public void shouldDoHMAC384SigningWithString() throws Exception {
Algorithm algorithm = Algorithm.HMAC384("secret");
String jwtContent = String.format("%s.%s", HS384Header, auth0IssPayload);
byte[] contentBytes = jwtContent.getBytes(StandardCharsets.UTF_8);
byte[] signatureBytes = algorithm.sign(contentBytes);
String jwtSignature = Base64.encodeBase64URLSafeString(signatureBytes);
String jwt = String.format("%s.%s", jwtContent, jwtSignature);
String expectedSignature = "4-y2Gxz_foN0jAOFimmBPF7DWxf4AsjM20zxNkHg8Zah5Q64G42P9GfjmUp4Hldt";
assertThat(signatureBytes, is(notNullValue()));
assertThat(jwtSignature, is(expectedSignature));
algorithm.verify(JWT.decode(jwt));
}
@Test
public void shouldDoHMAC512SigningWithString() throws Exception {
Algorithm algorithm = Algorithm.HMAC512("secret");
String jwtContent = String.format("%s.%s", HS512Header, auth0IssPayload);
byte[] contentBytes = jwtContent.getBytes(StandardCharsets.UTF_8);
byte[] signatureBytes = algorithm.sign(contentBytes);
String jwtSignature = Base64.encodeBase64URLSafeString(signatureBytes);
String jwt = String.format("%s.%s", jwtContent, jwtSignature);
String expectedSignature = "OXWyxmf-VcVo8viOiTFfLaEy6mrQqLEos5R82Xsx8mtFxQadJAQ1aVniIWN8qT2GNE_pMQPcdzk4x7Cqxsp1dw";
assertThat(signatureBytes, is(notNullValue()));
assertThat(jwtSignature, is(expectedSignature));
algorithm.verify(JWT.decode(jwt));
}
@Test
public void shouldThrowOnSignWhenSignatureAlgorithmDoesNotExists() throws Exception {
exception.expect(SignatureGenerationException.class);
exception.expectMessage("The Token's Signature couldn't be generated when signing using the Algorithm: some-algorithm");
exception.expectCause(isA(NoSuchAlgorithmException.class));
CryptoHelper crypto = mock(CryptoHelper.class);
when(crypto.createSignatureFor(anyString(), any(byte[].class), any(byte[].class)))
.thenThrow(NoSuchAlgorithmException.class);
Algorithm algorithm = new HMACAlgorithm(crypto, "some-alg", "some-algorithm", "secret".getBytes(StandardCharsets.UTF_8));
algorithm.sign(new byte[0]);
}
@Test
public void shouldThrowOnSignWhenTheSecretIsInvalid() throws Exception {
exception.expect(SignatureGenerationException.class);
exception.expectMessage("The Token's Signature couldn't be generated when signing using the Algorithm: some-algorithm");
exception.expectCause(isA(InvalidKeyException.class));
CryptoHelper crypto = mock(CryptoHelper.class);
when(crypto.createSignatureFor(anyString(), any(byte[].class), any(byte[].class)))
.thenThrow(InvalidKeyException.class);
Algorithm algorithm = new HMACAlgorithm(crypto, "some-alg", "some-algorithm", "secret".getBytes(StandardCharsets.UTF_8));
algorithm.sign(new byte[0]);
}
@Test
public void shouldReturnNullSigningKeyId() throws Exception {
assertThat(Algorithm.HMAC256("secret").getSigningKeyId(), is(nullValue()));
}
}