Bip32 Keys encryption in Golang Nacl Secretbox - go

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

Related

How do I encrypt special characters or numbers using AES-256?

I would like to encrypt a string in Go using AES-256, without any GCM processing, to compare against MQL4. I encounter issues when I try to encrypt special characters or numbers. Should I be pre-processing my plaintext somehow? I am new to Go so any help would be appreciated; my code is below this explanation.
If I encrypt the plaintext "This is a secret" and then decrypt the ciphertext (encoded to hex), I get the same result (i.e. "This is a secret"). pt is the variable name of the plaintext in the code below.
If I try to encrypt "This is a secret; 1234", the ciphertext has a group of zeroes at the end, and when I decrypt I only get "This is a secret". Similar ciphertext in MQL4 does not have zeroes at the end and decrypts correctly.
If I try to encrypt only "1234", I get build errors, stemming from "crypto/aes.(*aesCipherAsm).Encrypt(0xc0000c43c0, 0xc0000ac058, 0x4, 0x4, 0xc0000ac070, 0x4, 0x8)
C:/Program Files/Go/src/crypto/aes/cipher_asm.go:60 +0x125"
Here is my code:
package main
import (
"crypto/aes"
"encoding/hex"
"fmt"
)
func main() {
// cipher key
key := "thisis32bitlongpassphraseimusing"
// plaintext
pt := "This is a secret"
// pt := "This is a secret; 1234" // zeroes in ciphertext
// pt := "1234" // doesn't build
c := EncryptAES([]byte(key), pt)
// plaintext
fmt.Println(pt)
// ciphertext
fmt.Println(c)
// decrypt
DecryptAES([]byte(key), c)
}
func EncryptAES(key []byte, plaintext string) string {
c, err := aes.NewCipher(key)
CheckError(err)
out := make([]byte, len(plaintext))
c.Encrypt(out, []byte(plaintext))
return hex.EncodeToString(out)
}
func DecryptAES(key []byte, ct string) {
ciphertext, _ := hex.DecodeString(ct)
c, err := aes.NewCipher(key)
CheckError(err)
pt := make([]byte, len(ciphertext))
c.Decrypt(pt, ciphertext)
s := string(pt[:])
fmt.Println("DECRYPTED:", s)
}
func CheckError(err error) {
if err != nil {
panic(err)
}
}
You're creating a raw AES encryptor here. AES can only encrypt precisely 16 bytes of plaintext, producing exactly 16 bytes of cipher text. Your first example "This is a secret" is exactly 16 bytes long, so it works as expected. Your second example is too long. Only the first 16 bytes are being encrypted. The third example is too short and you're likely running into uninitialized memory.
The specific characters in your text are irrelevant. Encryption is performed on raw bytes, not letters.
In order to encrypt larger (or smaller) blocks of text, you need to use a block cipher mode on top of AES. Common modes are GCM, CBC, and CTR, but there are many others. In most cases, when someone says "AES" without any qualifier, they mean AES-CBC. (GCM is becoming much more popular, and it's a great mode, but it's not so popular that it's assumed quite yet.)
I don't know anything about MQL4, but I assume you're trying to reimplement CryptEncode? I don't see any documentation on how they do the encryption. You need to know what mode they use, how they derive their key, how they generate (and possibly encode) their IV, whether they include an HMAC or other auth, and more. You need to know exactly how they implement whatever they mean by "CRYPT_AES256." There is no one, standard answer to this.
MQL4 only supports a very specific implementation of AES encryption and unless you use the correct settings in your other code you will not achieve compatibility between the two platforms.
Specifically you need to ensure the following are implemented:
Padding Mode: Zeros
Cipher Mode: ECB (so no IV)
KeySize: 256
BlockSize: 128
You also need to remember in MQL4 that encryption/decryption is a two stage process (to AES256 then to BASE64).
You can try the online AES encryption/decryption tool to verify your results available here: The online toolbox

Converting to Type rsa.PublicKey

I'm trying to import my own RSA public key as opposed to generating one to encrypt a string with. Only thing is that I'm having issues changing to the correct type. Here's my current code:
func main() {
s := ""
i := new(big.Int)
i.SetString(s, 16)
encrypt(i)
}
func encrypt(i *big.Int) {
publicKey := PublicKey{N: i, E: 010001}
secretMessage := "This is super secret message!"
encryptedMessage := RSA_OAEP_Encrypt(secretMessage, publicKey)
fmt.Println("Cipher Text:", encryptedMessage)
}
Where it doesn't like publicKey's type
What I'm wondering is if there's a way that I can **convert type PublicKey** to **type rsa.PublicKey** so that I can use it for encryption.
There seem to be two types of key: one is the base interface, called just PublicKey. The type rsa.PublicKey is derived from that and should be used instead. Otherwise the key type is not set correctly and the code will fail. I presume it creates an anonymous type with the values set.

ed25519.Public result is different

Using the package https://github.com/golang/crypto/tree/master/ed25519 i m trying to get a public key for a given private key.
Those data are from http://www.bittorrent.org/beps/bep_0044.html: test 2 (mutable with salt)
Problem is, ed25519.Public() won t return the same public key when i fed it with the given private key.
The golang implementation returns the last 32 bytes of the PVK. But in my test data this is unexpected.
The code here https://play.golang.org/p/UJNPCyuGQB
package main
import (
"encoding/hex"
"golang.org/x/crypto/ed25519"
"log"
)
func main() {
priv := "e06d3183d14159228433ed599221b80bd0a5ce8352e4bdf0262f76786ef1c74db7e7a9fea2c0eb269d61e3b38e450a22e754941ac78479d6c54e1faf6037881d"
pub := "77ff84905a91936367c01360803104f92432fcd904a43511876df5cdf3e7e548"
sig := "6834284b6b24c3204eb2fea824d82f88883a3d95e8b4a21b8c0ded553d17d17ddf9a8a7104b1258f30bed3787e6cb896fca78c58f8e03b5f18f14951a87d9a08"
// d := hex.EncodeToString([]byte(priv))
privb, _ := hex.DecodeString(priv)
pvk := ed25519.PrivateKey(privb)
buffer := []byte("4:salt6:foobar3:seqi1e1:v12:Hello World!")
sigb := ed25519.Sign(pvk, buffer)
pubb, _ := hex.DecodeString(pub)
sigb2, _ := hex.DecodeString(sig)
log.Println(ed25519.Verify(pubb, buffer, sigb))
log.Printf("%x\n", pvk.Public())
log.Printf("%x\n", sigb)
log.Printf("%x\n", sigb2)
}
How to generate the same public key than the bep using golang ?
This is due to different ed25519 private key formats. An ed25519 key starts out as a 32 byte seed. This seed is hashed with SHA512 to produce 64 bytes (a couple of bits are flipped too). The first 32 bytes of these are used to generate the public key (which is also 32 bytes), and the last 32 bytes are used in the generation of the signature.
The Golang private key format is the 32 byte seed concatenated with the 32 byte public key. The private keys in the Bittorrent document you are using are the 64 byte result of the hash (or possibly just 64 random bytes that are used the same way as the hash result).
Since it’s not possible to reverse the hash, you can’t convert the Bittorrent keys to a format that the Golang API will accept.
You can produce a version of the Golang lib based on the existing package.
The following code depends on the internal package golang.org/x/crypto/ed25519/internal/edwards25519, so if you want to use it you will need to copy that package out so that it is available to you code. It’s also very “rough and ready”, I’ve basically just copied the chunks of code needed from the existing code to get this to work.
Note that the public key and signature formats are the same, so as long as you are not sharing private keys you don’t need to use this code to get a working implementation. You will only need it if you want to check the test vectors.
First generating the public key from a private key:
// Generate the public key corresponding to the already hashed private
// key.
//
// This code is mostly copied from GenerateKey in the
// golang.org/x/crypto/ed25519 package, from after the SHA512
// calculation of the seed.
func getPublicKey(privateKey []byte) []byte {
var A edwards25519.ExtendedGroupElement
var hBytes [32]byte
copy(hBytes[:], privateKey)
edwards25519.GeScalarMultBase(&A, &hBytes)
var publicKeyBytes [32]byte
A.ToBytes(&publicKeyBytes)
return publicKeyBytes[:]
}
Next generating a signature:
// Calculate the signature from the (pre hashed) private key, public key
// and message.
//
// This code is mostly copied from the Sign function from
// golang.org/x/crypto/ed25519, from after the SHA512 calculation of the
// seed.
func sign(privateKey, publicKey, message []byte) []byte {
var privateKeyA [32]byte
copy(privateKeyA[:], privateKey) // we need this in an array later
var messageDigest, hramDigest [64]byte
h := sha512.New()
h.Write(privateKey[32:])
h.Write(message)
h.Sum(messageDigest[:0])
var messageDigestReduced [32]byte
edwards25519.ScReduce(&messageDigestReduced, &messageDigest)
var R edwards25519.ExtendedGroupElement
edwards25519.GeScalarMultBase(&R, &messageDigestReduced)
var encodedR [32]byte
R.ToBytes(&encodedR)
h.Reset()
h.Write(encodedR[:])
h.Write(publicKey)
h.Write(message)
h.Sum(hramDigest[:0])
var hramDigestReduced [32]byte
edwards25519.ScReduce(&hramDigestReduced, &hramDigest)
var s [32]byte
edwards25519.ScMulAdd(&s, &hramDigestReduced, &privateKeyA, &messageDigestReduced)
signature := make([]byte, 64)
copy(signature[:], encodedR[:])
copy(signature[32:], s[:])
return signature
}
Finally we can use these two functions to demonstrate the test vectors:
privateKeyHex := "e06d3183d14159228433ed599221b80bd0a5ce8352e4bdf0262f76786ef1c74db7e7a9fea2c0eb269d61e3b38e450a22e754941ac78479d6c54e1faf6037881d"
expectedPublicKey := "77ff84905a91936367c01360803104f92432fcd904a43511876df5cdf3e7e548"
expectedSig := "6834284b6b24c3204eb2fea824d82f88883a3d95e8b4a21b8c0ded553d17d17ddf9a8a7104b1258f30bed3787e6cb896fca78c58f8e03b5f18f14951a87d9a08"
privateKey, _ := hex.DecodeString(privateKeyHex)
publicKey := getPublicKey(privateKey)
fmt.Printf("Calculated key: %x\n", publicKey)
fmt.Printf("Expected key: %s\n", expectedPublicKey)
keyMatches := expectedPublicKey == hex.EncodeToString(publicKey)
fmt.Printf("Public key matches expected: %v\n", keyMatches)
buffer := []byte("4:salt6:foobar3:seqi1e1:v12:Hello World!")
calculatedSig := sign(privateKey, publicKey, buffer)
fmt.Printf("Calculated sig: %x\n", calculatedSig)
fmt.Printf("Expected sig: %s\n", expectedSig)
sigMatches := expectedSig == hex.EncodeToString(calculatedSig)
fmt.Printf("Signature matches expected: %v\n", sigMatches)

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)

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