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",
|
"stable_deref_trait",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "base64"
|
||||||
|
version = "0.11.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bit_field"
|
name = "bit_field"
|
||||||
version = "0.9.0"
|
version = "0.9.0"
|
||||||
|
@ -32,12 +38,39 @@ version = "1.2.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
|
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]]
|
[[package]]
|
||||||
name = "bootloader"
|
name = "bootloader"
|
||||||
version = "0.8.3"
|
version = "0.8.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d596849a47f28abdea62d7a6a25c4f6e69c3d9b09b0a2877db6e9cda004ca993"
|
checksum = "d596849a47f28abdea62d7a6a25c4f6e69c3d9b09b0a2877db6e9cda004ca993"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "byte-tools"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "byteorder"
|
name = "byteorder"
|
||||||
version = "1.3.2"
|
version = "1.3.2"
|
||||||
|
@ -59,6 +92,31 @@ version = "0.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "22b8e308ccfc5acf3b82f79c0eac444cf6114cb2ac67a230ca6c177210068daa"
|
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]]
|
[[package]]
|
||||||
name = "generic-array"
|
name = "generic-array"
|
||||||
version = "0.12.3"
|
version = "0.12.3"
|
||||||
|
@ -97,6 +155,16 @@ dependencies = [
|
||||||
"hash32",
|
"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]]
|
[[package]]
|
||||||
name = "lazy_static"
|
name = "lazy_static"
|
||||||
version = "1.4.0"
|
version = "1.4.0"
|
||||||
|
@ -110,11 +178,15 @@ dependencies = [
|
||||||
name = "moros"
|
name = "moros"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"base64",
|
||||||
"bootloader",
|
"bootloader",
|
||||||
"heapless",
|
"heapless",
|
||||||
|
"hmac",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
|
"pbkdf2",
|
||||||
"pc-keyboard",
|
"pc-keyboard",
|
||||||
"pic8259_simple",
|
"pic8259_simple",
|
||||||
|
"sha2",
|
||||||
"spin",
|
"spin",
|
||||||
"volatile",
|
"volatile",
|
||||||
"x86_64",
|
"x86_64",
|
||||||
|
@ -126,6 +198,22 @@ version = "0.1.14"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb"
|
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]]
|
[[package]]
|
||||||
name = "pc-keyboard"
|
name = "pc-keyboard"
|
||||||
version = "0.5.0"
|
version = "0.5.0"
|
||||||
|
@ -164,6 +252,18 @@ version = "0.7.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
|
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]]
|
[[package]]
|
||||||
name = "spin"
|
name = "spin"
|
||||||
version = "0.5.2"
|
version = "0.5.2"
|
||||||
|
@ -176,6 +276,12 @@ version = "1.1.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8"
|
checksum = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "subtle"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2d67a5a62ba6e01cb2192ff309324cb4875d0c451d55fe2319433abe7a05a8ee"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "typenum"
|
name = "typenum"
|
||||||
version = "1.11.2"
|
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" }
|
pc-keyboard = { version = "0.5.0", git = "https://github.com/vinc/pc-keyboard", branch = "feature/add-dvorak-layout" }
|
||||||
heapless = "0.5.1"
|
heapless = "0.5.1"
|
||||||
lazy_static = { version = "1.0", features = ["spin_no_std"] }
|
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 fs;
|
||||||
pub mod gdt;
|
pub mod gdt;
|
||||||
pub mod interrupts;
|
pub mod interrupts;
|
||||||
|
pub mod random;
|
||||||
pub mod sleep;
|
pub mod sleep;
|
||||||
pub mod vga;
|
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();
|
moros::init();
|
||||||
include_file("/cfg/boot.sh", include_str!("../dsk/cfg/boot.sh"));
|
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/banner.txt", include_str!("../dsk/cfg/banner.txt"));
|
||||||
|
include_file("/cfg/passwords.csv", include_str!("../dsk/cfg/passwords.csv"));
|
||||||
loop {
|
loop {
|
||||||
user::shell::main(&["shell", "/cfg/boot.sh"]);
|
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 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 {
|
pub fn main(_args: &[&str]) -> user::shell::ExitCode {
|
||||||
login()
|
login()
|
||||||
|
@ -6,21 +12,91 @@ pub fn main(_args: &[&str]) -> user::shell::ExitCode {
|
||||||
|
|
||||||
// TODO: Add max number of attempts
|
// TODO: Add max number of attempts
|
||||||
pub fn login() -> user::shell::ExitCode {
|
pub fn login() -> user::shell::ExitCode {
|
||||||
print!("\nUsername: ");
|
let mut hashed_passwords: FnvIndexMap<String<U256>, String<U1024>, U256> = FnvIndexMap::new();
|
||||||
let username = kernel::console::get_line();
|
if let Some(file) = kernel::fs::File::open("/cfg/passwords.csv") {
|
||||||
if username != "root\n" {
|
for line in file.read().split("\n") {
|
||||||
kernel::sleep::sleep(1.0);
|
let mut rows = line.split(",");
|
||||||
return login();
|
if let Some(username) = rows.next() {
|
||||||
|
if let Some(hashed_password) = rows.next() {
|
||||||
|
hashed_passwords.insert(username.into(), hashed_password.into()).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
print!("Password: ");
|
print!("\nUsername: ");
|
||||||
kernel::console::disable_echo();
|
let mut username = kernel::console::get_line();
|
||||||
let password = kernel::console::get_line();
|
username.pop(); // Trim end of string
|
||||||
kernel::console::enable_echo();
|
match hashed_passwords.get(&username) {
|
||||||
print!("\n");
|
None => {
|
||||||
if password != "root\n" {
|
kernel::sleep::sleep(1.0);
|
||||||
kernel::sleep::sleep(1.0);
|
return login();
|
||||||
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
|
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 clear;
|
||||||
pub mod date;
|
pub mod date;
|
||||||
pub mod editor;
|
pub mod editor;
|
||||||
|
|
|
@ -141,6 +141,7 @@ impl Shell {
|
||||||
"sleep" => user::sleep::main(&args),
|
"sleep" => user::sleep::main(&args),
|
||||||
"clear" => user::clear::main(&args),
|
"clear" => user::clear::main(&args),
|
||||||
"login" => user::login::main(&args),
|
"login" => user::login::main(&args),
|
||||||
|
"base64" => user::base64::main(&args),
|
||||||
_ => ExitCode::CommandUnknown,
|
_ => ExitCode::CommandUnknown,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,4 +12,4 @@
|
||||||
"panic-strategy": "abort",
|
"panic-strategy": "abort",
|
||||||
"disable-redzone": true,
|
"disable-redzone": true,
|
||||||
"features": "-mmx,-sse,+soft-float"
|
"features": "-mmx,-sse,+soft-float"
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue