Jarosław Jedynak
- Software/Security Engineer @ CERT.pl
- CTF @ p4 team
- Kryptografia/Algorytmika
- Koty, ale tylko w .png (od biedy .jpg)
- Dekryptory ransomware @ https://nomoreransom.cert.pl/
- https://tailcall.net
- @MsmCode
- msm@tailcall.net
Jarosław Jedynak
Jarosław Jedynak
Temat: Czego nie robić z kryptografią
Temat: Czego nie robić z kryptografią Temat 2: Czego nie robić ze StackOverflow
Temat: Czego nie robić z kryptografią Temat 2: Czego nie robić ze StackOverflow Bonus: Wyśmiewanie się z niewinnych ludzi
Temat: Czego nie robić z kryptografią
Temat 2: Czego nie robić ze StackOverflow
Bonus: Wyśmiewanie się z niewinnych ludzi
Bonus: Poprawianie ludzi w dobrej wierze
def stream_cipher(data, key): pseudo_random_bytes = generate_bytes(key) result = '' for i in range(len(data)) result += data[i] ^ pseudo_random_bytes[i] return result
Cechy charakterystyczne:
Przykłady to np. RC4, Salsa20, ChaCha, Spritz
def block_cipher(data, key): blocks = chunks(data, BLOCK_SIZE) result = '' for block in blocks: result += raw_cipher(block, key) return result
Cechy charakterystyczne:
Przykłady to np. 3DES, AES, Blowfish
Mamy 16bajtowe bloki i 39bajtową wiadomość. Co robić?
Mamy 16bajtowe bloki i 48bajtową wiadomość. Co robić?
ct[0] = aes(pt[0]) ct[1] = aes(pt[1]) ct[2] = aes(pt[2])
Aplikacja webowa, trzymająca informacje o użytkowniku w ciasteczkach. Format:
{ "name": "msm", "has_admin": false }
Kod:
cipher = AES.new(SECRET_KEY) raw = pkcs7_pad(raw_cookie) return cipher.encrypt(raw).encode('hex')
Przykładowa zaszyfrowana wiadomość.
Użytkownik: msm
Czy jest tu potencjalnie jakiś problem?
Użytkownik: hacker
Użytkownik: hackertrue___________________x
{ "name": "hacker", "has_admin": true }
https://stackoverflow.com/questions/606179/what-encryption-algorithm-is-best-for-encrypting-cookies
function encrypt($text, $salt) { return trim(base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $salt, $text, MCRYPT_MODE_ECB, mcrypt_create_iv( mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB), MCRYPT_RAND)))); } function decrypt($text, $salt) { return trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $salt, base64_decode($text), MCRYPT_MODE_ECB, mcrypt_create_iv( mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB), MCRYPT_RAND))); }
1. sam pomysł szyfrowania cookies jest głupi
function encrypt($text, $salt) { return trim(base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $salt, $text, MCRYPT_MODE_ECB, mcrypt_create_iv( mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB), MCRYPT_RAND)))); } function decrypt($text, $salt) { return trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $salt, base64_decode($text), MCRYPT_MODE_ECB, mcrypt_create_iv( mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB), MCRYPT_RAND))); }
2. MCRYPT_MODE_ECB + mcrypt_create_iv = ?
function encrypt($text, $salt) { return trim(base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $salt, $text, MCRYPT_MODE_ECB, mcrypt_create_iv( mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB), MCRYPT_RAND)))); } function decrypt($text, $salt) { return trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $salt, base64_decode($text), MCRYPT_MODE_ECB, mcrypt_create_iv( mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB), MCRYPT_RAND))); }
(a warningi są dla słabych)
3. This is not the encryption algorithm you're looking for
function encrypt($text, $salt) { return trim(base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $salt, $text, MCRYPT_MODE_ECB, mcrypt_create_iv( mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB), MCRYPT_RAND)))); } function decrypt($text, $salt) { return trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $salt, base64_decode($text), MCRYPT_MODE_ECB, mcrypt_create_iv( mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB), MCRYPT_RAND))); }
(MCRYPT_RIJNDAEL_256 to mało zbadana, niszowa odmiana AES z 32bajtowymi blokami)
4. $salt? trim?
function encrypt($text, $salt) { return trim(base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $salt, $text, MCRYPT_MODE_ECB, mcrypt_create_iv( mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB), MCRYPT_RAND)))); } function decrypt($text, $salt) { return trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $salt, base64_decode($text), MCRYPT_MODE_ECB, mcrypt_create_iv( mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB), MCRYPT_RAND))); }
/albracu/software_venta_php/blob/master/core/Auth.php
private static function encryptCookie(string $value) : string { $key = self::aud(); $iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB); $iv = mcrypt_create_iv($iv_size, MCRYPT_RAND); return mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $value, MCRYPT_MODE_ECB, $iv); } public static function signIn(array $data) { $time = time() + ( 3600 * ServicesContainer::getConfig()['session-time'] ); setcookie( ServicesContainer::getConfig()['session-name'], Auth::encryptCookie( serialize($data) ), $time, '/' ); }
/chrislynch/engine4/blob/master/_e/plugins/cart/cart.php
public static function addToCartFormValue($Code,$Price,$QTY = 1,$Title = '',$Image = '',$Other = array()){ $data = array(); $data['Code'] = $Code; $data['Price'] = $Price; $data['QTY'] = $QTY; if ($Title == ''){ $data['Title'] = $Code; } else { $data['Title'] = $Title; } $data['Image'] = $Image; foreach($Other as $otherKey=>$otherValue){ $data[$otherKey] = $otherValue; } include_once('_e/plugins/cryptography/cryptography.php'); return _cryptography::encrypt(serialize($data)); }
Tytuł test
a:4:{s:5:"Title";s:4:"test";s:4:"Code";s:7:"code123";s:5:"Price";i:100;s:3:"QTY";i:1;}
Bloki:
a:4:{s:5:"Title" ;s:4:"test";s:4: "Code";s:7:"code 123";s:5:"Price" ;i:100;s:3:"QTY" ;i:1;}
Tytuł Title____;Price";i:001;s:3
a:4:{s:5:"Title";s:26:"Title____;Price";i:001;s:3";s:4:"Code";s:7:"code123";s:5:"Price";i:100;s:3:"QTY";i:1;}
Bloki:
a:4:{s:5:"Title" ;s:26:"Title____ ;Price";i:001;s: 3";s:4:"Code";s: 7:"code123";s:5: "Price";i:100;s: 3:"QTY";i:1;}
Tytuł Title____;Price";i:001;s:3
array(4) {
["Title"]=>
string(26) "Title____;Price";i:001;s:3"
["Code"]=>
string(7) "code123"
["Price"]=>
int(100)
["QTY"]=>
int(1)
}
a:4:{s:5:"Title"
;s:26:"Title____
;Price";i:001;s:
3";s:4:"Code";s:
7:"code123";s:5:
"Price";i:100;s:
3:"QTY";i:1;}
Tytuł Title____;Price";i:001;s:3
array(4) {
["Title"]=>
string(26) "Title____;Price";i:001;s:3"
["Code"]=>
string(7) "code123"
["Price"]=>
int(1)
["QTY"]=>
int(1)
}
a:4:{s:5:"Title"
;s:26:"Title____
;Price";i:001;s:
3";s:4:"Code";s:
7:"code123";s:5:
"Price";i:001;s:
3:"QTY";i:1;}
Mój ulubiony przykład
./abante/core/lib/customer.php
./abante/core/lib/encryption.php
AbanteCart, popularny silnik eCommerce
http://www.AbanteCart.com
Copyright © 2011-2016 Belavier Commerce LLC
function encrypt($str){ if (!$this->key) { return $str; } $enc_str = ''; if (!$this->_check_mcrypt()) { // non-mcrypt basic encryption for ($i = 0; $i < strlen($str); $i++){ $char = substr($str, $i, 1); $keychar = substr($this->key, ($i % strlen($this->key)) - 1, 1); $enc_str .= chr(ord($char) + ord($keychar)); } $enc_str = base64_encode($enc_str); } else{ $hash = hash('sha256', $this->key, true); $enc_str = base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $hash, $str, MCRYPT_MODE_ECB)); } return str_replace('==', '', strtr($enc_str, '+/', '-_')); }
function encrypt($str){ if (!$this->key) { return $str; } $enc_str = ''; if (!$this->_check_mcrypt()) { // non-mcrypt basic encryption for ($i = 0; $i < strlen($str); $i++){ $char = substr($str, $i, 1); $keychar = substr($this->key, ($i % strlen($this->key)) - 1, 1); $enc_str .= chr(ord($char) + ord($keychar)); } $enc_str = base64_encode($enc_str); } else{ $hash = hash('sha256', $this->key, true); $enc_str = base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $hash, $str, MCRYPT_MODE_ECB)); } return str_replace('==', '', strtr($enc_str, '+/', '-_')); }
function encrypt($str){ if (!$this->key) { return $str; } $enc_str = ''; if (!$this->_check_mcrypt()) { // non-mcrypt basic encryption for ($i = 0; $i < strlen($str); $i++){ $char = substr($str, $i, 1); $keychar = substr($this->key, ($i % strlen($this->key)) - 1, 1); $enc_str .= chr(ord($char) + ord($keychar)); } $enc_str = base64_encode($enc_str); } else{ $hash = hash('sha256', $this->key, true); $enc_str = base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $hash, $str, MCRYPT_MODE_ECB)); } return str_replace('==', '', strtr($enc_str, '+/', '-_')); }
function encrypt($str){ if (!$this->key) { return $str; } $enc_str = ''; if (!$this->_check_mcrypt()) { // non-mcrypt basic encryption for ($i = 0; $i < strlen($str); $i++){ $char = substr($str, $i, 1); $keychar = substr($this->key, ($i % strlen($this->key)) - 1, 1); $enc_str .= chr(ord($char) + ord($keychar)); } $enc_str = base64_encode($enc_str); } else{ $hash = hash('sha256', $this->key, true); $enc_str = base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $hash, $str, MCRYPT_MODE_ECB)); } return str_replace('==', '', strtr($enc_str, '+/', '-_')); }
function encrypt($str){ if (!$this->key) { return $str; } $enc_str = ''; if (!$this->_check_mcrypt()) { // non-mcrypt basic encryption for ($i = 0; $i < strlen($str); $i++){ $char = substr($str, $i, 1); $keychar = substr($this->key, ($i % strlen($this->key)) - 1, 1); $enc_str .= chr(ord($char) + ord($keychar)); } $enc_str = base64_encode($enc_str); } else{ $hash = hash('sha256', $this->key, true); $enc_str = base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $hash, $str, MCRYPT_MODE_ECB)); } return str_replace('==', '', strtr($enc_str, '+/', '-_')); }
function encrypt($str){ if (!$this->key) { return $str; } $enc_str = ''; if (!$this->_check_mcrypt()) { // non-mcrypt basic encryption for ($i = 0; $i < strlen($str); $i++){ $char = substr($str, $i, 1); $keychar = substr($this->key, ($i % strlen($this->key)) - 1, 1); $enc_str .= chr(ord($char) + ord($keychar)); } $enc_str = base64_encode($enc_str); } else{ $hash = hash('sha256', $this->key, true); $enc_str = base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $hash, $str, MCRYPT_MODE_ECB)); } return str_replace('==', '', strtr($enc_str, '+/', '-_')); }
function encrypt($str){ if (!$this->key) { return $str; } $enc_str = ''; if (!$this->_check_mcrypt()) { // non-mcrypt basic encryption for ($i = 0; $i < strlen($str); $i++){ $char = substr($str, $i, 1); $keychar = substr($this->key, ($i % strlen($this->key)) - 1, 1); $enc_str .= chr(ord($char) + ord($keychar)); } $enc_str = base64_encode($enc_str); } else{ $hash = hash('sha256', $this->key, true); $enc_str = base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $hash, $str, MCRYPT_MODE_ECB)); } return str_replace('==', '', strtr($enc_str, '+/', '-_')); }
2x bezpieczniejsza wersja poprzedniej funkcji:
function encrypt($str) { return base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $this->key, $str, MCRYPT_MODE_ECB)); }
(Już nawet nie wspominając o trybie ECB)
A jak to wszystko jest użyte?
$cutomer_data = $encryption->encrypt(serialize(array( 'first_name' => $this->firstname, 'customer_id' => $this->customer_id, 'script_name' => $this->request->server['SCRIPT_NAME'] ))); setcookie('customer', $cutomer_data, time() + 60 * 60 * 24 * 365, '/', $this->request->server['HTTP_HOST']);
Patrz kilka slajdów wcześniej, co się da zrobić z serialize i szyfrowaniem ECB.
To wszystko w dość popularnym rozwiązaniu eCommerce:
Wnioski na razie:
Wnioski na razie:
Ale w sumie to nie o tym miało być.
Projekt: "Confidentiality as a Service"
d = AES.new(key, AES.MODE_CTR, counter=lambda: counter) rts = d.decrypt(enc_p)
https://github.com/chinmaydd/CaaS/blob/ec6bb4de8e3929ba9abd670ec4b39a74bd53846e/client.py#L45
Opis: Confidentiality as a service is an innovative paradigm for preserving privacy between a user and a cloud service provider(CSP).
Projekt: off the wire crypto
def aesctr_decrypt(key1, key2, data): decryptor = AES.new(key1, AES.MODE_CTR, counter=lambda: key2) decrypted = decryptor.decrypt(data) return decrypted
Opis: off the wire crypto, (...) There is alot of different encryption libs u need to import in python to encrypt something this aims to be the only library u need to import, easy to use, secure and free :)
Projekt: LayerProx
def aesctr_decrypt(key1, key2, data): decryptor = AES.new(key1, AES.MODE_CTR, counter=lambda: key2) decrypted = decryptor.decrypt(data) return decrypted
https://github.com/flipchan/LayerProx/blob/d9097a83a207769421e6b7f316ac9654cb9cf6e2/bin/otw.py#L77
Projekt: SecuriText, GUI Text Editor with Crypto operations
def encrypt(key, message, cipher): if cipher == 1: #AES iv = Random.new().read(AES.block_size) cipher = AES.new(key, AES.MODE_CTR, iv, counter=lambda: iv) msg = iv + cipher.encrypt(message) return msg.encode("base64")
https://github.com/micael-grilo/securitext/blob/dc7bbe6725063c8b1f8536ce9f80f19964207ef6/cen.py#L30
Projekt: DataMining/SecurityAssign1
if (mode == AES.MODE_CTR): ctr = os.urandom(16) cipher = AES.new(key, mode, counter=lambda: ctr)
Mamy 16bajtowe bloki i 48bajtową wiadomość. Co robić?
ct[0] = aes(pt[0] ^ iv) ct[1] = aes(pt[1] ^ ct[0]) ct[2] = aes(pt[2] ^ ct[1]) ...
function encrypt($str) { if (!$this->key) { return $str; } $enc_str = ''; if (!$this->_check_openssl()) { //non openssl basic encryption for ($i = 0; $i < strlen($str); $i++){ $char = substr($str, $i, 1); $keychar = substr($this->key, ($i % strlen($this->key)) - 1, 1); $enc_str .= chr(ord($char) + ord($keychar)); } $enc_str = base64_encode($enc_str); } else { $iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length('aes-256-cbc')); $enc_str = base64_encode(openssl_encrypt($str, 'aes-256-cbc', $this->key, 0, $iv) . '::' . $iv); } return str_replace('==', '', strtr($enc_str, '+/', '-_')); }
function encrypt($str) { if (!$this->key) { return $str; } $enc_str = ''; if (!$this->_check_openssl()) { //non openssl basic encryption for ($i = 0; $i < strlen($str); $i++){ $char = substr($str, $i, 1); $keychar = substr($this->key, ($i % strlen($this->key)) - 1, 1); $enc_str .= chr(ord($char) + ord($keychar)); } $enc_str = base64_encode($enc_str); } else { $iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length('aes-256-cbc')); $enc_str = base64_encode(openssl_encrypt($str, 'aes-256-cbc', $this->key, 0, $iv) . '::' . $iv); } return str_replace('==', '', strtr($enc_str, '+/', '-_')); }
function encrypt($str) { $iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length('aes-256-cbc')); return base64_encode(openssl_encrypt($str, 'aes-256-cbc', $this->key, 0, $iv) . '::' . $iv); }
IV:
61 73 39 64 38 37 39 38 39 33 68 38 77 65 73 66
Wiadomość zaszyfrowana AES-CBC:
81 32 30 85 2d ed 78 2d f0 5d 5b a1 c9 e9 b3 72
Oryginalna wiadomość:
m s m & a d m i n = 0 05 05 05 05 05
Nie znamy klucza
IV:
60 73 39 64 38 37 39 38 39 33 68 38 77 65 73 66
Wiadomość zaszyfrowana AES-CBC:
81 32 30 85 2d ed 78 2d f0 5d 5b a1 c9 e9 b3 72
Zdeszyfrowana wiadomość:
l s m & a d m i n = 0 05 05 05 05 05
Dalej nie znamy klucza
IV:
61 73 39 64 38 37 39 38 39 33 69 38 77 65 73 66
Wiadomość zaszyfrowana AES-CBC:
81 32 30 85 2d ed 78 2d f0 5d 5b a1 c9 e9 b3 72
Zdeszyfrowana wiadomość:
m s m & a d m i n = 1 05 05 05 05 05
I ciągle nie znamy klucza
Kod logowania z AbanteCart:
$customer_data = $encryption->encrypt(serialize(array ( 'first_name' => $this->firstname, 'customer_id' => $this->customer_id, 'script_name' => $this->request->server['SCRIPT_NAME'] ))); setcookie('customer', $customer_data /* ... */);
Przykładowy wynik:
a:3:{s:10:"first_name";s:6:"msm123";s:11:"customer_id";i:123;s:11:"script_name";N;}
Dla danych:
array(3) { ["first_name"]=> string(6) "msm123" ["customer_id"]=> int(123) ["script_name"]=> NULL }
Zaszyfrowane - AES-CBC.
Możemy trywialnie wpłynąc na pierwsze 16 bajtów danych!
a:3:{s:10:"first_name";s:6:"msm123";s:11:"customer_id";i:123;s:11:"script_name";N;}
a:3:{s:10:"first_name";s:6:"msm123";s:11:"customer_id";i:123;s:11:"script_name";N;}
Ale hm, możemy dowolnie nazwać użytkownika
a:3:{s:10:"first_name";s:6:"asdoj@:12939- /xys";s:11:"customer_id";i:123;s:11:"script_name";N;}
A co jakby nazwać swojego użytkownika tak?
;N;s:11:"customer_id";i:1;s:18:
Co nam to da?
Zaszyfrowane dane:
a:3:{s:10:"first_name";s:31:";N;s:11:"customer_id";i:1 ;s:18:";s:11:"customer_id";i:123;s:11:"script_name";N;}
Zmieniając tylko dwa bajty...
a:3:{s:10:"first_name";s:31:";N;s:11:"customer_id";i:1 ;s:18:";s:11:"customer_id";i:123;s:11:"script_name";N;}
a:4:{s:17:"first_name";s:31:";N;s:11:"customer_id";i:1 ;s:18:";s:11:"customer_id";i:123;s:11:"script_name";N;}
Zmieniając tylko jeden bajt...
array(3) {
["first_name"]=>
";N;s:11:"customer_id";i:1;s:18:"
["customer_id"]=>
int(123)
["script_name"]=>
NULL
}
array(4) {
["first_name";s:31:"]=>
NULL
["customer_id"]=>
int(1)
[";s:11:_customer_id"]=>
int(123)
["script_name"]=>
NULL
}
class ControllerPagesIndexForgotPassword extends AController { // ... public function main() { // ... if ($this->request->is_POST() && $this->_validate()) { //generate hash $hash = genToken(32); $enc = new AEncryption($this->config->get('encryption_key')); $rtoken = $enc->encrypt($this->request->post['username'].'::'.$hash); $link = $this->html->getSecureURL( 'index/forgot_password/validate', '&rtoken='.$rtoken); // ...
class ControllerResponsesExtensionDefaultPaymate extends AController { // ... public function callback(){ // .. if (isset($this->request->post['responseCode'])){ if ($this->request->post['responseCode'] == 'PA' || $this->request->post['responseCode'] == 'PP'){ if (isset($this->request->get['oid']) && isset($this->request->get['conf'])) { $this->load->library('encryption'); $encryption = new AEncryption($this->config->get('encryption_key')); $order_id = $encryption->decrypt($this->request->get['oid']); if(!$order_id){ exit; } $this->load->model('checkout/order'); // ...
Chyba że akurat służy
Chyba że akurat służy To wtedy ok
Chyba że akurat służy To wtedy ok
Przykłady: MD5, SHA-1, SHA-2, SHA3
Funkcja skrótu to:
Przykłady: MD5, SHA-1, SHA-2, SHA3
Funkcja skrótu to:
Przykłady: MD5, SHA-1, SHA-2, SHA-3
Funkcja skrótu to:
Przykłady: MD5, SHA-1, SHA-2 (SHA-224, SHA-256, SHA-384, SHA-512, SHA-512/224, SHA-512/256), SHA-3
Funkcja skrótu to:
Przykłady: MD5, SHA-1, SHA-2 (SHA-224, SHA-256, SHA-384, SHA-512, SHA-512/224, SHA-512/256), SHA-3 (SHA3-224, SHA3-256, SHA3-384, SHA3-512)
Funkcja skrótu to:
Przykłady: MD5, SHA-1, SHA-2 (SHA-224, SHA-256, SHA-384, SHA-512, SHA-512/224, SHA-512/256), SHA-3 = Keccak (SHA3-224, SHA3-256, SHA3-384, SHA3-512 (SHAKE128, SHAKE256, KangooroTwelve))
Funkcja skrótu to:
Własności:
Własności:
To nie jest podpisywanie wiadomości:
import hashlib SECRET = '53e49e1d8cce03c52f24bd472169c1f7'.decode('hex') def sign(message): return hashlib.sha256(SECRET + message).hexdigest()
To jest podpisywanie wiadomości:
import hashlib SECRET = '53e49e1d8cce03c52f24bd472169c1f7'.decode('hex') def sign(message): return hashlib.hmac(message, SECRET, hashlib.sha256).hexdigest()
Rabat na jabłka!
name=rabat_na_jablka&amount=10
Generowanie podpisu:
>>> hashlib.md5('pH2ef4OhUdec3eSPdrujAy4gdec3eSPdrudec3eSPdru' + ':name=rabat_na_jablka&amount=10').hexdigest() '8b990fdf27e79353a7fadf639e5fa7c4'
Pobieramy https://github.com/bwall/HashPump
sudo apt install hashpump
Atakujemy:
$ hashpump -d ':name=rabat_na_jablka&amount=10' -s '8b990fdf27e79353a7fadf639e5fa7c4' -k 44 -a '&amount=100' ef7ca4ca05a171525a668d23ac6c639a :name=rabat_na_jablka&amount=10\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00X\x02\x00\x00\x00\x00\x00\x00&amount=100
Nowa wiadomość:
:name=rabat_na_jablka&amount=10\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00X\x02\x00\x00\x00\x00\x00\x00&amount=100
Nowy hash:
ef7ca4ca05a171525a668d23ac6c639a
Czas wykonania ataku: ~~minuta
5 minut łącznie z pobieraniem
>>> hashlib.md5('pH2ef4OhUdec3eSPdrujAy4gdec3eSPdrudec3eSPdru:name=rabat_na_jablka& amount=10\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 \x00\x00\x00\x00\x00X\x02\x00\x00\x00\x00\x00\x00&amount=100').hexdigest() 'ef7ca4ca05a171525a668d23ac6c639a'
Schemat "podpisywania danych":
vpc_Amount=10000
vpc_Card=1234567890123456
vpc_Name=Joe
Dane są sklejane:
100001234567890123456Joe
I "podpisywane":
md5(secret + data)
Schemat "podpisywania danych":
vpc_Amount=1
vpc_B=0000
vpc_Card=1234567890123456
vpc_Name=Joe
Dane są sklejane:
100001234567890123456Joe
I "podpisywane":
md5(secret + data)
vpc_Amount=10000
vpc_Card=1234567890123456
vpc_Name=Joe
Dane są sklejane:
100001234567890123456Joe
I "podpisywane":
md5(secret + data)
vpc_Amount=1
vpc_B=0000
vpc_Card=1234567890123456
vpc_Name=Joe
Dane są sklejane:
100001234567890123456Joe
I "podpisywane":
md5(secret + data)
Zagadka!
Jeśli użycie gotowych prymitywów kryptograficznych jest trudne...
To stworzenie własnych prymitywów kryptograficznych od zera i użycie ich jest ...?
Zagadka!
Jeśli użycie gotowych prymitywów kryptograficznych jest trudne...
To stworzenie własnych prymitywów kryptograficznych od zera i użycie ich jest bardzo trudne
Valerie Aurora, CC BY-SA, http://valerieaurora.org/hash.html.
Wszystkie stworzone przez ekspertów w dziedzinie kryptografii.
https://journals.umcs.pl/ai/article/viewFile/3353/2547
http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.197.pdf
StreamHash: a new family of cryptographic hash functions / Warsaw University of Technology. Faculty of Electronics and Information Technology
Evolution of the StreamHash hash function family: Annales UMCS Sectio AI Informatica,
StreamHash4; presentation on (ISC)2 Polish Chapter Conference
Stan: s0
, s1
, s2
, s3
(startowo c0
, c1
, c2
, c3
)
Funkcja rundy:
def update(state, data): s0, s1, s2, s3 = state s0 = aes_round(s0 ^ data, c0) s1 = aes_round(s1 ^ data, c1) s2 = aes_round(s2 ^ data, c2) s3 = aes_round(s3 ^ data, c3) # (simplified version) return s0, s1, s2, s3
Na koniec:
result = finalize(state)
Czyli szyfrowanie wiadomości z czterema blokami:
def streamhash4(msg): # msg = a0 + a1 + a2 + a3 msg = '.................' a0, a1, a2, a3 = chunks(msg, 16) result = (c0, c1, c2, c3) result = update(result, a1) result = update(result, a2) result = update(result, a3) result = update(result, a4) return finalize(result)
streamhash4(A) = streamhash4(B)
Ofc zakładamy że A != B, bo inaczej problem byłby trywialny
streamhash4(A) = streamhash4(B)
Rozwijając:
a0, a1, a2, a3 = A
b0, b1, b3, b4 = B
C = c0, c1, c2, c3
update(update(update(update(C, a0), a1), a2), a3)
= update(update(update(update(C, b0), b1), b2), b3)
aes(aes(aes(aes(a0 ^ c0, c0) ^ c0, c0) ^ a2, c0) ^ a3, c0)
= aes(aes(aes(aes(b0 ^ c0, c0) ^ c0, c0) ^ b2, c0) ^ b3, c0)
aes(aes(aes(aes(a0 ^ c1, c1) ^ c1, c1) ^ a2, c1) ^ a3, c1)
= aes(aes(aes(aes(b0 ^ c1, c1) ^ c1, c1) ^ b2, c1) ^ b3, c1)
aes(aes(aes(aes(a0 ^ c2, c2) ^ c2, c2) ^ a2, c2) ^ a3, c2)
= aes(aes(aes(aes(b0 ^ c2, c2) ^ c2, c2) ^ b2, c2) ^ b3, c2)
aes(aes(aes(aes(a0 ^ c3, c3) ^ c3, c3) ^ a2, c3) ^ a3, c3)
= aes(aes(aes(aes(b0 ^ c3, c3) ^ c3, c3) ^ b2, c3) ^ b3, c3)
A00 = aes(a0 ^ c0, c0) B00 = aes(b0 ^ c0, c0)
A01 = aes(a0 ^ c1, c1) B01 = aes(b0 ^ c1, c1)
A02 = aes(a0 ^ c2, c2) B02 = aes(b0 ^ c2, c2)
A03 = aes(a0 ^ c3, c3) B03 = aes(b0 ^ c3, c3)
Warunek kolizji:
aes(aes(aes(A00 ^ c0, c0) ^ a2, c0) ^ a3, c0) = aes(aes(aes(B00 ^ c0, c0) ^ b2, c0) ^ b3, c0)
aes(aes(aes(A01 ^ c1, c1) ^ a2, c1) ^ a3, c1) = aes(aes(aes(B01 ^ c1, c1) ^ b2, c1) ^ b3, c1)
aes(aes(aes(A02 ^ c2, c2) ^ a2, c2) ^ a3, c2) = aes(aes(aes(B02 ^ c2, c2) ^ b2, c2) ^ b3, c2)
aes(aes(aes(A03 ^ c3, c3) ^ a2, c3) ^ a3, c3) = aes(aes(aes(B03 ^ c3, c3) ^ b2, c3) ^ b3, c3)
A10 = aes(A00 ^ c0, c0) B10 = aes(B00 ^ c0, c0)
A11 = aes(A01 ^ c1, c1) B11 = aes(B01 ^ c1, c1)
A12 = aes(A02 ^ c2, c2) B12 = aes(B02 ^ c2, c2)
A13 = aes(A03 ^ c3, c3) B13 = aes(B03 ^ c3, c3)
Warunek kolizji:
aes(aes(A10 ^ a2, c0) ^ a3, c0) = aes(aes(B10 ^ b2, c0) ^ b3, c0)
aes(aes(A11 ^ a2, c1) ^ a3, c1) = aes(aes(B11 ^ b2, c1) ^ b3, c1)
aes(aes(A12 ^ a2, c2) ^ a3, c2) = aes(aes(B12 ^ b2, c2) ^ b3, c2)
aes(aes(A13 ^ a2, c3) ^ a3, c3) = aes(aes(B13 ^ b2, c3) ^ b3, c3)
Przed:
aes(aes(A10 ^ a2, c0) ^ a3, c0) = aes(aes(B10 ^ b2, c0) ^ b3, c0)
aes(aes(A11 ^ a2, c1) ^ a3, c1) = aes(aes(B11 ^ b2, c1) ^ b3, c1)
aes(aes(A12 ^ a2, c2) ^ a3, c2) = aes(aes(B12 ^ b2, c2) ^ b3, c2)
aes(aes(A13 ^ a2, c3) ^ a3, c3) = aes(aes(B13 ^ b2, c3) ^ b3, c3)
Po:
aes(A10 ^ a2, c0) ^ a3 = aes(B10 ^ b2, c0) ^ b3
aes(A11 ^ a2, c1) ^ a3 = aes(B11 ^ b2, c1) ^ b3
aes(A12 ^ a2, c2) ^ a3 = aes(B12 ^ b2, c2) ^ b3
aes(A13 ^ a2, c3) ^ a3 = aes(B13 ^ b2, c3) ^ b3
Przed:
aes(A10 ^ a2, c0) ^ a3 = aes(B10 ^ b2, c0) ^ b3
aes(A11 ^ a2, c1) ^ a3 = aes(B11 ^ b2, c1) ^ b3
aes(A12 ^ a2, c2) ^ a3 = aes(B12 ^ b2, c2) ^ b3
aes(A13 ^ a2, c3) ^ a3 = aes(B13 ^ b2, c3) ^ b3
Po:
aes(A10 ^ a2, c0) = aes(B10 ^ b2, c0) ^ b3 ^ a3
aes(A11 ^ a2, c1) = aes(B11 ^ b2, c1) ^ b3 ^ a3
aes(A12 ^ a2, c2) = aes(B12 ^ b2, c2) ^ b3 ^ a3
aes(A13 ^ a2, c3) = aes(B13 ^ b2, c3) ^ b3 ^ a3
Przed:
aes(A10 ^ a2, c0) = aes(B10 ^ b2, c0) ^ (b3 ^ a3)
aes(A11 ^ a2, c1) = aes(B11 ^ b2, c1) ^ (b3 ^ a3)
aes(A12 ^ a2, c2) = aes(B12 ^ b2, c2) ^ (b3 ^ a3)
aes(A13 ^ a2, c3) = aes(B13 ^ b2, c3) ^ (b3 ^ a3)
Po:
ar(mx(sr(sb(A10 ^ a2))), c0) = ar(mx(sr(sb(B10 ^ b2))), c0) ^ (b3 ^ a3)
ar(mx(sr(sb(A11 ^ a2))), c1) = ar(mx(sr(sb(B11 ^ b2))), c1) ^ (b3 ^ a3)
ar(mx(sr(sb(A12 ^ a2))), c2) = ar(mx(sr(sb(B12 ^ b2))), c2) ^ (b3 ^ a3)
ar(mx(sr(sb(A13 ^ a2))), c3) = ar(mx(sr(sb(B13 ^ b2))), c3) ^ (b3 ^ a3)
Przed:
ar(mx(sr(sb(A10 ^ a2))), c0) = ar(mx(sr(sb(B10 ^ b2))), c0) ^ (b3 ^ a3)
ar(mx(sr(sb(A11 ^ a2))), c1) = ar(mx(sr(sb(B11 ^ b2))), c1) ^ (b3 ^ a3)
ar(mx(sr(sb(A12 ^ a2))), c2) = ar(mx(sr(sb(B12 ^ b2))), c2) ^ (b3 ^ a3)
ar(mx(sr(sb(A13 ^ a2))), c3) = ar(mx(sr(sb(B13 ^ b2))), c3) ^ (b3 ^ a3)
Po:
mx(sr(sb(A10 ^ a2))) ^ c0 = mx(sr(sb(B10 ^ b2))) ^ c0 ^ (b3 ^ a3)
mx(sr(sb(A11 ^ a2))) ^ c1 = mx(sr(sb(B11 ^ b2))) ^ c1 ^ (b3 ^ a3)
mx(sr(sb(A12 ^ a2))) ^ c2 = mx(sr(sb(B12 ^ b2))) ^ c2 ^ (b3 ^ a3)
mx(sr(sb(A13 ^ a2))) ^ c3 = mx(sr(sb(B13 ^ b2))) ^ c3 ^ (b3 ^ a3)
Przed:
mx(sr(sb(A10 ^ a2))) ^ c0 = mx(sr(sb(B10 ^ b2))) ^ c0 ^ (b3 ^ a3)
mx(sr(sb(A11 ^ a2))) ^ c1 = mx(sr(sb(B11 ^ b2))) ^ c1 ^ (b3 ^ a3)
mx(sr(sb(A12 ^ a2))) ^ c2 = mx(sr(sb(B12 ^ b2))) ^ c2 ^ (b3 ^ a3)
mx(sr(sb(A13 ^ a2))) ^ c3 = mx(sr(sb(B13 ^ b2))) ^ c3 ^ (b3 ^ a3)
Po:
mx(sr(sb(A10 ^ a2))) = mx(sr(sb(B10 ^ b2))) ^ (b3 ^ a3)
mx(sr(sb(A11 ^ a2))) = mx(sr(sb(B11 ^ b2))) ^ (b3 ^ a3)
mx(sr(sb(A12 ^ a2))) = mx(sr(sb(B12 ^ b2))) ^ (b3 ^ a3)
mx(sr(sb(A13 ^ a2))) = mx(sr(sb(B13 ^ b2))) ^ (b3 ^ a3)
Przed:
mx(sr(sb(A10 ^ a2))) = mx(sr(sb(B10 ^ b2))) ^ (b3 ^ a3)
mx(sr(sb(A11 ^ a2))) = mx(sr(sb(B11 ^ b2))) ^ (b3 ^ a3)
mx(sr(sb(A12 ^ a2))) = mx(sr(sb(B12 ^ b2))) ^ (b3 ^ a3)
mx(sr(sb(A13 ^ a2))) = mx(sr(sb(B13 ^ b2))) ^ (b3 ^ a3)
Po:
mx(sr(sb(A10 ^ a2))) = mx(sr(sb(B10 ^ b2)) ^ invmx(b3 ^ a3))
mx(sr(sb(A11 ^ a2))) = mx(sr(sb(B11 ^ b2)) ^ invmx(b3 ^ a3))
mx(sr(sb(A12 ^ a2))) = mx(sr(sb(B12 ^ b2)) ^ invmx(b3 ^ a3))
mx(sr(sb(A13 ^ a2))) = mx(sr(sb(B13 ^ b2)) ^ invmx(b3 ^ a3))
mx(A) ^ B = mx(A ^ invmx(B))
Przed:
mx(sr(sb(A10 ^ a2))) = mx(sr(sb(B10 ^ b2))) ^ invmx(b3 ^ a3))
mx(sr(sb(A11 ^ a2))) = mx(sr(sb(B11 ^ b2))) ^ invmx(b3 ^ a3))
mx(sr(sb(A12 ^ a2))) = mx(sr(sb(B12 ^ b2))) ^ invmx(b3 ^ a3))
mx(sr(sb(A13 ^ a2))) = mx(sr(sb(B13 ^ b2))) ^ invmx(b3 ^ a3))
Po:
sr(sb(A10 ^ a2)) = sr(sb(B10 ^ b2)) ^ invmx(b3 ^ a3)
sr(sb(A11 ^ a2)) = sr(sb(B11 ^ b2)) ^ invmx(b3 ^ a3)
sr(sb(A12 ^ a2)) = sr(sb(B12 ^ b2)) ^ invmx(b3 ^ a3)
sr(sb(A13 ^ a2)) = sr(sb(B13 ^ b2)) ^ invmx(b3 ^ a3)
mx(X) = mx(Y) <=> X = Y
Przed:
sr(sb(A10 ^ a2)) = sr(sb(B10 ^ b2)) ^ invmx(b3 ^ a3)
sr(sb(A11 ^ a2)) = sr(sb(B11 ^ b2)) ^ invmx(b3 ^ a3)
sr(sb(A12 ^ a2)) = sr(sb(B12 ^ b2)) ^ invmx(b3 ^ a3)
sr(sb(A13 ^ a2)) = sr(sb(B13 ^ b2)) ^ invmx(b3 ^ a3)
Po:
sr(sb(A10 ^ a2)) = sr(sb(B10 ^ b2) ^ invsr(invmx(b3 ^ a3)))
sr(sb(A11 ^ a2)) = sr(sb(B11 ^ b2) ^ invsr(invmx(b3 ^ a3)))
sr(sb(A12 ^ a2)) = sr(sb(B12 ^ b2) ^ invsr(invmx(b3 ^ a3)))
sr(sb(A13 ^ a2)) = sr(sb(B13 ^ b2) ^ invsr(invmx(b3 ^ a3)))
sr(A) ^ B = sr(A ^ invsr(B))
Przed:
sr(sb(A10 ^ a2)) = sr(sb(B10 ^ b2) ^ invsr(invmx(b3 ^ a3)))
sr(sb(A11 ^ a2)) = sr(sb(B11 ^ b2) ^ invsr(invmx(b3 ^ a3)))
sr(sb(A12 ^ a2)) = sr(sb(B12 ^ b2) ^ invsr(invmx(b3 ^ a3)))
sr(sb(A13 ^ a2)) = sr(sb(B13 ^ b2) ^ invsr(invmx(b3 ^ a3)))
Po:
sb(A10 ^ a2) = sb(B10 ^ b2) ^ invsr(invmx(b3 ^ a3))
sb(A11 ^ a2) = sb(B11 ^ b2) ^ invsr(invmx(b3 ^ a3))
sb(A12 ^ a2) = sb(B12 ^ b2) ^ invsr(invmx(b3 ^ a3))
sb(A13 ^ a2) = sb(B13 ^ b2) ^ invsr(invmx(b3 ^ a3))
sr(X) = sr(Y) <=> X = Y
Przed:
sb(A10 ^ a2) = sb(B10 ^ b2) ^ invsr(invmx(b3 ^ a3))
sb(A11 ^ a2) = sb(B11 ^ b2) ^ invsr(invmx(b3 ^ a3))
sb(A12 ^ a2) = sb(B12 ^ b2) ^ invsr(invmx(b3 ^ a3))
sb(A13 ^ a2) = sb(B13 ^ b2) ^ invsr(invmx(b3 ^ a3))
Po:
invsr(invmx(b3 ^ a3)) = sb(B10 ^ b2) ^ sb(A10 ^ a2)
invsr(invmx(b3 ^ a3)) = sb(B11 ^ b2) ^ sb(A11 ^ a2)
invsr(invmx(b3 ^ a3)) = sb(B12 ^ b2) ^ sb(A12 ^ a2)
invsr(invmx(b3 ^ a3)) = sb(B13 ^ b2) ^ sb(A13 ^ a2)
Przed:
invsr(invmx(b3 ^ a3)) = sb(B10 ^ b2) ^ sb(A10 ^ a2)
invsr(invmx(b3 ^ a3)) = sb(B11 ^ b2) ^ sb(A11 ^ a2)
invsr(invmx(b3 ^ a3)) = sb(B12 ^ b2) ^ sb(A12 ^ a2)
invsr(invmx(b3 ^ a3)) = sb(B13 ^ b2) ^ sb(A13 ^ a2)
Po:
sb(B10 ^ b2) ^ sb(A10 ^ a2)
= sb(B11 ^ b2) ^ sb(A11 ^ a2)
= sb(B12 ^ b2) ^ sb(A12 ^ a2)
= sb(B13 ^ b2) ^ sb(A13 ^ a2)
sb(B10^b2)^sb(A10^a2) = sb(B11^b2)^sb(A11^a2) = sb(B12^b2)^sb(A12^a2) = sb(B13^b2)^sb(A13^a2)
Przypomnienie: jeśli będziemy w stanie rozwiązać to równanie, to (odwracając wszystkie kroki) dostaniemy kolizję hasha.
sb(B10^b2)^sb(A10^a2) = sb(B11^b2)^sb(A11^a2) = sb(B12^b2)^sb(A12^a2) = sb(B13^b2)^sb(A13^a2)
sb(x) = Substitutions[x]
Substitutions[256] = { 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, (...) 0x76, 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, (...) 0xC0, 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, (...) 0x15, 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, (...) 0x75, 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, (...) 0x84, 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, (...) 0xCF, 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, (...) 0xA8, 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, (...) 0xD2, 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, (...) 0x73, (...) (...) (...) (...) (...) (...) (...) (...) (...) (...) (...) (...) 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, (...) 0x16 };
sb(B10 ^ b2) ^ sb(A10 ^ a2)
wynik[0] = sb(B10[0] ^ b2[0]) ^ sb(A10[0] ^ a2[0])
wynik[1] = sb(B10[1] ^ b2[1]) ^ sb(A10[1] ^ a2[1])
wynik[2] = sb(B10[2] ^ b2[2]) ^ sb(A10[2] ^ a2[2])
...
sb(B10 ^ b2) ^ sb(A10 ^ a2)
wynik[0] = sb(B10[0] ^ b2[0]) ^ sb(A10[0] ^ a2[0])
wynik[1] = sb(B10[1] ^ b2[1]) ^ sb(A10[1] ^ a2[1])
wynik[2] = sb(B10[2] ^ b2[2]) ^ sb(A10[2] ^ a2[2])
...
Wniosek: można zgadywać rozwiązanie równania "bajt po bajcie" - co jest bardzo szybkie.
sb(B10 ^ b2)[ 0] ^ sb(A10 ^ a2)[ 0]
= sb(B11 ^ b2)[ 0] ^ sb(A11 ^ a2)[ 0]
= sb(B12 ^ b2)[ 0] ^ sb(A12 ^ a2)[ 0]
= sb(B13 ^ b2)[ 0] ^ sb(A13 ^ a2)[ 0]
sb(B10 ^ b2)[ 0] ^ sb(A10 ^ a2)[ 0]
= sb(B11 ^ b2)[ 0] ^ sb(A11 ^ a2)[ 0]
= sb(B12 ^ b2)[ 0] ^ sb(A12 ^ a2)[ 0]
= sb(B13 ^ b2)[ 0] ^ sb(A13 ^ a2)[ 0]
Atak: brute-forcujemy bajt po bajcie b2 aż równanie będzie spełnione.
Złożoność: 2**8
sb(B10 ^ b2)[ 0] ^ sb(A10 ^ a2)[ 0]
= sb(B11 ^ b2)[ 0] ^ sb(A11 ^ a2)[ 0]
= sb(B12 ^ b2)[ 0] ^ sb(A12 ^ a2)[ 0]
= sb(B13 ^ b2)[ 0] ^ sb(A13 ^ a2)[ 0]
Atak: brute-forcujemy bajt po bajcie b2 i a2 aż równanie będzie spełnione.
Złożoność: 2**(8+8) = 2**16
for i in range(16): B00i, B01i, B02i = ord(B00[i]), ord(B01[i]), ord(B02[i]) A00i, A01i, A02i = ord(A00[i]), ord(A01[i]), ord(A02[i]) for a1 in range(256): for b1 in range(256): AB2_0 = aes.Sbox[A00i ^ a1] ^ aes.Sbox[B00i ^ b1] AB2_1 = aes.Sbox[A01i ^ a1] ^ aes.Sbox[B01i ^ b1] AB2_2 = aes.Sbox[A02i ^ a1] ^ aes.Sbox[B02i ^ b1] if AB2_0 == AB2_1 == AB2_2: a1_out[i] = a1 b1_out[i] = b1 break
sb(B10 ^ b2)[ 0] ^ sb(A10 ^ a2)[ 0]
= sb(B11 ^ b2)[ 0] ^ sb(A11 ^ a2)[ 0]
= sb(B12 ^ b2)[ 0] ^ sb(A12 ^ a2)[ 0]
= sb(B13 ^ b2)[ 0] ^ sb(A13 ^ a2)[ 0]
???
sb(B10 ^ b2)[ 0] ^ sb(A10 ^ a2)[ 0]
= sb(B11 ^ b2)[ 0] ^ sb(A11 ^ a2)[ 0]
= sb(B12 ^ b2)[ 0] ^ sb(A12 ^ a2)[ 0]
= sb(B13 ^ b2)[ 0] ^ sb(A13 ^ a2)[ 0]
Atak: brute-forcujemy jeden bajt z a2 i b2, oraz dodatkowo cztery bajty z a2 aż równanie będzie spełnione.
Złożoność: 2**(8+8+32) = 2**48
bool brute_row(int seg) { char a0_inv[16]; for (uint64_t mod = 0x0; mod < 256LL*256*256*256; mod++) { *(uint32_t*)&a0[seg*4] = mod; inv_shift_rows(a0_inv, a0); for (int i = seg*4; i < seg*4+4; i++) { struct find_result res = find(*(__m128i*)a0_inv, i); if (res.a1 >= 0 && res.b1 >= 0) { if (i >= seg*4+3) { hexdump(a0); return true; } } else { break; } } } return false; }
collision.1.bin
4d6f676c6173206d6f6a61206279632c
fafb16f8b77339b985d5c24936415776
df044e598f03deb2204f77d9e603e63c
00000000000000000000000000000000
collision.2.bin
4b72797a79736f7761206e61727a6563
00000000000000000000000000000000
c09724a230bad9348bf38216bfc2f6f6
de9ba28a01f0673fe6524ef7d122bb2d
Zagadka!
Jeśli nawet algorytmy stworzone przez najlepszych kryptografów są łamane... (md5, sha1, streamhash)
To szansa że my, prości programiści, wymyślimy coś naprawdę bezpiecznego jest zerowa
(PS. Prościej atakować niż bronić)
If you're typing the letters AES into your code, you're doing it wrong
Praktyczna kryptografia: Szyfry blokowe
Praktyczna kryptografia: Hashowanie i podpisy cyfrowe