Merge branch 'fix-crypt_r-utf8' into 'master'
fix: crypt: treat key as raw bytes instead of requiring UTF-8 See merge request redox-os/relibc!1442
This commit is contained in:
@@ -4,11 +4,11 @@ use argon2::{
|
||||
password_hash::{PasswordHash, PasswordVerifier},
|
||||
};
|
||||
|
||||
pub fn crypt_argon2(key: &str, setting: &str) -> Option<String> {
|
||||
pub fn crypt_argon2(key: &[u8], setting: &str) -> Option<String> {
|
||||
let hash = PasswordHash::new(setting).ok()?;
|
||||
let argon2 = Argon2::default();
|
||||
|
||||
if argon2.verify_password(key.as_bytes(), &hash).is_ok() {
|
||||
if argon2.verify_password(key, &hash).is_ok() {
|
||||
Some(setting.to_string())
|
||||
} else {
|
||||
None
|
||||
|
||||
@@ -61,14 +61,14 @@ fn split_with_prefix(hash: &str) -> Option<(&str, &str, c_uint)> {
|
||||
/// # Note
|
||||
/// The `crypt_blowfish` function uses the Blowfish block cipher for hashing.
|
||||
/// The output of the Blowfish operation is base64-encoded using the BCrypt variant of base64.
|
||||
pub fn crypt_blowfish(passw: &str, setting: &str) -> Option<String> {
|
||||
pub fn crypt_blowfish(passw: &[u8], setting: &str) -> Option<String> {
|
||||
if let Some((prefix, setting, cost)) = split_with_prefix(setting) {
|
||||
if !(MIN_COST..=MAX_COST).contains(&cost) {
|
||||
return None;
|
||||
}
|
||||
// Passwords need to be null terminated
|
||||
let mut vec = Vec::with_capacity(passw.len() + 1);
|
||||
vec.extend_from_slice(passw.as_bytes());
|
||||
vec.extend_from_slice(passw);
|
||||
vec.push(0);
|
||||
|
||||
// We only consider the first 72 chars; truncate if necessary.
|
||||
|
||||
@@ -27,7 +27,7 @@ fn encode_md5(source: &[c_uchar]) -> Option<[c_uchar; PW_SIZE_MD5]> {
|
||||
|
||||
/// Function taken from PR: https://github.com/RustCrypto/password-hashes/pull/351
|
||||
/// This won't be needed once the PR is merged
|
||||
fn inner_md5(passw: &str, setting: &str) -> Option<String> {
|
||||
fn inner_md5(passw: &[u8], setting: &str) -> Option<String> {
|
||||
let mut digest_b = Md5::default();
|
||||
digest_b.update(passw);
|
||||
digest_b.update(setting);
|
||||
@@ -124,7 +124,7 @@ fn inner_md5(passw: &str, setting: &str) -> Option<String> {
|
||||
/// # Note
|
||||
/// The `crypt_md5` function uses the MD5 hashing algorithm for hashing.
|
||||
/// The output of the MD5 operation is base64-encoded using the BCrypt variant of base64.
|
||||
pub fn crypt_md5(passw: &str, setting: &str) -> Option<String> {
|
||||
pub fn crypt_md5(passw: &[u8], setting: &str) -> Option<String> {
|
||||
/* reject large keys */
|
||||
if passw.len() > KEY_MAX {
|
||||
return None;
|
||||
|
||||
@@ -73,12 +73,14 @@ pub unsafe extern "C" fn crypt_r(
|
||||
unsafe { *data = crypt_data::new() };
|
||||
}
|
||||
|
||||
let key = unsafe { CStr::from_ptr(key) }
|
||||
.to_str()
|
||||
.expect("key must be utf-8");
|
||||
let setting = unsafe { CStr::from_ptr(setting) }
|
||||
.to_str()
|
||||
.expect("setting must be utf-8");
|
||||
let key = unsafe { CStr::from_ptr(key) }.to_bytes();
|
||||
let setting = match unsafe { CStr::from_ptr(setting) }.to_str() {
|
||||
Ok(s) => s,
|
||||
Err(_) => {
|
||||
platform::ERRNO.set(EINVAL);
|
||||
return ptr::null_mut();
|
||||
}
|
||||
};
|
||||
|
||||
let encoded = if setting.starts_with('$') {
|
||||
if setting.starts_with("$1$") {
|
||||
|
||||
@@ -36,7 +36,7 @@ use sha2::Sha256;
|
||||
/// # Note
|
||||
/// The `crypt_pbkdf2` function uses the SHA256 hashing algorithm for the PBKDF2 operation.
|
||||
/// The output of the PBKDF2 operation is base64-encoded using the BCrypt variant of base64.
|
||||
pub fn crypt_pbkdf2(passw: &str, setting: &str) -> Option<String> {
|
||||
pub fn crypt_pbkdf2(passw: &[u8], setting: &str) -> Option<String> {
|
||||
if let Some((iter_str, salt)) = &setting[3..].split_once('$') {
|
||||
if salt.contains('$') {
|
||||
return None;
|
||||
@@ -50,7 +50,7 @@ pub fn crypt_pbkdf2(passw: &str, setting: &str) -> Option<String> {
|
||||
|
||||
let iter = u32::from_str_radix(iter_str, 16).ok()?;
|
||||
let mut buffer = [0u8; 32];
|
||||
pbkdf2_hmac::<Sha256>(passw.as_bytes(), actual_salt.as_bytes(), iter, &mut buffer);
|
||||
pbkdf2_hmac::<Sha256>(passw, actual_salt.as_bytes(), iter, &mut buffer);
|
||||
|
||||
Some(format!(
|
||||
"$8${}${}${}",
|
||||
|
||||
@@ -92,7 +92,7 @@ fn read_setting(setting: &str) -> Option<(c_uchar, c_uint, c_uint, String)> {
|
||||
/// # Note
|
||||
/// The `crypt_scrypt` function uses the Scrypt key derivation function for hashing.
|
||||
/// The output of the Scrypt operation is base64-encoded using the BCrypt variant of base64.
|
||||
pub fn crypt_scrypt(passw: &str, setting: &str) -> Option<String> {
|
||||
pub fn crypt_scrypt(passw: &[u8], setting: &str) -> Option<String> {
|
||||
if setting.len() < 14 {
|
||||
return None;
|
||||
}
|
||||
@@ -102,7 +102,7 @@ pub fn crypt_scrypt(passw: &str, setting: &str) -> Option<String> {
|
||||
let params = Params::new(nlog2, r, p, 32).ok()?;
|
||||
let mut output = [0u8; 32];
|
||||
|
||||
scrypt(passw.as_bytes(), salt.as_bytes(), ¶ms, &mut output).ok()?;
|
||||
scrypt(passw, salt.as_bytes(), ¶ms, &mut output).ok()?;
|
||||
|
||||
Some(format!(
|
||||
"$7${}${}${}",
|
||||
|
||||
@@ -53,7 +53,7 @@ pub enum ShaType {
|
||||
/// # Note
|
||||
/// The `crypt_sha` function uses the SHA256 or SHA512 hashing algorithm for hashing.
|
||||
/// The output of the SHA operation is base64-encoded using the BCrypt variant of base64.
|
||||
pub fn crypt_sha(passw: &str, setting: &str, cipher: ShaType) -> Option<String> {
|
||||
pub fn crypt_sha(passw: &[u8], setting: &str, cipher: ShaType) -> Option<String> {
|
||||
let mut cursor = 3;
|
||||
let rounds;
|
||||
|
||||
@@ -117,12 +117,12 @@ pub fn crypt_sha(passw: &str, setting: &str, cipher: ShaType) -> Option<String>
|
||||
ShaType::Sha256 => {
|
||||
let params = Sha256Params::new(rounds as usize)
|
||||
.unwrap_or(Sha256Params::new(ROUNDS_DEFAULT).unwrap());
|
||||
sha256_crypt_b64(passw.as_bytes(), setting.as_bytes(), ¶ms)
|
||||
sha256_crypt_b64(passw, setting.as_bytes(), ¶ms)
|
||||
}
|
||||
ShaType::Sha512 => {
|
||||
let params = Sha512Params::new(rounds as usize)
|
||||
.unwrap_or(Sha512Params::new(ROUNDS_DEFAULT).unwrap());
|
||||
sha512_crypt_b64(passw.as_bytes(), setting.as_bytes(), ¶ms)
|
||||
sha512_crypt_b64(passw, setting.as_bytes(), ¶ms)
|
||||
}
|
||||
} {
|
||||
let (r_slice, rn_slice) = if has_round {
|
||||
|
||||
+16
-2
@@ -1,5 +1,7 @@
|
||||
#include <assert.h>
|
||||
#include <crypt.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
@@ -12,14 +14,26 @@ int main()
|
||||
// No salt
|
||||
result = crypt("pleaseletmein", "$7$C6..../....");
|
||||
assert(result != NULL);
|
||||
|
||||
|
||||
// Invalid encoded number for r
|
||||
result = crypt("pleaseletmein", "$7$C6.../....SodiumChloride");
|
||||
assert(result == NULL);
|
||||
|
||||
|
||||
// Invalid encoded number for p
|
||||
result = crypt("pleaseletmein", "$7$C6..../...SodiumChloride");
|
||||
assert(result == NULL);
|
||||
|
||||
// Non-UTF-8 key should succeed (treated as raw bytes)
|
||||
char key[] = {(char)0xC0, (char)0x01, '\0'};
|
||||
result = crypt(key, "$5$saltsalt$");
|
||||
assert(result != NULL);
|
||||
|
||||
// Non-UTF-8 setting should return NULL with errno=EINVAL
|
||||
char setting[] = {'$', '5', '$', (char)0xFE, (char)0xFF, '$', '\0'};
|
||||
errno = 0;
|
||||
result = crypt("password", setting);
|
||||
assert(result == NULL);
|
||||
assert(errno == EINVAL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user