def decrypt(self, enc): enc = base64.b64decode(enc) cipher = pyaes.blockfeeder.Decrypter( pyaes.AESModeOfOperationECB(self.key)) plain_text = cipher.feed(enc) plain_text += cipher.feed() return plain_text
def encrypt(self, raw): _ = self._pad(raw) cipher = pyaes.blockfeeder.Encrypter( pyaes.AESModeOfOperationECB(self.key.encode())) crypted_text = cipher.feed(raw) crypted_text += cipher.feed() return crypted_text
def bip38_encrypt(private_hex, address, password, flagbyte=b'\xe0'): """ BIP0038 non-ec-multiply encryption. Returns BIP0038 encrypted private key Based on code from https://github.com/nomorecoin/python-bip38-testing :param private_hex: Private key in hex format :type private_hex: str :param address: Address string :type address: str :param password: Required password for encryption :type password: str :param flagbyte: Flagbyte prefix for WIF :type flagbyte: bytes :return str: BIP38 password encrypted private key """ if isinstance(address, str): address = address.encode('utf-8') if isinstance(password, str): password = password.encode('utf-8') addresshash = double_sha256(address)[0:4] key = scrypt.hash(password, addresshash, 16384, 8, 8, 64) derivedhalf1 = key[0:32] derivedhalf2 = key[32:64] aes = pyaes.AESModeOfOperationECB(derivedhalf2) encryptedhalf1 = \ aes.encrypt((int(private_hex[0:32], 16) ^ int.from_bytes(derivedhalf1[0:16], 'big')).to_bytes(16, 'big')) encryptedhalf2 = \ aes.encrypt((int(private_hex[32:64], 16) ^ int.from_bytes(derivedhalf1[16:32], 'big')).to_bytes(16, 'big')) encrypted_privkey = b'\x01\x42' + flagbyte + addresshash + encryptedhalf1 + encryptedhalf2 encrypted_privkey += double_sha256(encrypted_privkey)[:4] return change_base(encrypted_privkey, 256, 58)
def bip38_encrypt(self, passphrase): """ BIP0038 non-ec-multiply encryption. Returns BIP0038 encrypted privkey. Based on code from https://github.com/nomorecoin/python-bip38-testing :param passphrase: Required passphrase for encryption :type passphrase: str :return str: BIP38 passphrase encrypted private key """ if self.compressed: flagbyte = b'\xe0' addr = self.address() else: flagbyte = b'\xc0' addr = self.address_uncompressed() privkey = self.private_hex if isinstance(addr, str) and sys.version_info > (3,): addr = addr.encode('utf-8') addresshash = hashlib.sha256(hashlib.sha256(addr).digest()).digest()[0:4] key = scrypt.hash(passphrase, addresshash, 16384, 8, 8) derivedhalf1 = key[0:32] derivedhalf2 = key[32:64] aes = pyaes.AESModeOfOperationECB(derivedhalf2) encryptedhalf1 = aes.encrypt(binascii.unhexlify('%0.32x' % (int(privkey[0:32], 16) ^ int(binascii.hexlify(derivedhalf1[0:16]), 16)))) encryptedhalf2 = aes.encrypt(binascii.unhexlify('%0.32x' % (int(privkey[32:64], 16) ^ int(binascii.hexlify(derivedhalf1[16:32]), 16)))) encrypted_privkey = b'\x01\x42' + flagbyte + addresshash + encryptedhalf1 + encryptedhalf2 encrypted_privkey += hashlib.sha256(hashlib.sha256(encrypted_privkey).digest()).digest()[:4] return change_base(encrypted_privkey, 256, 58)
def bip38_encrypt(private_hex, address, passphrase, flagbyte=b'\xe0'): """ BIP0038 non-ec-multiply encryption. Returns BIP0038 encrypted private key Based on code from https://github.com/nomorecoin/python-bip38-testing :param private_hex: Private key in hex format :type private_hex: str :param address: Address string :type address: str :param passphrase: Required passphrase for encryption :type passphrase: str :param flagbyte: Flagbyte prefix for WIF :type flagbyte: bytes :return str: BIP38 passphrase encrypted private key """ if isinstance(address, str) and sys.version_info > (3,): address = address.encode('utf-8') if isinstance(passphrase, str) and sys.version_info > (3,): passphrase = passphrase.encode('utf-8') addresshash = double_sha256(address)[0:4] key = scrypt.hash(passphrase, addresshash, 16384, 8, 8, 64) derivedhalf1 = key[0:32] derivedhalf2 = key[32:64] aes = pyaes.AESModeOfOperationECB(derivedhalf2) encryptedhalf1 = aes.encrypt(binascii.unhexlify('%0.32x' % (int(private_hex[0:32], 16) ^ int(binascii.hexlify(derivedhalf1[0:16]), 16)))) encryptedhalf2 = aes.encrypt(binascii.unhexlify('%0.32x' % (int(private_hex[32:64], 16) ^ int(binascii.hexlify(derivedhalf1[16:32]), 16)))) encrypted_privkey = b'\x01\x42' + flagbyte + addresshash + encryptedhalf1 + encryptedhalf2 encrypted_privkey += double_sha256(encrypted_privkey)[:4] return change_base(encrypted_privkey, 256, 58)
def _decryptNoEC(self, passphrase : str) -> tuple: # returns the (WIF private key, Address) on success, raises Error on failure. assert isinstance(passphrase, str), "Passphrase must be a string!" scryptBuf = Bip38Key._scrypt(password = passphrase, salt = self.salt, N=16384, r=8, p=8, dkLen=64) derivedHalf1 = scryptBuf[0:32] derivedHalf2 = scryptBuf[32:64] encryptedHalf1 = self.dec[7:23] encryptedHalf2 = self.dec[23:39] h = pyaes.AESModeOfOperationECB(derivedHalf2) k1 = h.decrypt(encryptedHalf1) k2 = h.decrypt(encryptedHalf2) keyBytes = bytearray(32) for i in range(16): keyBytes[i] = k1[i] ^ derivedHalf1[i] keyBytes[i+16] = k2[i] ^ derivedHalf1[i+16] keyBytes = bytes(keyBytes) eckey = regenerate_key(keyBytes) pubKey = eckey.GetPubKey(self.compressed) from .address import Address addr = Address.from_pubkey(pubKey) addrHashed = Hash(addr.to_storage_string(net=self.net))[0:4] assert len(addrHashed) == len(self.salt) for i in range(len(addrHashed)): if addrHashed[i] != self.salt[i]: raise Bip38Key.PasswordError('Supplied password failed to decrypt bip38 key.') return serialize_privkey(keyBytes, self.compressed, 'p2pkh', net=self.net), addr
def decrypt(self,cipherText): cryptor = pyaes.AESModeOfOperationECB(self.key) plainText = cryptor.decrypt(a2b_hex(cipherText)) # 将秘钥转换为二进制流 # 返回值为二进制流,因为有很多不可打印字符 # plainText = cryptor.decrypt(a2b_base64(cipherText)) return plainText
def digest_secure_bootloader(args): """ Calculate the digest of a bootloader image, in the same way the hardware secure boot engine would do so. Can be used with a pre-loaded key to update a secure bootloader. """ if args.iv is not None: print("WARNING: --iv argument is for TESTING PURPOSES ONLY") iv = args.iv.read(128) else: iv = os.urandom(128) plaintext_image = args.image.read() args.image.seek(0) # secure boot engine reads in 128 byte blocks (ie SHA512 block # size), but also doesn't look for any appended SHA-256 digest fw_image = esptool.ESP32FirmwareImage(args.image) if fw_image.append_digest: if len(plaintext_image) % 128 <= 32: # ROM bootloader will read to the end of the 128 byte block, but not # to the end of the SHA-256 digest at the end new_len = len(plaintext_image) - (len(plaintext_image) % 128) plaintext_image = plaintext_image[:new_len] # if image isn't 128 byte multiple then pad with 0xFF (ie unwritten flash) # as this is what the secure boot engine will see if len(plaintext_image) % 128 != 0: plaintext_image += "\xFF" * (128 - (len(plaintext_image) % 128)) plaintext = iv + plaintext_image # Secure Boot digest algorithm in hardware uses AES256 ECB to # produce a ciphertext, then feeds output through SHA-512 to # produce the digest. Each block in/out of ECB is reordered # (due to hardware quirks not for security.) key = _load_hardware_key(args.keyfile) aes = pyaes.AESModeOfOperationECB(key) digest = hashlib.sha512() for block in get_chunks(plaintext, 16): block = block[::-1] # reverse each input block cipher_block = aes.encrypt(block) # reverse and then byte swap each word in the output block cipher_block = cipher_block[::-1] for block in get_chunks(cipher_block, 4): # Python hashlib can build each SHA block internally digest.update(block[::-1]) if args.output is None: args.output = os.path.splitext( args.image.name)[0] + "-digest-0x0000.bin" with open(args.output, "wb") as f: f.write(iv) digest = digest.digest() for word in get_chunks(digest, 4): f.write(word[::-1]) # swap word order in the result f.write(b'\xFF' * (0x1000 - f.tell())) # pad to 0x1000 f.write(plaintext_image) print("digest+image written to %s" % args.output)
def encryptECB(uint8Array, key): aes = pyaes.AESModeOfOperationECB(key) stringPayload = "".join(chr(b) for b in uint8Array) encrypted = aes.encrypt(stringPayload) return encrypted
def __init__(self, seed=None): if seed is None: self.key = os.urandom(32) else: assert len(seed) in [16, 24, 32] self.key = seed self.aes = pyaes.AESModeOfOperationECB(self.key) self.state = [0, 1, 2, 3] self.state_len = len(self.state)
def get_seed_from_ewifv1(ewif, password): regex = re.compile('^[1-9A-HJ-NP-Za-km-z]*$') if not re.search(regex, ewif): print("Error: the format of EWIF is invalid") sys.exit(1) wif_bytes = b58_decode(ewif) if len(wif_bytes) != 39: print("Error: the size of EWIF is invalid") sys.exit(1) wif_no_checksum = wif_bytes[0:-2] checksum_from_ewif = wif_bytes[-2:] fi = wif_bytes[0:1] salt = wif_bytes[1:5] encryptedhalf1 = wif_bytes[5:21] encryptedhalf2 = wif_bytes[21:37] if fi != b'\x02': print("Error: It's not a EWIF format") sys.exit(1) # Checksum Control checksum = nacl.hash.sha256( nacl.hash.sha256(wif_no_checksum, nacl.encoding.RawEncoder), nacl.encoding.RawEncoder)[0:2] if checksum_from_ewif != checksum: print("Error: bad checksum of EWIF address") sys.exit(1) # SCRYPT password = password.encode("utf-8") scrypt_seed = scrypt.hash(password, salt, 16384, 8, 8, 64) derivedhalf1 = scrypt_seed[0:32] derivedhalf2 = scrypt_seed[32:64] # AES aes = pyaes.AESModeOfOperationECB(derivedhalf2) decryptedhalf1 = aes.decrypt(encryptedhalf1) decryptedhalf2 = aes.decrypt(encryptedhalf2) # XOR seed1 = xor_bytes(decryptedhalf1, derivedhalf1[0:16]) seed2 = xor_bytes(decryptedhalf2, derivedhalf1[16:32]) seed = seed1 + seed2 seedhex = nacl.encoding.HexEncoder.encode(seed).decode("utf-8") # Password Control salt_from_seed = nacl.hash.sha256( nacl.hash.sha256(b58_decode(get_publickey_from_seed(seedhex)), nacl.encoding.RawEncoder), nacl.encoding.RawEncoder)[0:4] if salt_from_seed != salt: print("Error: bad Password of EWIF address") sys.exit(1) return seedhex
def encrypt_message(plaintext, id): key = array_clients[int(id)].aes_key.encode() encrypter = pyaes.Encrypter(pyaes.AESModeOfOperationECB(key)) ciphertext = encrypter.feed(plaintext) ciphertext += encrypter.feed() ciphertextbase64 = base64.b64encode(ciphertext) return ciphertextbase64.decode()
def DekriptimiMeECB(ciphertext,celesi): #PADDED decrypted = [] decrypted_1 = [] aes = pyaes.AESModeOfOperationECB(celesi) ciphertext_list = re.findall('.{1,16}', ciphertext.decode('utf-8')) for i in range(len(ciphertext_list)): decrypted.append(aes.decrypt(ciphertext_list[i])) decrypted_1.append(decrypted[i].decode("utf-8")) decrypted_padded_str = ''.join(str(e) for e in decrypted_1) return decrypted_padded_str
def get_stream(self, quality): quality_to_number = { 'MP3_128': '1', 'MP3_320': '3', 'FLAC': '9', '360_RA3': '15', '360_RA2': '14', '360_RA1': '13', } quality = quality_to_number[quality] # get track url # step 1: put a bunch of info together and hash it step1 = b'\xa4'.join(map(lambda s: s.encode(), [ self.md5_origin, quality, str(self.song_id), self.media_version ] )) hash = hashlib.new('md5') hash.update(step1) step1_hash = hash.hexdigest() # - step 2: hash + info + add padding step2 = str.encode(step1_hash) + b'\xa4' + step1 + b'\xa4' while len(step2) % 16 > 0: step2 += b'.' # - step 3: AES encryption to get url # it will encrypt in parts of 16 step3 = b'' aes = pyaes.AESModeOfOperationECB(b'jo6aey6haid2Teih') for index in range(int(len(step2) / 16)): block = step2[(index * 16):(index * 16) + 16] step3 += binascii.hexlify(aes.encrypt(block)) # - step 4: make url url = 'http://e-cdn-proxy-{}.deezer.com/mobile/1/{}'.format( self.md5_origin[0], # first char of md5origin is cdn to use step3.decode('utf-8') ) try: response = urlopen(url) except urllib.error.HTTPError as e: return False except ConnectionResetError as e: print(e) raise NotImplementedError('Error getting deezer track url') output_stream = bytearray() return DeezerTrackStream(url)
def encode_line(plaintext, real_key, buf_len): aes = pyaes.AESModeOfOperationECB(real_key) text_len = len(plaintext) pad_len = buf_len - text_len pad_chr = bytes(chr(pad_len), "utf8") plaintext = plaintext.encode() + pad_chr * pad_len encrypted_text = b''.join([ aes.encrypt(plaintext[i:i + 16]) for i in range(0, len(plaintext), 16) ]) return encrypted_text
def aes_ecb_dec(blob: bytes, key: bytes) -> bytes: """ Decodes the blob in 16 bytes chunks. Returns the concatination of all 16 byte results. """ aes = pyaes.AESModeOfOperationECB(key) comb = b'' for b in divide(blob, 16): comb += aes.decrypt(b) return comb
def __decrypt(self, ciphertext): try: ciphertext = base64.b64decode(ciphertext) decrypter = pyaes.Decrypter(pyaes.AESModeOfOperationECB(self.key)) plaintext = decrypter.feed(ciphertext) plaintext += decrypter.feed() return plaintext except Exception: return
def from_ewif_hex(cls: Type[SigningKeyType], ewif_hex: str, password: str) -> SigningKeyType: """ Return SigningKey instance from Duniter EWIF in hexadecimal format :param ewif_hex: EWIF string in hexadecimal format :param password: Password of the encrypted seed """ ewif_bytes = Base58Encoder.decode(ewif_hex) if len(ewif_bytes) != 39: raise Exception("Error: the size of EWIF is invalid") # extract data fi = ewif_bytes[0:1] checksum_from_ewif = ewif_bytes[-2:] ewif_no_checksum = ewif_bytes[0:-2] salt = ewif_bytes[1:5] encryptedhalf1 = ewif_bytes[5:21] encryptedhalf2 = ewif_bytes[21:37] # check format flag if fi != b"\x02": raise Exception("Error: bad format version, not EWIF") # checksum control checksum = libnacl.crypto_hash_sha256(libnacl.crypto_hash_sha256(ewif_no_checksum))[0:2] if checksum_from_ewif != checksum: raise Exception("Error: bad checksum of the EWIF") # SCRYPT password_bytes = password.encode("utf-8") scrypt_seed = scrypt(password_bytes, salt, 16384, 8, 8, 64) derivedhalf1 = scrypt_seed[0:32] derivedhalf2 = scrypt_seed[32:64] # AES aes = pyaes.AESModeOfOperationECB(derivedhalf2) decryptedhalf1 = aes.decrypt(encryptedhalf1) decryptedhalf2 = aes.decrypt(encryptedhalf2) # XOR seed1 = xor_bytes(decryptedhalf1, derivedhalf1[0:16]) seed2 = xor_bytes(decryptedhalf2, derivedhalf1[16:32]) seed = bytes(seed1 + seed2) # Password Control signer = SigningKey(seed) salt_from_seed = libnacl.crypto_hash_sha256( libnacl.crypto_hash_sha256( Base58Encoder.decode(signer.pubkey)))[0:4] if salt_from_seed != salt: raise Exception("Error: bad Password of EWIF address") return cls(seed)
def digest_secure_bootloader(args): """ Calculate the digest of a bootloader image, in the same way the hardware secure boot engine would do so. Can be used with a pre-loaded key to update a secure bootloader. """ if args.iv is not None: print("WARNING: --iv argument is for TESTING PURPOSES ONLY") iv = args.iv.read(128) else: iv = os.urandom(128) plaintext_image = args.image.read() # secure boot engine reads in 128 byte blocks (ie SHA512 block # size) , so pad plaintext image with 0xFF (ie unwritten flash) if len(plaintext_image) % 128 != 0: plaintext_image += "\xFF" * (128 - (len(plaintext_image) % 128)) plaintext = iv + plaintext_image # Secure Boot digest algorithm in hardware uses AES256 ECB to # produce a ciphertext, then feeds output through SHA-512 to # produce the digest. Each block in/out of ECB is reordered # (due to hardware quirks not for security.) key = args.keyfile.read() if len(key) != 32: raise esptool.FatalError( "Key file contains wrong length (%d bytes), 32 expected." % len(key)) aes = pyaes.AESModeOfOperationECB(key) digest = hashlib.sha512() for block in get_chunks(plaintext, 16): block = block[::-1] # reverse each input block cipher_block = aes.encrypt(block) # reverse and then byte swap each word in the output block cipher_block = cipher_block[::-1] for block in get_chunks(cipher_block, 4): # Python hashlib can build each SHA block internally digest.update(block[::-1]) if args.output is None: args.output = os.path.splitext( args.image.name)[0] + "-digest-0x0000.bin" with open(args.output, "wb") as f: f.write(iv) digest = digest.digest() for word in get_chunks(digest, 4): f.write(word[::-1]) # swap word order in the result f.write(b'\xFF' * (0x1000 - f.tell())) # pad to 0x1000 f.write(plaintext_image) print("digest+image written to %s" % args.output)
def encrypt(self, raw): if AES: raw = self._pad(raw) cipher = AES.new(self.key, mode=AES.MODE_ECB, IV='') crypted_text = cipher.encrypt(raw) else: cipher = pyaes.blockfeeder.Encrypter( pyaes.AESModeOfOperationECB( self.key)) # no IV, auto pads to 16 crypted_text = cipher.feed(raw) crypted_text += cipher.feed() # flush final block #print('crypted_text %r' % crypted_text) return base64.b64encode(crypted_text)
def decrypt(self, enc, use_base64=True): if use_base64: enc = base64.b64decode(enc) # if Crypto: # cipher = AES.new(self.key, AES.MODE_ECB) # raw = cipher.decrypt(enc) # return self._unpad(raw).decode('utf-8') # else: cipher = pyaes.blockfeeder.Decrypter(pyaes.AESModeOfOperationECB(self.key)) plain_text = cipher.feed(enc) plain_text += cipher.feed() return plain_text
def decrypt(self, enc): enc = base64.b64decode(enc) if Crypto: cipher = AES.new(self.key, AES.MODE_ECB) raw = cipher.decrypt(enc) return self._unpad(raw).decode('utf-8') else: cipher = pyaes.blockfeeder.Decrypter( pyaes.AESModeOfOperationECB( self.key)) # no IV, auto pads to 16 plain_text = cipher.feed(enc) plain_text += cipher.feed() # flush final block return plain_text
def decrypt_message(ciphertextb64, id): key = array_clients[int(id)].aes_key.encode() ciphertextb64 = base64.b64decode(ciphertextb64) decryptor = pyaes.Decrypter(pyaes.AESModeOfOperationECB(key)) decryptedmessage = decryptor.feed(ciphertextb64) decryptedmessage = decryptor.feed( ciphertextb64[:int(len(ciphertextb64) / 2)]) decryptedmessage += decryptor.feed( ciphertextb64[int(len(ciphertextb64) / 2):]) return decryptedmessage.decode()
def _flash_encryption_operation(output_file, input_file, flash_address, keyfile, flash_crypt_conf, do_decrypt): key = keyfile.read() if len(key) != 32: raise esptool.FatalError( "Key file contains wrong length (%d bytes), 32 expected." % len(key)) if flash_address % 16 != 0: raise esptool.FatalError( "Starting flash address 0x%x must be a multiple of 16" % flash_address) if flash_crypt_conf == 0: print("WARNING: Setting FLASH_CRYPT_CONF to zero is not recommended") tweak_range = _flash_encryption_tweak_range(flash_crypt_conf) aes = None while True: block_offs = flash_address + input_file.tell() block = input_file.read(16) if len(block) == 0: break elif len(block) < 16: if do_decrypt: raise esptool.FatalError( "Data length is not a multiple of 16 bytes") pad = 16 - len(block) block = block + os.urandom(pad) print( "WARNING: Padding with %d bytes of random data (encrypted data must be multiple of 16 bytes long)" % pad) if (block_offs % 32 == 0) or aes is None: # each bit of the flash encryption key is XORed with tweak bits derived from the offset of 32 byte block of flash block_key = _flash_encryption_tweak_key(key, block_offs, tweak_range) aes = pyaes.AESModeOfOperationECB(block_key) block = block[::-1] # reverse input block byte order # note AES is used inverted for flash encryption, so # "decrypting" flash uses AES encrypt algorithm and vice # versa. (This does not weaken AES.) if do_decrypt: block = aes.encrypt(block) else: block = aes.decrypt(block) block = block[::-1] # reverse output block byte order output_file.write(block)
def instantiate(self, entropy_in, per_string=b''): ''' Method handling initialization of the DRBG (see Specification) Parameters ---------- entropy_in : hex byterray (e.g. \xFF\xF1....etc (len = seedlen_bits /8)) full entropy seed for DRBG, it must be seedlen bits per_string : hex byterray (e.g. \xFF\xF1....etc (len must be less or equal seedlen)) additional input which will be xored with the input entropy for added security (optional) Returns ------- ''' if len(per_string) is not 0: temp = len(per_string) # NB len is in bytes if temp < self.seedlen: per_string = per_string + b"\x00" * (self.seedlen - temp ) # pad else: raise ValueError( "Length of personalization string must be equal or less than seedlen" ) else: per_string = b"\x00" * self.seedlen seed_material = int(entropy_in.hex(), 16) ^ int(per_string.hex(), 16) seed_material = seed_material.to_bytes(self.seedlen, byteorder='big', signed=False) self.key = b"\x00" * self.keylen self.V = b"\x00" * self.outlen self.aes = pyaes.AESModeOfOperationECB(self.key) self._update(seed_material) self.reseed_counter = 1
def encrypt(self, raw): if Crypto: raw = self._pad(raw) cipher = AES.new(self.key, mode=AES.MODE_ECB) crypted_text = cipher.encrypt(raw) else: _ = self._pad(raw) cipher = pyaes.blockfeeder.Encrypter( pyaes.AESModeOfOperationECB( self.key)) # no IV, auto pads to 16 crypted_text = cipher.feed(raw) crypted_text += cipher.feed() # flush final block crypted_text_b64 = base64.b64encode(crypted_text) return crypted_text_b64
def change_key(self, master_key): """Given a new master key, prepare a new auth key""" self.__master_key = long_to_bytes(master_key, 32) self.__aes_ecb = pyaes.AESModeOfOperationECB(self.__master_key) self.__auth_key = bytes_to_long(self.__aes_ecb.encrypt(b"\x00" * 16)) # precompute the table for multiplication in finite field table = [] # for 8-bit for i in range(16): row = [] for j in range(256): row.append(self.gf_2_128_mul(self.__auth_key, j << (8 * i))) table.append(tuple(row)) self.__pre_table = tuple(table)
async def encrypt(self, data, b64=True) -> bytes: #data = self._pad(data) #cipher = AES.new(self._key, AES.MODE_ECB) #encrypted_data = cipher.encrypt(data) cipher = pyaes.blockfeeder.Encrypter( pyaes.AESModeOfOperationECB(self._key)) encrypted_data = cipher.feed(data) encrypted_data += cipher.feed() if b64: return base64.b64encode(encrypted_data) else: return encrypted_data
def _bip38_decrypt(encrypted_privkey, passphrase): """ BIP0038 non-ec-multiply decryption. Returns WIF private key. Based on code from https://github.com/nomorecoin/python-bip38-testing This method is called by Key class init function when importing BIP0038 key. :param encrypted_privkey: Encrypted private key using WIF protected key format :type encrypted_privkey: str :param passphrase: Required passphrase for decryption :type passphrase: str :return str: Private Key WIF """ # TODO: Also check first 2 bytes d = change_base(encrypted_privkey, 58, 256)[2:] flagbyte = d[0:1] d = d[1:] if flagbyte == b'\xc0': compressed = False elif flagbyte == b'\xe0': compressed = True else: raise Warning("Unrecognised password protected key format. Flagbyte incorrect.") addresshash = d[0:4] d = d[4:-4] key = scrypt.hash(passphrase, addresshash, 16384, 8, 8) derivedhalf1 = key[0:32] derivedhalf2 = key[32:64] encryptedhalf1 = d[0:16] encryptedhalf2 = d[16:32] aes = pyaes.AESModeOfOperationECB(derivedhalf2) decryptedhalf2 = aes.decrypt(encryptedhalf2) decryptedhalf1 = aes.decrypt(encryptedhalf1) priv = decryptedhalf1 + decryptedhalf2 priv = binascii.unhexlify('%064x' % (int(binascii.hexlify(priv), 16) ^ int(binascii.hexlify(derivedhalf1), 16))) if compressed: # FIXME: This works but does probably not follow the BIP38 standards (was before: priv = b'\0' + priv) priv += b'\1' key_format = 'wif_compressed' else: key_format = 'wif' k = Key(priv, compressed=compressed) wif = k.wif() addr = k.address() if isinstance(addr, str) and sys.version_info > (3,): addr = addr.encode('utf-8') if hashlib.sha256(hashlib.sha256(addr).digest()).digest()[0:4] != addresshash: print('Addresshash verification failed! Password is likely incorrect.') return wif, key_format
def encrypt(self, raw, use_base64 = True): if Crypto: raw = self._pad(raw) cipher = AES.new(self.key, mode=AES.MODE_ECB) crypted_text = cipher.encrypt(raw) else: _ = self._pad(raw) cipher = pyaes.blockfeeder.Encrypter(pyaes.AESModeOfOperationECB(self.key)) # no IV, auto pads to 16 crypted_text = cipher.feed(raw) crypted_text += cipher.feed() # flush final block #print('crypted_text (%d) %r' % (len(crypted_text), crypted_text)) if use_base64: return base64.b64encode(crypted_text) else: return crypted_text