001/* 002 * nimbus-jose-jwt 003 * 004 * Copyright 2012-2018, Connect2id Ltd and contributors. 005 * 006 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use 007 * this file except in compliance with the License. You may obtain a copy of the 008 * License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software distributed 013 * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 014 * CONDITIONS OF ANY KIND, either express or implied. See the License for the 015 * specific language governing permissions and limitations under the License. 016 */ 017 018package com.nimbusds.jose.jwk.gen; 019 020import java.security.GeneralSecurityException; 021import java.security.InvalidKeyException; 022import java.util.Collections; 023import java.util.LinkedHashSet; 024import java.util.Set; 025 026import com.google.crypto.tink.subtle.Ed25519Sign; 027import com.google.crypto.tink.subtle.X25519; 028import com.nimbusds.jose.JOSEException; 029import com.nimbusds.jose.jwk.Curve; 030import com.nimbusds.jose.jwk.OctetKeyPair; 031import com.nimbusds.jose.util.Base64URL; 032 033 034/** 035 * Octet Key Pair (OKP) JSON Web Key (JWK) generator. 036 * 037 * <p>Supported curves: 038 * 039 * <ul> 040 * <li>{@link Curve#X25519 X25519} 041 * <li>{@link Curve#Ed25519 Ed25519} 042 * </ul> 043 * 044 * @author Tim McLean 045 * @version 2018-07-18 046 */ 047public class OctetKeyPairGenerator extends JWKGenerator<OctetKeyPair> { 048 049 050 /** 051 * The curve. 052 */ 053 private final Curve crv; 054 055 056 /** 057 * The supported values for the "crv" property. 058 */ 059 public static final Set<Curve> SUPPORTED_CURVES; 060 061 062 static { 063 Set<Curve> curves = new LinkedHashSet<>(); 064 curves.add(Curve.X25519); 065 curves.add(Curve.Ed25519); 066 SUPPORTED_CURVES = Collections.unmodifiableSet(curves); 067 } 068 069 070 /** 071 * Creates a new OctetKeyPair JWK generator. 072 * 073 * @param crv The curve. Must not be {@code null}. 074 */ 075 public OctetKeyPairGenerator(final Curve crv) { 076 077 if (crv == null) { 078 throw new IllegalArgumentException("The curve must not be null"); 079 } 080 081 if (! SUPPORTED_CURVES.contains(crv)) { 082 throw new IllegalArgumentException("Curve not supported for OKP generation"); 083 } 084 085 this.crv = crv; 086 } 087 088 089 @Override 090 public OctetKeyPair generate() 091 throws JOSEException { 092 093 final Base64URL privateKey; 094 final Base64URL publicKey; 095 096 if (this.crv.equals(Curve.X25519)) { 097 098 final byte[] privateKeyBytes; 099 final byte[] publicKeyBytes; 100 101 try { 102 privateKeyBytes = X25519.generatePrivateKey(); 103 publicKeyBytes = X25519.publicFromPrivate(privateKeyBytes); 104 105 } catch (InvalidKeyException e) { 106 // internal Tink error, should not happen 107 throw new JOSEException(e.getMessage(), e); 108 } 109 110 privateKey = Base64URL.encode(privateKeyBytes); 111 publicKey = Base64URL.encode(publicKeyBytes); 112 113 } else if (this.crv.equals(Curve.Ed25519)) { 114 115 final Ed25519Sign.KeyPair tinkKeyPair; 116 117 try { 118 tinkKeyPair = Ed25519Sign.KeyPair.newKeyPair(); 119 120 } catch (GeneralSecurityException e) { 121 // internal Tink error, should not happen 122 throw new JOSEException(e.getMessage(), e); 123 } 124 125 privateKey = Base64URL.encode(tinkKeyPair.getPrivateKey()); 126 publicKey = Base64URL.encode(tinkKeyPair.getPublicKey()); 127 128 } else { 129 130 throw new JOSEException("Curve not supported"); 131 } 132 133 OctetKeyPair.Builder builder = new OctetKeyPair.Builder(crv, publicKey) 134 .d(privateKey) 135 .keyUse(use) 136 .keyOperations(ops) 137 .algorithm(alg); 138 139 if (x5tKid) { 140 builder.keyIDFromThumbprint(); 141 } else { 142 builder.keyID(kid); 143 } 144 145 return builder.build(); 146 } 147}