KevKosDev
KevKosDev

Reputation: 849

Manually create JWK from (RSA) PublicKey

I need to convert a RSA PublicKey into a valid JWK. Especially the values "n" an "e" of the JWK are the ones I'm struggling with. The encoding does not seem to be correct, when looking at example JWK's at https://www.rfc-editor.org/rfc/rfc7517#page-25

Currently my code looks basically like this:

private Map<String, Object> generateJWK(PublicKey publicKey){

    RSAPublicKey rsa = (RSAPublicKey) publicKey;

    Map<String, Object> values = new HashMap<>();

    values.put("kty", rsa.getAlgorithm()); // getAlgorithm() returns kty not algorithm
    values.put("kid", "someuniqueid");
    values.put("n", Base64.encode(rsa.getModulus().toString()));
    values.put("e", Base64.encode(rsa.getPublicExponent().toString()));
    values.put("alg", "RS256");
    values.put("use", "sig");

    return values;
}

The output however does not seem to be correctly encoded or something, e for example looks like this: NjU1Mzc=

n does not include special characters like -, _ and + . :

jMzk1MNT0xTk2NED1xzzgNyQ00IykADzMAM0c0wz0M0MONj2z5TgNzI3yAM0OONYzzMjzwNzDxgAzxDxzMMAjTwNNDYMINMgNQDOEAkIM2jMQzkjUTDUYONNg1A00Tw1Nx4YEzAzjUT1MTNMjDjMM1MNNAjyTMIzxNADDINQANwT5yTDEMjEzNz2z2gOgjDDDNyNDjTzz43ETOYMI35gDjE00MYYM2DzDjDgww53Mwz0ME1NMgOM3MIzYTzMwzOMIQU5MjOzUjMNQNNg50U5NIDNzw2DMMOggNcQQM21TI5NMzDTN5Mj123O33MNNMkyNTNONxMM5wMMc04jTgAUE3MM1zMg4NNMT4MNDMM5yTO2j4jNDEMy1yNANNAzOIEUDzNwzExwTIkNjUjkN54Uz0DT5x0zM51k2MxYkx0zMNzxMkDUDTTQN3gAYODATQDDwMDMjMMcONjxMNTYMT5kgxNkMjNMQU0jzMEwIIMzTzUD4MgYDkDNzcAzN0TN4yNTz11DMxDUjDM2MyDMy4DEINMwT22QxjNNEzNDATy1OM1NNDxYgz5TxDkj3gQ32kIwNNkDO3xczDAENcTMNO0MOjTDwE3g11wNUcgNTwQk30kjjNNzTz4jTj4OOjQNYzMzcMjTQMkyzNNNUQOTOMMkMMMNzwNxDOEkg4xADIT4DNxMz2TENT4yN4z2I2zjyMU3DTOEQN4MIQjNDMU5Y11QkccwMNI0kNzyNjMMN4NMTTNMzMwxMjjDzgAANO1zwjYIEUjM1ADgDNjxTITMNNkIYxzyzzEEDMzDzNjzM4NjNNjc3ITTD0T5jzN=

Am I assuming right that both values n and e are not properly encoded? How should I convert the PublicKey to JWK? (Can not use 3rd party libraries)

Upvotes: 12

Views: 16490

Answers (2)

user2718758
user2718758

Reputation: 1

code below works fine, use Apache Base64, search by phrases

RFC 4648 vs RFC 2045 codec difference

and

java biginteger to byte array leading zero

private static byte[] toByteArray(BigInteger bigInteger)
    {
        byte[] bytes = bigInteger.toByteArray();
        byte[] result;
        if ((bigInteger.bitLength() % 8 == 0) && (bytes[0] == 0) && bytes.length > 1)
        {
            result = new byte[bytes.length - 1];
            System.arraycopy(bytes, 1, result, 0, result.length);
        }
        else {result = bytes;}
        return result;
    }
...
import org.apache.commons.codec.binary.Base64;
...
jwk.put("n", Base64.encodeBase64URLSafeString(toByteArray(publicKey.getModulus()) ) );
jwk.put("e", Base64.encodeBase64URLSafeString(publicKey.getPublicExponent().toByteArray()) );

Upvotes: 0

pedrofb
pedrofb

Reputation: 39261

JWK uses base64url encoding which is slighly different to base64. Additionally, do not use toString() method on BigInteger values. Get directly the data as byte array

Change

Base64.encode(rsa.getModulus().toString())
Base64.encode(rsa.getPublicExponent().toString())

To

Base64.getUrlEncoder().encodeToString(rsa.getModulus().toByteArray())
Base64.getUrlEncoder().encodeToString(rsa.getPublicExponent().toByteArray())

Upvotes: 18

Related Questions