github.com/tommi2day/gomodules@v1.13.2-0.20240423190010-b7d55d252a27/pwlib/rsa.go (about) 1 // Package pwlib passwords encryption functions 2 package pwlib 3 4 // alternative: https://gist.github.com/wongoo/2b974a9594627114bea3e53c794980cd 5 import ( 6 "bytes" 7 "crypto/aes" 8 "crypto/cipher" 9 "crypto/rand" 10 "crypto/rsa" 11 "crypto/sha256" 12 "crypto/x509" 13 "encoding/base64" 14 "encoding/pem" 15 "errors" 16 "fmt" 17 "io" 18 "os" 19 "strings" 20 21 log "github.com/sirupsen/logrus" 22 ) 23 24 // GenRsaKey generate new key pair 25 func GenRsaKey(pubfilename string, privfilename string, password string) (publicKey *rsa.PublicKey, privateKey *rsa.PrivateKey, err error) { 26 bits := defaultRsaKeySize 27 privateKey, err = rsa.GenerateKey(rand.Reader, bits) 28 if err != nil || privateKey == nil { 29 log.Debugf("generate Key failed: %s", err) 30 return 31 } 32 publicKey = &privateKey.PublicKey 33 34 // save to file if required 35 if len(privfilename) > 0 { 36 // Convert it to pem 37 privbytes, _ := x509.MarshalPKCS8PrivateKey(privateKey) 38 block := &pem.Block{ 39 Type: "RSA PRIVATE KEY", 40 Bytes: privbytes, 41 } 42 43 // Encrypt the pem 44 if password != "" { 45 //nolint gosec 46 block, err = x509.EncryptPEMBlock(rand.Reader, block.Type, block.Bytes, []byte(password), x509.PEMCipherAES256) 47 if err != nil { 48 log.Errorf("cannot encrypt private key %s", err) 49 return 50 } 51 } 52 // save it 53 privatekeyPem := pem.EncodeToMemory(block) 54 err = os.WriteFile(privfilename, privatekeyPem, 0600) 55 if err != nil { 56 log.Errorf("cannot write %s: %s", privfilename, err) 57 return 58 } 59 log.Debugf("private key written to %s", privfilename) 60 } 61 62 if len(pubfilename) > 0 { 63 pubbytes, _ := x509.MarshalPKIXPublicKey(publicKey) 64 block := &pem.Block{ 65 Type: "PUBLIC KEY", 66 Bytes: pubbytes, 67 } 68 pubkeyPem := pem.EncodeToMemory(block) 69 //nolint gosec 70 err = os.WriteFile(pubfilename, pubkeyPem, 0644) 71 if err != nil { 72 log.Errorf("cannot write %s: %s", pubfilename, err) 73 return 74 } 75 log.Debugf("public key written to %s", pubfilename) 76 } 77 log.Debug("Keys generated") 78 return 79 } 80 81 // GetPrivateKeyFromFile read private key from PEM encoded File and returns publicKey and private key objects 82 func GetPrivateKeyFromFile(privfilename string, rsaPrivateKeyPassword string) (publicKey *rsa.PublicKey, privateKey *rsa.PrivateKey, err error) { 83 var parsedKey interface{} 84 var privPemBytes []byte 85 86 log.Debugf("GetPrivateKeyFromFile entered for %s", privfilename) 87 //nolint gosec 88 priv, err := os.ReadFile(privfilename) 89 if err != nil { 90 log.Debugf("cannot read %s: %s", privfilename, err) 91 return 92 } 93 privPem, _ := pem.Decode(priv) 94 if privPem == nil { 95 log.Debugf("cannot decode pem in %s", privfilename) 96 return 97 } 98 if privPem.Type != "RSA PRIVATE KEY" { 99 log.Debugf("rsa private key is of the wrong type %s", privPem.Type) 100 return 101 } 102 103 if rsaPrivateKeyPassword != "" { 104 //nolint gosec 105 privPemBytes, err = x509.DecryptPEMBlock(privPem, []byte(rsaPrivateKeyPassword)) 106 if err != nil { 107 log.Debugf("rsa private password error:%s", err) 108 return 109 } 110 } else { 111 privPemBytes = privPem.Bytes 112 } 113 parsedKey, err = x509.ParsePKCS8PrivateKey(privPemBytes) 114 if err != nil { 115 if strings.Contains(err.Error(), "use ParsePKCS1PrivateKey") { 116 log.Debug("ParsePKCS8PrivateKey failed, trying ParsePKCS1PrivateKey") 117 parsedKey, err = x509.ParsePKCS1PrivateKey(privPemBytes) 118 } 119 if err != nil { 120 log.Debugf("unable to parse RSA private key: %s", err) 121 return 122 } 123 } 124 privateKey = parsedKey.(*rsa.PrivateKey) 125 if privateKey == nil { 126 err = fmt.Errorf("unable to cast private key") 127 log.Debugf("%s:", err) 128 return 129 } 130 publicKey = &privateKey.PublicKey 131 log.Debugf("Keys successfully loaded") 132 return 133 } 134 135 // GetPublicKeyFromFile read public key from PEM encoded File 136 func GetPublicKeyFromFile(publicKeyFile string) (publicKey *rsa.PublicKey, err error) { 137 var parsedKey interface{} 138 log.Debugf("load public key from %s", publicKeyFile) 139 //nolint gosec 140 pub, err := os.ReadFile(publicKeyFile) 141 if err != nil { 142 log.Debugf("Cannot Read %s: %s", publicKeyFile, err) 143 return 144 } 145 pubPem, _ := pem.Decode(pub) 146 if pubPem == nil { 147 log.Debugf("Cannot Decode %s", publicKeyFile) 148 return 149 } 150 if pubPem.Type != "PUBLIC KEY" { 151 log.Debugf("RSA public key is of the wrong type %s", pubPem.Type) 152 return 153 } 154 155 parsedKey, err = x509.ParsePKIXPublicKey(pubPem.Bytes) 156 if err != nil { 157 log.Debugf("unable to parse RSA public key: %s", err) 158 return 159 } 160 161 publicKey = parsedKey.(*rsa.PublicKey) 162 if publicKey == nil { 163 err = errors.New("unable to cast public key") 164 log.Debugf("%s:", err) 165 } 166 log.Debugf("public key loaded successfully") 167 return 168 } 169 170 // PubEncryptFileGo encrypts a file with public key with GO API 171 func PubEncryptFileGo(plainFile string, targetFile string, publicKeyFile string) (err error) { 172 const rb = 16 173 var plaindata []byte 174 log.Debugf("Encrypt %s with public key %s", plainFile, publicKeyFile) 175 publicKey, err := GetPublicKeyFromFile(publicKeyFile) 176 if err != nil { 177 return 178 } 179 sessionKey := make([]byte, rb) 180 _, err = rand.Read(sessionKey) 181 if err != nil { 182 log.Debugf("Cannot generate session key:%s", err) 183 return 184 } 185 //nolint gosec 186 plaindata, err = os.ReadFile(plainFile) 187 if err != nil { 188 log.Debugf("Cannot read plaintext file %s:%s", plainFile, err) 189 return 190 } 191 192 // sha1 for compatibility with python version 193 hash := sha256.New() 194 // oder rsa.EncryptPKCS1v15() 195 encSessionKey, err := rsa.EncryptOAEP(hash, rand.Reader, publicKey, sessionKey, label) 196 skl := len(encSessionKey) 197 log.Debugf("Session key len: %d", skl) 198 if err != nil { 199 log.Error(err) 200 return 201 } 202 block, err := aes.NewCipher(sessionKey) 203 if err != nil { 204 log.Debugf("Cannot create cipher: %s", err.Error()) 205 return 206 } 207 208 aesgcm, err := cipher.NewGCM(block) 209 if err != nil { 210 log.Debugf("Cannot create easgcm: %s", err.Error()) 211 return 212 } 213 ns := aesgcm.NonceSize() 214 // Never use more than 2^32 random nonces with a given key because of the risk of a repeat. 215 // must be 12 for GCM 216 nonce := make([]byte, ns) 217 if _, err = io.ReadFull(rand.Reader, nonce); err != nil { 218 log.Debugf("Cannot create nounce: %s", err.Error()) 219 return 220 } 221 222 // do encryption and seal 223 cipherdata := aesgcm.Seal(nil, nonce, plaindata, nil) 224 225 // encode all parts in base64 226 bindata := bytes.Join([][]byte{encSessionKey, nonce, cipherdata}, []byte("")) 227 b64 := base64.StdEncoding.EncodeToString(bindata) 228 229 // write crypted output file 230 //nolint gosec 231 err = os.WriteFile(targetFile, []byte(b64), 0644) 232 if err != nil { 233 log.Debugf("Cannot write: %s", err.Error()) 234 return 235 } 236 return 237 } 238 239 // PrivateDecryptFileGo Decrypt a file with private key with GO API 240 func PrivateDecryptFileGo(cryptedfile string, privatekeyfile string, keypass string) (content string, err error) { 241 log.Debugf("decrypt %s with private key %s", cryptedfile, privatekeyfile) 242 //nolint gosec 243 data, err := os.ReadFile(cryptedfile) 244 if err != nil { 245 log.Debugf("Cannot Read file '%s': %s", cryptedfile, err) 246 return 247 } 248 _, privkey, err := GetPrivateKeyFromFile(privatekeyfile, keypass) 249 if err != nil { 250 log.Debugf("Cannot read keys from '%s': %s", privatekeyfile, err) 251 return 252 } 253 bindata, err := base64.StdEncoding.DecodeString(string(data)) 254 if err != nil { 255 log.Debugf("decode base64 for %s failed: %s", cryptedfile, err) 256 return 257 } 258 s := 0 259 e := privkey.Size() 260 encSessionKey := bindata[s:e] 261 262 hash := sha256.New() 263 // oder rsa.EncryptPKCS1v15() 264 sessionKey, err := rsa.DecryptOAEP(hash, rand.Reader, privkey, encSessionKey, label) 265 if err != nil { 266 log.Debugf("decode session key failed:%s", err) 267 return 268 } 269 // sk := string(sessionKey) 270 log.Debug("Session key decrypted") 271 272 block, err := aes.NewCipher(sessionKey) 273 if err != nil { 274 log.Debugf("Cannot init cipher:%s", err) 275 return 276 } 277 278 aesgcm, err := cipher.NewGCM(block) 279 if err != nil { 280 log.Debugf("Cannot setup AESGCM:%s", err) 281 return 282 } 283 284 // split parts 285 ns := aesgcm.NonceSize() 286 s = e 287 e = s + ns 288 nonce := bindata[s:e] 289 s = e 290 cipherdata := bindata[s:] 291 292 // do decrypt 293 plaindata, err := aesgcm.Open(nil, nonce, cipherdata, nil) 294 if err != nil { 295 log.Debugf("Cannot decode crypted data:%s", err) 296 return 297 } 298 // return content 299 content = string(plaindata) 300 log.Debug("Decoding successfully") 301 return 302 } 303 304 // PrivateDecryptString Decrypt a string with private key 305 func PrivateDecryptString(crypted string, privatekeyfile string, keypass string) (plain string, err error) { 306 // echo -n "$CRYPTED"|base64 -d |openssl rsautl -decrypt -inkey ${PRIVATEKEYFILE} -passin pass:$KEYPASS 307 log.Debugf("decrypt string with private key %s", privatekeyfile) 308 _, privkey, err := GetPrivateKeyFromFile(privatekeyfile, keypass) 309 if err != nil { 310 log.Debugf("Cannot read keys from '%s': %s", privatekeyfile, err) 311 return 312 } 313 b64dec, err := base64.StdEncoding.DecodeString(crypted) 314 if err != nil { 315 log.Debugf("decode base64 failed: %s", err) 316 return 317 } 318 319 data, err := rsa.DecryptPKCS1v15(rand.Reader, privkey, b64dec) 320 if err != nil { 321 log.Debugf("decode session key failed:%s", err) 322 return 323 } 324 plain = string(data) 325 return 326 } 327 328 // PublicEncryptString Encrypt a string with public key 329 func PublicEncryptString(plain string, publicKeyFile string) (crypted string, err error) { 330 // echo -n "$plain"|openssl rsautl -encrypt -pkcs -inkey $PUBLICKEYFILE -pubin |base64 331 log.Debugf("encrypt string with public key %s", publicKeyFile) 332 pubkey, err := GetPublicKeyFromFile(publicKeyFile) 333 if err != nil { 334 log.Debugf("Cannot read keys from '%s': %s", publicKeyFile, err) 335 return 336 } 337 338 data, err := rsa.EncryptPKCS1v15(rand.Reader, pubkey, []byte(plain)) 339 if err != nil { 340 log.Debugf("decode session key failed:%s", err) 341 return 342 } 343 crypted = base64.StdEncoding.EncodeToString(data) 344 if err != nil { 345 log.Debugf("decode base64 failed: %s", err) 346 return 347 } 348 return 349 }