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 020 021import java.security.GeneralSecurityException; 022import java.security.InvalidKeyException; 023import java.util.Collections; 024import java.util.LinkedHashSet; 025import java.util.Set; 026 027import com.google.crypto.tink.subtle.Ed25519Sign; 028import com.google.crypto.tink.subtle.X25519; 029 030import com.nimbusds.jose.JOSEException; 031import com.nimbusds.jose.jwk.Curve; 032import com.nimbusds.jose.jwk.OctetKeyPair; 033import com.nimbusds.jose.util.Base64URL; 034 035 036/** 037 * Octet Key Pair (OKP) JSON Web Key (JWK) generator. 038 * 039 * <p>Supported curves: 040 * 041 * <ul> 042 * <li>{@link Curve#X25519 X25519} 043 * <li>{@link Curve#Ed25519 Ed25519} 044 * </ul> 045 * 046 * @author Tim McLean 047 * @version 2023-01-02 048 */ 049public class OctetKeyPairGenerator extends JWKGenerator<OctetKeyPair> { 050 051 052 /** 053 * The curve. 054 */ 055 private final Curve crv; 056 057 058 /** 059 * The supported values for the "crv" property. 060 */ 061 public static final Set<Curve> SUPPORTED_CURVES; 062 063 064 static { 065 Set<Curve> curves = new LinkedHashSet<>(); 066 curves.add(Curve.X25519); 067 curves.add(Curve.Ed25519); 068 SUPPORTED_CURVES = Collections.unmodifiableSet(curves); 069 } 070 071 072 /** 073 * Creates a new OctetKeyPair JWK generator. 074 * 075 * @param crv The curve. Must not be {@code null}. 076 */ 077 public OctetKeyPairGenerator(final Curve crv) { 078 079 if (crv == null) { 080 throw new IllegalArgumentException("The curve must not be null"); 081 } 082 083 if (! SUPPORTED_CURVES.contains(crv)) { 084 throw new IllegalArgumentException("Curve not supported for OKP generation"); 085 } 086 087 this.crv = crv; 088 } 089 090 091 @Override 092 public OctetKeyPair generate() 093 throws JOSEException { 094 095 final Base64URL privateKey; 096 final Base64URL publicKey; 097 098 if (this.crv.equals(Curve.X25519)) { 099 100 final byte[] privateKeyBytes; 101 final byte[] publicKeyBytes; 102 103 try { 104 // TODO Use super.secureRandom if it is set 105 106 privateKeyBytes = X25519.generatePrivateKey(); 107 publicKeyBytes = X25519.publicFromPrivate(privateKeyBytes); 108 109 } catch (InvalidKeyException e) { 110 // internal Tink error, should not happen 111 throw new JOSEException(e.getMessage(), e); 112 } 113 114 privateKey = Base64URL.encode(privateKeyBytes); 115 publicKey = Base64URL.encode(publicKeyBytes); 116 117 } else if (this.crv.equals(Curve.Ed25519)) { 118 119 final Ed25519Sign.KeyPair tinkKeyPair; 120 121 try { 122 // TODO Use super.secureRandom if it is set 123 124 tinkKeyPair = Ed25519Sign.KeyPair.newKeyPair(); 125 126 } catch (GeneralSecurityException e) { 127 // internal Tink error, should not happen 128 throw new JOSEException(e.getMessage(), e); 129 } 130 131 privateKey = Base64URL.encode(tinkKeyPair.getPrivateKey()); 132 publicKey = Base64URL.encode(tinkKeyPair.getPublicKey()); 133 134 } else { 135 136 throw new JOSEException("Curve not supported"); 137 } 138 139 OctetKeyPair.Builder builder = new OctetKeyPair.Builder(crv, publicKey) 140 .d(privateKey) 141 .keyUse(use) 142 .keyOperations(ops) 143 .algorithm(alg) 144 .expirationTime(exp) 145 .notBeforeTime(nbf) 146 .issueTime(iat); 147 148 if (x5tKid) { 149 builder.keyIDFromThumbprint(); 150 } else { 151 builder.keyID(kid); 152 } 153 154 return builder.build(); 155 } 156}