Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Speaker Deck
PRO
Sign in
Sign up for free
80,000 Plaintext Passwords: An Open Source Love Story in Three Acts
T.J. Schuck
June 26, 2014
Programming
5
830
80,000 Plaintext Passwords: An Open Source Love Story in Three Acts
T.J. Schuck
June 26, 2014
Tweet
Share
Other Decks in Programming
See All in Programming
[월간 데이터리안 세미나 6월] 스스로 성장하는 분석가 커리어 이야기
datarian
0
250
ゴーファーくんと辿るプログラミング言語の歴史/history-of-programming-languages-with-gopher
iwasiman
8
4k
Managing Error Messages with your Oracle Database REST APIs
thatjeffsmith
0
160
設計の学び方:自分流のススメ
masuda220
PRO
10
7.5k
Licences open source : entre guerre de clochers et radicalité
pylapp
2
510
#JJUG_CCC 「サポート」は製品開発? - JDBCライブラリ屋さんが実践する攻めのテクニカルサポートとJavaエンジニアのキャリアについて -
cdataj
0
430
Web API連携でCSRF対策がどう実装されてるか調べた / how to implements csrf-detection on Web API
yasuakiomokawa
2
510
Beyond Micro Frontends: Frontend Moduliths for the Enterprise @wad2022
manfredsteyer
PRO
0
140
iOS 16からのロック画面Widget争奪戦に備える
tsuzuki817
0
270
エンジニアによる事業指標計測のススメ
doyaaaaaken
1
190
What's new in Android development tools まとめ
mkeeda
0
410
A Philosophy of Software Design 後半
yosuke_furukawa
PRO
10
2.9k
Featured
See All Featured
Designing with Data
zakiwarfel
91
3.9k
Making Projects Easy
brettharned
98
4.3k
Navigating Team Friction
lara
175
11k
Why You Should Never Use an ORM
jnunemaker
PRO
47
7.6k
The Brand Is Dead. Long Live the Brand.
mthomps
46
2.7k
Building Adaptive Systems
keathley
25
1.1k
The Mythical Team-Month
searls
209
39k
XXLCSS - How to scale CSS and keep your sanity
sugarenia
236
1M
Java REST API Framework Comparison - PWX 2021
mraible
PRO
11
4.7k
4 Signs Your Business is Dying
shpigford
169
20k
Teambox: Starting and Learning
jrom
123
7.7k
A better future with KSS
kneath
225
15k
Transcript
80,000 Plaintext Passwords @tjschuck
Act I
mallory@local$ ′
None
T.J. Schuck @tjschuck
HARVEST getHarvest.com
I am not a Security Expert™
mallory@local$ ′
Layers Layers Layers Layers
mallory@local$ perl haxor.pl ′
mallory@local$ perl haxor.pl ! +------+-----------------------+------------+ | id | email |
password | +------+-----------------------+------------+ | 6125 | provos@openbsd.org | honeyd | | 6126 | schneier@schneier.com | blowfish | | 6127 | tj@tjschuck.com | peppercorn | | 6128 | rivest@mit.edu | md1947 | +------+-----------------------+------------+
“But…”
mallory@local$ perl haxor.pl ! +------+-----------------------+------------+ | id | email |
password | +------+-----------------------+------------+ | 6125 | provos@openbsd.org | honeyd | | 6126 | schneier@schneier.com | blowfish | | 6127 | tj@tjschuck.com | peppercorn | | 6128 | rivest@mit.edu | md1947 | +------+-----------------------+------------+
mallory@local$ perl haxor.pl ! +------+-----------------------+------------+ | id | email |
password | +------+-----------------------+------------+ | 6125 | provos@openbsd.org | ubarlq | | 6126 | schneier@schneier.com | oybjsvfu | | 6127 | tj@tjschuck.com | crccrepbea | | 6128 | rivest@mit.edu | zq1947 | +------+-----------------------+------------+
Encryption is reversible
Hashing is irreversible
None
hash(‘peppercorn’) => 6a58d0ad2619df7d7fabc2603b79063f
hash(‘peppercorn’) => 6a58d0ad2619df7d7fabc2603b79063f hash(‘secret1234’) => bdfc2db0aa599f5919e565c328216a51
hash(‘peppercorn’) => 6a58d0ad2619df7d7fabc2603b79063f hash(‘secret1234’) => bdfc2db0aa599f5919e565c328216a51 => 18ad6448e70b7b0254cad4d77653f2d7
hash(‘peppercorn’) => 6a58d0ad2619df7d7fabc2603b79063f hash(‘secret1234’) => bdfc2db0aa599f5919e565c328216a51 => 18ad6448e70b7b0254cad4d77653f2d7 ?
Hashing is deterministic
None
hash(‘peppercorn’) => 6a58d0ad2619df7d7fabc2603b79063f
hash(‘peppercorn’) => 6a58d0ad2619df7d7fabc2603b79063f hash(‘peppercorn’) => 6a58d0ad2619df7d7fabc2603b79063f
hash(‘peppercorn’) => 6a58d0ad2619df7d7fabc2603b79063f hash(‘peppercorn’) => 6a58d0ad2619df7d7fabc2603b79063f hash(‘peppercorn’) => 6a58d0ad2619df7d7fabc2603b79063f
Hashing is deterministic (but not obvious)
hash(‘peppercorn’) => 6a58d0ad2619df7d7fabc2603b79063f hash(‘peppercorn’) => 6a58d0ad2619df7d7fabc2603b79063f !
hash(‘peppercorn’) => 6a58d0ad2619df7d7fabc2603b79063f hash(‘peppercorn’) => 6a58d0ad2619df7d7fabc2603b79063f ! hash(‘Peppercorn’) => b8bfa4f1b72ee60755a71dbdf0700fe9
hash(‘peppercorn’) => 6a58d0ad2619df7d7fabc2603b79063f hash(‘peppercorn’) => 6a58d0ad2619df7d7fabc2603b79063f ! hash(‘Peppercorn’) => b8bfa4f1b72ee60755a71dbdf0700fe9
=> b8bfa4f1b72ee60755a71dbdf0700fe8
hash(‘peppercorn’) => 6a58d0ad2619df7d7fabc2603b79063f hash(‘peppercorn’) => 6a58d0ad2619df7d7fabc2603b79063f ! hash(‘Peppercorn’) => b8bfa4f1b72ee60755a71dbdf0700fe9
=> b8bfa4f1b72ee60755a71dbdf0700fe8 ?
mallory@local$ perl haxor.pl ! +------+-----------------------+----------------------------------+ | id | email |
password | +------+-----------------------+----------------------------------+ | 6125 | provos@openbsd.org | 6ee717a4bc91d99170ce0d0922ab6c43 | | 6126 | schneier@schneier.com | b258a419ddbc13d92b8e7fc25c2b9d6c | | 6127 | tj@tjschuck.com | 6a58d0ad2619df7d7fabc2603b79063f | | 6128 | rivest@mit.edu | 0304432f4c8080781f1b210c6b92b12f | +------+-----------------------+----------------------------------+
Hashing is deterministic
hash(‘peppercorn’) => 6a58d0ad2619df7d7fabc2603b79063f hash(‘peppercorn’) => 6a58d0ad2619df7d7fabc2603b79063f hash(‘peppercorn’) => 6a58d0ad2619df7d7fabc2603b79063f
None
Rainbow Tables
mallory@local$ perl haxor.pl ! +------+-----------------------+----------------------------------+ | id | email |
password | +------+-----------------------+----------------------------------+ | 6125 | provos@openbsd.org | 6ee717a4bc91d99170ce0d0922ab6c43 | | 6126 | schneier@schneier.com | b258a419ddbc13d92b8e7fc25c2b9d6c | | 6127 | tj@tjschuck.com | 6a58d0ad2619df7d7fabc2603b79063f | | 6128 | rivest@mit.edu | 0304432f4c8080781f1b210c6b92b12f | +------+-----------------------+----------------------------------+
None
6a58d0ad2619df7d7fabc2603b79063f
None
None
Defeating the Rainbow
hash(‘peppercorn’) => 6a58d0ad2619df7d7fabc2603b79063f
hash(‘peppercorn-tc5gplQopZ617zRQ8h9pAg’) => c5dde1b5cc0e6d89bda0f5e350bda319
None
WE DID IT!
(no we didn’t)
Proof of Concept
peppercorn
pepper8 pepper83 pepper88 pepper99 ! pepperdog pepperi1 peppermint peppermint1 pepperoni
pepperpepper peppers peppers4 peppi123 peppone pepsi pepsi1 pepsi123 pepsi2006 pepsi5 pepsi78bottle pepsicat pepsico pepsii pepsimax pepsione pepsis12 pequot per12fect peralta1 peppercorn
un1v3r53 1q2w#E$R fkg7h4f3v6
SALTING
SALTING
hash(‘peppercorn-tc5gplQopZ617zRQ8h9pAg’) => c5dde1b5cc0e6d89bda0f5e350bda319 hash(‘peppercorn-R1XrmmZVRedKMTE9nlIy9Q’) => fc5ad4a64796506086424af78f57df9d
mallory@local$ perl haxor.pl ! +------+----------------------------------+------------------------+ | id | password |
salt | +------+----------------------------------+------------------------+ | 6125 | 5b5f47a49cdd4386611ee0a63577eccd | CeVDwwrT7saa_cY2rV_qng | | 6126 | a50f4854739e10773c99d5576dbb2f73 | rRWjkN4ioELXIPpQ6aDY4w | | 6127 | 94c91484c8bb05113b28f9da2b7ea624 | XvALmgae9uUGmpikd8sohg | | 6128 | 5d2ee837249e9340624b12e653c5e4a3 | D-ZUYoaSadkCze1fPibbgg | +------+----------------------------------+------------------------+
This is pretty good…
This is pretty good… for 1976.
None
None
None
None
bcrypt ✓ One-way hash ✓ Pre-image resistant ✓ Deterministic ✓
Built-in per-password salts
Eksblowfish
Adaptive Cost
mallory@local$ perl haxor.pl ! +-----------------------+--------------------------------------------------------------+ | email | password |
+-----------------------+--------------------------------------------------------------+ | provos@openbsd.org | $2a$10$1ObnU/cPb3AjVU5iu8ntfe77xO83roRhoJMyBqYhlq5ZMMbHCcELK | | schneier@schneier.com | $2a$10$CelbCnmBjJez5ego4w.mbusfnZGOn/lRhLjrr37R0iUCr1UIC6ZyC | | tj@tjschuck.com | | | rivest@mit.edu | $2a$10$9WLufYmucbh.yaTHKKUuUeihbcA3hBUiI.XiW7ygmaYcYXtl4MBKy | +-----------------------+--------------------------------------------------------------+ $ 2a 10 LrfFlMh6Yc7JWKlpRwVjUuPCOPU5574fXAVrvLZRFT87cT55oLBEe $ $
$ 2a 10 LrfFlMh6Yc7JWKlpRwVjUuPCOPU5574fXAVrvLZRFT87cT55oLBEe $ $
$ 2a 10 LrfFlMh6Yc7JWKlpRwVjUu PCOPU5574fXAVrvLZRFT87cT55oLBEe $ $
$ 2a 10 LrfFlMh6Yc7JWKlpRwVjUu PCOPU5574fXAVrvLZRFT87cT55oLBEe $ $
$ 2a 10 LrfFlMh6Yc7JWKlpRwVjUu PCOPU5574fXAVrvLZRFT87cT55oLBEe $ $
$ 2a 10 LrfFlMh6Yc7JWKlpRwVjUu PCOPU5574fXAVrvLZRFT87cT55oLBEe $ $
$ 2a 10 LrfFlMh6Yc7JWKlpRwVjUu PCOPU5574fXAVrvLZRFT87cT55oLBEe $ $
$ 2a 10 LrfFlMh6Yc7JWKlpRwVjUu PCOPU5574fXAVrvLZRFT87cT55oLBEe $ $ “Cost”
None
bcrypt(‘peppercorn’, 10) =>
bcrypt(‘peppercorn’, 10) => $2a$10$41JmpddjOSEGWU099uQx7O7Y1EiQMTRQFZCcFqFMlYWekR5pj9xFi
bcrypt(‘peppercorn’, 10) => $2a$10$41JmpddjOSEGWU099uQx7O7Y1EiQMTRQFZCcFqFMlYWekR5pj9xFi bcrypt(‘peppercorn’, 10) =>
bcrypt(‘peppercorn’, 10) => $2a$10$41JmpddjOSEGWU099uQx7O7Y1EiQMTRQFZCcFqFMlYWekR5pj9xFi bcrypt(‘peppercorn’, 10) => $2a$10$8ONmT2oiKPoPn/KQTrvHq.gWTnqQ5p.T13lw.lCm9d.QoqIZzbHPS
bcrypt(‘peppercorn’, 10) => $2a$10$41JmpddjOSEGWU099uQx7O7Y1EiQMTRQFZCcFqFMlYWekR5pj9xFi bcrypt(‘peppercorn’, 10) => $2a$10$8ONmT2oiKPoPn/KQTrvHq.gWTnqQ5p.T13lw.lCm9d.QoqIZzbHPS bcrypt(‘peppercorn’, 14)
=>
bcrypt(‘peppercorn’, 10) => $2a$10$41JmpddjOSEGWU099uQx7O7Y1EiQMTRQFZCcFqFMlYWekR5pj9xFi bcrypt(‘peppercorn’, 10) => $2a$10$8ONmT2oiKPoPn/KQTrvHq.gWTnqQ5p.T13lw.lCm9d.QoqIZzbHPS bcrypt(‘peppercorn’, 14)
=> $2a$14$4US.NV/qyRkctl.LaYvNzOln70yIaqGfJeMq1deb/bPJMMmtcxOU.
bcrypt(‘peppercorn’, 10) => $2a$10$41JmpddjOSEGWU099uQx7O7Y1EiQMTRQFZCcFqFMlYWekR5pj9xFi bcrypt(‘peppercorn’, 10) => $2a$10$8ONmT2oiKPoPn/KQTrvHq.gWTnqQ5p.T13lw.lCm9d.QoqIZzbHPS bcrypt(‘peppercorn’, 14)
=> $2a$14$4US.NV/qyRkctl.LaYvNzOln70yIaqGfJeMq1deb/bPJMMmtcxOU.
bcrypt(‘peppercorn’, 10) => $2a$10$41JmpddjOSEGWU099uQx7O7Y1EiQMTRQFZCcFqFMlYWekR5pj9xFi bcrypt(‘peppercorn’, 10) => $2a$10$8ONmT2oiKPoPn/KQTrvHq.gWTnqQ5p.T13lw.lCm9d.QoqIZzbHPS bcrypt(‘peppercorn’, 14)
=> $2a$14$4US.NV/qyRkctl.LaYvNzOln70yIaqGfJeMq1deb/bPJMMmtcxOU. 0.0656 seconds
bcrypt(‘peppercorn’, 10) => $2a$10$41JmpddjOSEGWU099uQx7O7Y1EiQMTRQFZCcFqFMlYWekR5pj9xFi bcrypt(‘peppercorn’, 10) => $2a$10$8ONmT2oiKPoPn/KQTrvHq.gWTnqQ5p.T13lw.lCm9d.QoqIZzbHPS bcrypt(‘peppercorn’, 14)
=> $2a$14$4US.NV/qyRkctl.LaYvNzOln70yIaqGfJeMq1deb/bPJMMmtcxOU. 0.0656 seconds 0.0657 seconds
bcrypt(‘peppercorn’, 10) => $2a$10$41JmpddjOSEGWU099uQx7O7Y1EiQMTRQFZCcFqFMlYWekR5pj9xFi bcrypt(‘peppercorn’, 10) => $2a$10$8ONmT2oiKPoPn/KQTrvHq.gWTnqQ5p.T13lw.lCm9d.QoqIZzbHPS bcrypt(‘peppercorn’, 14)
=> $2a$14$4US.NV/qyRkctl.LaYvNzOln70yIaqGfJeMq1deb/bPJMMmtcxOU. 0.0656 seconds 0.0657 seconds 1.0481 seconds
Cost Seconds 9 0.0344 10 0.0656 11 0.1333 12 0.2646
13 0.5236 14 1.0481 15 2.1645 16 4.2801
“Well, actually…”
The Fix
def authenticate(plaintext_password)! if old_hashing_method(plaintext_password) == password_digest! self! end! end
def authenticate(plaintext_password)! if BCrypt::Password.new(password_digest) == plaintext_password! self! end! end
def authenticate(plaintext_password)! return unless convert_old_hash_to_bcrypt(plaintext_password)! ! if BCrypt::Password.new(password_digest) == plaintext_password!
self! end! end
def convert_old_hash_to_bcrypt(plaintext_password)! return true if BCrypt::Password.valid_hash?(password_digest)! ! if old_hashing_method(plaintext_password) ==
password_digest! update_column :password_digest,! BCrypt::Password.create(plaintext_password)! end! end
None
None
None
—Act II—
Fat Binary Gems —Act II— You make the rockin’ world
go ’round
bcrypt-ruby github.com/codahale/bcrypt-ruby
None
None
None
None
None
None
None
None
None
None
None
None
None
None
Well shit.
None
None
rake-compiler-dev-box with Rubies, GCC, JDK, MinGW…
None
LOLOLOLOL NO.
None
rake-compiler#79
Act III
Act III Luis Lavena
None
• One-Click Ruby Installer for Windows
• One-Click Ruby Installer for Windows • Ruby core
• One-Click Ruby Installer for Windows • Ruby core •
Ruby Hero (2010)
• One-Click Ruby Installer for Windows • Ruby core •
Ruby Hero (2010) • rake-compiler
rake-compiler-dev-box#2
None
None
None
None
None
@luislavena <3 <3 <3
Find your Luis
“Be the Luis you wish to see in the world”
What have we learned?
1. Just use bcrypt
2. Distribute a dev box
3. Release, collaborate, iterate
Thank You @tjschuck getHarvest.com