Substitute for load_pem_private_key() in golang - go

I have this code in python
privateKey = appAuth["privateKey"]
passphrase = appAuth["passphrase"]
from cryptography.hazmat.primitives.serialization import load_pem_private_key
key = load_pem_private_key(
data=privateKey.encode('utf8'),
password=passphrase.encode('utf8'),
backend=default_backend(),)
I want to replicate this in golang.
Basically I have this:-
"appAuth": {
"publicKeyID": "2qwqckds",
"privateKey": "-----BEGIN ENCRYPTED PRIVATE KEY-----\nMIIFDjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0AeQwwDgQIkkci4MFCUtsCAggA\nMBQGCCqGSIb3DQMHBAjyW3BUgbqg9ASCBMjEpz/mhgRXFKkFpSL4SAq7YLxYzO7H\nYfbisbcsrN4C1wAiXpT4FMBuGnHzRrm/slu+DnTdbsKrg2SxiyW3Zy5FtBfYGPHF\nYim4It2lPywMHHS62b2qXdIicW4pfst/eqeisLpl0bBTR7UYbxr6vpsVFKrGkjEI\n8+VtADGgm6ORH975NBZiLrCEO2aLOfeXlQrdWHcNEB46emvoasBKRZ0bUTxUqKN9\negGPprpfEb7yp0UoJZayYpxcZOSEuM42jXiGELQ9qM7xeADlTP5rbw2d6r/Hbr67\nvyDk2fydvRra4XlbDgeKfiD71OaetoyF8o07Zo4VJegdZnHYW7BW2kXuD5uCiNYI\nWN3l9TpX8i6FU1i++NidH80t5cHAHlhBc2v0if5g8TlmRDarOo6pX8d2KLV98V7F\n7iWmS9vHtyZZvIgaWDchQ+fVQ2ZS6KCRGnGipxkmGyDXnPcx60YPiN9NxCmKs0ji\n8e7xtM+QXzYPWF/rUQh/YmISYGoktOj2XMxXmpNXdpcHFIWEbuW0LuWhV++4WrnO\nly9Vc3PwnHi5KE+IzgoOtgPkxDkr664fd5H0DD3RD1ytWuMW0rtKMr8jx/vRUkzM\n+yzGo0UMe4XW0M0Xcrpq+o+0NBwa05xGA6vlrerMuLcsYG3MexdBkuVMammpmxdM\ntQ+Ch65ikggn9Er2LbwJyddw7bUaIox0hXPUaiAyICY77D7m4SEsBfMFjy420UoR\numz1+ss4edJ0ago0FumG3QaUJzTGUfCHd/johD3AkYAQsFvwiCkMcL2wQEcYDx4x\nx8OCdM1rTn61sQOHHYH4fN4V8TAEbhG57kSzz/GLBlIu84m7zew+NN3pTTw5oU+V\nVHFyBj1eW9ywtING1oEnbKXIdzSs4dWF7zwlzDUfbS5GY6Crm7vhre6pnZY0zs3O\n+MzcGe0AHPwRPOtR4gUiuW5tbBhLM9Nd8xFdS29QUnydKDpSbhySJgCPcYkTtbSG\nsQZMAK7d/Dv178Qta5a+oO0XMh7I4qZ6tuBlGH06QEUh2NJrfzp42hUS0zd9XIZ5\nStD/R9aTSLTr0ljfzrgs/brGj9S0eSHuxV/4teTYapmZoO+G3G7SfViSRn+IdDdK\nOLa5sLeOu/KCdH0mIyVDupmJKt0adAza3S4Wp719HZVrgOOJc4Ni9GXPiPR5Qxv5\nG+/oUIrBxvBpK4gB6Fzr1iRz51FmvukURdeHVDJfbNyEvFWyQ6w5ZXrSbWnD73WB\nk7/J4N2gLKYVYagI/J9GZ4q/cfM5w+JztdqeBXOKa7fyEBE3iEv5hKs/C7lvxuQs\no0yrqTok0GnrlSGq4R0ve/t6eQ4nyWLM1yMxhl/JMGw7QFq7bhfeAhwVcQB7f1eT\n/krRppgbBwkGHaES47LkoBV9AyZlRIymFaF128SePSSa1YgIaivxghcopdqC3HD1\n/NSFA9zvxXv54Neqv9sO2Mc2PHaiOq3RPQbP4zPV7CD8bBSUwztLNAJJC99OeNah\n1nyvS69JvysuM7Mxgv3e8VK4+hQ+I1uMwL8UlfCJZ+ejHwpLX26kc7NfKP/NWzm7\n6JCsEbbtoR7OWnVgXf0lkIlJPcs86HPoX1DzlzVUQsAtKLpnhxLBBfDH5NwVtolM\nn74=\n-----END ENCRYPTED PRIVATE KEY-----\n",
"passphrase": "2788518b2900d77fafc71dbf4f764927"
}
In golang, I have tried this so far:-
block, _ := pem.Decode([]byte(privateKey)) \\ privateKey is a string
key, err := x509.ParsePKCS1PrivateKey(block.Bytes)
But it doesn't work.
Please Help.

To decrypt encrypted pkcs8 key (an example of such key is mentioned in the question) in go
there is an awesome library https://github.com/youmark/pkcs8/.
import "github.com/youmark/pkcs8"
block, _ := pem.Decode([]byte(config.BoxAppSetting.AppAuth.PrivateKey))
decryptedPrivateKey, err := pkcs8.ParsePKCS8PrivateKey(block.Bytes, []byte(config.BoxAppSetting.AppAuth.PassPhrase))

Related

x509 Go package - ParsePKIXPublicKey is to DER or PEM?

I'm trying to get an object of rsa.PublicKey and I made these steps:
----BEGIN RSA PUBLIC KEY----
....
----END RSA PUBLIC KEY----
package main
import (
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/pem"
"fmt"
"io/ioutil"
)
func main() {
key, err := ioutil.ReadFile("./new_public.pem")
if err != nil {
fmt.Println(err.Error())
}
block, _ := pem.Decode([]byte(key))
if block == nil {
fmt.Println("unable to decode publicKey to request")
}
pub, err := x509.ParsePKIXPublicKey(block.Bytes)
if err != nil {
panic("failed to parse RSA encoded public key" + err.Error())
}
switch pub := pub.(type) {
case *rsa.PublicKey:
fmt.Println("pub is of type RSA:", pub)
default:
panic("error")
}
}
After this, when I try to x509.ParsePKIXPublicKey(block.Bytes) I get an error:
panic: failed to parse RSA encoded public keyasn1:
structure error: tags don't match (16 vs {class:0 tag:2 length:129 isCompound:false})
{
optional:false
explicit:false
application:false
private:false
defaultValue:<nil> tag:<nil>
stringType:0
timeType:0
set:false
omitEmpty:false
} AlgorithmIdentifier #3
So, I read some blogs and documentations about DER and PEM formats, and they are differents ways to encode an certificate, basicaly one use base64 and other is just bytes.
In x509's package of Golang, the x509.ParsePKIXPublicKey says:
ParsePKIXPublicKey parses a DER-encoded public key. These values are typically found in PEM blocks with "BEGIN PUBLIC KEY"
And, in the example of this function use the pem.Decode(). I'm very confused about this because this should use pem.Decode or something like der.Decode() ?
Also, what's the real difference between x509.ParsePKCS1PublicKey() and x509.ParsePKIXPublicKey() ? Both do the same job to get a rsa.PublicKey ?
The issue here is understanding the difference between x509.ParsePKCS1PublicKey (PKCS#1) and x509.ParsePKIXPublicKey (PKCS#8).
Usually when the PEM header has the type as RSA PUBLIC KEY, it is referring to a PKCS#1 encoded RSA public key, which is defined in RFC 8017 (PKCS#1) as:
RSAPublicKey ::= SEQUENCE {
modulus INTEGER, -- n
publicExponent INTEGER -- e
}
You haven't actually provided the body of your public key (it would be safe to do so), but it is a fair assumption that, if decoding the key using x509.ParsePKIXPublicKey failed, your key is likely in the above format (x509.ParsePKIXPublicKey uses PKCS#8 encoding).
If this is the case, you should be able to get an rsa.PublicKey from the file using the following code (don't forget to add the error handling):
rawPem, _ := ioutil.ReadFile("./public.key")
pemBlock, _ := pem.Decode(rawPem)
publicKey, _ := x509.ParsePKCS1PublicKey(pemBlock.Bytes)
If this doesn't solve your problem, try pasting the key you have into this site to see what ASN.1 structure it uses. For reference, the key I used to test this is included here:
-----BEGIN RSA PUBLIC KEY-----
MIIBCgKCAQEApW1W9dnfdFF7FHrq6HPveR/9T+nM70yO7QOGytR0j/chMBJcJBjG
hJOuKPFbkVyS+BE/4M8CojLgvz4ex82Re0sFa5TqnoWvuP5P4vktR6M5W53sTW3y
gUnfF/oHcEmARQ1xKZdgVnlIfrdbpjecPyLi1Ng4HmhEfCFUOW64koxpb4XeH5O5
q+vc/731ExVOYBU8Sl6kPdjpJuVjS3DHKAVgfVEhscXd3JDjDuMDT3w1IYNb5c2s
wHE55q4Jnc1cr42jdynnkXzmuOGo2C6yD95kbBDLp7wSiBxaMA8gbRkzWJ99T+6l
KsKG2zfndMF3jZW1v1wWiEbYRN07qbN0NQIDAQAB
-----END RSA PUBLIC KEY-----
Here you go.
https://golang.org/src/crypto/tls/generate_cert.go
You have to generate the certificates using the code above.
Like this:
./generate_cert --host="source:destination" -rsa-bits 1024
openssl pkcs8 -topk8 -nocrypt -in key.pem -out privatekey.pcks8
openssl x509 -pubkey -noout -in cert.pem > publickey.pem
This should solve the issue for you and give you the files you need.

Bip32 Keys encryption in Golang Nacl Secretbox

I have created the Assymetric struct which generates a BIP39 and BIP32 Master public and private key. Now I want to use these keys and their derived children to encrypt files or strings depending upon the use case. Please correct me if I am wrong — the keys generated from Mnemonics BIP32 are Elliptic curve keys(secp256k1). I am trying to use the NACL Go implementation to encrypt text with these keys, but it only accepts keys which are 32 bytes but the keys that are being generated from Mnemonics are 256 Bytes. Please help. The bip32 implementation can be found here https://github.com/tyler-smith/go-bip32/blob/master/bip32.go#L59
After going through the implementation, I have found out that the resulting key is a combination of Key and chaincode, key.Key is a 32byte key that must be used for encryption. Just wanted to check if this is the right way to do it and guarantees security.
package encryption
import (
"github.com/tyler-smith/go-bip39"
"github.com/tyler-smith/go-bip32"
"crypto/ecdsa"
"crypto/elliptic"
"golang.org/x/crypto/nacl/secretbox"
"crypto/rand"
"encoding/hex"
"io"
"log"
)
type Encryption interface {
GenerateMnemonic() ( *bip32.Key, *bip32.Key)
}
type Assymetric struct{
RootPrivateKey *bip32.Key
RootPublicKeyKey *bip32.Key
RootMnemonic string
RootPassphrase string
}
func (c *Assymetric) GenerateMnemonic() (*bip32.Key, *bip32.Key){
entropy, _ := bip39.NewEntropy(256)
mnemonic, _ := bip39.NewMnemonic(entropy)
seed := bip39.NewSeed(mnemonic, c.RootPassphrase)
rootPrivateKey, _ := bip32.NewMasterKey(seed)
rootPublicKey := rootPrivateKey.PublicKey()
// Display mnemonic and keys
//c.RootMnemonic = mnemonic
c.RootPrivateKey = rootPrivateKey
c.RootPublicKeyKey = rootPublicKey
key, _ := rootPrivateKey.NewChildKey(0)
log.Printf("Private key 0 is %s", key)
log.Printf("Public key 0 is %s", key.PublicKey())
// You must use a different nonce for each message you encrypt with the
// same key. Since the nonce here is 192 bits long, a random value
// provides a sufficiently small probability of repeats.
log.Printf("This is the secret key %s", secretKey)
var nonce [24]byte
if _, err := io.ReadFull(rand.Reader, nonce[:]); err != nil {
panic(err)
}
log.Printf("This is the nonce %s", nonce)
var a [32]byte
copy(a[:], key.Key)
log.Printf("\nlen=%d cap=%d %v\n", len(a), cap(a), a)
encrypted := secretbox.Seal(nonce[:], []byte("hello world"), &nonce, &a)
log.Println(encrypted)
return rootPrivateKey, rootPublicKey

How to store ECDSA private key in Go

I am using the ecdsa.GenerateKey method to generate a private/public key pair in Go. I would like to store the private key in a file on the users computer, and load it whenever the program starts. There is a method elliptic.Marshal that marshals the public key, but nothing for the private key. Should I simply roll my own, or is there a recommended way to store the private key?
Here is a code sample that demonstrates encoding and decoding of keys in Go. It helps to know that you need to connect couple of steps. Crypto algorithm is the fist step, in this case ECDSA key. Then you need standard encoding, x509 is most commontly used standard. Finally you need a file format, PEM is again commonly used one. This is currently most commonly used combination, but feel free to substitute any other algoriths or encoding.
func encode(privateKey *ecdsa.PrivateKey, publicKey *ecdsa.PublicKey) (string, string) {
x509Encoded, _ := x509.MarshalECPrivateKey(privateKey)
pemEncoded := pem.EncodeToMemory(&pem.Block{Type: "PRIVATE KEY", Bytes: x509Encoded})
x509EncodedPub, _ := x509.MarshalPKIXPublicKey(publicKey)
pemEncodedPub := pem.EncodeToMemory(&pem.Block{Type: "PUBLIC KEY", Bytes: x509EncodedPub})
return string(pemEncoded), string(pemEncodedPub)
}
func decode(pemEncoded string, pemEncodedPub string) (*ecdsa.PrivateKey, *ecdsa.PublicKey) {
block, _ := pem.Decode([]byte(pemEncoded))
x509Encoded := block.Bytes
privateKey, _ := x509.ParseECPrivateKey(x509Encoded)
blockPub, _ := pem.Decode([]byte(pemEncodedPub))
x509EncodedPub := blockPub.Bytes
genericPublicKey, _ := x509.ParsePKIXPublicKey(x509EncodedPub)
publicKey := genericPublicKey.(*ecdsa.PublicKey)
return privateKey, publicKey
}
func test() {
privateKey, _ := ecdsa.GenerateKey(elliptic.P384(), rand.Reader)
publicKey := &privateKey.PublicKey
encPriv, encPub := encode(privateKey, publicKey)
fmt.Println(encPriv)
fmt.Println(encPub)
priv2, pub2 := decode(encPriv, encPub)
if !reflect.DeepEqual(privateKey, priv2) {
fmt.Println("Private keys do not match.")
}
if !reflect.DeepEqual(publicKey, pub2) {
fmt.Println("Public keys do not match.")
}
}
I believe the standard format for those keys is to use the X.509 ASN.1 DER representation. See http://golang.org/pkg/crypto/x509/#MarshalECPrivateKey and http://golang.org/pkg/crypto/x509/#ParseECPrivateKey.
I adapted a really quick and dirty way to do it, as suggested by one of the geth team in late '15 in my library https://github.com/DaveAppleton/ether_go
it is a far simpler solution (but puts keys in plain sight)

AWS SNS signature verification with GO

I want to implement AWS SNS signature verification in GO. Here is the signature verification tutorial provided by AWS.
However, there are some points I can not get it.
7: Generate the derived hash value of the Amazon SNS message. Submit the Amazon SNS message, in canonical format, to the same hash function used to generate the signature.
How to derived the hash value? Which hash function should I use?
8: Generate the asserted hash value of the Amazon SNS message. The asserted hash value is the result of using the public key value (from step 3) to decrypt the signature delivered with the Amazon SNS message.
How to get the asserted hash value?
Here is my code, I have a struct for notification:
type Notification struct {
Message string
MessageId string
Signature string
SignatureVersion string
SigningCertURL string
SubscribeURL string
Subject string
Timestamp string
TopicArn string
Type string
UnsubscribeURL string
}
and I've already generated the canonical string:
signString := fmt.Sprintf(`Message
%v
MessageId
%v`, self.Message, self.MessageId)
if self.Subject != "" {
signString = signString + fmt.Sprintf(`
Subject
%v`, self.Subject)
}
signString = signString + fmt.Sprintf(`
Timestamp
%v
TopicArn
%v
Type
%v`, self.Timestamp, self.TopicArn, self.Type)
Decode signature from base64
signed, err := base64.StdEncoding.DecodeString(self.Signature)
Get the certificate from .pem
resp, _ := http.Get(self.SigningCertURL)
defer resp.Body.Close()
body, _ := ioutil.ReadAll(resp.Body)
p, _ := pem.Decode(body)
cert, err := x509.ParseCertificate(p.Bytes)
Now, how can I verify the signature with my canonical string? Is the following code right?
cert.CheckSignature(x509.SHA1WithRSA, signed, []byte(signString))
I always get crypto/rsa: verification error from above code.
Thanks!
I know this is a really old question, but I had the same problems as the reporter so I took a day to figure this out with the assistance of AWS. I have open sourced my work as an external library, now available here.
You can use it like this (notificationJson is a JSON string):
import (
"encoding/json"
"fmt"
"github.com/robbiet480/go.sns"
)
var notificationPayload sns.Payload
err := json.Unmarshal([]byte(notificationJson), &notificationPayload)
if err != nil {
fmt.Print(err)
}
verifyErr := notificationPayload.VerifyPayload()
if verifyErr != nil {
fmt.Print(verifyErr)
}
fmt.Print("Payload is valid!")
Thanks for your initial work on this lazywei, I based my library on your above code!
In the context of this discussion about Amazon SNS message signature verification, it’s also important to notice that Amazon SNS now supports message signatures based on SHA256 hashing:
https://aws.amazon.com/about-aws/whats-new/2022/09/amazon-sns-supports-message-signatures-based-sha256-hashing/
Here's the launch blog post:
https://aws.amazon.com/blogs/security/sign-amazon-sns-messages-with-sha256-hashing-for-http-subscriptions/

Encrypt message with RSA private key (as in OpenSSL's RSA_private_encrypt)

I'm trying to implement Chef API client in Go, but stuck trying to create correct request header RSA signature. According to documentation:
A canonical header is signed with the private key used by the client machine from which the request is sent, and is also encoded using Base64.
The following ruby call to OpenSSL::PKey::RSA.private_encrypt() can be found in mixlib-authentication gem code, it uses OpenSSL bindings, private_encrypt() method calls RSA_private_encrypt openssl function.
Unfortunately, I cannot find matching function in Go's standard library; crypto/rsa looks close, but it only implements conventional cryptography methods: encryption with public key, hash signing with private key. OpenSSL's RSA_private_encrypt does the opposite: it encrypts (small) message with private key (akin to creating a signature from message hash).
This "signing" can also be achieved with this command:
openssl rsautl -sign -inkey path/to/private/key.pem \
-in file/to/encrypt -out encrypted/output
Are there any native Go libraries to achieve the same result as OpenSSL's RSA_private_encrypt, or the only way is using Cgo to call this function from OpenSSL library? Maybe I'm missing something. My idea was implementing the client without any non-go dependencies.
I'm a Go newbie, so I'm not sure I can dive into crypto/rsa module sources.
Found the similar question, but the answer to use SignPKCS1v15 is obviously wrong (this function encrypts message's hash, not the message itself).
With great help of the golang community, the solution was found:
Original code posted at http://play.golang.org/p/jrqN2KnUEM by Alex (see mailing list).
I've added input block size check as specified in Section 8 of rfc2313: http://play.golang.org/p/dGTl9siO8E
Here's the code:
package main
import (
"crypto/rsa"
"crypto/x509"
"encoding/pem"
"errors"
"fmt"
"io/ioutil"
"math/big"
"os/exec"
)
var (
ErrInputSize = errors.New("input size too large")
ErrEncryption = errors.New("encryption error")
)
func PrivateEncrypt(priv *rsa.PrivateKey, data []byte) (enc []byte, err error) {
k := (priv.N.BitLen() + 7) / 8
tLen := len(data)
// rfc2313, section 8:
// The length of the data D shall not be more than k-11 octets
if tLen > k-11 {
err = ErrInputSize
return
}
em := make([]byte, k)
em[1] = 1
for i := 2; i < k-tLen-1; i++ {
em[i] = 0xff
}
copy(em[k-tLen:k], data)
c := new(big.Int).SetBytes(em)
if c.Cmp(priv.N) > 0 {
err = ErrEncryption
return
}
var m *big.Int
var ir *big.Int
if priv.Precomputed.Dp == nil {
m = new(big.Int).Exp(c, priv.D, priv.N)
} else {
// We have the precalculated values needed for the CRT.
m = new(big.Int).Exp(c, priv.Precomputed.Dp, priv.Primes[0])
m2 := new(big.Int).Exp(c, priv.Precomputed.Dq, priv.Primes[1])
m.Sub(m, m2)
if m.Sign() < 0 {
m.Add(m, priv.Primes[0])
}
m.Mul(m, priv.Precomputed.Qinv)
m.Mod(m, priv.Primes[0])
m.Mul(m, priv.Primes[1])
m.Add(m, m2)
for i, values := range priv.Precomputed.CRTValues {
prime := priv.Primes[2+i]
m2.Exp(c, values.Exp, prime)
m2.Sub(m2, m)
m2.Mul(m2, values.Coeff)
m2.Mod(m2, prime)
if m2.Sign() < 0 {
m2.Add(m2, prime)
}
m2.Mul(m2, values.R)
m.Add(m, m2)
}
}
if ir != nil {
// Unblind.
m.Mul(m, ir)
m.Mod(m, priv.N)
}
enc = m.Bytes()
return
}
func main() {
// o is output from openssl
o, _ := exec.Command("openssl", "rsautl", "-sign", "-inkey", "t.key", "-in", "in.txt").Output()
// t.key is private keyfile
// in.txt is what to encode
kt, _ := ioutil.ReadFile("t.key")
e, _ := ioutil.ReadFile("in.txt")
block, _ := pem.Decode(kt)
privkey, _ := x509.ParsePKCS1PrivateKey(block.Bytes)
encData, _ := PrivateEncrypt(privkey, e)
fmt.Println(encData)
fmt.Println(o)
fmt.Println(string(o) == string(encData))
}
Update: we can expect to have a native support for this kind of signing in Go 1.3, see the appropriate commit.
Since go 1.3, you can easily do this using SignPKCS1v15
rsa.SignPKCS1v15(nil, priv, crypto.Hash(0), signedData)
refer: https://groups.google.com/forum/#!topic/Golang-Nuts/Vocj33WNhJQ
I stuck on this question for a while.
Eventually, I soleved that with the code here:
https://github.com/bitmartexchange/bitmart-go-api/blob/master/bm_client.go
// Sign secret with rsa with PKCS 1.5 as the padding algorithm
// The result should be exactly same as "openssl rsautl -sign -inkey "YOUR_RSA_PRIVATE_KEY" -in "YOUR_PLAIN_TEXT""
signer, err := rsa.SignPKCS1v15(rand.Reader, rsaPrivateKey.(*rsa.PrivateKey), crypto.Hash(0), []byte(message))
Welcome to the joys of openssl... That is an incredibly poorly named function. If you poke around in the ruby code it's calling this openssl function
http://www.openssl.org/docs/crypto/RSA_private_encrypt.html
Reading the documentation, this is actually signing the buffer with the private
key and not encrypting it.
DESCRIPTION
These functions handle RSA signatures at a low level.
RSA_private_encrypt() signs the flen bytes at from (usually a message digest with an algorithm identifier) using the private key rsa and stores the signature in to. to must point to RSA_size(rsa) bytes of memory.

Resources