Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Encrypt decrypt #2130

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
48 changes: 48 additions & 0 deletions btcec/ciphering.go
Expand Up @@ -5,6 +5,12 @@
package btcec

import (
"bytes"
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"crypto/sha256"
"fmt"
secp "github.com/decred/dcrd/dcrec/secp256k1/v4"
)

Expand All @@ -14,3 +20,45 @@ import (
func GenerateSharedSecret(privkey *PrivateKey, pubkey *PublicKey) []byte {
return secp.GenerateSharedSecret(privkey, pubkey)
}

// Encrypt encrypts data for the target public key using AES-128-GCM
yemmyharry marked this conversation as resolved.
Show resolved Hide resolved
func Encrypt(pubKey *PublicKey, msg []byte) ([]byte, error) {
yemmyharry marked this conversation as resolved.
Show resolved Hide resolved
var pt bytes.Buffer

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You want to copy the cipher text into a different variable?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

var pt bytes.Buffer is used to accumulate the encrypted data in a buffer, which is then returned as a single byte slice at the end of the function

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not return the cipher text itself?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i didnt return the ciphertext itself because i need some details in the decrypt function. the tag (and other parameters like nonce etc) are appended to the ciphertext in the encrypt function and in the decrypt function the tag is separated from the ciphertext to verify authenticity.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the tag is in the cipher text already

Is there a reason that you did not just do this:

nonce := make([]byte, aead.NonceSize())
ciphertext := make([]byte, 4+len(ephemeralPubKey))
binary.LittleEndian.PutUint32(ciphertext, uint32(len(ephemeralPubKey)))
copy(ciphertext[4:], ephemeralPubKey)
ciphertext = aead.Seal(ciphertext, nonce, plaintext, ephemeralPubKey)

Gotten from here: https://pkg.go.dev/github.com/decred/dcrd/dcrec/secp256k1/v4#section-readme

No need for the intermediary pt bytes in this case.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both approaches are valid. I used a buffer as it automatically grows and shrinks as needed, reducing manual memory management.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO, I do not think the buffer is needed at all when the cipher text can just be returned directly unless there is need to copy the cipher text into a different variable. if not maybe we should not use extra space.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i didnt return the ciphertext itself because i need some details in the decrypt function. the tag (and other parameters like nonce etc) are appended to the ciphertext in the encrypt function and in the decrypt function the tag is separated from the ciphertext to verify authenticity.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nonce := make([]byte, aead.NonceSize())
ciphertext := make([]byte, 4+len(ephemeralPubKey))
binary.LittleEndian.PutUint32(ciphertext, uint32(len(ephemeralPubKey)))
copy(ciphertext[4:], ephemeralPubKey)
ciphertext = aead.Seal(ciphertext, nonce, plaintext, ephemeralPubKey)

If you write it this way would you still need the intermediary buffer?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ephemeral, err := NewPrivateKey()
if err != nil {
return nil, fmt.Errorf("failed to generate private key: %v", err)
}

pt.Write(ephemeral.PubKey().SerializeUncompressed())

ecdhKey := GenerateSharedSecret(ephemeral, pubKey)
hashedSecret := sha256.Sum256(ecdhKey)
encryptionKey := hashedSecret[:16]

block, err := aes.NewCipher(encryptionKey)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like you sliced the shared secret to 16 bytes here

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes for compatibility with AES-128-GCM encryption

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ohh thought you said AES-256-GCM here: a2245a6#r1570762508 but looks like the comment has been updated.

if err != nil {
return nil, err
}

nonce := make([]byte, 16)
if _, err := rand.Read(nonce); err != nil {
return nil, err
}

pt.Write(nonce)

gcm, err := cipher.NewGCMWithNonceSize(block, 16)
if err != nil {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would like to understand why it has to be a nonce size of 16 instead of the default 12

return nil, err
}

ciphertext := gcm.Seal(nil, nonce, msg, nil)

tag := ciphertext[len(ciphertext)-gcm.NonceSize():]
pt.Write(tag)
ciphertext = ciphertext[:len(ciphertext)-len(tag)]
pt.Write(ciphertext)

return pt.Bytes(), nil
}