github.com/hairyhenderson/gomplate/v4@v4.0.0-pre-2.0.20240520121557-362f058f0c93/crypto/rsa.go (about) 1 package crypto 2 3 import ( 4 "bytes" 5 "crypto/rand" 6 "crypto/rsa" 7 "crypto/x509" 8 "encoding/pem" 9 "fmt" 10 "strings" 11 ) 12 13 // RSAEncrypt - use the given public key to encrypt the given plaintext. The key 14 // should be a PEM-encoded RSA public key in PKIX, ASN.1 DER form, typically 15 // beginning with "PUBLIC KEY". PKCS#1 format is also supported as a fallback. 16 // The output will not be encoded, so consider base64-encoding it for display. 17 func RSAEncrypt(key string, in []byte) ([]byte, error) { 18 block, _ := pem.Decode([]byte(key)) 19 if block == nil { 20 return nil, fmt.Errorf("failed to read key %q: no key found", key) 21 } 22 23 pub, err := x509.ParsePKIXPublicKey(block.Bytes) 24 if err != nil { 25 if strings.Contains(err.Error(), "use ParsePKCS1PublicKey instead") { 26 pub, err = x509.ParsePKCS1PublicKey(block.Bytes) 27 } 28 if err != nil { 29 return nil, fmt.Errorf("failed to parse public key: %w", err) 30 } 31 } 32 pubKey, ok := pub.(*rsa.PublicKey) 33 if !ok { 34 return nil, fmt.Errorf("public key in wrong format, was %T", pub) 35 } 36 37 out, err := rsa.EncryptPKCS1v15(rand.Reader, pubKey, in) 38 return out, err 39 } 40 41 // RSADecrypt - decrypt the ciphertext with the given private key. The key 42 // must be a PEM-encoded RSA private key in PKCS#1, ASN.1 DER form, typically 43 // beginning with "RSA PRIVATE KEY". The input text must be plain ciphertext, 44 // not base64-encoded. 45 func RSADecrypt(key string, in []byte) ([]byte, error) { 46 block, _ := pem.Decode([]byte(key)) 47 if block == nil { 48 return nil, fmt.Errorf("failed to read key %q: no key found", key) 49 } 50 51 priv, err := x509.ParsePKCS1PrivateKey(block.Bytes) 52 if err != nil { 53 return nil, fmt.Errorf("invalid private key: %w", err) 54 } 55 56 out, err := priv.Decrypt(nil, in, nil) 57 if err != nil { 58 return nil, fmt.Errorf("failed to decrypt: %w", err) 59 } 60 return out, nil 61 } 62 63 // RSAGenerateKey - 64 func RSAGenerateKey(bits int) ([]byte, error) { 65 // Protect against CWE-326: Inadequate Encryption Strength 66 // https://cwe.mitre.org/data/definitions/326.html 67 if bits < 2048 { 68 return nil, fmt.Errorf("RSA key size must be at least 2048 bits") 69 } 70 priv, err := rsa.GenerateKey(rand.Reader, bits) 71 if err != nil { 72 return nil, fmt.Errorf("failed to generate RSA private key: %w", err) 73 } 74 block := &pem.Block{ 75 Type: "RSA PRIVATE KEY", 76 Bytes: x509.MarshalPKCS1PrivateKey(priv), 77 } 78 buf := &bytes.Buffer{} 79 err = pem.Encode(buf, block) 80 if err != nil { 81 return nil, fmt.Errorf("failed to encode generated RSA private key: pem encoding failed: %w", err) 82 } 83 return buf.Bytes(), nil 84 } 85 86 // RSADerivePublicKey - 87 func RSADerivePublicKey(privateKey []byte) ([]byte, error) { 88 block, _ := pem.Decode(privateKey) 89 if block == nil { 90 return nil, fmt.Errorf("failed to read key: no key found") 91 } 92 93 priv, err := x509.ParsePKCS1PrivateKey(block.Bytes) 94 if err != nil { 95 return nil, fmt.Errorf("invalid private key: %w", err) 96 } 97 98 b, err := x509.MarshalPKIXPublicKey(&priv.PublicKey) 99 if err != nil { 100 return nil, fmt.Errorf("failed to marshal PKIX public key: %w", err) 101 } 102 103 block = &pem.Block{ 104 Type: "PUBLIC KEY", 105 Bytes: b, 106 } 107 108 return pem.EncodeToMemory(block), nil 109 }