mirror of https://github.com/vinc/moros.git
Add password hashing
This commit is contained in:
parent
e87b485a86
commit
0b59c0d310
|
@ -20,6 +20,12 @@ dependencies = [
|
|||
"stable_deref_trait",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7"
|
||||
|
||||
[[package]]
|
||||
name = "bit_field"
|
||||
version = "0.9.0"
|
||||
|
@ -32,12 +38,39 @@ version = "1.2.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
|
||||
|
||||
[[package]]
|
||||
name = "block-buffer"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b"
|
||||
dependencies = [
|
||||
"block-padding",
|
||||
"byte-tools",
|
||||
"byteorder",
|
||||
"generic-array 0.12.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "block-padding"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5"
|
||||
dependencies = [
|
||||
"byte-tools",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bootloader"
|
||||
version = "0.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d596849a47f28abdea62d7a6a25c4f6e69c3d9b09b0a2877db6e9cda004ca993"
|
||||
|
||||
[[package]]
|
||||
name = "byte-tools"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.3.2"
|
||||
|
@ -59,6 +92,31 @@ version = "0.2.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "22b8e308ccfc5acf3b82f79c0eac444cf6114cb2ac67a230ca6c177210068daa"
|
||||
|
||||
[[package]]
|
||||
name = "crypto-mac"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4434400df11d95d556bac068ddfedd482915eb18fe8bea89bc80b6e4b1c179e5"
|
||||
dependencies = [
|
||||
"generic-array 0.12.3",
|
||||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5"
|
||||
dependencies = [
|
||||
"generic-array 0.12.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fake-simd"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed"
|
||||
|
||||
[[package]]
|
||||
name = "generic-array"
|
||||
version = "0.12.3"
|
||||
|
@ -97,6 +155,16 @@ dependencies = [
|
|||
"hash32",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hmac"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5dcb5e64cda4c23119ab41ba960d1e170a774c8e4b9d9e6a9bc18aabf5e59695"
|
||||
dependencies = [
|
||||
"crypto-mac",
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
|
@ -110,11 +178,15 @@ dependencies = [
|
|||
name = "moros"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"bootloader",
|
||||
"heapless",
|
||||
"hmac",
|
||||
"lazy_static",
|
||||
"pbkdf2",
|
||||
"pc-keyboard",
|
||||
"pic8259_simple",
|
||||
"sha2",
|
||||
"spin",
|
||||
"volatile",
|
||||
"x86_64",
|
||||
|
@ -126,6 +198,22 @@ version = "0.1.14"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb"
|
||||
|
||||
[[package]]
|
||||
name = "opaque-debug"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c"
|
||||
|
||||
[[package]]
|
||||
name = "pbkdf2"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "006c038a43a45995a9670da19e67600114740e8511d4333bf97a56e66a7542d9"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"crypto-mac",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pc-keyboard"
|
||||
version = "0.5.0"
|
||||
|
@ -164,6 +252,18 @@ version = "0.7.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
|
||||
|
||||
[[package]]
|
||||
name = "sha2"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7b4d8bfd0e469f417657573d8451fb33d16cfe0989359b93baf3a1ffc639543d"
|
||||
dependencies = [
|
||||
"block-buffer",
|
||||
"digest",
|
||||
"fake-simd",
|
||||
"opaque-debug",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "spin"
|
||||
version = "0.5.2"
|
||||
|
@ -176,6 +276,12 @@ version = "1.1.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8"
|
||||
|
||||
[[package]]
|
||||
name = "subtle"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2d67a5a62ba6e01cb2192ff309324cb4875d0c451d55fe2319433abe7a05a8ee"
|
||||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.11.2"
|
||||
|
|
|
@ -17,3 +17,7 @@ pic8259_simple = "0.1.1"
|
|||
pc-keyboard = { version = "0.5.0", git = "https://github.com/vinc/pc-keyboard", branch = "feature/add-dvorak-layout" }
|
||||
heapless = "0.5.1"
|
||||
lazy_static = { version = "1.0", features = ["spin_no_std"] }
|
||||
base64 = { version = "0.11", default-features = false }
|
||||
pbkdf2 = { version = "0.3", default-features = false }
|
||||
sha2 = { version = "0.8", default-features = false }
|
||||
hmac = { version = "0.7", default-features = false }
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
root,1$AAAQAA$nvQAFYGhN1a4NmHS8ooWrA$7zOWQLxpmRF4AC3G3+F2OVJ9IejzdH52TXQFlbRAmLg
|
|
|
@ -4,5 +4,6 @@ pub mod console;
|
|||
pub mod fs;
|
||||
pub mod gdt;
|
||||
pub mod interrupts;
|
||||
pub mod random;
|
||||
pub mod sleep;
|
||||
pub mod vga;
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
use x86_64::instructions::random::RdRand;
|
||||
|
||||
pub fn rand64() -> Option<u64> {
|
||||
match RdRand::new() {
|
||||
Some(rand) => rand.get_u64(),
|
||||
None => None
|
||||
}
|
||||
}
|
|
@ -11,6 +11,7 @@ fn main(_boot_info: &'static BootInfo) -> ! {
|
|||
moros::init();
|
||||
include_file("/cfg/boot.sh", include_str!("../dsk/cfg/boot.sh"));
|
||||
include_file("/cfg/banner.txt", include_str!("../dsk/cfg/banner.txt"));
|
||||
include_file("/cfg/passwords.csv", include_str!("../dsk/cfg/passwords.csv"));
|
||||
loop {
|
||||
user::shell::main(&["shell", "/cfg/boot.sh"]);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
use crate::{print, user};
|
||||
use heapless::{String, Vec};
|
||||
use heapless::consts::*;
|
||||
|
||||
pub fn main(args: &[&str]) -> user::shell::ExitCode {
|
||||
if args.len() != 2 {
|
||||
user::shell::ExitCode::CommandError
|
||||
} else {
|
||||
let buf = encode(args[1].as_bytes());
|
||||
let encoded = String::from_utf8(buf).unwrap();
|
||||
print!("{}\n", encoded);
|
||||
user::shell::ExitCode::CommandSuccessful
|
||||
}
|
||||
}
|
||||
|
||||
pub fn encode(s: &[u8]) -> Vec<u8, U1024> {
|
||||
let mut buf = Vec::<u8, U1024>::new();
|
||||
buf.resize(s.len() * 4 / 3 + 4, 0).unwrap(); // Resize to base64 + padding
|
||||
let bytes_written = base64::encode_config_slice(s, base64::STANDARD_NO_PAD, &mut buf);
|
||||
buf.resize(bytes_written, 0).unwrap(); // Resize back to actual size
|
||||
buf
|
||||
}
|
||||
|
||||
pub fn decode(s: &[u8]) -> Vec<u8, U1024> {
|
||||
let mut buf = Vec::<u8, U1024>::new();
|
||||
buf.resize(s.len(), 0).unwrap();
|
||||
let bytes_written = base64::decode_config_slice(s, base64::STANDARD_NO_PAD, &mut buf).unwrap();
|
||||
buf.resize(bytes_written, 0).unwrap();
|
||||
buf
|
||||
}
|
|
@ -1,4 +1,10 @@
|
|||
use crate::{print, kernel, user};
|
||||
use heapless::{String, FnvIndexMap, Vec};
|
||||
use heapless::consts::*;
|
||||
use core::convert::TryInto;
|
||||
use core::str;
|
||||
use hmac::Hmac;
|
||||
use sha2::Sha256;
|
||||
|
||||
pub fn main(_args: &[&str]) -> user::shell::ExitCode {
|
||||
login()
|
||||
|
@ -6,21 +12,91 @@ pub fn main(_args: &[&str]) -> user::shell::ExitCode {
|
|||
|
||||
// TODO: Add max number of attempts
|
||||
pub fn login() -> user::shell::ExitCode {
|
||||
print!("\nUsername: ");
|
||||
let username = kernel::console::get_line();
|
||||
if username != "root\n" {
|
||||
kernel::sleep::sleep(1.0);
|
||||
return login();
|
||||
let mut hashed_passwords: FnvIndexMap<String<U256>, String<U1024>, U256> = FnvIndexMap::new();
|
||||
if let Some(file) = kernel::fs::File::open("/cfg/passwords.csv") {
|
||||
for line in file.read().split("\n") {
|
||||
let mut rows = line.split(",");
|
||||
if let Some(username) = rows.next() {
|
||||
if let Some(hashed_password) = rows.next() {
|
||||
hashed_passwords.insert(username.into(), hashed_password.into()).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
print!("Password: ");
|
||||
kernel::console::disable_echo();
|
||||
let password = kernel::console::get_line();
|
||||
kernel::console::enable_echo();
|
||||
print!("\n");
|
||||
if password != "root\n" {
|
||||
kernel::sleep::sleep(1.0);
|
||||
return login();
|
||||
print!("\nUsername: ");
|
||||
let mut username = kernel::console::get_line();
|
||||
username.pop(); // Trim end of string
|
||||
match hashed_passwords.get(&username) {
|
||||
None => {
|
||||
kernel::sleep::sleep(1.0);
|
||||
return login();
|
||||
},
|
||||
Some(hashed_password) => {
|
||||
print!("Password: ");
|
||||
kernel::console::disable_echo();
|
||||
let mut password = kernel::console::get_line();
|
||||
kernel::console::enable_echo();
|
||||
print!("\n");
|
||||
password.pop();
|
||||
if !check(&password, hashed_password) {
|
||||
kernel::sleep::sleep(1.0);
|
||||
return login();
|
||||
}
|
||||
}
|
||||
}
|
||||
user::shell::ExitCode::CommandSuccessful
|
||||
}
|
||||
|
||||
pub fn check(password: &str, hashed_password: &str) -> bool {
|
||||
let fields: Vec<_, U4> = hashed_password.split('$').collect();
|
||||
if fields.len() != 4 || fields[0] != "1" {
|
||||
return false;
|
||||
}
|
||||
|
||||
let decoded_field = user::base64::decode(&fields[1].as_bytes());
|
||||
let c = u32::from_be_bytes(decoded_field[0..4].try_into().unwrap());
|
||||
|
||||
let decoded_field = user::base64::decode(&fields[2].as_bytes());
|
||||
let salt: [u8; 16] = decoded_field[0..16].try_into().unwrap();
|
||||
|
||||
let mut hash = [0u8; 32];
|
||||
pbkdf2::pbkdf2::<Hmac<Sha256>>(password.as_bytes(), &salt, c as usize, &mut hash);
|
||||
let encoded_hash = String::from_utf8(user::base64::encode(&hash)).unwrap();
|
||||
|
||||
encoded_hash == fields[3]
|
||||
}
|
||||
|
||||
// Password hashing version 1 => PBKDF2-HMAC-SHA256 + BASE64
|
||||
// Fields: "<version>$<c>$<salt>$<hash>"
|
||||
// Example: "1$AAAQAA$PDkXP0I8O7SxNOxvUKmHHQ$BwIUWBxKs50BTpH6i4ImF3SZOxADv7dh4xtu3IKc3o8"
|
||||
pub fn hash(password: &str) -> String<U1024> {
|
||||
let v = "1"; // Password hashing version
|
||||
let c = 4096u32; // Number of iterations
|
||||
let mut salt = [0u8; 16];
|
||||
let mut hash = [0u8; 32];
|
||||
|
||||
// Generating salt
|
||||
for i in 0..2 {
|
||||
let num = kernel::random::rand64().unwrap();
|
||||
let buf = num.to_be_bytes();
|
||||
let n = buf.len();
|
||||
for j in 0..n {
|
||||
salt[i * n + j] = buf[j];
|
||||
}
|
||||
}
|
||||
|
||||
// Hashing password with PBKDF2-HMAC-SHA256
|
||||
pbkdf2::pbkdf2::<Hmac<Sha256>>(password.as_bytes(), &salt, c as usize, &mut hash);
|
||||
|
||||
// Encoding in Base64 standard without padding
|
||||
let c = c.to_be_bytes();
|
||||
let mut res: String<U1024> = String::from(v);
|
||||
res.push('$').unwrap();
|
||||
res.push_str(&String::from_utf8(user::base64::encode(&c)).unwrap()).unwrap();
|
||||
res.push('$').unwrap();
|
||||
res.push_str(&String::from_utf8(user::base64::encode(&salt)).unwrap()).unwrap();
|
||||
res.push('$').unwrap();
|
||||
res.push_str(&String::from_utf8(user::base64::encode(&hash)).unwrap()).unwrap();
|
||||
res
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
pub mod base64;
|
||||
pub mod clear;
|
||||
pub mod date;
|
||||
pub mod editor;
|
||||
|
|
|
@ -141,6 +141,7 @@ impl Shell {
|
|||
"sleep" => user::sleep::main(&args),
|
||||
"clear" => user::clear::main(&args),
|
||||
"login" => user::login::main(&args),
|
||||
"base64" => user::base64::main(&args),
|
||||
_ => ExitCode::CommandUnknown,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,4 +12,4 @@
|
|||
"panic-strategy": "abort",
|
||||
"disable-redzone": true,
|
||||
"features": "-mmx,-sse,+soft-float"
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue