Serenity Operating System
at master 70 lines 1.8 kB view raw
1/* 2 * Copyright (c) 2020, Peter Elliott <pelliott@serenityos.org> 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7#include <AK/Base64.h> 8#include <AK/Types.h> 9#include <LibCrypto/Hash/SHA2.h> 10#include <crypt.h> 11#include <errno.h> 12#include <string.h> 13 14extern "C" { 15 16static struct crypt_data crypt_data; 17 18char* crypt(char const* key, char const* salt) 19{ 20 crypt_data.initialized = true; 21 return crypt_r(key, salt, &crypt_data); 22} 23 24static constexpr size_t crypt_salt_max = 16; 25 26char* crypt_r(char const* key, char const* salt, struct crypt_data* data) 27{ 28 if (!data->initialized) { 29 errno = EINVAL; 30 return nullptr; 31 } 32 33 // We only support SHA-256 at the moment 34 if (salt[0] != '$' || salt[1] != '5') { 35 errno = EINVAL; 36 return nullptr; 37 } 38 39 char const* salt_value = salt + 3; 40 size_t salt_len = min(strcspn(salt_value, "$"), crypt_salt_max); 41 size_t header_len = salt_len + 3; 42 43 bool fits = DeprecatedString(salt, header_len).copy_characters_to_buffer(data->result, sizeof(data->result)); 44 if (!fits) { 45 errno = EINVAL; 46 return nullptr; 47 } 48 data->result[header_len] = '$'; 49 50 Crypto::Hash::SHA256 sha; 51 sha.update(StringView { key, strlen(key) }); 52 sha.update(reinterpret_cast<u8 const*>(salt_value), salt_len); 53 54 auto digest = sha.digest(); 55 auto string_or_error = encode_base64({ digest.immutable_data(), digest.data_length() }); 56 if (string_or_error.is_error()) { 57 errno = ENOMEM; 58 return nullptr; 59 } 60 61 auto string = string_or_error.value().bytes_as_string_view(); 62 fits = string.copy_characters_to_buffer(data->result + header_len + 1, sizeof(data->result) - header_len - 1); 63 if (!fits) { 64 errno = EINVAL; 65 return nullptr; 66 } 67 68 return data->result; 69} 70}