Breaking GPUs: When Is A Hash Not Just A Single Hash?

Password hashes can be cracked with GPUs. How? Because GPUs have multiple cores, and each core can be used to split a hashing task up. The…

Ref: Here

Breaking GPUs: When Is A Hash Not Just A Single Hash?

Password hashes can be cracked with GPUs. How? Because GPUs have multiple cores, and each core can be used to split a hashing task up. The NVIDIA GeForce RTX 3080, for example, has over 8,700 cores. Thus if it takes 8,700 days to crack a hash, we could crack it in just a day with a single GeForce RTX 3080 GPU. If we add more GPUs we can cut it down each more.

So how do we stop GPUs from cracking hashes? Well, we can put the hash into a loop, and where we have to hash a given number of times. This significantly reduces the opportunity to crack the hash with a GPU as we now cannot parallelize the process. Now we can only use one core to compute each hash. So let’s look at the different methods for the hashing methods.

For MD5 crypt, we have a format which is defined between “$” symbols. A sample hash is “$1$Y6tL9oGA$FoYF9naVmbEd29gU915J00”, and which has the fields of [here]:

  • Type: 1 (MD5 crypt).
  • Salt: Y6tL9oGA.
  • Hash: FoYF9naVmbEd29gU915J00.

We can test with OpenSSL for a password of “hello123”:

% openssl passwd -1 -salt Y6tL9oGA hello123
$1$Y6tL9oGA$FoYF9naVmbEd29gU915J00

For bcrypt, we have a cost value, and which relates to a number of rounds. A sample hash is: “$2b$10$ralFpkUktJLdXmyN.XP0YOFqUw4hw6IeIRTV8f0UVdv.QABffgvGW”, and which has the fields of [here]:

  • Type: 2b (bcrypt).
  • Cost: 10 (2¹⁰= 1,024 rounds).
  • Salt: ralFpkUktJLdXmyN.XP0YO (128-bit value).
  • Hash: FqUw4hw6IeIRTV8f0UVdv.QABffgvGW.

For SHA-1 crypt, a sample hash is: “$sha1$20498$gY6FhauW$uIkSNXp8Xw9hS6f4UJKM1G9LvBxX”, we get [here]:

  • Type: sha1 (SHA-1 crypt).
  • Rounds: 20498.
  • Salt: gY6FhauW (8 bytes).
  • Hash: uIkSNXp8Xw9hS6f4UJKM1G9LvBxX.

With SHA-256 crypt, a sample hash is “$5$/hqmQOhPafzx4Ld9$NvyxMsyM8HJziXuoaBlpQtz.f2IkfbOYvLBVaYK7SfC”, we get [here]:

  • Type: 5 (SHA-256 crypt)
  • Salt: /hqmQOhPafzx4Ld9 (16 Base-64 characters — 96 bits)
  • Hash: NvyxMsyM8HJziXuoaBlpQtz.f2IkfbOYvLBVaYK7SfC (256 bits)

We can also have a $rounds=X$ field. If this is omitted the number of rounds is 5,000. For “SHA-512 Crypt, a sample hash is: “$\6\$q5D7B8Z9tRWLWuas\$8WNTuTtm5HxfMmLJ0RMiocrLcBcOQgfHsbaRKPA6AswjB1LKGpy3f0KsgZmk1ix62sdEZ5MPG7DfJnPk76gdM/” [here]:

  • Type: 6 (SHA-512 crypt)
  • Salt: q5D7B8Z9tRWLWuas (8 bytes)
  • Hash: uIkSNXp8Xw9hS6f4UJKM1G9LvBxX

We can also have a $rounds=X$ field. If this is omitted the number of rounds is 656000. The code is [here]:

extern crate pwhash;
use pwhash::{bcrypt,md5_crypt,sha1_crypt,sha256_crypt,sha512_crypt,bsdi_crypt,unix_crypt};

use std::env;
fn main() {

let mut password="password";
let args: Vec<String> = env::args().collect();

if args.len() >1 { password = args[1].as_str();}
    println!("Password:\t{:}",password);
    let mut h_new = bcrypt::hash(password).unwrap();
println!("\nBcrypt:\t\t{:}",h_new);
    h_new = bsdi_crypt::hash(password).unwrap();
println!("BSDI Crypt:\t{:}",h_new);
    h_new = md5_crypt::hash(password).unwrap();
println!("MD5 Crypt:\t{:}",h_new);
    h_new = sha1_crypt::hash(password).unwrap();
println!("SHA1 Crypt:\t{:}",h_new);
    h_new = sha256_crypt::hash(password).unwrap();
println!("SHA-256 Crypt:\t{:}",h_new);

    h_new = unix_crypt::hash(password).unwrap();
println!("Unix crypt:\t{:}",h_new);
//    let rtn=bcrypt::verify(password, h);
// println!("{:?}",rtn);
}

A sample run is [here]:

Password:	hello123
Bcrypt:		$2b$10$1gZgrJFeD8CclpR3UJ1AsuStQcvNCW7l6qX2cK4h26WB0znfA44fe
BSDI Crypt: _Gl/.00S/WNrZl.GgeM.
MD5 Crypt: $1$Y6tL9oGA$FoYF9naVmbEd29gU915J00
SHA1 Crypt: $sha1$20498$gY6FhauW$uIkSNXp8Xw9hS6f4UJKM1G9LvBxX
SHA-256 Crypt: $5$/hqmQOhPafzx4Ld9$NvyxMsyM8HJziXuoaBlpQtz.f2IkfbOYvLBVaYK7SfC
SHA-512 Crypt: $6$q5D7B8Z9tRWLWuas$8WNTuTtm5HxfMmLJ0RMiocrLcBcOQgfHsbaRKPA6AswjB1LKGpy3f0KsgZmk1ix62sdEZ5MPG7DfJnPk76gdM/
Unix crypt: mUsMoOrweXet6