11package io .nats .nkey ;
22
3+ import org .bouncycastle .crypto .UpdateOutputStream ;
4+ import org .bouncycastle .crypto .asymmetric .AsymmetricEdDSAPrivateKey ;
5+ import org .bouncycastle .crypto .asymmetric .AsymmetricEdDSAPublicKey ;
6+ import org .bouncycastle .crypto .fips .FipsEdEC ;
7+ import org .bouncycastle .crypto .fips .FipsOutputSigner ;
8+ import org .bouncycastle .crypto .fips .FipsOutputVerifier ;
39import org .bouncycastle .jcajce .provider .BouncyCastleFipsProvider ;
410import org .jspecify .annotations .NullMarked ;
511
12+ import java .io .IOException ;
613import java .security .*;
714
15+ import static io .nats .nkey .NKeyConstants .ED25519_PUBLIC_KEYSIZE ;
16+ import static io .nats .nkey .NKeyConstants .ED25519_SEED_SIZE ;
17+ import static io .nats .nkey .NKeyProviderUtils .encodeSeed ;
18+ import static io .nats .nkey .NKeyProviderUtils .nkeyDecode ;
19+
820@ NullMarked
921public class FipsNKeyProvider extends NKeyProvider {
1022 static {
@@ -26,7 +38,14 @@ public FipsNKeyProvider() {
2638 */
2739 @ Override
2840 public NKey createNKey (NKeyType type , byte [] seed ) {
29- throw new UnsupportedOperationException ("createPair not supported yet." );
41+ byte [] pubBytes = FipsEdEC .computePublicData (FipsEdEC .Ed25519 .getAlgorithm (), seed );
42+
43+ byte [] bytes = new byte [pubBytes .length + seed .length ];
44+ System .arraycopy (seed , 0 , bytes , 0 , seed .length );
45+ System .arraycopy (pubBytes , 0 , bytes , seed .length , pubBytes .length );
46+
47+ char [] encoded = encodeSeed (type , bytes );
48+ return new NKey (this , type , null , encoded );
3049 }
3150
3251 /**
@@ -35,22 +54,70 @@ public NKey createNKey(NKeyType type, byte[] seed) {
3554 @ Override
3655 public KeyPair getKeyPair (NKey nkey ) {
3756 nkey .ensurePair ();
38- throw new UnsupportedOperationException ("getKeyPair not supported yet." );
57+ NKeyDecodedSeed decoded = nkey .getDecodedSeed ();
58+ byte [] seedBytes = new byte [ED25519_SEED_SIZE ];
59+ byte [] pubBytes = new byte [ED25519_PUBLIC_KEYSIZE ];
60+
61+ System .arraycopy (decoded .bytes , 0 , seedBytes , 0 , seedBytes .length );
62+ System .arraycopy (decoded .bytes , seedBytes .length , pubBytes , 0 , pubBytes .length );
63+
64+ AsymmetricEdDSAPrivateKey privateKey = new AsymmetricEdDSAPrivateKey (FipsEdEC .Ed25519 .getAlgorithm (), seedBytes , pubBytes );
65+ AsymmetricEdDSAPublicKey publicKey = new AsymmetricEdDSAPublicKey (FipsEdEC .Ed25519 .getAlgorithm (), pubBytes );
66+
67+ return new KeyPair (new PublicKeyWrapper (publicKey ), new PrivateKeyWrapper (privateKey ));
3968 }
4069
4170 /**
4271 * {@inheritDoc}
4372 */
4473 @ Override
4574 public byte [] sign (NKey nkey , byte [] input ) {
46- throw new UnsupportedOperationException ("sign not supported yet." );
75+ KeyPair keyPair = nkey .getKeyPair ();
76+ byte [] seedBytes = keyPair .getPrivate ().getEncoded ();
77+ byte [] pubBytes = keyPair .getPublic ().getEncoded ();
78+ AsymmetricEdDSAPrivateKey privateKey = new AsymmetricEdDSAPrivateKey (FipsEdEC .Ed25519 .getAlgorithm (), seedBytes , pubBytes );
79+
80+ FipsEdEC .EdDSAOperatorFactory factory = new FipsEdEC .EdDSAOperatorFactory ();
81+ FipsOutputSigner <FipsEdEC .Parameters > signer = factory .createSigner (privateKey , FipsEdEC .EdDSA );
82+
83+ try {
84+ UpdateOutputStream stream = signer .getSigningStream ();
85+ stream .update (input , 0 , input .length );
86+ stream .finished ();
87+ return signer .getSignature ();
88+ }
89+ catch (IOException e ) {
90+ throw new RuntimeException (e );
91+ }
4792 }
4893
4994 /**
5095 * {@inheritDoc}
5196 */
5297 @ Override
5398 public boolean verify (NKey nkey , byte [] input , byte [] signature ) {
54- throw new UnsupportedOperationException ("verify not supported yet." );
99+ AsymmetricEdDSAPublicKey publicKey ;
100+ if (nkey .isPair ()) {
101+ byte [] pubBytes = nkey .getKeyPair ().getPublic ().getEncoded ();
102+ publicKey = new AsymmetricEdDSAPublicKey (FipsEdEC .Ed25519 .getAlgorithm (), pubBytes );
103+ }
104+ else {
105+ char [] encodedPublicKey = nkey .getPublicKey ();
106+ byte [] decodedPublicKey = nkeyDecode (nkey .getType (), encodedPublicKey );
107+ publicKey = new AsymmetricEdDSAPublicKey (FipsEdEC .Ed25519 .getAlgorithm (), decodedPublicKey );
108+ }
109+
110+ FipsEdEC .EdDSAOperatorFactory factory = new FipsEdEC .EdDSAOperatorFactory ();
111+ FipsOutputVerifier <FipsEdEC .Parameters > verifier = factory .createVerifier (publicKey , FipsEdEC .EdDSA );
112+
113+ try {
114+ UpdateOutputStream stream = verifier .getVerifyingStream ();
115+ stream .update (input , 0 , input .length );
116+ stream .close ();
117+ return verifier .isVerified (signature );
118+ }
119+ catch (IOException e ) {
120+ throw new RuntimeException (e );
121+ }
55122 }
56123}
0 commit comments