PageRenderTime 60ms CodeModel.GetById 31ms RepoModel.GetById 0ms app.codeStats 0ms

/SIDCrypto.py

https://gitlab.com/bcolin/sid
Python | 193 lines | 120 code | 61 blank | 12 comment | 14 complexity | d2bb74c2b9efbc1174422125d850a31d MD5 | raw file
  1. from Crypto.Cipher import AES,Blowfish,CAST,DES3
  2. from Crypto.Hash import MD5,SHA256,SHA512
  3. from Crypto import Random
  4. ############################################## NULLCIPHER
  5. #Implements a cipher which doesnt change anything. Useful for debugging.
  6. class Null:
  7. def new(key, mode, iv):
  8. res = NullCipher(key, mode, iv)
  9. return res
  10. MODE_CBC = True
  11. key_size = [8]
  12. block_size = 8
  13. class NullCipher:
  14. def __init__(self, key, mode, iv):
  15. self.key = key
  16. self.mode = mode
  17. self.iv = iv
  18. self.block_size = 8
  19. def encrypt(self, s):
  20. assert len(s)%self.block_size == 0
  21. return s
  22. def decrypt(self, s):
  23. return s
  24. algos = {"AES":AES, "Blowfish":Blowfish, "CAST":CAST, "DES3":DES3, "SHA256":SHA256, "SHA512":SHA512, \
  25. "MD5":MD5, "None":Null}
  26. class SIDCrypto:
  27. def __init__(self, password, algo_cipher="AES", algo_hash = "SHA256", saltlen = 8, globalkey=None):
  28. self.algo_hash = algos[algo_hash]
  29. self.saltlen = saltlen
  30. self.password = self.hash(password)
  31. self.algo_cipher = algos[algo_cipher]
  32. self.keylen, self.ivlen = self.algo_cipher.key_size[-1], self.algo_cipher.block_size
  33. self.rand = Random.new()
  34. self.globalKey = globalkey
  35. def generateGlobalKey(self): #returns a new global key. Should be useful for version-dependant encryption
  36. return self.rand.read(self.algo_cipher.key_size[0])
  37. def setGlobalKey(self, key): #usual setter
  38. self.globalKey = key
  39. def setPassword(self, newpassword): #usual setter
  40. self.password = self.hash(newpassword)
  41. def isPassword(self, string):
  42. return hash(string) == self.password
  43. def key_iv_salt_generator(self,seed):
  44. iv = (self.rand).read(self.ivlen) #random generation of the iv
  45. salt = (self.rand).read(self.saltlen) #random generation of the salt
  46. key = self.hash(seed + salt , converting_bytes = True) #the key is the hash of the global key +the salt
  47. key = key[:self.keylen]
  48. return (key,iv,salt)
  49. ############################################################ ENCRYPTION FUNCTION
  50. def encrypt(self, path, usePassword = False):
  51. #the path is the one of the file that will be ciphered
  52. o = open(path, 'rb')
  53. clear = o.read() #message contained in the file
  54. o.close()
  55. m = self.encryptBytes(clear, usePassword)
  56. return m
  57. def encryptBytes(self, clear, usePassword = False):
  58. if self.globalKey is None or usePassword:
  59. (key,iv,salt) = self.key_iv_salt_generator(self.password)
  60. else:
  61. (key,iv,salt) = self.key_iv_salt_generator(self.globalKey)
  62. cipher = self.algo_cipher.new(key, self.algo_cipher.MODE_CBC, iv)
  63. clear += self.hash(clear, converting_bytes = True)
  64. #begin padding
  65. padlen = cipher.block_size
  66. if padlen != len(clear)%padlen:
  67. padlen = padlen - (len(clear)%padlen)
  68. clear += bytearray((chr(padlen)*padlen).encode("utf-8"))
  69. c = cipher.encrypt(clear) #the message is ciphered
  70. c += iv #the iv is appended to the ciphered message
  71. c += salt #the salt is appended to the ciphered message after the iv
  72. return c #the output is a bytes array containing the ciphered message + the encrypted iv
  73. ########################################################## DECRYPTION FUNCTION
  74. def decrypt(self, path, usePassword=False):
  75. o = open(path, 'rb')
  76. c = o.read()
  77. m = self.decryptBytes(c)
  78. return m #the output is a byte array containing the message.
  79. def decryptBytes(self, s, usePassword=False):
  80. #the string is splitted into the actual ciphered message, the hash, the iv, and the salt
  81. c = s[:len(s)-(self.saltlen + self.ivlen)]
  82. iv = s[len(s)-(self.ivlen+self.saltlen):len(s)-self.saltlen]
  83. salt = s[len(s)-self.saltlen:]
  84. #assert self.globalKey != None #an error is thrown if globalKey has not been defined
  85. #the key is the hash of the password+the salt
  86. if self.globalKey is None or usePassword:
  87. key = self.hash(self.password + salt , converting_bytes = True)[:self.keylen]
  88. else:
  89. key = self.hash(self.globalKey + salt , converting_bytes = True)[:self.keylen]
  90. cipher = self.algo_cipher.new(key, self.algo_cipher.MODE_CBC, iv)
  91. m = cipher.decrypt(c)
  92. assert len(m)%(cipher.block_size) == 0 #makes sure m is conveniently padded. Else, throws an error.
  93. #begin unpadding
  94. padlen = m[-1]
  95. m = m[:-padlen]
  96. #integrity control
  97. assert self.hash(m[:-self.algo_hash.digest_size], converting_bytes = True) == m[-self.algo_hash.digest_size:]
  98. return m[:-self.algo_hash.digest_size] #the output is a byte array containing the message.
  99. ############################################################### HASH FUNCTION
  100. def hash(self, name, version = -1, converting_bytes = False, hash_file = False):
  101. if (not converting_bytes):
  102. if hash_file:
  103. f = open(name,'br')
  104. s = f.read()
  105. else:
  106. if version == -1:
  107. s = name
  108. else:
  109. s = name + str(version)
  110. s = s.encode("utf-8")
  111. else:
  112. s = name
  113. h = (self.algo_hash).new()
  114. h.update(s)
  115. return h.digest()
  116. if __name__ == "__main__":
  117. import getpass
  118. password = getpass.getpass('password: ')
  119. algo = input("algorithme a utiliser : ")
  120. sid = SIDCrypto(password, algo_cipher=algo)
  121. sid.globalKey = sid.rand.read(sid.algo_cipher.key_size[0])
  122. message_clair = input("message a chiffrer : ").encode('utf-8')
  123. clear = open("clear.txt", 'bw')
  124. clear.write(message_clair)
  125. clear.close()
  126. message_chiffre = sid.encrypt("clear.txt")
  127. encrypted = open("encrypted.txt", 'bw')
  128. encrypted.write(message_chiffre)
  129. encrypted.close()
  130. decrypted = open("decrypted.txt", 'bw')
  131. decrypted.write(sid.decrypt("encrypted.txt"))
  132. decrypted.close()