github.com/storacha/go-ucanto@v0.7.2/principal/rsa/signer/signer.go (about) 1 package signer 2 3 import ( 4 "crypto" 5 "crypto/rand" 6 "crypto/rsa" 7 "crypto/sha256" 8 "crypto/x509" 9 "fmt" 10 11 "github.com/multiformats/go-multibase" 12 "github.com/storacha/go-ucanto/did" 13 "github.com/storacha/go-ucanto/principal" 14 "github.com/storacha/go-ucanto/principal/multiformat" 15 "github.com/storacha/go-ucanto/principal/rsa/verifier" 16 "github.com/storacha/go-ucanto/ucan/crypto/signature" 17 ) 18 19 const Code = 0x1305 20 const Name = verifier.Name 21 22 const SignatureCode = verifier.SignatureCode 23 const SignatureAlgorithm = verifier.SignatureAlgorithm 24 25 const keySize = 2048 26 27 func Generate() (principal.Signer, error) { 28 priv, err := rsa.GenerateKey(rand.Reader, keySize) 29 if err != nil { 30 return nil, fmt.Errorf("generating RSA key: %w", err) 31 } 32 33 // Next we need to encode public key, because `RSAVerifier` uses it to 34 // for implementing the `DID()` method. 35 pubbytes := multiformat.TagWith(verifier.Code, x509.MarshalPKCS1PublicKey(&priv.PublicKey)) 36 37 verif, err := verifier.Decode(pubbytes) 38 if err != nil { 39 return nil, fmt.Errorf("decoding public bytes: %w", err) 40 } 41 42 // Export key in Private Key Cryptography Standards (PKCS) format and extract 43 // the bytes corresponding to the private key, which we tag with RSA private 44 // key multiformat code. With both binary and actual key representation we 45 // create a RSASigner view. 46 prvbytes := multiformat.TagWith(Code, x509.MarshalPKCS1PrivateKey(priv)) 47 48 return RSASigner{bytes: prvbytes, privKey: priv, verifier: verif}, nil 49 } 50 51 func Parse(str string) (principal.Signer, error) { 52 _, bytes, err := multibase.Decode(str) 53 if err != nil { 54 return nil, fmt.Errorf("decoding multibase string: %w", err) 55 } 56 return Decode(bytes) 57 } 58 59 func Format(signer principal.Signer) (string, error) { 60 return multibase.Encode(multibase.Base64pad, signer.Encode()) 61 } 62 63 func Decode(b []byte) (principal.Signer, error) { 64 utb, err := multiformat.UntagWith(Code, b, 0) 65 if err != nil { 66 return nil, err 67 } 68 69 priv, err := x509.ParsePKCS1PrivateKey(utb) 70 if err != nil { 71 return nil, fmt.Errorf("parsing private key: %w", err) 72 } 73 74 pubbytes := multiformat.TagWith(verifier.Code, x509.MarshalPKCS1PublicKey(&priv.PublicKey)) 75 76 verif, err := verifier.Decode(pubbytes) 77 if err != nil { 78 return nil, fmt.Errorf("decoding public bytes: %w", err) 79 } 80 81 return RSASigner{bytes: b, privKey: priv, verifier: verif}, nil 82 } 83 84 // FromRaw takes raw RSA private key in PKCS #1, ASN.1 DER form and tags with 85 // the RSA signer and verifier multiformat codes, returning an RSA signer. 86 func FromRaw(b []byte) (principal.Signer, error) { 87 tb := multiformat.TagWith(Code, b) 88 priv, err := x509.ParsePKCS1PrivateKey(b) 89 if err != nil { 90 return nil, fmt.Errorf("parsing private key: %w", err) 91 } 92 verif, err := verifier.FromRaw(x509.MarshalPKCS1PublicKey(&priv.PublicKey)) 93 if err != nil { 94 return nil, fmt.Errorf("decoding public bytes: %w", err) 95 } 96 return RSASigner{bytes: tb, privKey: priv, verifier: verif}, nil 97 } 98 99 type RSASigner struct { 100 bytes []byte 101 privKey *rsa.PrivateKey 102 verifier principal.Verifier 103 } 104 105 func (s RSASigner) Code() uint64 { 106 return Code 107 } 108 109 func (s RSASigner) SignatureCode() uint64 { 110 return SignatureCode 111 } 112 113 func (s RSASigner) SignatureAlgorithm() string { 114 return SignatureAlgorithm 115 } 116 117 func (s RSASigner) Verifier() principal.Verifier { 118 return s.verifier 119 } 120 121 func (s RSASigner) DID() did.DID { 122 return s.verifier.DID() 123 } 124 125 func (s RSASigner) Encode() []byte { 126 return s.bytes 127 } 128 129 func (s RSASigner) Raw() []byte { 130 b, _ := multiformat.UntagWith(Code, s.bytes, 0) 131 return b 132 } 133 134 func (s RSASigner) Sign(msg []byte) signature.SignatureView { 135 hash := sha256.New() 136 hash.Write(msg) 137 digest := hash.Sum(nil) 138 sig, _ := rsa.SignPKCS1v15(nil, s.privKey, crypto.SHA256, digest) 139 return signature.NewSignatureView(signature.NewSignature(SignatureCode, sig)) 140 }