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

Conversation

yemmyharry
Copy link

@yemmyharry yemmyharry commented Mar 4, 2024

btcec Encrypt / Decrypt used to be available in btcec but wasn't present in btcec/v2. This PR adds it in btcec/v2.
https://pkg.go.dev/github.com/btcsuite/btcd/btcec/v2
Closes #1880

@coveralls
Copy link

Pull Request Test Coverage Report for Build 8143981554

Details

  • 50 of 68 (73.53%) changed or added relevant lines in 1 file are covered.
  • 7 unchanged lines in 2 files lost coverage.
  • Overall coverage increased (+0.01%) to 56.787%

Changes Missing Coverage Covered Lines Changed/Added Lines %
btcec/ciphering.go 50 68 73.53%
Files with Coverage Reduction New Missed Lines %
connmgr/connmanager.go 2 86.62%
peer/peer.go 5 74.16%
Totals Coverage Status
Change from base Build 8117173129: 0.01%
Covered Lines: 29340
Relevant Lines: 51667

💛 - Coveralls

@Chinwendu20
Copy link

Nice this is the commit that removes it:
87e8fe9#diff-c24bf040ebe7e026d5ae1d5f3c14771574b4d2b87f5245d71f6b211ff784160c

I think we might get more context as to why it was removed. The function that was used to type alias the functions removed here does not have it either:
https://pkg.go.dev/github.com/decred/dcrd/dcrec/secp256k1/v4#pkg-functions

@yemmyharry
Copy link
Author

@Chinwendu20 The context as to why it was removed is found here: #1880 (comment).
The dcrd package doesn't have it but they gave an example as to how it can be done here: https://pkg.go.dev/github.com/decred/dcrd/dcrec/secp256k1/v4#example-package-EncryptDecryptMessage. Having the functions to make it easy for users seems better don't you think?

@lazynina
Copy link

@guggero - is it possible to get a review of this PR please? I have a project that we recently upgraded to the latest version of the library and ended up copying over this code. Would be great to have this functionality available in the library again.

@guggero
Copy link
Collaborator

guggero commented Apr 17, 2024

@guggero - is it possible to get a review of this PR please? I have a project that we recently upgraded to the latest version of the library and ended up copying over this code. Would be great to have this functionality available in the library again.

I'm super busy right now. You're welcome to add a review yourself, since you seem to need the code.

Copy link

@Chinwendu20 Chinwendu20 left a comment

Choose a reason for hiding this comment

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

Thanks a lot for the PR and sharing the reference doc, it helped me review. Left a question and other comments. Also is there a reason why this b9f98b6 is a separate commit? Can it not be merged with previous?

Commits are usually in the form: package name: commit message. Here is the guideline:
https://github.com/lightningnetwork/lnd/blob/master/docs/code_contribution_guidelines.md#ideal-git-commit-structure

I think maybe these guidelines should be included in this repo as well.
Also I am not entirely sure why this should be here (same withe the sharedSecrets function), I do not think we use them any where, maybe there is a reason it was left for users to create themselves, it is not even in the decred
secp256k1 package itself. Maybe it would be more appropriate to have that there? then we can have encrypt functions for AES-256, AES-128, etc.

btcec/ciphering.go Show resolved Hide resolved
btcec/ciphering.go Outdated Show resolved Hide resolved
@Chinwendu20
Copy link

Also I am not entirely sure why this should be here (same withe the sharedSecrets function), I do not think we use them any where, maybe there is a reason it was left for users to create themselves, it is not even in the decred secp256k1 package itself. Maybe it would be more appropriate to have that there? then we can have encrypt functions for AES-256, AES-128, etc.

Ohh I see btcec was created as a standalone golang bitcoin as opposed to decred that is for a different ecosystem.

Copy link

@Chinwendu20 Chinwendu20 left a comment

Choose a reason for hiding this comment

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

I could be wrong but I think the point of the issue that birthed this PR is to bring back the Encrypt and Decrypt function here back here:

https://github.com/Roasbeef/btcd/blob/e8e2167a1af6c20f1f32abb76bd387ee87763bc9/btcec/ciphering.go#L51-L118

Left comments in the Resolved thread as well. Maybe hold on, on resolving comment for now.

btcec/ciphering.go Outdated Show resolved Hide resolved
btcec/ciphering.go Outdated Show resolved Hide resolved
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.

}

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

@@ -22,14 +23,19 @@ func GenerateSharedSecret(privkey *PrivateKey, pubkey *PublicKey) []byte {

// Encrypt encrypts data for the target public key using AES-128-GCM
func Encrypt(pubKey *PublicKey, msg []byte) ([]byte, error) {
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.

@@ -62,3 +63,44 @@ func Encrypt(pubKey *PublicKey, msg []byte) ([]byte, error) {

return pt.Bytes(), nil
}

// Decrypt decrypts a passed message with a receiver private key, returns plaintext or decryption error
Copy link

Choose a reason for hiding this comment

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

format: Line length
Edit:
80 cols limit

// Decrypt decrypts a passed message with a receiver private key, returns plaintext or decryption error
func Decrypt(privkey *PrivateKey, msg []byte) ([]byte, error) {
// Message cannot be less than length of public key (65) + nonce (16) + tag (16)
if len(msg) <= (1 + 32 + 32 + 16 + 16) {

Choose a reason for hiding this comment

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

Isn't the length of public key compressed 33 bytes? Maybe make comments clearer on how the number came about, what does 1 represent here?

Copy link
Author

Choose a reason for hiding this comment

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

An uncompressed public key in Elliptic Curve Cryptography (ECC) consists of:
1 byte for the curve type
32 bytes for the X coordinate
32 bytes for the Y coordinate

Choose a reason for hiding this comment

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

An uncompressed public key in Elliptic Curve Cryptography (ECC) consists of: 1 byte for the curve type 32 bytes for the X coordinate 32 bytes for the Y coordinate

Was actually referring to serialized compressed public key which is what was written into the bytes during the encryption.

Copy link
Author

Choose a reason for hiding this comment

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

its actually an uncompressed public key.

Choose a reason for hiding this comment

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

Oh that is true, I can see that an uncompressed public key was used in the encrypt function. Maybe this code would be clearer this way:

Suggested change
if len(msg) <= (1 + 32 + 32 + 16 + 16) {
// Message cannot be less than the size of an
// uncompressed public key (65 bytes) + nonce (16 bytes)
// + tag (16 bytes)
if len(msg) <= (65+ 16 + 16) {

Or something better
If 1+ 32 + 32 is to be included maybe include where the numbers are from in the comment as well?

@Chinwendu20
Copy link

Chinwendu20 commented Apr 20, 2024

I could be wrong but I think the point of the issue that birthed this PR is to bring back the Encrypt and Decrypt function here back here:

https://github.com/Roasbeef/btcd/blob/e8e2167a1af6c20f1f32abb76bd387ee87763bc9/btcec/ciphering.go#L51-L118

Left comments in the Resolved thread as well. Maybe hold on, on resolving comment for now.

I think in general the point of this PR is to bring back the encrypt and decrypt function that was previously in btcec as opposed to writing a new one. Though maybe new encryption and decryption functions could be included as well but not the point of the issue.

Others can give their opinion.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

btcec Encrypt / Decrypt
5 participants