44 "encoding/pem"
55 "fmt"
66
7+ "github.com/cloudflare/circl/kem/mlkem/mlkem1024"
8+ "github.com/cloudflare/circl/sign/mldsa/mldsa87"
79 "golang.org/x/crypto/ed25519"
810)
911
@@ -13,20 +15,25 @@ const ( //cert banners
1315)
1416
1517const ( //key-agreement-key banners
16- X25519PrivateKeyBanner = "NEBULA X25519 PRIVATE KEY"
17- X25519PublicKeyBanner = "NEBULA X25519 PUBLIC KEY"
18- P256PrivateKeyBanner = "NEBULA P256 PRIVATE KEY"
19- P256PublicKeyBanner = "NEBULA P256 PUBLIC KEY"
18+ X25519PrivateKeyBanner = "NEBULA X25519 PRIVATE KEY"
19+ X25519PublicKeyBanner = "NEBULA X25519 PUBLIC KEY"
20+ P256PrivateKeyBanner = "NEBULA P256 PRIVATE KEY"
21+ P256PublicKeyBanner = "NEBULA P256 PUBLIC KEY"
22+ MLKEM1024PrivateKeyBanner = "NEBULA MLKEM1024 PRIVATE KEY"
23+ MLKEM1024PublicKeyBanner = "NEBULA MLKEM1024 PUBLIC KEY"
2024)
2125
2226/* including "ECDSA" in the P256 banners is a clue that these keys should be used only for signing */
2327const ( //signing key banners
24- EncryptedECDSAP256PrivateKeyBanner = "NEBULA ECDSA P256 ENCRYPTED PRIVATE KEY"
25- ECDSAP256PrivateKeyBanner = "NEBULA ECDSA P256 PRIVATE KEY"
26- ECDSAP256PublicKeyBanner = "NEBULA ECDSA P256 PUBLIC KEY"
27- EncryptedEd25519PrivateKeyBanner = "NEBULA ED25519 ENCRYPTED PRIVATE KEY"
28- Ed25519PrivateKeyBanner = "NEBULA ED25519 PRIVATE KEY"
29- Ed25519PublicKeyBanner = "NEBULA ED25519 PUBLIC KEY"
28+ EncryptedECDSAP256PrivateKeyBanner = "NEBULA ECDSA P256 ENCRYPTED PRIVATE KEY"
29+ ECDSAP256PrivateKeyBanner = "NEBULA ECDSA P256 PRIVATE KEY"
30+ ECDSAP256PublicKeyBanner = "NEBULA ECDSA P256 PUBLIC KEY"
31+ EncryptedEd25519PrivateKeyBanner = "NEBULA ED25519 ENCRYPTED PRIVATE KEY"
32+ Ed25519PrivateKeyBanner = "NEBULA ED25519 PRIVATE KEY"
33+ Ed25519PublicKeyBanner = "NEBULA ED25519 PUBLIC KEY"
34+ EncryptedMLDSA87PrivateKeyBanner = "NEBULA MLDSA87 ENCRYPTED PRIVATE KEY"
35+ MLDSA87PrivateKeyBanner = "NEBULA MLDSA87 PRIVATE KEY"
36+ MLDSA87PublicKeyBanner = "NEBULA MLDSA87 PUBLIC KEY"
3037)
3138
3239// UnmarshalCertificateFromPEM will try to unmarshal the first pem block in a byte array, returning any non consumed
@@ -74,6 +81,8 @@ func MarshalPublicKeyToPEM(curve Curve, b []byte) []byte {
7481 return pem .EncodeToMemory (& pem.Block {Type : X25519PublicKeyBanner , Bytes : b })
7582 case Curve_P256 :
7683 return pem .EncodeToMemory (& pem.Block {Type : P256PublicKeyBanner , Bytes : b })
84+ case Curve_PQ :
85+ return pem .EncodeToMemory (& pem.Block {Type : MLKEM1024PublicKeyBanner , Bytes : b })
7786 default :
7887 return nil
7988 }
@@ -87,6 +96,8 @@ func MarshalSigningPublicKeyToPEM(curve Curve, b []byte) []byte {
8796 return pem .EncodeToMemory (& pem.Block {Type : Ed25519PublicKeyBanner , Bytes : b })
8897 case Curve_P256 :
8998 return pem .EncodeToMemory (& pem.Block {Type : ECDSAP256PublicKeyBanner , Bytes : b })
99+ case Curve_PQ :
100+ return pem .EncodeToMemory (& pem.Block {Type : MLDSA87PublicKeyBanner , Bytes : b })
90101 default :
91102 return nil
92103 }
@@ -107,6 +118,12 @@ func UnmarshalPublicKeyFromPEM(b []byte) ([]byte, []byte, Curve, error) {
107118 // Uncompressed
108119 expectedLen = 65
109120 curve = Curve_P256
121+ case MLKEM1024PublicKeyBanner :
122+ expectedLen = mlkem1024 .PublicKeySize
123+ curve = Curve_PQ
124+ case MLDSA87PublicKeyBanner :
125+ expectedLen = mldsa87 .PublicKeySize
126+ curve = Curve_PQ
110127 default :
111128 return nil , r , 0 , fmt .Errorf ("bytes did not contain a proper public key banner" )
112129 }
@@ -122,6 +139,8 @@ func MarshalPrivateKeyToPEM(curve Curve, b []byte) []byte {
122139 return pem .EncodeToMemory (& pem.Block {Type : X25519PrivateKeyBanner , Bytes : b })
123140 case Curve_P256 :
124141 return pem .EncodeToMemory (& pem.Block {Type : P256PrivateKeyBanner , Bytes : b })
142+ case Curve_PQ :
143+ return pem .EncodeToMemory (& pem.Block {Type : MLKEM1024PrivateKeyBanner , Bytes : b })
125144 default :
126145 return nil
127146 }
@@ -133,6 +152,8 @@ func MarshalSigningPrivateKeyToPEM(curve Curve, b []byte) []byte {
133152 return pem .EncodeToMemory (& pem.Block {Type : Ed25519PrivateKeyBanner , Bytes : b })
134153 case Curve_P256 :
135154 return pem .EncodeToMemory (& pem.Block {Type : ECDSAP256PrivateKeyBanner , Bytes : b })
155+ case Curve_PQ :
156+ return pem .EncodeToMemory (& pem.Block {Type : MLDSA87PrivateKeyBanner , Bytes : b })
136157 default :
137158 return nil
138159 }
@@ -154,6 +175,9 @@ func UnmarshalPrivateKeyFromPEM(b []byte) ([]byte, []byte, Curve, error) {
154175 case P256PrivateKeyBanner :
155176 expectedLen = 32
156177 curve = Curve_P256
178+ case MLKEM1024PrivateKeyBanner :
179+ expectedLen = mlkem1024 .PrivateKeySize
180+ curve = Curve_PQ
157181 default :
158182 return nil , r , 0 , fmt .Errorf ("bytes did not contain a proper private key banner" )
159183 }
@@ -184,8 +208,15 @@ func UnmarshalSigningPrivateKeyFromPEM(b []byte) ([]byte, []byte, Curve, error)
184208 if len (k .Bytes ) != 32 {
185209 return nil , r , 0 , fmt .Errorf ("key was not 32 bytes, is invalid ECDSA P256 private key" )
186210 }
211+ case EncryptedMLDSA87PrivateKeyBanner :
212+ return nil , nil , Curve_PQ , ErrPrivateKeyEncrypted
213+ case MLDSA87PrivateKeyBanner :
214+ curve = Curve_PQ
215+ if len (k .Bytes ) != mldsa87 .PrivateKeySize {
216+ return nil , r , 0 , fmt .Errorf ("key was not %d bytes, is invalid ML-DSA-87 private key" , mldsa87 .PrivateKeySize )
217+ }
187218 default :
188- return nil , r , 0 , fmt .Errorf ("bytes did not contain a proper Ed25519/ECDSA private key banner" )
219+ return nil , r , 0 , fmt .Errorf ("bytes did not contain a proper Ed25519/ECDSA/MLDSA87 private key banner" )
189220 }
190221 return k .Bytes , r , curve , nil
191222}
0 commit comments