Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Crypto Pitfalls

Crypto Pitfalls

How what you think you know about cryptography can lead to catastrophic consequences.

Stephen Touset

February 07, 2013
Tweet

Other Decks in Programming

Transcript

  1. “Whatever. It’s secure enough. It’s not like we need to

    defend against the NSA.” Monday, March 4, 13
  2. Cryptography is either done correctly, or it is done broken.

    There is rarely a middle ground. Monday, March 4, 13
  3. “Don’t roll your own crypto” • Don’t invent your own

    algorithms • Don’t invent your own protocols Monday, March 4, 13
  4. “Don’t roll your own crypto” • Don’t invent your own

    algorithms • Don’t invent your own protocols • Don’t implement algorithms or protocols Monday, March 4, 13
  5. “Don’t roll your own crypto” • Don’t invent your own

    algorithms • Don’t invent your own protocols • Don’t implement algorithms or protocols • Use the highest-level abstraction possible Monday, March 4, 13
  6. “Don’t roll your own crypto” • Don’t invent your own

    protocols • Don’t implement algorithms or protocols • Use the highest-level abstraction possible Monday, March 4, 13
  7. Even if you think you’re doing everything right... • Forgeable

    Signatures • Forgeable Ciphertexts • Padding Oracle Attacks • Timing Attacks • ... Monday, March 4, 13
  8. User Creation API query = “?company_id=4” + “&username=bdole” + “&admin=false”

    } headers[‘signature’] == Digest::MD5.hexdigest( key + company_id + username + admin ) Monday, March 4, 13
  9. Spot the Security Flaw query = “?company_id=4” + “&username=bdole” +

    “&admin=false” } headers[‘signature’] == Digest::MD5.hexdigest( key + company_id + username + admin ) Monday, March 4, 13
  10. Message Boundary Fix Sign the query parameters themselves query =

    “?company_id=4” + “&username=bdole” + “&admin=false” } headers[‘signature’] == Digest::MD5.hexdigest( key + “?company_id=4” + “&username=bdole” + “&admin=false” ) Monday, March 4, 13
  11. Spot the Security Flaw query = “?company_id=4” + “&username=bdole” +

    “&admin=false” } headers[‘signature’] == Digest::MD5.hexdigest( key + “?company_id=4” + “&username=bdole” + “&admin=false” ) Monday, March 4, 13
  12. String Comparison class String def ==(other) return false if self.bytesize

    != other.bytesize self.bytes.with_index.all? do |byte, i| other.bytes.to_a[i] == other end end end Monday, March 4, 13
  13. String Comparison “098f6bcd...” == “098f6bbd...” class String def ==(other) return

    false if self.bytesize != other.bytesize self.bytes.with_index.all? do |byte, i| other.bytes.to_a[i] == other end end end Monday, March 4, 13
  14. String Comparison “098f6bcd...” == “098f6bbd...” class String def ==(other) return

    false if self.bytesize != other.bytesize self.bytes.with_index.all? do |byte, i| other.bytes.to_a[i] == other end end end Monday, March 4, 13
  15. String Comparison “098f6bcd...” == “098f6bbd...” class String def ==(other) return

    false if self.bytesize != other.bytesize self.bytes.with_index.all? do |byte, i| other.bytes.to_a[i] == other end end end Monday, March 4, 13
  16. String Comparison “098f6bcd...” == “098f6bbd...” class String def ==(other) return

    false if self.bytesize != other.bytesize self.bytes.with_index.all? do |byte, i| other.bytes.to_a[i] == other end end end Monday, March 4, 13
  17. String Comparison “098f6bcd...” == “098f6bbd...” class String def ==(other) return

    false if self.bytesize != other.bytesize self.bytes.with_index.all? do |byte, i| other.bytes.to_a[i] == other end end end Monday, March 4, 13
  18. String Comparison “098f6bcd...” == “098f6bbd...” class String def ==(other) return

    false if self.bytesize != other.bytesize self.bytes.with_index.all? do |byte, i| other.bytes.to_a[i] == other end end end Monday, March 4, 13
  19. String Comparison “098f6bcd...” == “098f6bbd...” class String def ==(other) return

    false if self.bytesize != other.bytesize self.bytes.with_index.all? do |byte, i| other.bytes.to_a[i] == other end end end Monday, March 4, 13
  20. String Comparison class String def ==(other) return false if self.bytesize

    != other.bytesize self.bytes.with_index.all? do |byte, i| other.bytes.to_a[i] == other end end end “098f6bcd...” == “098f6bbd...” Monday, March 4, 13
  21. String Comparison class String def constant_time_compare(other) return false if self.bytesize

    != other.bytesize pairs = self.bytes.zip(other.bytes) xors = pairs.map {|left, right| left ^ right } sum = xors.inject {|sum, i | sum + i } sum == 0 end end (in constant time) Monday, March 4, 13
  22. Timing Attack Fix query = “?company_id=4” + “&username=bdole” + “&admin=false”

    } headers[‘signature’].constant_time_compare( Digest::MD5.hexdigest( key + “?company_id=4” + “&username=bdole” + “&admin=false” ) ) Monday, March 4, 13
  23. Spot the Security Flaw query = “?company_id=4” + “&username=bdole” +

    “&admin=false” } headers[‘signature’].constant_time_compare( Digest::MD5.hexdigest( key + “?company_id=4” + “&username=bdole” + “&admin=false” ) ) Monday, March 4, 13
  24. Length-Extension Attack query = “?company_id=4” + “&username=bdole” + “&admin=false” +

    “\x01\x00...\x28&admin=true” } headers[‘signature’].constant_time_compare( Digest::MD5.hexdigest( key + “?company_id=4” + “&username=bdole” + “&admin=false” + “\x01\x00...\x28admin=true&” ) ) Monday, March 4, 13
  25. Let’s Talk Padding MD5( H e l l o )

    MD5( 48 65 6c 6c 6f 00 00 00 ) Monday, March 4, 13
  26. Let’s Talk Padding MD5( H e l l o )

    MD5( 48 65 6c 6c 6f 00 00 00 ) this is dangerous — multiple messages collide Monday, March 4, 13
  27. Let’s Talk Padding MD5( H e l l o )

    MD5( 48 65 6c 6c 6f 00 00 00 ) this is dangerous — multiple messages collide MD5( H e l l o \0 ) MD5( 48 65 6c 6c 6f 00 00 00 ) Monday, March 4, 13
  28. So We Pad MD5( H e l l o )

    MD5( 48 65 6c 6c 6f 01 00 05 ) Monday, March 4, 13
  29. So We Pad MD5( H e l l o )

    MD5( 48 65 6c 6c 6f 01 00 05 ) aren’t there still collisions? Monday, March 4, 13
  30. So We Pad MD5( H e l l o )

    MD5( 48 65 6c 6c 6f 01 00 05 ) aren’t there still collisions? MD5( H e l l o \1 \0 \5 ) MD5( 48 65 6c 6c 6f 01 00 05 + 01 00 00 00 00 00 00 08 ) Monday, March 4, 13
  31. Length Extension Given an MD5 (or SHA-1, SHA-256) digest D

    of an unknown string S, it is trivial to find the digest of a string beginning with S plus its padding Monday, March 4, 13
  32. md5 = MD5_init(“”); Spad = MD5_pad(S); D = MD5_add(md5, S

    + Spad ); md5 = MD5_init(D); forgery = “&admin=true” forgepad = MD5_pad(forgery); Dforgery = MD5_add(md5, forgery + forgepad); Monday, March 4, 13
  33. Length-Extension Attack query = “?company_id=4” + “&username=bdole” + “&admin=false” +

    “\x01\x00...\x28&admin=true” } How did we guess the correct paddding? Monday, March 4, 13
  34. Length-Extension Fix Use the right tool: HMAC query = “?company_id=4”

    + “&username=bdole” + “&admin=false” } headers[‘signature’].constant_time_compare( OpenSSL::HMAC.digest ‘MD5’, key, “?company_id=4” + “&username=bdole” + “&admin=false” ) Monday, March 4, 13
  35. opad = 0x5c5c5c... ipad = 0x363636... Ko = K ^

    opad Ki = K ^ ipad HMAC(H,K,m) = H( Ko + H( Ki + m ) ) Monday, March 4, 13
  36. Anything Still Broken? query = “?company_id=4” + “&username=bdole” + “&admin=false”

    } headers[‘signature’].constant_time_compare( OpenSSL::HMAC.digest ‘MD5’, key, “?company_id=4” + “&username=bdole” + “&admin=false” ) Monday, March 4, 13
  37. Mode + - Year CBC widely available sequential, needs padding,

    corruption propagates 1998 CTR random access, parallelizable security lost if IV reused 2001 GCM authenticated security lost if IV reused, not widely available 2007 Monday, March 4, 13
  38. a ^ a = 0 a ^ b ^ a

    = b ^ (a ^ a) = b ^ 0 = b Monday, March 4, 13
  39. So, CBC Mode key = 79 19 2D 01 plaintext

    = AF 3C 26 0C C1 Given a random secret key and a plaintext you wish to keep secret Monday, March 4, 13
  40. Step 1: Generate a random IV iv = 39 87

    DB 3F Monday, March 4, 13
  41. Step 1: Generate a random IV iv = 39 87

    DB 3F Step 2: Break the plaintext into blocks plaintext = AF 3C 26 0C C1 Monday, March 4, 13
  42. Step 1: Generate a random IV iv = 39 87

    DB 3F Step 2: Break the plaintext into blocks plaintext = AF 3C 26 0C C1 Step 3: Pad the plaintext plaintext = AF 3C 26 0C C1 03 03 03 Monday, March 4, 13
  43. Step 4 39 87 DB 3F AF 3C 26 0C

    C1 03 03 03 79 19 2D 01 79 19 2D 01 96 BB FD 33 encrypt 6C BF 4C D0 encrypt AD BC 4F D3 2D A3 84 E3 Monday, March 4, 13
  44. Padding Oracle Anything you can pass a ciphertext into which

    returns information about whether decryption succeeded Monday, March 4, 13
  45. Breaking CBC Step 1: Pick a block to start attacking

    2D A3 84 E3 AD BC 4F D3 Monday, March 4, 13
  46. Breaking CBC Step 1: Pick a block to start attacking

    2D A3 84 E3 AD BC 4F D3 Step 2: Set the preceding block to all zeroes 2D A3 84 E3 00 00 00 00 Monday, March 4, 13
  47. Breaking CBC Step 1: Pick a block to start attacking

    2D A3 84 E3 AD BC 4F D3 Step 2: Set the preceding block to all zeroes 2D A3 84 E3 00 00 00 00 Step 3: Submit this “guess” to the Padding Oracle Monday, March 4, 13
  48. Breaking CBC Step 4: Increment the last byte of our

    forged block until the padding oracle tells us decryption succeeded Monday, March 4, 13
  49. Breaking CBC Step 4: Increment the last byte of our

    forged block until the padding oracle tells us decryption succeeded 00 00 00 00 2D A3 84 E3 Monday, March 4, 13
  50. Breaking CBC Step 4: Increment the last byte of our

    forged block until the padding oracle tells us decryption succeeded 00 00 00 00 2D A3 84 E3 00 00 00 01 2D A3 84 E3 Monday, March 4, 13
  51. Breaking CBC Step 4: Increment the last byte of our

    forged block until the padding oracle tells us decryption succeeded 00 00 00 00 2D A3 84 E3 00 00 00 01 2D A3 84 E3 00 00 00 02 2D A3 84 E3 Monday, March 4, 13
  52. Breaking CBC Step 4: Increment the last byte of our

    forged block until the padding oracle tells us decryption succeeded 00 00 00 00 2D A3 84 E3 00 00 00 01 2D A3 84 E3 00 00 00 02 2D A3 84 E3 00 00 00 .. 2D A3 84 E3 Monday, March 4, 13
  53. Breaking CBC Step 4: Increment the last byte of our

    forged block until the padding oracle tells us decryption succeeded 00 00 00 00 2D A3 84 E3 00 00 00 01 2D A3 84 E3 00 00 00 02 2D A3 84 E3 00 00 00 .. 2D A3 84 E3 00 00 00 D1 2D A3 84 E3 Monday, March 4, 13
  54. What We Know The padding oracle returning success tells us

    one thing and one thing only: The last bytes of the decryption had a valid padding. 01 02 02 03 03 03 04 04 04 04 ... Monday, March 4, 13
  55. Now What? 00 00 00 D1 2D A3 84 E3

    AD BC 4F D3 2D A3 84 E3 Monday, March 4, 13
  56. Pb = Cb-1 ^ C’ b-1 ^ p’ b Now

    What? 00 00 00 D1 2D A3 84 E3 AD BC 4F D3 2D A3 84 E3 Monday, March 4, 13
  57. Pb = Cb-1 ^ C’ b-1 ^ p’ b Now

    What? = D3 ^ D1 ^ p’ b 00 00 00 D1 2D A3 84 E3 AD BC 4F D3 2D A3 84 E3 Monday, March 4, 13
  58. Pb = Cb-1 ^ C’ b-1 ^ p’ b Now

    What? = D3 ^ D1 ^ p’ b = D3 ^ D1 ^ 01 00 00 00 D1 2D A3 84 E3 AD BC 4F D3 2D A3 84 E3 Monday, March 4, 13
  59. Pb = Cb-1 ^ C’ b-1 ^ p’ b Now

    What? = D3 ^ D1 ^ p’ b = D3 ^ D1 ^ 01 Pb = 03 00 00 00 D1 2D A3 84 E3 AD BC 4F D3 2D A3 84 E3 Monday, March 4, 13
  60. Breaking CBC Step 5: Refine guess based on next padding

    value 03 = D3 ^ D1 ^ 01 Monday, March 4, 13
  61. Breaking CBC Step 5: Refine guess based on next padding

    value 03 = D3 ^ D1 ^ 01 03 = D3 ^ C’ b-1 ^ 02 Monday, March 4, 13
  62. Breaking CBC Step 5: Refine guess based on next padding

    value 03 = D3 ^ D1 ^ 01 03 = D3 ^ C’ b-1 ^ 02 C’ b-1 = D3 ^ 03 ^ 02 Monday, March 4, 13
  63. Breaking CBC Step 5: Refine guess based on next padding

    value 03 = D3 ^ D1 ^ 01 03 = D3 ^ C’ b-1 ^ 02 C’ b-1 = D2 C’ b-1 = D3 ^ 03 ^ 02 Monday, March 4, 13
  64. Breaking CBC Step 6: Iterate 00 00 00 D2 2D

    A3 84 E3 Monday, March 4, 13
  65. Breaking CBC Step 6: Iterate 00 00 00 D2 2D

    A3 84 E3 00 00 01 D2 2D A3 84 E3 Monday, March 4, 13
  66. Breaking CBC Step 6: Iterate 00 00 00 D2 2D

    A3 84 E3 00 00 01 D2 2D A3 84 E3 00 00 02 D2 2D A3 84 E3 Monday, March 4, 13
  67. Breaking CBC Step 6: Iterate 00 00 00 D2 2D

    A3 84 E3 00 00 01 D2 2D A3 84 E3 00 00 02 D2 2D A3 84 E3 00 00 .. D2 2D A3 84 E3 Monday, March 4, 13
  68. Breaking CBC Step 6: Iterate 00 00 00 D2 2D

    A3 84 E3 00 00 01 D2 2D A3 84 E3 00 00 02 D2 2D A3 84 E3 00 00 .. D2 2D A3 84 E3 00 00 4E D2 2D A3 84 E3 Monday, March 4, 13
  69. Breaking CBC Step 6: Iterate 00 00 4E D2 2D

    A3 84 E3 AD BC 4F D3 2D A3 84 E3 Monday, March 4, 13
  70. Breaking CBC Step 6: Iterate Pb = Cb-1 ^ C’

    b-1 ^ p’ b 00 00 4E D2 2D A3 84 E3 AD BC 4F D3 2D A3 84 E3 Monday, March 4, 13
  71. Breaking CBC Step 6: Iterate Pb = Cb-1 ^ C’

    b-1 ^ p’ b = 4F ^ 4E ^ 02 00 00 4E D2 2D A3 84 E3 AD BC 4F D3 2D A3 84 E3 Monday, March 4, 13
  72. Breaking CBC Step 6: Iterate Pb = Cb-1 ^ C’

    b-1 ^ p’ b = 4F ^ 4E ^ 02 Pb = 03 00 00 4E D2 2D A3 84 E3 AD BC 4F D3 2D A3 84 E3 Monday, March 4, 13
  73. Breaking CBC Step 6: Iterate 00 00 4E D2 2D

    A3 84 E3 Monday, March 4, 13
  74. Breaking CBC Step 6: Iterate 00 00 4E D2 2D

    A3 84 E3 00 BC 4F D3 2D A3 84 E3 Monday, March 4, 13
  75. Breaking CBC Step 6: Iterate 00 00 4E D2 2D

    A3 84 E3 00 BC 4F D3 2D A3 84 E3 68 BB 48 D4 2D A3 84 E3 Monday, March 4, 13
  76. Breaking CBC Step 7: You have a whole decrypted block!

    68 BB 48 D4 2D A3 84 E3 2D A3 84 E3 AD BC 4F D3 Monday, March 4, 13
  77. Breaking CBC Step 7: You have a whole decrypted block!

    68 BB 48 D4 2D A3 84 E3 AD BC 4F D3 2D A3 84 E3 AD BC 4F D3 Monday, March 4, 13
  78. Breaking CBC Step 7: You have a whole decrypted block!

    68 BB 48 D4 2D A3 84 E3 ^ 68 BB 48 D4 AD BC 4F D3 2D A3 84 E3 AD BC 4F D3 Monday, March 4, 13
  79. Breaking CBC Step 7: You have a whole decrypted block!

    68 BB 48 D4 2D A3 84 E3 ^ 68 BB 48 D4 AD BC 4F D3 2D A3 84 E3 AD BC 4F D3 ^ 04 04 04 04 Monday, March 4, 13
  80. Breaking CBC Step 7: You have a whole decrypted block!

    68 BB 48 D4 2D A3 84 E3 ^ 68 BB 48 D4 AD BC 4F D3 2D A3 84 E3 AD BC 4F D3 ^ 04 04 04 04 ----------- C1 03 03 03 Monday, March 4, 13
  81. Rule of Thumb 1 “If you’re typing the letters A-E-S

    into your code, you’re doing it wrong.” — Thomas Ptacek Monday, March 4, 13
  82. Rule of Thumb 3 If you’re calling a crypto function

    and its parameter names don’t logically match yours, you’re probably using the wrong tool. Monday, March 4, 13