PageRenderTime 134ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/cryptmd1/__init__.py

https://bitbucket.org/adrians/cryptmd1
Python | 203 lines | 190 code | 13 blank | 0 comment | 1 complexity | 9b1b65496f76520b3d264be4ef169777 MD5 | raw file
  1. __version__ = "0.2-2"
  2. import base64
  3. from Crypto.Cipher import AES, ARC2, Blowfish, CAST, DES, DES3
  4. from Crypto.Random import get_random_bytes
  5. class Cryptmd1Error(Exception):
  6. pass
  7. def add_byte_padding(content, block_size):
  8. l = len(content)
  9. d = block_size - (l % block_size)
  10. suffix = chr(0) * (d - 1) + chr(d)
  11. return content + suffix
  12. def remove_byte_padding(content):
  13. c = ord(content[-1])
  14. return content[:-c]
  15. add_padding = add_byte_padding
  16. remove_padding = remove_byte_padding
  17. ciphers = {
  18. "aes": {"key_sizes": (16, 24, 32), "class": AES},
  19. "arc2": {"key_sizes": None, "class": ARC2},
  20. "blowfish": {"key_sizes": None, "class": Blowfish},
  21. "cast": {"key_sizes": None, "class": CAST},
  22. "des": {"key_sizes": (8,), "class": DES},
  23. "des3": {"key_sizes": (16,), "class": DES3},
  24. }
  25. def key_generate(size, as_ascii=False):
  26. key = get_random_bytes(size)
  27. return key
  28. def key_generate_ascii(size):
  29. key = key_generate(size)
  30. return base64.b64encode(key)
  31. def key_from_ascii(ascii_key):
  32. return base64.b64decode(ascii_key)
  33. def key_from_ascii_file(filename):
  34. with open(filename, "r") as fil:
  35. data = fil.read()
  36. key = key_from_ascii(data)
  37. return key
  38. def xor_blocks(block1, block2):
  39. return "".join((chr(ord(x) ^ ord(y))) for (x, y) in zip(block1, block2))
  40. def cbc_encrypt(file_in, file_out, key, cipher_class=AES):
  41. cipher = cipher_class.new(key)
  42. block_size = cipher.block_size
  43. ve = get_random_bytes(block_size)
  44. file_out.write(ve)
  45. input_end = False
  46. while not input_end:
  47. data = file_in.read(block_size)
  48. if len(data) < block_size:
  49. input_end = True
  50. data = add_padding(data, block_size)
  51. data = xor_blocks(data, ve)
  52. e = cipher.encrypt(data)
  53. file_out.write(e)
  54. ve = e
  55. def cbc_decrypt(file_in, file_out, key, cipher_class=AES):
  56. cipher = cipher_class.new(key)
  57. block_size = cipher.block_size
  58. ve = file_in.read(block_size)
  59. d = ""
  60. while True:
  61. data = file_in.read(block_size)
  62. l = len(data)
  63. assert l == block_size or l == 0
  64. if l == 0:
  65. file_out.write(remove_padding(d))
  66. break
  67. else:
  68. file_out.write(d)
  69. d = cipher.decrypt(data)
  70. d = xor_blocks(d, ve)
  71. ve = data
  72. def steal_enc(cipher, pn1, pn, cn2):
  73. m = len(pn)
  74. b = len(pn1)
  75. xn1 = xor_blocks(pn1, cn2)
  76. en1 = cipher.encrypt(xn1)
  77. cn = en1[:m]
  78. p = pn + chr(0) * (b - m)
  79. dn = xor_blocks(en1, p)
  80. cn1 = cipher.encrypt(dn)
  81. return cn1, cn
  82. def steal_dec(cipher, cn1, cn, cn2):
  83. m = len(cn)
  84. b = len(cn1)
  85. dn = cipher.decrypt(cn1)
  86. c = cn + chr(0) * (b - m)
  87. xn = xor_blocks(dn, c)
  88. pn = xn[:m]
  89. en1 = cn + xn[-(b - m):]
  90. xn1 = cipher.decrypt(en1)
  91. pn1 = xor_blocks(xn1, cn2)
  92. return pn1, pn
  93. def cbc_steal_encrypt(file_in, file_out, key, cipher_class=AES):
  94. cipher = cipher_class.new(key)
  95. block_size = cipher.block_size
  96. ve = chr(0) * block_size
  97. d0 = file_in.read(block_size)
  98. if len(d0) != block_size:
  99. raise Cryptmd1Error("Input must be at least %d bytes" % block_size)
  100. while True:
  101. d1 = file_in.read(block_size)
  102. if len(d1) < block_size:
  103. cn1, cn = steal_enc(cipher, d0, d1, ve)
  104. file_out.write(cn1 + cn)
  105. return
  106. d = xor_blocks(d0, ve)
  107. e = cipher.encrypt(d)
  108. file_out.write(e)
  109. ve = e
  110. d0 = d1
  111. def cbc_steal_decrypt(file_in, file_out, key, cipher_class=AES):
  112. cipher = cipher_class.new(key)
  113. block_size = cipher.block_size
  114. ve = chr(0) * block_size
  115. d0 = file_in.read(block_size)
  116. if len(d0) != block_size:
  117. raise Cryptmd1Error("Input must be at least %d bytes" % block_size)
  118. while True:
  119. d1 = file_in.read(block_size)
  120. if len(d1) < block_size:
  121. pn1, pn = steal_dec(cipher, d0, d1, ve)
  122. file_out.write(pn1 + pn)
  123. return
  124. d = cipher.decrypt(d0)
  125. d = xor_blocks(d, ve)
  126. file_out.write(d)
  127. ve = d0
  128. d0 = d1
  129. def cfb_encrypt(file_in, file_out, key, cipher_class=AES):
  130. cipher = cipher_class.new(key)
  131. block_size = cipher.block_size
  132. ve = get_random_bytes(block_size)
  133. file_out.write(ve)
  134. data = file_in.read(block_size)
  135. while len(data) > 0:
  136. enc = cipher.encrypt(ve)
  137. d = xor_blocks(enc, data)
  138. file_out.write(d)
  139. ve = d
  140. data = file_in.read(block_size)
  141. def cfb_decrypt(file_in, file_out, key, cipher_class=AES):
  142. cipher = cipher_class.new(key)
  143. block_size = cipher.block_size
  144. ve = file_in.read(block_size)
  145. data = file_in.read(block_size)
  146. while len(data) > 0:
  147. dec = cipher.encrypt(ve)
  148. d = xor_blocks(dec, data)
  149. file_out.write(d)
  150. ve = data
  151. data = file_in.read(block_size)
  152. crypt_functions = {
  153. "cbc": {"encrypt": cbc_encrypt, "decrypt": cbc_decrypt},
  154. "cbc-steal": {"encrypt": cbc_steal_encrypt, "decrypt": cbc_steal_decrypt},
  155. "cfb": {"encrypt": cfb_encrypt, "decrypt": cfb_decrypt},
  156. }
  157. def cipher_class_from_str(key):
  158. return ciphers[key]["class"]