nip44: simplify slightly.
This commit is contained in:
@@ -22,7 +22,6 @@ import (
|
|||||||
const version byte = 2
|
const version byte = 2
|
||||||
|
|
||||||
const (
|
const (
|
||||||
MinPlaintextSize = 0x0001 // 1b msg => padded to 32b
|
|
||||||
MaxPlaintextSize = 0xffff // 65535 (64kb-1) => padded to 64kb
|
MaxPlaintextSize = 0xffff // 65535 (64kb-1) => padded to 64kb
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -59,14 +58,14 @@ func Encrypt(plaintext string, conversationKey [32]byte, applyOptions ...func(op
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cc20key, cc20nonce, hmackey, err := messageKeys(conversationKey, nonce)
|
cc20key, cc20nonce, hmacKey, err := messageKeys(conversationKey, nonce)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
plain := []byte(plaintext)
|
plain := []byte(plaintext)
|
||||||
size := len(plain)
|
size := len(plain)
|
||||||
if size < MinPlaintextSize || size > MaxPlaintextSize {
|
if size == 0 || size > MaxPlaintextSize {
|
||||||
return "", fmt.Errorf("plaintext should be between 1b and 64kB")
|
return "", fmt.Errorf("plaintext should be between 1b and 64kB")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,7 +79,7 @@ func Encrypt(plaintext string, conversationKey [32]byte, applyOptions ...func(op
|
|||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
mac, err := sha256Hmac(hmackey, ciphertext, nonce)
|
mac, err := sha256Hmac(hmacKey, ciphertext, nonce)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
@@ -97,7 +96,7 @@ func Encrypt(plaintext string, conversationKey [32]byte, applyOptions ...func(op
|
|||||||
func Decrypt(b64ciphertextWrapped string, conversationKey [32]byte) (string, error) {
|
func Decrypt(b64ciphertextWrapped string, conversationKey [32]byte) (string, error) {
|
||||||
cLen := len(b64ciphertextWrapped)
|
cLen := len(b64ciphertextWrapped)
|
||||||
if cLen < 132 || cLen > 87472 {
|
if cLen < 132 || cLen > 87472 {
|
||||||
return "", fmt.Errorf(fmt.Sprintf("invalid payload length: %d", cLen))
|
return "", fmt.Errorf("invalid payload length: %d", cLen)
|
||||||
}
|
}
|
||||||
if b64ciphertextWrapped[0:1] == "#" {
|
if b64ciphertextWrapped[0:1] == "#" {
|
||||||
return "", fmt.Errorf("unknown version")
|
return "", fmt.Errorf("unknown version")
|
||||||
@@ -109,24 +108,24 @@ func Decrypt(b64ciphertextWrapped string, conversationKey [32]byte) (string, err
|
|||||||
}
|
}
|
||||||
|
|
||||||
if decoded[0] != version {
|
if decoded[0] != version {
|
||||||
return "", fmt.Errorf(fmt.Sprintf("unknown version %d", decoded[0]))
|
return "", fmt.Errorf("unknown version %d", decoded[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
dLen := len(decoded)
|
dLen := len(decoded)
|
||||||
if dLen < 99 || dLen > 65603 {
|
if dLen < 99 || dLen > 65603 {
|
||||||
return "", fmt.Errorf(fmt.Sprintf("invalid data length: %d", dLen))
|
return "", fmt.Errorf("invalid data length: %d", dLen)
|
||||||
}
|
}
|
||||||
|
|
||||||
var nonce [32]byte
|
var nonce [32]byte
|
||||||
copy(nonce[:], decoded[1:33])
|
copy(nonce[:], decoded[1:33])
|
||||||
ciphertext := decoded[33 : dLen-32]
|
ciphertext := decoded[33 : dLen-32]
|
||||||
givenMac := decoded[dLen-32:]
|
givenMac := decoded[dLen-32:]
|
||||||
cc20key, cc20nonce, hmackey, err := messageKeys(conversationKey, nonce)
|
cc20key, cc20nonce, hmacKey, err := messageKeys(conversationKey, nonce)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
expectedMac, err := sha256Hmac(hmackey, ciphertext, nonce)
|
expectedMac, err := sha256Hmac(hmacKey, ciphertext, nonce)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
@@ -141,8 +140,7 @@ func Decrypt(b64ciphertextWrapped string, conversationKey [32]byte) (string, err
|
|||||||
}
|
}
|
||||||
|
|
||||||
unpaddedLen := binary.BigEndian.Uint16(padded[0:2])
|
unpaddedLen := binary.BigEndian.Uint16(padded[0:2])
|
||||||
if unpaddedLen < uint16(MinPlaintextSize) || unpaddedLen > uint16(MaxPlaintextSize) ||
|
if unpaddedLen == 0 || unpaddedLen > MaxPlaintextSize || len(padded) != 2+calcPadding(int(unpaddedLen)) {
|
||||||
len(padded) != 2+calcPadding(int(unpaddedLen)) {
|
|
||||||
return "", fmt.Errorf("invalid padding")
|
return "", fmt.Errorf("invalid padding")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -160,7 +158,7 @@ func GenerateConversationKey(pub nostr.PubKey, sk [32]byte) ([32]byte, error) {
|
|||||||
var ck [32]byte
|
var ck [32]byte
|
||||||
|
|
||||||
if bytes.Compare(sk[:], maxThreshold) != -1 || sk == [32]byte{} {
|
if bytes.Compare(sk[:], maxThreshold) != -1 || sk == [32]byte{} {
|
||||||
return ck, fmt.Errorf("invalid private key: x coordinate %s is not on the secp256k1 curve", sk)
|
return ck, fmt.Errorf("invalid private key: x coordinate %x is not on the secp256k1 curve", sk)
|
||||||
}
|
}
|
||||||
|
|
||||||
shared, err := computeSharedSecret(pub, sk)
|
shared, err := computeSharedSecret(pub, sk)
|
||||||
|
|||||||
@@ -1,11 +1,8 @@
|
|||||||
package nip44
|
package nip44
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/rand"
|
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"fiatjaf.com/nostr"
|
"fiatjaf.com/nostr"
|
||||||
@@ -1072,48 +1069,6 @@ func TestMessageKeyGeneration033(t *testing.T) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMaxLength(t *testing.T) {
|
|
||||||
sk1 := nostr.GeneratePrivateKey()
|
|
||||||
sk2 := nostr.GeneratePrivateKey()
|
|
||||||
pub2 := nostr.GetPublicKey(sk2)
|
|
||||||
salt := make([]byte, 32)
|
|
||||||
rand.Read(salt)
|
|
||||||
conversationKey, _ := GenerateConversationKey(pub2, sk1)
|
|
||||||
plaintext := strings.Repeat("a", MaxPlaintextSize)
|
|
||||||
encrypted, err := Encrypt(plaintext, conversationKey, WithCustomNonce(salt))
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
assertCryptPub(t,
|
|
||||||
hex.EncodeToString(sk1[:]),
|
|
||||||
hex.EncodeToString(pub2[:]),
|
|
||||||
fmt.Sprintf("%x", conversationKey),
|
|
||||||
fmt.Sprintf("%x", salt),
|
|
||||||
plaintext,
|
|
||||||
encrypted,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func assertCryptPub(t *testing.T, sk1 string, pub2 string, conversationKey string, customNonce string, plaintext string, expected string) {
|
|
||||||
k1, err := hexDecode32Array(conversationKey)
|
|
||||||
require.NoErrorf(t, err, "hex decode failed for conversation key: %v", err)
|
|
||||||
|
|
||||||
assertConversationKeyGenerationPub(t, sk1, pub2, conversationKey)
|
|
||||||
|
|
||||||
s, err := hex.DecodeString(customNonce)
|
|
||||||
require.NoErrorf(t, err, "hex decode failed for salt: %v", err)
|
|
||||||
|
|
||||||
actual, err := Encrypt(plaintext, k1, WithCustomNonce(s))
|
|
||||||
require.NoError(t, err, "encryption failed: %v", err)
|
|
||||||
require.Equalf(t, expected, actual, "wrong encryption")
|
|
||||||
|
|
||||||
decrypted, err := Decrypt(expected, k1)
|
|
||||||
require.NoErrorf(t, err, "decryption failed: %v", err)
|
|
||||||
|
|
||||||
require.Equal(t, decrypted, plaintext, "wrong decryption")
|
|
||||||
}
|
|
||||||
|
|
||||||
func hexDecode32Array(hexString string) (res [32]byte, err error) {
|
func hexDecode32Array(hexString string) (res [32]byte, err error) {
|
||||||
_, err = hex.Decode(res[:], []byte(hexString))
|
_, err = hex.Decode(res[:], []byte(hexString))
|
||||||
return res, err
|
return res, err
|
||||||
|
|||||||
Reference in New Issue
Block a user