diff --git a/encryption.go b/encryption.go index d3f801d..743ef3f 100644 --- a/encryption.go +++ b/encryption.go @@ -64,11 +64,25 @@ func DecryptWithPrivateKeyString(privateKey, data string) (string, error) { } // EncryptShared will encrypt data and provide shared keys for decryption -func EncryptShared(u1priv *bsvec.PrivateKey, u2pub *bsvec.PublicKey, in []byte) ( +func EncryptShared(user1PrivateKey *bsvec.PrivateKey, user2PubKey *bsvec.PublicKey, data []byte) ( *bsvec.PrivateKey, *bsvec.PublicKey, []byte, error) { + // Generate shared keys that can be decrypted by either user - sharedPrivKey, sharedPubKey := GenerateSharedKeyPair(u1priv, u2pub) + sharedPrivKey, sharedPubKey := GenerateSharedKeyPair(user1PrivateKey, user2PubKey) + // Encrypt data with shared key - encryptedData, err := bsvec.Encrypt(sharedPubKey, in) + encryptedData, err := bsvec.Encrypt(sharedPubKey, data) return sharedPrivKey, sharedPubKey, encryptedData, err } + +// EncryptSharedString will encrypt data and provide shared keys for decryption +func EncryptSharedString(user1PrivateKey *bsvec.PrivateKey, user2PubKey *bsvec.PublicKey, data string) ( + *bsvec.PrivateKey, *bsvec.PublicKey, string, error) { + + // Generate shared keys that can be decrypted by either user + sharedPrivKey, sharedPubKey := GenerateSharedKeyPair(user1PrivateKey, user2PubKey) + + // Encrypt data with shared key + encryptedData, err := bsvec.Encrypt(sharedPubKey, []byte(data)) + return sharedPrivKey, sharedPubKey, hex.EncodeToString(encryptedData), err +} diff --git a/encryption_test.go b/encryption_test.go index 1691956..f3fbf53 100644 --- a/encryption_test.go +++ b/encryption_test.go @@ -1,12 +1,15 @@ package bitcoin import ( + "encoding/hex" "fmt" "testing" "github.com/bitcoinsv/bsvd/bsvec" ) +const testEncryptionMessage = "testing 1, 2, 3..." + // TestEncryptWithPrivateKey will test the method EncryptWithPrivateKey() func TestEncryptWithPrivateKey(t *testing.T) { t.Parallel() @@ -411,32 +414,112 @@ func BenchmarkDecryptWithPrivateKeyString(b *testing.B) { } } +// TestEncryptShared will test the method EncryptShared() func TestEncryptShared(t *testing.T) { - // This data will be encrypted / shared - testString := "testing 1, 2, 3..." + // User 1's private key + privKey1, _ := CreatePrivateKey() + + // User 2's private key + privKey2, _ := CreatePrivateKey() + + // User 1 encrypts using their private key and user 2's pubkey + _, _, encryptedData, err := EncryptShared(privKey1, privKey2.PubKey(), []byte(testEncryptionMessage)) + if err != nil { + t.Fatalf("failed to encrypt data for sharing %s", err) + } + + // Generate the shared key + user2SharedPrivKey, _ := GenerateSharedKeyPair(privKey2, privKey1.PubKey()) + + // User 2 can decrypt using the shared private key + var decryptedTestData []byte + decryptedTestData, err = bsvec.Decrypt(user2SharedPrivKey, encryptedData) + if err != nil { + t.Fatalf("failed to decrypt test data %s", err) + } + + // Test the result + if string(decryptedTestData) != testEncryptionMessage { + t.Fatalf("decrypted string doesnt match %s", decryptedTestData) + } + + // todo: test bad keys? +} + +// TestEncryptSharedPanic tests for nil case in EncryptShared() +func TestEncryptSharedPanic(t *testing.T) { + t.Parallel() + + defer func() { + if r := recover(); r == nil { + t.Errorf("the code did not panic") + } + }() + + privateKey, _, _, err := EncryptShared(nil, nil, []byte("")) + if err == nil { + t.Fatalf("expected error") + } else if privateKey != nil { + t.Fatalf("expected privateKey to be nil") + } +} + +// todo: examples and benchmark for EncryptShared() - // user 1 +// TestEncryptSharedString will test the method EncryptSharedString() +func TestEncryptSharedString(t *testing.T) { + + // User 1's private key privKey1, _ := CreatePrivateKey() - // user 2 + // User 2's private key privKey2, _ := CreatePrivateKey() - // user 1 encrypts it - _, _, encryptedData, err := EncryptShared(privKey1, privKey2.PubKey(), []byte(testString)) + // User 1 encrypts using their private key and user 2's pubkey + _, _, encryptedData, err := EncryptSharedString(privKey1, privKey2.PubKey(), testEncryptionMessage) if err != nil { - t.Errorf("Failed to encrypt data for sharing %s", err) + t.Fatalf("failed to encrypt data for sharing %s", err) } - // user 2 decrypts it + // Generate the shared key user2SharedPrivKey, _ := GenerateSharedKeyPair(privKey2, privKey1.PubKey()) - decryptedTestData, err := bsvec.Decrypt(user2SharedPrivKey, encryptedData) + // User 2 can decrypt using the shared private key + var decryptedTestData, decoded []byte + decoded, err = hex.DecodeString(encryptedData) + if err != nil { + t.Fatalf("failed to decoded %s", err) + } + decryptedTestData, err = bsvec.Decrypt(user2SharedPrivKey, decoded) if err != nil { - t.Errorf("Failed to decrypt test data %s", err) + t.Fatalf("failed to decrypt test data %s", err) + } + + // Test the result + if string(decryptedTestData) != testEncryptionMessage { + t.Fatalf("decrypted string doesnt match %s", decryptedTestData) } - if string(decryptedTestData) != testString { - t.Errorf("Decrypted string doesnt match %s", decryptedTestData) + // todo: test bad keys? +} + +// TestEncryptSharedStringPanic tests for nil case in EncryptSharedString() +func TestEncryptSharedStringPanic(t *testing.T) { + t.Parallel() + + defer func() { + if r := recover(); r == nil { + t.Errorf("the code did not panic") + } + }() + + privateKey, _, _, err := EncryptSharedString(nil, nil, "") + if err == nil { + t.Fatalf("expected error") + } else if privateKey != nil { + t.Fatalf("expected privateKey to be nil") } } + +// todo: examples and benchmark for EncryptSharedString() diff --git a/examples/encrypt_shared_keys/encrypt_shared_keys.go b/examples/encrypt_shared_keys/encrypt_shared_keys.go new file mode 100644 index 0000000..ea27a5f --- /dev/null +++ b/examples/encrypt_shared_keys/encrypt_shared_keys.go @@ -0,0 +1,42 @@ +package main + +import ( + "encoding/hex" + "log" + + "github.com/bitcoinschema/go-bitcoin" + "github.com/bitcoinsv/bsvd/bsvec" +) + +func main() { + + // This data will be encrypted / shared + testString := "testing 1, 2, 3..." + + // User 1's private key + privKey1, _ := bitcoin.CreatePrivateKey() + + // User 2's private key + privKey2, _ := bitcoin.CreatePrivateKey() + + // User 1 encrypts using their private key and user 2's pubkey + _, _, encryptedData, err := bitcoin.EncryptShared(privKey1, privKey2.PubKey(), []byte(testString)) + if err != nil { + log.Fatalf("failed to encrypt data for sharing %s", err) + } + + // Generate the shared key + user2SharedPrivKey, _ := bitcoin.GenerateSharedKeyPair(privKey2, privKey1.PubKey()) + + // User 2 can decrypt using the shared private key + var decryptedTestData []byte + decryptedTestData, err = bsvec.Decrypt(user2SharedPrivKey, encryptedData) + if err != nil { + log.Fatalf("failed to decrypt test data %s", err) + } + + // Success + log.Printf("test string: %s", testString) + log.Printf("encrypted: %s", hex.EncodeToString(encryptedData)) + log.Printf("decrypted: %s", decryptedTestData) +} diff --git a/private_key.go b/private_key.go index 2e35288..3a6dcf2 100644 --- a/private_key.go +++ b/private_key.go @@ -12,10 +12,13 @@ import ( ) // GenerateSharedKeyPair creates shared keys that can be used to encrypt/decrypt data -// that can be decrypted by yourself (privkey) and also the owner of the given public key -func GenerateSharedKeyPair(privKey *bsvec.PrivateKey, pubKey *bsvec.PublicKey) (*bsvec.PrivateKey, *bsvec.PublicKey) { - sharedSecret := bsvec.GenerateSharedSecret(privKey, pubKey) - return bsvec.PrivKeyFromBytes(bsvec.S256(), sharedSecret) +// that can be decrypted by yourself (privateKey) and also the owner of the given public key +func GenerateSharedKeyPair(privateKey *bsvec.PrivateKey, + pubKey *bsvec.PublicKey) (*bsvec.PrivateKey, *bsvec.PublicKey) { + return bsvec.PrivKeyFromBytes( + bsvec.S256(), + bsvec.GenerateSharedSecret(privateKey, pubKey), + ) } // PrivateKeyFromString turns a private key (hex encoded string) into an bsvec.PrivateKey diff --git a/private_key_test.go b/private_key_test.go index fd8f469..9c9787c 100644 --- a/private_key_test.go +++ b/private_key_test.go @@ -8,12 +8,11 @@ import ( "github.com/bitcoinsv/bsvd/bsvec" ) -// TestGenerateSharedKeyPair will test creating a shared key that can be used to encrypt data that can be decrypted by yourself (privkey) and also the owner of the given public key +// TestGenerateSharedKeyPair will test creating a shared key that can be used to +// encrypt data that can be decrypted by yourself (privkey) and also the owner +// of the given public key func TestGenerateSharedKeyPair(t *testing.T) { - // The data that will be encrypted / shared - testString := "testing 1, 2, 3..." - // User 1 privKey1, _ := CreatePrivateKey() @@ -23,7 +22,7 @@ func TestGenerateSharedKeyPair(t *testing.T) { _, user1SharedPubKey := GenerateSharedKeyPair(privKey1, privKey2.PubKey()) // encrypt something with the shared public key - eciesTest, err := bsvec.Encrypt(user1SharedPubKey, []byte(testString)) + encryptTest, err := bsvec.Encrypt(user1SharedPubKey, []byte(testEncryptionMessage)) if err != nil { t.Errorf("Failed to encrypt test data %s", err) } @@ -31,16 +30,19 @@ func TestGenerateSharedKeyPair(t *testing.T) { // user 2 decrypts it user2SharedPrivKey, _ := GenerateSharedKeyPair(privKey2, privKey1.PubKey()) - decryptedTestData, err := bsvec.Decrypt(user2SharedPrivKey, eciesTest) + var decryptedTestData []byte + decryptedTestData, err = bsvec.Decrypt(user2SharedPrivKey, encryptTest) if err != nil { t.Errorf("Failed to decrypt test data %s", err) } - if string(decryptedTestData) != testString { + if string(decryptedTestData) != testEncryptionMessage { t.Errorf("Decrypted string doesnt match %s", decryptedTestData) } } +// todo: examples and benchmark for GenerateSharedKeyPair() + // TestCreatePrivateKey will test the method CreatePrivateKey() func TestCreatePrivateKey(t *testing.T) { rawKey, err := CreatePrivateKey()