mirror of https://github.com/jwtk/jjwt.git
Merge pull request #363 from jwtk/350-key-factories
Add Key generators to the public API
This commit is contained in:
commit
45f83d0cb1
|
@ -5,14 +5,15 @@ language: java
|
||||||
jdk:
|
jdk:
|
||||||
- openjdk7
|
- openjdk7
|
||||||
- oraclejdk8
|
- oraclejdk8
|
||||||
- oraclejdk9
|
# - oraclejdk9
|
||||||
- oraclejdk10
|
# - oraclejdk10
|
||||||
- openjdk10
|
# - openjdk10
|
||||||
# - openjdk11
|
# - openjdk11
|
||||||
# - oraclejdk-ea
|
# - oraclejdk-ea
|
||||||
|
|
||||||
before_install:
|
before_install:
|
||||||
- export BUILD_COVERAGE="$([ $TRAVIS_JDK_VERSION == 'oraclejdk8' ] && echo 'true')"
|
- export BUILD_COVERAGE="$([ $TRAVIS_JDK_VERSION == 'oraclejdk8' ] && echo 'true')"
|
||||||
|
# - if [[ "$TRAVIS_JDK_VERSION" != 'openjdk7' && "$TRAVIS_JDK_VERSION" != 'oraclejdk8' ]]; then export MAVEN_OPTS='--add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.io=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED'; fi;
|
||||||
|
|
||||||
install: true
|
install: true
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,161 @@
|
||||||
|
package io.jsonwebtoken.crypto;
|
||||||
|
|
||||||
|
import io.jsonwebtoken.SignatureAlgorithm;
|
||||||
|
import io.jsonwebtoken.lang.Assert;
|
||||||
|
import io.jsonwebtoken.lang.Classes;
|
||||||
|
|
||||||
|
import javax.crypto.SecretKey;
|
||||||
|
import java.security.KeyPair;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility class for securely generating {@link SecretKey}s and {@link KeyPair}s.
|
||||||
|
*
|
||||||
|
* @since 0.10.0
|
||||||
|
*/
|
||||||
|
public final class Keys {
|
||||||
|
|
||||||
|
private static final String MAC = "io.jsonwebtoken.impl.crypto.MacProvider";
|
||||||
|
private static final String RSA = "io.jsonwebtoken.impl.crypto.RsaProvider";
|
||||||
|
private static final String EC = "io.jsonwebtoken.impl.crypto.EllipticCurveProvider";
|
||||||
|
|
||||||
|
private static final Class[] SIG_ARG_TYPES = new Class[]{SignatureAlgorithm.class};
|
||||||
|
|
||||||
|
//prevent instantiation
|
||||||
|
private Keys() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a new {@link SecretKey} with a key length suitable for use with the specified {@link SignatureAlgorithm}.
|
||||||
|
*
|
||||||
|
* <p><a href="https://tools.ietf.org/html/rfc7518#section-3.2">JWA Specification (RFC 7518), Section 3.2</a>
|
||||||
|
* requires minimum key lengths to be used for each respective Signature Algorithm. This method returns a
|
||||||
|
* secure-random generated SecretKey that adheres to the required minimum key length. The lengths are:</p>
|
||||||
|
*
|
||||||
|
* <table>
|
||||||
|
* <tr>
|
||||||
|
* <th>Algorithm</th>
|
||||||
|
* <th>Key Length</th>
|
||||||
|
* </tr>
|
||||||
|
* <tr>
|
||||||
|
* <td>HS256</td>
|
||||||
|
* <td>256 bits (32 bytes)</td>
|
||||||
|
* </tr>
|
||||||
|
* <tr>
|
||||||
|
* <td>HS384</td>
|
||||||
|
* <td>384 bits (48 bytes)</td>
|
||||||
|
* </tr>
|
||||||
|
* <tr>
|
||||||
|
* <td>HS512</td>
|
||||||
|
* <td>512 bits (64 bytes)</td>
|
||||||
|
* </tr>
|
||||||
|
* </table>
|
||||||
|
*
|
||||||
|
* @param alg the {@code SignatureAlgorithm} to inspect to determine which key length to use.
|
||||||
|
* @return a new {@link SecretKey} instance suitable for use with the specified {@link SignatureAlgorithm}.
|
||||||
|
* @throws IllegalArgumentException for any input value other than {@link SignatureAlgorithm#HS256},
|
||||||
|
* {@link SignatureAlgorithm#HS384}, or {@link SignatureAlgorithm#HS512}
|
||||||
|
*/
|
||||||
|
public static SecretKey secretKeyFor(SignatureAlgorithm alg) throws IllegalArgumentException {
|
||||||
|
Assert.notNull(alg, "SignatureAlgorithm cannot be null.");
|
||||||
|
switch (alg) {
|
||||||
|
case HS256:
|
||||||
|
case HS384:
|
||||||
|
case HS512:
|
||||||
|
return Classes.invokeStatic(MAC, "generateKey", SIG_ARG_TYPES, alg);
|
||||||
|
default:
|
||||||
|
String msg = "The " + alg.name() + " algorithm does not support shared secret keys.";
|
||||||
|
throw new IllegalArgumentException(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a new {@link KeyPair} suitable for use with the specified asymmetric algorithm.
|
||||||
|
*
|
||||||
|
* <p>If the {@code alg} argument is an RSA algorithm, a KeyPair is generated based on the following:</p>
|
||||||
|
*
|
||||||
|
* <table>
|
||||||
|
* <tr>
|
||||||
|
* <th>JWA Algorithm</th>
|
||||||
|
* <th>Key Size</th>
|
||||||
|
* </tr>
|
||||||
|
* <tr>
|
||||||
|
* <td>RS256</td>
|
||||||
|
* <td>2048 bits</td>
|
||||||
|
* </tr>
|
||||||
|
* <tr>
|
||||||
|
* <td>PS256</td>
|
||||||
|
* <td>2048 bits</td>
|
||||||
|
* </tr>
|
||||||
|
* <tr>
|
||||||
|
* <td>RS384</td>
|
||||||
|
* <td>3072 bits</td>
|
||||||
|
* </tr>
|
||||||
|
* <tr>
|
||||||
|
* <td>PS256</td>
|
||||||
|
* <td>3072 bits</td>
|
||||||
|
* </tr>
|
||||||
|
* <tr>
|
||||||
|
* <td>RS512</td>
|
||||||
|
* <td>4096 bits</td>
|
||||||
|
* </tr>
|
||||||
|
* <tr>
|
||||||
|
* <td>PS512</td>
|
||||||
|
* <td>4096 bits</td>
|
||||||
|
* </tr>
|
||||||
|
* </table>
|
||||||
|
*
|
||||||
|
* <p>If the {@code alg} argument is an Elliptic Curve algorithm, a KeyPair is generated based on the following:</p>
|
||||||
|
*
|
||||||
|
* <table>
|
||||||
|
* <tr>
|
||||||
|
* <th>JWA Algorithm</th>
|
||||||
|
* <th>Key Size</th>
|
||||||
|
* <th><a href="https://tools.ietf.org/html/rfc7518#section-7.6.2">JWA Curve Name</a></th>
|
||||||
|
* <th><a href="https://tools.ietf.org/html/rfc5480#section-2.1.1.1">ASN1 OID Curve Name</a></th>
|
||||||
|
* </tr>
|
||||||
|
* <tr>
|
||||||
|
* <td>EC256</td>
|
||||||
|
* <td>256 bits</td>
|
||||||
|
* <td>{@code P-256}</td>
|
||||||
|
* <td>{@code secp256r1}</td>
|
||||||
|
* </tr>
|
||||||
|
* <tr>
|
||||||
|
* <td>EC384</td>
|
||||||
|
* <td>384 bits</td>
|
||||||
|
* <td>{@code P-384}</td>
|
||||||
|
* <td>{@code secp384r1}</td>
|
||||||
|
* </tr>
|
||||||
|
* <tr>
|
||||||
|
* <td>EC512</td>
|
||||||
|
* <td>512 bits</td>
|
||||||
|
* <td>{@code P-512}</td>
|
||||||
|
* <td>{@code secp521r1}</td>
|
||||||
|
* </tr>
|
||||||
|
* </table>
|
||||||
|
*
|
||||||
|
* @param alg the {@code SignatureAlgorithm} to inspect to determine which asymmetric algorithm to use.
|
||||||
|
* @return a new {@link KeyPair} suitable for use with the specified asymmetric algorithm.
|
||||||
|
* @throws IllegalArgumentException if {@code alg} equals {@link SignatureAlgorithm#HS256 HS256},
|
||||||
|
* {@link SignatureAlgorithm#HS384 HS384}, {@link SignatureAlgorithm#HS512 HS512}
|
||||||
|
* or {@link SignatureAlgorithm#NONE NONE}.
|
||||||
|
*/
|
||||||
|
public static KeyPair keyPairFor(SignatureAlgorithm alg) throws IllegalArgumentException {
|
||||||
|
Assert.notNull(alg, "SignatureAlgorithm cannot be null.");
|
||||||
|
switch (alg) {
|
||||||
|
case RS256:
|
||||||
|
case PS256:
|
||||||
|
case RS384:
|
||||||
|
case PS384:
|
||||||
|
case RS512:
|
||||||
|
case PS512:
|
||||||
|
return Classes.invokeStatic(RSA, "generateKeyPair", SIG_ARG_TYPES, alg);
|
||||||
|
case ES256:
|
||||||
|
case ES384:
|
||||||
|
case ES512:
|
||||||
|
return Classes.invokeStatic(EC, "generateKeyPair", SIG_ARG_TYPES, alg);
|
||||||
|
default:
|
||||||
|
String msg = "The " + alg.name() + " algorithm does not support Key Pairs.";
|
||||||
|
throw new IllegalArgumentException(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,6 +17,7 @@ package io.jsonwebtoken.lang;
|
||||||
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.lang.reflect.Constructor;
|
import java.lang.reflect.Constructor;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @since 0.1
|
* @since 0.1
|
||||||
|
@ -185,6 +186,23 @@ public final class Classes {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 0.10.0
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public static <T> T invokeStatic(String fqcn, String methodName, Class[] argTypes, Object... args) {
|
||||||
|
try {
|
||||||
|
Class clazz = Classes.forName(fqcn);
|
||||||
|
Method method = clazz.getDeclaredMethod(methodName, argTypes);
|
||||||
|
method.setAccessible(true);
|
||||||
|
return(T)method.invoke(null, args);
|
||||||
|
} catch (Exception e) {
|
||||||
|
String msg = "Unable to invoke class method " + fqcn + "#" + methodName + ". Ensure the necessary " +
|
||||||
|
"implementation is in the runtime classpath.";
|
||||||
|
throw new IllegalStateException(msg, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @since 1.0
|
* @since 1.0
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -0,0 +1,106 @@
|
||||||
|
package io.jsonwebtoken.crypto
|
||||||
|
|
||||||
|
import io.jsonwebtoken.SignatureAlgorithm
|
||||||
|
import io.jsonwebtoken.lang.Classes
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
import org.powermock.core.classloader.annotations.PrepareForTest
|
||||||
|
import org.powermock.modules.junit4.PowerMockRunner
|
||||||
|
|
||||||
|
import javax.crypto.SecretKey
|
||||||
|
import java.security.KeyPair
|
||||||
|
|
||||||
|
import static org.easymock.EasyMock.eq
|
||||||
|
import static org.easymock.EasyMock.expect
|
||||||
|
import static org.easymock.EasyMock.same
|
||||||
|
import static org.junit.Assert.assertEquals
|
||||||
|
import static org.junit.Assert.assertSame
|
||||||
|
import static org.junit.Assert.fail
|
||||||
|
import static org.powermock.api.easymock.PowerMock.mockStatic
|
||||||
|
import static org.powermock.api.easymock.PowerMock.createMock
|
||||||
|
import static org.powermock.api.easymock.PowerMock.replay
|
||||||
|
import static org.powermock.api.easymock.PowerMock.reset
|
||||||
|
import static org.powermock.api.easymock.PowerMock.verify
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This test class is for cursory API-level testing only (what is available to the API module at build time).
|
||||||
|
*
|
||||||
|
* The actual implementation assertions are done in KeysImplTest in the impl module.
|
||||||
|
*/
|
||||||
|
@RunWith(PowerMockRunner)
|
||||||
|
@PrepareForTest([Classes, Keys])
|
||||||
|
class KeysTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testPrivateCtor() { //for code coverage only
|
||||||
|
new Keys()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testSecretKeyFor() {
|
||||||
|
|
||||||
|
for (SignatureAlgorithm alg : SignatureAlgorithm.values()) {
|
||||||
|
|
||||||
|
String name = alg.name()
|
||||||
|
|
||||||
|
if (name.startsWith('H')) {
|
||||||
|
|
||||||
|
mockStatic(Classes)
|
||||||
|
|
||||||
|
def key = createMock(SecretKey)
|
||||||
|
expect(Classes.invokeStatic(eq(Keys.MAC), eq("generateKey"), same(Keys.SIG_ARG_TYPES), same(alg))).andReturn(key)
|
||||||
|
|
||||||
|
replay Classes, key
|
||||||
|
|
||||||
|
assertSame key, Keys.secretKeyFor(alg)
|
||||||
|
|
||||||
|
verify Classes, key
|
||||||
|
|
||||||
|
reset Classes, key
|
||||||
|
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
Keys.secretKeyFor(alg)
|
||||||
|
fail()
|
||||||
|
} catch (IllegalArgumentException expected) {
|
||||||
|
assertEquals "The $name algorithm does not support shared secret keys." as String, expected.message
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testKeyPairFor() {
|
||||||
|
|
||||||
|
for (SignatureAlgorithm alg : SignatureAlgorithm.values()) {
|
||||||
|
|
||||||
|
String name = alg.name()
|
||||||
|
|
||||||
|
if (name.equals('NONE') || name.startsWith('H')) {
|
||||||
|
try {
|
||||||
|
Keys.keyPairFor(alg)
|
||||||
|
fail()
|
||||||
|
} catch (IllegalArgumentException expected) {
|
||||||
|
assertEquals "The $name algorithm does not support Key Pairs." as String, expected.message
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
String fqcn = name.startsWith('E') ? Keys.EC : Keys.RSA
|
||||||
|
|
||||||
|
mockStatic Classes
|
||||||
|
|
||||||
|
def pair = createMock(KeyPair)
|
||||||
|
expect(Classes.invokeStatic(eq(fqcn), eq("generateKeyPair"), same(Keys.SIG_ARG_TYPES), same(alg))).andReturn(pair)
|
||||||
|
|
||||||
|
replay Classes, pair
|
||||||
|
|
||||||
|
assertSame pair, Keys.keyPairFor(alg)
|
||||||
|
|
||||||
|
verify Classes, pair
|
||||||
|
|
||||||
|
reset Classes, pair
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
48
core/pom.xml
48
core/pom.xml
|
@ -1,48 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!--
|
|
||||||
~ Copyright 2018 JWTK
|
|
||||||
~
|
|
||||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
~ you may not use this file except in compliance with the License.
|
|
||||||
~ You may obtain a copy of the License at
|
|
||||||
~
|
|
||||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
~
|
|
||||||
~ Unless required by applicable law or agreed to in writing, software
|
|
||||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
~ See the License for the specific language governing permissions and
|
|
||||||
~ limitations under the License.
|
|
||||||
-->
|
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
|
||||||
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
|
||||||
|
|
||||||
<parent>
|
|
||||||
<groupId>io.jsonwebtoken</groupId>
|
|
||||||
<artifactId>jjwt-root</artifactId>
|
|
||||||
<version>0.10.0-SNAPSHOT</version>
|
|
||||||
<relativePath>../pom.xml</relativePath>
|
|
||||||
</parent>
|
|
||||||
|
|
||||||
<artifactId>jjwt-core</artifactId>
|
|
||||||
<name>JJWT :: Core</name>
|
|
||||||
<packaging>jar</packaging>
|
|
||||||
|
|
||||||
<properties>
|
|
||||||
<jjwt.root>${basedir}/..</jjwt.root>
|
|
||||||
</properties>
|
|
||||||
|
|
||||||
<dependencies>
|
|
||||||
<dependency>
|
|
||||||
<groupId>io.jsonwebtoken</groupId>
|
|
||||||
<artifactId>jjwt-api</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>io.jsonwebtoken</groupId>
|
|
||||||
<artifactId>jjwt-impl</artifactId>
|
|
||||||
<scope>runtime</scope>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
|
|
||||||
</project>
|
|
|
@ -114,6 +114,36 @@ public abstract class RsaProvider extends SignatureProvider {
|
||||||
return generateKeyPair(keySizeInBits, DEFAULT_SECURE_RANDOM);
|
return generateKeyPair(keySizeInBits, DEFAULT_SECURE_RANDOM);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a new RSA secure-randomly key pair suitable for the specified SignatureAlgorithm using JJWT's
|
||||||
|
* default {@link SignatureProvider#DEFAULT_SECURE_RANDOM SecureRandom instance}. This is a convenience method
|
||||||
|
* that immediately delegates to {@link #generateKeyPair(int)} based on the relevant key size for the specified
|
||||||
|
* algorithm.
|
||||||
|
*
|
||||||
|
* @param alg the signature algorithm to inspect to determine a size in bits.
|
||||||
|
* @return a new RSA secure-random key pair of the specified size.
|
||||||
|
* @see #generateKeyPair()
|
||||||
|
* @see #generateKeyPair(int, SecureRandom)
|
||||||
|
* @see #generateKeyPair(String, int, SecureRandom)
|
||||||
|
* @since 0.10.0
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unused") //used by io.jsonwebtoken.crypto.Keys
|
||||||
|
public static KeyPair generateKeyPair(SignatureAlgorithm alg) {
|
||||||
|
Assert.isTrue("RSA".equalsIgnoreCase(alg.getFamilyName()), "Only RSA algorithms are supported by this method.");
|
||||||
|
int keySizeInBits = 4096;
|
||||||
|
switch (alg) {
|
||||||
|
case RS256:
|
||||||
|
case PS256:
|
||||||
|
keySizeInBits = 2048;
|
||||||
|
break;
|
||||||
|
case RS384:
|
||||||
|
case PS384:
|
||||||
|
keySizeInBits = 3072;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return generateKeyPair(keySizeInBits, DEFAULT_SECURE_RANDOM);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates a new RSA secure-random key pair of the specified size using the given SecureRandom number generator.
|
* Generates a new RSA secure-random key pair of the specified size using the given SecureRandom number generator.
|
||||||
* This is a convenience method that immediately delegates to {@link #generateKeyPair(String, int, SecureRandom)}
|
* This is a convenience method that immediately delegates to {@link #generateKeyPair(String, int, SecureRandom)}
|
||||||
|
|
|
@ -0,0 +1,99 @@
|
||||||
|
package io.jsonwebtoken.crypto
|
||||||
|
|
||||||
|
import io.jsonwebtoken.SignatureAlgorithm
|
||||||
|
import org.junit.Test
|
||||||
|
|
||||||
|
import javax.crypto.SecretKey
|
||||||
|
import java.security.KeyPair
|
||||||
|
import java.security.PrivateKey
|
||||||
|
import java.security.PublicKey
|
||||||
|
import java.security.interfaces.ECPrivateKey
|
||||||
|
import java.security.interfaces.ECPublicKey
|
||||||
|
import java.security.interfaces.RSAPrivateKey
|
||||||
|
|
||||||
|
import static org.junit.Assert.*
|
||||||
|
|
||||||
|
class KeysImplTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testPrivateCtor() { //for code coverage purposes only
|
||||||
|
new Keys()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testSecretKeyFor() {
|
||||||
|
|
||||||
|
for (SignatureAlgorithm alg : SignatureAlgorithm.values()) {
|
||||||
|
|
||||||
|
String name = alg.name()
|
||||||
|
|
||||||
|
int bitLength = name.equalsIgnoreCase("NONE") ? 0 : name.substring(2).toInteger()
|
||||||
|
|
||||||
|
if (name.startsWith('H')) {
|
||||||
|
SecretKey key = Keys.secretKeyFor(alg)
|
||||||
|
assertEquals bitLength, key.getEncoded().length * 8 //convert byte count to bit count
|
||||||
|
assertEquals alg.jcaName, key.algorithm
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
Keys.secretKeyFor(alg)
|
||||||
|
fail()
|
||||||
|
} catch (IllegalArgumentException expected) {
|
||||||
|
assertEquals "The $name algorithm does not support shared secret keys." as String, expected.message
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testKeyPairFor() {
|
||||||
|
|
||||||
|
for (SignatureAlgorithm alg : SignatureAlgorithm.values()) {
|
||||||
|
|
||||||
|
String name = alg.name()
|
||||||
|
int bitLength = name.equalsIgnoreCase("NONE") ? 0 : name.substring(2).toInteger()
|
||||||
|
|
||||||
|
if (name.startsWith('R') || name.startsWith('P')) {
|
||||||
|
|
||||||
|
KeyPair pair = Keys.keyPairFor(alg)
|
||||||
|
assertNotNull pair
|
||||||
|
PublicKey pub = pair.getPublic()
|
||||||
|
PrivateKey priv = pair.getPrivate()
|
||||||
|
assert priv instanceof RSAPrivateKey
|
||||||
|
assertEquals alg.familyName, pub.algorithm
|
||||||
|
assertEquals alg.familyName, priv.algorithm
|
||||||
|
assertEquals bitLength * 8, priv.modulus.bitLength()
|
||||||
|
|
||||||
|
} else if (name.startsWith('E')) {
|
||||||
|
|
||||||
|
KeyPair pair = Keys.keyPairFor(alg);
|
||||||
|
assertNotNull pair
|
||||||
|
|
||||||
|
if (alg == SignatureAlgorithm.ES512) {
|
||||||
|
bitLength = 521
|
||||||
|
}
|
||||||
|
|
||||||
|
String asn1oid = "secp${bitLength}r1"
|
||||||
|
|
||||||
|
PublicKey pub = pair.getPublic()
|
||||||
|
assert pub instanceof ECPublicKey
|
||||||
|
assertEquals "ECDSA", pub.algorithm
|
||||||
|
assertEquals asn1oid, pub.params.name
|
||||||
|
assertEquals bitLength, pub.params.order.bitLength()
|
||||||
|
|
||||||
|
PrivateKey priv = pair.getPrivate()
|
||||||
|
assert priv instanceof ECPrivateKey
|
||||||
|
assertEquals "ECDSA", priv.algorithm
|
||||||
|
assertEquals asn1oid, priv.params.name
|
||||||
|
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
Keys.keyPairFor(alg)
|
||||||
|
fail()
|
||||||
|
} catch (IllegalArgumentException expected) {
|
||||||
|
assertEquals "The $name algorithm does not support Key Pairs." as String, expected.message
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
6
pom.xml
6
pom.xml
|
@ -111,7 +111,6 @@
|
||||||
<module>api</module>
|
<module>api</module>
|
||||||
<module>impl</module>
|
<module>impl</module>
|
||||||
<module>extensions</module>
|
<module>extensions</module>
|
||||||
<module>core</module>
|
|
||||||
</modules>
|
</modules>
|
||||||
|
|
||||||
<dependencyManagement>
|
<dependencyManagement>
|
||||||
|
@ -127,11 +126,6 @@
|
||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
<scope>runtime</scope>
|
<scope>runtime</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>io.jsonwebtoken</groupId>
|
|
||||||
<artifactId>jjwt-core</artifactId>
|
|
||||||
<version>${project.version}</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.jsonwebtoken</groupId>
|
<groupId>io.jsonwebtoken</groupId>
|
||||||
<artifactId>jjwt-jackson</artifactId>
|
<artifactId>jjwt-jackson</artifactId>
|
||||||
|
|
Loading…
Reference in New Issue