PageRenderTime 120ms CodeModel.GetById 49ms RepoModel.GetById 1ms app.codeStats 0ms

/blowfishcipher/__init__.py

https://github.com/dahool/vertaal
Python | 120 lines | 96 code | 7 blank | 17 comment | 2 complexity | 4ad6ec157be29deac0c5fa4a11bc1ed8 MD5 | raw file
  1. """Copyright (c) 20012 Sergio Gabriel Teves
  2. All rights reserved.
  3. This program is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation, either version 3 of the License, or
  6. (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program. If not, see <http://www.gnu.org/licenses/>.
  13. """
  14. from random import randrange
  15. import base64
  16. class Cipher:
  17. def __init__(self, key):
  18. if len(key) < 8: raise Exception('Key length must be greater than 8')
  19. def encrypt(self, text):
  20. raise NotImplementedError
  21. def decrypt(self, b64text):
  22. raise NotImplementedError
  23. class LocalCipher(Cipher):
  24. def __init__(self, key):
  25. Cipher.__init__(self, key)
  26. self.__cipher = Blowfish(key)
  27. def encrypt(self, text):
  28. padtext = self.__pad_text(text)
  29. res = []
  30. for n in range(0,len(padtext),8):
  31. part = padtext[n:n+8]
  32. res.append(self.__cipher.encrypt(part))
  33. ciphertext = ''.join(res)
  34. return base64.b64encode(ciphertext)
  35. def decrypt(self, b64text):
  36. enctext = b64text
  37. try:
  38. ciphertext = base64.b64decode(enctext)
  39. except TypeError:
  40. # text is not encrypted
  41. return enctext
  42. res = []
  43. for n in range(0,len(ciphertext),8):
  44. part = ciphertext[n:n+8]
  45. res.append(self.__cipher.decrypt(part))
  46. cleartext = ''.join(res)
  47. return self.__depad_text(cleartext)
  48. # Blowfish cipher needs 8 byte blocks to work with
  49. def __pad_text(self, text):
  50. pad_bytes = 8 - (len(text) % 8)
  51. # try to deal with unicode strings
  52. asc_text = str(text)
  53. for i in range(pad_bytes - 1):
  54. asc_text += chr(randrange(0, 256))
  55. # final padding byte; % by 8 to get the number of padding bytes
  56. bflag = randrange(6, 248); bflag -= bflag % 8 - pad_bytes
  57. asc_text += chr(bflag)
  58. return asc_text
  59. def __depad_text(self, text):
  60. pad_bytes = ord(text[-1]) % 8
  61. if not pad_bytes: pad_bytes = 8
  62. return text[:-pad_bytes]
  63. class CryptoCipher(Cipher):
  64. def __init__(self, key):
  65. Cipher.__init__(self, key)
  66. self.__cipher = Blowfish.new(key)
  67. def encrypt(self, text):
  68. ciphertext = self.__cipher.encrypt(self.__pad_file(text))
  69. return base64.b64encode(ciphertext)
  70. def decrypt(self, b64text):
  71. try:
  72. ciphertext = base64.b64decode(b64text)
  73. except TypeError:
  74. # text is not encrypted
  75. return b64text
  76. cleartext = self.__depad_file(self.__cipher.decrypt(ciphertext))
  77. return cleartext
  78. # Blowfish cipher needs 8 byte blocks to work with
  79. def __pad_file(self, text):
  80. pad_bytes = 8 - (len(text) % 8)
  81. # try to deal with unicode strings
  82. asc_text = str(text)
  83. for i in range(pad_bytes - 1):
  84. asc_text += chr(randrange(0, 256))
  85. # final padding byte; % by 8 to get the number of padding bytes
  86. bflag = randrange(6, 248); bflag -= bflag % 8 - pad_bytes
  87. asc_text += chr(bflag)
  88. return asc_text
  89. def __depad_file(self, text):
  90. pad_bytes = ord(text[-1]) % 8
  91. if not pad_bytes: pad_bytes = 8
  92. return text[:-pad_bytes]
  93. try:
  94. from Crypto.Cipher import Blowfish
  95. cipher = CryptoCipher
  96. except:
  97. from blowfishcipher.blowfish import Blowfish
  98. cipher = LocalCipher