def encrypt( cls, *, secret: bytes, password: str, path: str = '', kdf_salt: bytes = randbits(256).to_bytes(32, 'big'), aes_iv: bytes = randbits(128).to_bytes(16, 'big') ) -> 'Keystore': """ Encrypt a secret (BLS SK) as an EIP 2335 Keystore. """ keystore = cls() keystore.uuid = str(uuid4()) keystore.crypto.kdf.params['salt'] = kdf_salt decryption_key = keystore.kdf(password=cls._process_password(password), **keystore.crypto.kdf.params) keystore.crypto.cipher.params['iv'] = aes_iv cipher = AES_128_CTR(key=decryption_key[:16], **keystore.crypto.cipher.params) keystore.crypto.cipher.message = cipher.encrypt(secret) keystore.crypto.checksum.message = SHA256( decryption_key[16:32] + keystore.crypto.cipher.message) keystore.pubkey = bls.SkToPk(int.from_bytes(secret, 'big')).hex() keystore.path = path return keystore
def create_from_private_key( cls, *, secret: bytes, password: str, index: int = DEFAULT_INDEX, threshold: int = DEFAULT_THRESHOLD, shared_public_key: str = DEFAULT_SHARED_PUBLIC_KEY, shared_withdrawal_credentials: str = DEFAULT_SHARED_WITHDRAWAL_CREDS ) -> HorcruxPbkdf2Keystore: keystore = cls() keystore.uuid = str(uuid4()) keystore.crypto.kdf.params["salt"] = randbits(256).to_bytes(32, "big") decryption_key = keystore.kdf(password=cls._process_password(password), **keystore.crypto.kdf.params) keystore.crypto.cipher.params["iv"] = randbits(128).to_bytes(16, "big") cipher = AES_128_CTR(key=decryption_key[:16], **keystore.crypto.cipher.params) keystore.crypto.cipher.message = cipher.encrypt(secret) keystore.crypto.checksum.message = SHA256( decryption_key[16:32] + keystore.crypto.cipher.message) keystore.index = index keystore.threshold = threshold keystore.shared_public_key = shared_public_key keystore.shared_withdrawal_credentials = shared_withdrawal_credentials return keystore
def decrypt(self, password: str) -> bytes: decryption_key = self.kdf(password=password, **self.crypto.kdf.params) assert SHA256( decryption_key[16:32] + self.crypto.cipher.message) == self.crypto.checksum.message cipher = AES_128_CTR(key=decryption_key[:16], **self.crypto.cipher.params) return cipher.decrypt(self.crypto.cipher.message)
def decrypt(self, password: str) -> bytes: """ Retrieve the secret (BLS SK) from the self keystore by decrypting it with `password` """ decryption_key = self.kdf(password=self._process_password(password), **self.crypto.kdf.params) if SHA256(decryption_key[16:32] + self.crypto.cipher.message) != self.crypto.checksum.message: raise ValueError("Checksum message error") cipher = AES_128_CTR(key=decryption_key[:16], **self.crypto.cipher.params) return cipher.decrypt(self.crypto.cipher.message)
def encrypt(cls, *, secret: bytes, password: str, path: str='', kdf_salt: bytes=randbits(256).to_bytes(32, 'big'), aes_iv: bytes=randbits(128).to_bytes(16, 'big')): keystore = cls() keystore.crypto.kdf.params['salt'] = kdf_salt decryption_key = keystore.kdf(password=password, **keystore.crypto.kdf.params) keystore.crypto.cipher.params['iv'] = aes_iv cipher = AES_128_CTR(key=decryption_key[:16], **keystore.crypto.cipher.params) keystore.crypto.cipher.message = cipher.encrypt(secret) keystore.crypto.checksum.message = SHA256(decryption_key[16:32] + keystore.crypto.cipher.message) keystore.pubkey = bls.PrivToPub(int.from_bytes(secret, 'big')).hex() keystore.path = path return keystore
def test_AES_128_CTR(key, iv, valid): if valid: AES_128_CTR(key=key, iv=iv) else: with pytest.raises(ValueError): AES_128_CTR(key=key, iv=iv)