bsv/ecies/
mod.rs

1use crate::{BSVErrors, Hash, PrivateKey, PublicKey, AES};
2use elliptic_curve::sec1::ToEncodedPoint;
3use k256::PublicKey as K256PublicKey;
4
5pub mod ecies_ciphertext;
6pub use ecies_ciphertext::*;
7
8/**
9 * Electrum compatible ECIES implementation.
10 * Comparable to Ecies.electrumEncrypt in BSV.JS
11 */
12#[derive(Clone)]
13pub struct ECIES {}
14
15#[derive(Clone)]
16pub struct CipherKeys {
17    pub(crate) iv: Vec<u8>,
18    pub(crate) ke: Vec<u8>,
19    pub(crate) km: Vec<u8>,
20}
21
22impl CipherKeys {
23    pub fn get_iv(&self) -> Vec<u8> {
24        self.iv.clone()
25    }
26
27    pub fn get_ke(&self) -> Vec<u8> {
28        self.ke.clone()
29    }
30
31    pub fn get_km(&self) -> Vec<u8> {
32        self.km.clone()
33    }
34}
35
36impl ECIES {
37    pub(crate) fn encrypt_impl(message: &[u8], private_key: &PrivateKey, recipient_pub_key: &PublicKey, exclude_pub_key: bool) -> Result<ECIESCiphertext, BSVErrors> {
38        let cipher = ECIES::derive_cipher_keys_impl(private_key, recipient_pub_key)?;
39        let cipher_text = AES::encrypt_impl(&cipher.ke, &cipher.iv, message, crate::AESAlgorithms::AES128_CBC)?;
40
41        let mut buffer: Vec<u8> = Vec::new();
42        buffer.extend_from_slice(b"BIE1");
43
44        let r_buf = match exclude_pub_key {
45            true => None,
46            false => {
47                let pub_key = private_key.to_public_key_impl()?.to_compressed_impl()?.to_bytes_impl()?;
48                buffer.extend_from_slice(&pub_key);
49                Some(pub_key)
50            }
51        };
52        buffer.extend_from_slice(&cipher_text);
53
54        let hmac = Hash::sha_256_hmac(&buffer, &cipher.km).to_bytes();
55
56        Ok(ECIESCiphertext {
57            ciphertext_bytes: cipher_text,
58            public_key_bytes: r_buf,
59            hmac_bytes: hmac,
60            keys: Some(cipher),
61        })
62    }
63
64    /**
65     * Encrypt with a randomly generate private key.
66     * This is intended to be used if you want to anonymously send a party an encrypted message.
67     */
68    pub(crate) fn encrypt_with_ephemeral_private_key_impl(message: &[u8], recipient_pub_key: &PublicKey) -> Result<ECIESCiphertext, BSVErrors> {
69        let private_key = PrivateKey::from_random();
70        ECIES::encrypt_impl(message, &private_key, recipient_pub_key, false)
71    }
72
73    pub(crate) fn decrypt_impl(ciphertext: &ECIESCiphertext, recipient_priv_key: &PrivateKey, sender_pub_key: &PublicKey) -> Result<Vec<u8>, BSVErrors> {
74        let cipher_keys = ECIES::derive_cipher_keys_impl(recipient_priv_key, sender_pub_key)?;
75
76        let hmac = &ciphertext.hmac_bytes;
77
78        let mut preimage = b"BIE1".to_vec();
79        if let Some(pk) = &ciphertext.public_key_bytes {
80            preimage.extend_from_slice(pk);
81        }
82        preimage.extend_from_slice(&ciphertext.ciphertext_bytes);
83
84        let verify_hmac = Hash::sha_256_hmac(&preimage, &cipher_keys.km);
85
86        if hmac != &verify_hmac.to_bytes() {
87            return Err(BSVErrors::ECIESError("Invalid Checksum".into()));
88        }
89
90        let plain_text = AES::decrypt_impl(&cipher_keys.ke, &cipher_keys.iv, &ciphertext.ciphertext_bytes, crate::AESAlgorithms::AES128_CBC)?;
91        Ok(plain_text)
92    }
93
94    pub(crate) fn derive_cipher_keys_impl(priv_key: &PrivateKey, pub_key: &PublicKey) -> Result<CipherKeys, BSVErrors> {
95        let private_scalar = *priv_key.secret_key.to_nonzero_scalar();
96        let pub_key_point = K256PublicKey::from_sec1_bytes(&pub_key.to_bytes_impl()?)?.to_projective();
97
98        let shared_point = pub_key_point * private_scalar;
99        let shared_pub = K256PublicKey::from_affine(shared_point.to_affine())?;
100
101        let shared_mod_point = shared_pub.to_encoded_point(true);
102        let hash = Hash::sha_512(shared_mod_point.as_bytes()).to_bytes();
103
104        Ok(CipherKeys {
105            iv: hash[0..16].into(),
106            ke: hash[16..32].into(),
107            km: hash[32..64].into(),
108        })
109    }
110}
111
112impl ECIES {
113    pub fn encrypt(message: &[u8], sender_priv_key: &PrivateKey, recipient_pub_key: &PublicKey, exclude_pub_key: bool) -> Result<ECIESCiphertext, BSVErrors> {
114        ECIES::encrypt_impl(message, sender_priv_key, recipient_pub_key, exclude_pub_key)
115    }
116
117    /**
118     * Encrypt with a randomly generate private key.
119     * This is intended to be used if you want to anonymously send a party an encrypted message.
120     */
121    pub fn encrypt_with_ephemeral_private_key(message: &[u8], recipient_pub_key: &PublicKey) -> Result<ECIESCiphertext, BSVErrors> {
122        ECIES::encrypt_with_ephemeral_private_key_impl(message, recipient_pub_key)
123    }
124
125    pub fn decrypt(ciphertext: &ECIESCiphertext, recipient_priv_key: &PrivateKey, sender_pub_key: &PublicKey) -> Result<Vec<u8>, BSVErrors> {
126        ECIES::decrypt_impl(ciphertext, recipient_priv_key, sender_pub_key)
127    }
128
129    pub fn derive_cipher_keys(priv_key: &PrivateKey, pub_key: &PublicKey) -> Result<CipherKeys, BSVErrors> {
130        ECIES::derive_cipher_keys_impl(priv_key, pub_key)
131    }
132}