Guest User

Untitled

a guest
Jun 6th, 2012
283
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 3.22 KB | None | 0 0
  1. # The simplest digest function from the article
  2. # No salt, no frills
  3. def getDigest(password):
  4.     return hashlib.sha256(password).hexdigest()
  5.  
  6.  
  7. # I have a dictionary file with 38600 words
  8. # pw_digest will be the SHA-256 hash of an arbitrarily picked dictionary word
  9. pw_digest = getDigest('???')
  10.  
  11.  
  12. # This will be our model of the server
  13. # It hashes the supplied password, then compares the hash against the
  14. # expected hash using '=='
  15. def verify_password(pw):
  16.     time_used = 0
  17.  
  18.     # This is our '=='
  19.     # We'll use the hex digest here, like in the example function
  20.     digests_equal = False
  21.     for pw_char, correct_char in zip(getDigest(pw), pw_digest):
  22.         time_used += 1
  23.         if pw_char != correct_char:
  24.             break
  25.     else:
  26.         digests_equal = True
  27.  
  28.     # Oops, we have side channel leak!
  29.     print 'Used', time_used, 'ms to verify password'
  30.  
  31.     return digests_equal
  32.  
  33.  
  34. # Example output:
  35. # sha256('foo') => 2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae
  36. verify_password('foo')
  37. # Used 1 ms to verify password
  38. # False
  39.  
  40. # Okay, so how many calls to verify_password do we need to discover the correct password?
  41. # Let's find out!
  42.  
  43. # We'll start off with some nonsense words, the contents doesn't matter as long as we know the hash
  44. # sha256('000016') => 054cb08ba55a5a5f8885578644125c1862ab996db04c4cf523b3848bca85579a
  45. verify_password('000016')
  46. # Used 1 ms to verify password
  47. # False
  48.  
  49. # '0...' is out
  50.  
  51. # sha256('000014') => 1f5dbbbc4af3816b8ebdafe6d3c458cab237e586622900de5347c63be1184e6c
  52. verify_password('000014')
  53. # Used 1 ms to verify password
  54. # False
  55.  
  56. # (Snipped 3 attempts)
  57.  
  58. # sha256('000025') => 6fb53cf99da69b910aa03ea5a4748a00189ca724d6989e99005968f7c39ea948
  59. verify_password('000025')
  60. # Used 2 ms to verify password
  61. # False
  62.  
  63. # All right, looks like our hash starts with '6'
  64. # Let's move on to the next digit
  65.  
  66. # sha256('000083') => 60bdf9c8fe2df773120ba841d57a6dc95b8b5ac512cc2800a2e12f65ba40e0af
  67. verify_password('000083')
  68. # Used 2 ms to verify password
  69. # False
  70.  
  71. # (Snipped 10 attempts)
  72.  
  73. # sha256('000586') => 6b0a43a32299596db396b968527881dff409c3ea32ff7190498f827f66a6f3e4
  74. verify_password('000586')
  75. # Used 3 ms to verify password
  76. # False
  77.  
  78. # '6b...'
  79.  
  80. # (Snipped 3 attempts)
  81.  
  82. # sha256('003496') => 6b311f8c360053cf3cc7856e1c3542936ab48b26764950ea48a017544be8b11e
  83. verify_password('003496')
  84. # Used 4 ms to verify password
  85. # False
  86.  
  87. # '6b3...'
  88. # All right, so we're doing pretty good here.
  89. # We could keep going, but we're already down to five words out of 38600
  90. # Here's our potential matches: ['biannual', 'cackling', 'dismal', 'grabber', 'mated']
  91. # I'll just try them in order:
  92.  
  93. # sha256('biannual') => 6b3a622042d40e23a50c068772325d0c789fa97e50c583edf8419ca2dc10ee00
  94. verify_password('biannual')
  95. # Used 64 ms to verify password
  96. # True
  97.  
  98. # Oh, look, there it was.
  99. # So how many login attempts did we make?
  100. # All counted, 23.
  101. # Now in the real world that would be multiplied by some number in order to get
  102. # a statistically significant timing sample, but still, that's not bad.
  103. # Keep in mind, if we had run a dictionary attack directly to the verify
  104. # function, we would have required on average 19300 calls.
  105. # Bet that would have set off a few alarms!
Advertisement
Add Comment
Please, Sign In to add comment