【问题标题】:AES 128 CTR random access decryption with cryptography.hazmat in Python在 Python 中使用 cryptography.hazmat 的 AES 128 CTR 随机访问解密
【发布时间】:2021-08-13 11:34:11
【问题描述】:

理论上,CTR 模式下的 AES 加密允许在任何块索引处解密(也就是说,如果您只想从某个位置/块索引解密,则不必从一开始就解密整个加密数据)。您只需将所需的块索引添加到计数器的初始值中,然后使用此更新的计数器即可开始解密。 在实践中,我尝试在 Python 中使用 cryptography.hazmat 库执行此操作,但我无法做到。

我通过指定initial_value=0 用于完整文件加密和inital_value=desiredAESBlockIndex 在构造用于在指定AES 块索引处解密的密码时使用pycryptodome 模块设法做到了这一点。

这是我的代码(使用加密模块):

import os
import sys

from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes

def tstFullFileCryptography(aFilePath, aKey, aIV):
  fileRawData = b''
  with open(aFilePath, 'rb') as file:
    fileRawData = file.read()

  cipher = Cipher(algorithms.AES(aKey), modes.CTR(aIV))
  encryptor = cipher.encryptor()

  encryptedData = encryptor.update(fileRawData) + encryptor.finalize()
  
  with open(aFilePath + ".cry", 'wb') as file:
    file.write(encryptedData)

  ######### test #############
  decryptor = cipher.decryptor()
  decryptedData = decryptor.update(encryptedData) + decryptor.finalize()
  if decryptedData == fileRawData:
    print("OK - cryptography: full encryption")
  else:
    print("ERROR - cryptography: full encryption")

def tstCryptographyFromIndex(aFilePath, aKey, aIV):
  algAES = algorithms.AES(aKey)
  # the desired AES block index and size of data to decrypt
  tstAESBlockIndex = 1
  tstSizeInBytes = 16 * 13

  tstRaw = b''
  with open(aFilePath, 'rb') as file:
    file.seek(tstAESBlockIndex * algAES.block_size)
    tstRaw = file.read(tstSizeInBytes)

  tstEncryptedData = b''
  with open(aFilePath + ".cry", 'rb') as file:
    file.seek(tstAESBlockIndex * algAES.block_size)
    tstEncryptedData = file.read(tstSizeInBytes)
  print(f"\ntstEncryptedData: {tstEncryptedData}\n")
  
  ################ decrypt from desired block index; advance iv
  ivNum = int.from_bytes(aIV, byteorder=sys.byteorder)
  incrementedIVNum = ivNum + tstAESBlockIndex
  incrementedIV = incrementedIVNum.to_bytes(16, byteorder=sys.byteorder)
  decryptor = Cipher(algAES, modes.CTR(incrementedIV)).decryptor()
  
  tstDecryptedData = decryptor.update(tstEncryptedData) + decryptor.finalize()
  print(f"tstDecryptedData: {tstDecryptedData}\n")

  if tstRaw == tstDecryptedData:
    print("OK - cryptography: index decryption")
  else:
    print("ERROR - cryptography: index decryption")


def main():
  key = os.urandom(32)
  iv = os.urandom(16)
  
  tstFullFileCryptography("C:\\work\\python\\tstdata\\video.mp4", key, iv)
  tstCryptographyFromIndex("C:\\work\\python\\tstdata\\video.mp4", key, iv)
  
  return 0

if __name__ == "__main__":
  main()

【问题讨论】:

    标签: python cryptography random-access


    【解决方案1】:

    这是修复后的代码您的代码中有 2 个错误导致您的解密和文件搜索不正确。

    import os
    import sys
    
    from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
    
    def tstFullFileCryptography(aFilePath, aKey, aIV):
      fileRawData = b''
      with open(aFilePath, 'rb') as file:
        fileRawData = file.read()
    
      cipher = Cipher(algorithms.AES(aKey), modes.CTR(aIV))
      encryptor = cipher.encryptor()
    
      encryptedData = encryptor.update(fileRawData) + encryptor.finalize()
      
      with open(aFilePath + ".cry", 'wb') as file:
        file.write(encryptedData)
    
      ######### test #############
      decryptor = cipher.decryptor()
      decryptedData = decryptor.update(encryptedData) + decryptor.finalize()
      if decryptedData == fileRawData:
        print("OK - cryptography: full encryption")
      else:
        print("ERROR - cryptography: full encryption")
    
    def tstCryptographyFromIndex(aFilePath, aKey, aIV):
      algAES = algorithms.AES(aKey)
      # the desired AES block index and size of data to decrypt
      tstAESBlockIndex = 1
      tstSizeInBytes = 16 * 13
    
      tstRaw = b''
      with open(aFilePath, 'rb') as file:
        file.seek(tstAESBlockIndex * 16)
        tstRaw = file.read(tstSizeInBytes)
    
      tstEncryptedData = b''
      with open(aFilePath + ".cry", 'rb') as file:
        file.seek(tstAESBlockIndex * 16)
        tstEncryptedData = file.read(tstSizeInBytes)
      print(f"\ntstEncryptedData: {tstEncryptedData}\n")
      
      ################ decrypt from desired block index; advance iv
      ivNum = int.from_bytes(aIV, byteorder="big")
      incrementedIVNum = ivNum + tstAESBlockIndex
      incrementedIV = incrementedIVNum.to_bytes(16, byteorder="big")
      decryptor = Cipher(algAES, modes.CTR(incrementedIV)).decryptor()
      
      tstDecryptedData = decryptor.update(tstEncryptedData) + decryptor.finalize()
      print(f"tstDecryptedData: {tstDecryptedData}\n")
    
      if tstRaw == tstDecryptedData:
        print("OK - cryptography: index decryption")
      else:
        print("ERROR - cryptography: index decryption")
    
    
    def main():
      key = os.urandom(32)
      iv = os.urandom(16)
      
      tstFullFileCryptography("text", key, iv)
      tstCryptographyFromIndex("text", key, iv)
      
      return 0
    
    if __name__ == "__main__":
      main()
    

    第一个错误是您使用不正确的block_size 进行搜索,因为在您的情况下,搜索是按字节级别进行的,而block_size 是位级别 = 128

    第二个错误是sys.byte_order,如果您使用 x86 处理器,而所有加密操作都以大字节序完成,那么您基本上是在反转字节,导致不正确的解密修复两个错误现在让我成功解密。

    【讨论】:

    • 谢谢!随着您的更改,它的工作原理! (我在以字节为单位的 PyCrypto/pycryptodome block_size 和以比特为单位的密码学 block_size 之间切换感到困惑)
    • 我也不知道 byte_order 格式。
    猜你喜欢
    • 2014-07-07
    • 1970-01-01
    • 2017-03-17
    • 1970-01-01
    • 1970-01-01
    • 2015-06-09
    • 1970-01-01
    • 2018-04-04
    • 1970-01-01
    相关资源
    最近更新 更多