fork download
  1. import base64
  2. import hashlib
  3. import re
  4. import os
  5. from Crypto.Cipher import DES
  6.  
  7. """
  8. Note about PBEWithMD5AndDES in java crypto library:
  9.  
  10. Encrypt:
  11. Generate a salt (random): 8 bytes
  12. <start derived key generation>
  13. Append salt to the password
  14. MD5 Hash it, and hash the result, hash the result ... 1000 times
  15. MD5 always gives us a 16 byte hash
  16. Final result: first 8 bytes is the "key" and the next is the "initialization vector"
  17. (there is something about the first 8 bytes needing to be of odd paraity, therefore
  18. the least significant bit needs to be changed to 1 if required. We don't do it,
  19. maybe the python crypto library does it for us)
  20. <end derived key generation>
  21.  
  22. Pad the input string with 1-8 bytes (note: not 0-7, so we always have padding)
  23. so that the result is a multiple of 8 bytes. Padding byte value is same as number of
  24. bytes being padded, eg, \x07 if 7 bytes need to be padded.
  25. Use the key and iv to encrypt the input string, using DES with CBC mode.
  26. Prepend the encrypted value with the salt (needed for decrypting since it is random)
  27. Base64 encode it -> this is your result
  28.  
  29. Decrypt:
  30. Base64 decode the input message
  31. Extract the salt (first 8 bytes). The rest is the encoded text.
  32. Use derived key generation as in Encrypt above to get the key and iv
  33. Decrypt the encoded text using key and iv
  34. Remove padding -> this is your result
  35.  
  36. """
  37.  
  38. def get_derived_key(password, salt, count):
  39. key = password + salt
  40. for i in range(count):
  41. m = hashlib.md5(key)
  42. key = m.digest()
  43. return (key[:8], key[8:])
  44.  
  45. def decrypt(msg, password):
  46. msg_bytes = base64.b64decode(msg)
  47. salt = msg_bytes[:8]
  48. enc_text = msg_bytes[8:]
  49. (dk, iv) = get_derived_key(password, salt, 1000)
  50. crypter = DES.new(dk, DES.MODE_CBC, iv)
  51. text = crypter.decrypt(enc_text)
  52. # remove the padding at the end, if any
  53. return re.sub(r'[\x01-\x08]','',text)
  54.  
  55. def encrypt(msg, password):
  56. salt = os.urandom(8)
  57. pad_num = 8 - (len(msg) % 8)
  58. for i in range(pad_num):
  59. msg += chr(pad_num)
  60. (dk, iv) = get_derived_key(password, salt, 1000)
  61. crypter = DES.new(dk, DES.MODE_CBC, iv)
  62. enc_text = crypter.encrypt(msg)
  63. return base64.b64encode(salt + enc_text)
  64.  
  65. def main():
  66. msg = "11111111"
  67. passwd = "Moxanet"
  68. s = encrypt(msg, passwd)
  69. print s
  70. print decrypt(s, passwd)
  71.  
  72. if __name__ == "__main__":
  73. main()
Success #stdin #stdout 0.02s 9760KB
stdin
Standard input is empty
stdout
spV5BSRpq+hz2m6d6qRFMfvbnfOTLtap
11111111