Skip to content

Commit 1777f70

Browse files
authored
hash: Adds ChaCha20 CSPRNG functions, updates TOTP generator, adds Base32 (tgstation#225)
1 parent de89d44 commit 1777f70

6 files changed

Lines changed: 360 additions & 54 deletions

File tree

‎Cargo.lock‎

Lines changed: 9 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎Cargo.toml‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,9 @@ uuid = { version = "1.18", optional = true, features = [
7373
"fast-rng",
7474
] }
7575
cuid2 = { version = "0.1.4", optional = true }
76+
rand_chacha = { version = "0.9.0", optional = true }
77+
hmac = { version = "0.12.1", optional = true }
78+
base32 = { version = "0.5.1", optional = true }
7679
indexmap = { version = "2.11.4", optional = true, features = [
7780
"serde",
7881
"rayon",
@@ -142,10 +145,14 @@ dmi = ["png", "image", "qrcode", "serde_repr"]
142145
file = []
143146
git = ["gix", "chrono"]
144147
hash = [
148+
"base32",
145149
"base64",
146150
"const-random",
147151
"md-5",
148152
"hex",
153+
"hmac",
154+
"rand",
155+
"rand_chacha",
149156
"sha-1",
150157
"sha2",
151158
"twox-hash",

‎dmsrc/hash.dm‎

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,67 @@
11
#define rustg_hash_string(algorithm, text) RUSTG_CALL(RUST_G, "hash_string")(algorithm, text)
22
#define rustg_hash_file(algorithm, fname) RUSTG_CALL(RUST_G, "hash_file")(algorithm, fname)
3-
#define rustg_hash_generate_totp(seed) RUSTG_CALL(RUST_G, "generate_totp")(seed)
4-
#define rustg_hash_generate_totp_tolerance(seed, tolerance) RUSTG_CALL(RUST_G, "generate_totp_tolerance")(seed, tolerance)
3+
4+
/// Supported algorithms: RUSTG_HASH_SHA1, RUSTG_HASH_SHA256, RUSTG_HASH_SHA512
5+
/// Seed must be between 10 bytes to 64 bytes (padded or unpadded) of base32. 20 bytes is recommended. Use a CSPRNG.
6+
/// Refresh rate is fixed at 30sec and digit count is fixed at 6
7+
#define rustg_hash_generate_totp(algorithm, seed) RUSTG_CALL(RUST_G, "generate_totp")(algorithm, seed)
8+
/// Supported algorithms: RUSTG_HASH_SHA1, RUSTG_HASH_SHA256, RUSTG_HASH_SHA512
9+
/// Seed must be between 10 bytes to 64 bytes (padded or unpadded) of base32. 20 bytes is recommended. Use a CSPRNG.
10+
/// Refresh rate is fixed at 30sec and digit count is fixed at 6
11+
/// Tolerance is the number of codes +-30sec from the current one that are allowed.
12+
#define rustg_hash_generate_totp_tolerance(algorithm, seed, tolerance) RUSTG_CALL(RUST_G, "generate_totp_tolerance")(algorithm, seed, tolerance)
13+
14+
/// Creates a cryptographically-secure pseudorandom number generator using the OS-level PRNG as a seed
15+
/// n_bytes is the number of bytes provided to the RNG, the length of the string output varies by format
16+
/// The output string length and characters contained in each format is as follows:
17+
/// RUSTG_RNG_FORMAT_HEX: n_bytes * 2, [a-z0-9]
18+
/// RUSTG_RNG_FORMAT_ALPHANUMERIC: n_bytes, [A-Za-z0-9]
19+
/// RUSTG_RNG_FORMAT_BASE32: ceil(n_bytes / 5 * 8) [A-Z2-7]
20+
/// RUSTG_RNG_FORMAT_BASE32_PADDED: ceil(n_bytes / 5) * 8 [A-Z2-7=]
21+
/// RUSTG_RNG_FORMAT_BASE64: 4 * ceil(n_bytes/3), [A-Za-z0-9+/=]
22+
/// Outputs "ERROR: [reason]" if the format string provided is invalid, or n_bytes is not a positive non-zero integer
23+
#define rustg_csprng_chacha20(format, n_bytes) RUSTG_CALL(RUST_G, "csprng_chacha20")(format, "[n_bytes]")
24+
25+
/// Creates a seeded pseudorandom number generator using the SHA256 hash output bytes of the seed string
26+
/// Note that this function is NOT suitable for use in cryptography and is intended for high-quality **predictable** RNG
27+
/// Use rustg_csprng_chacha20 for a cryptographically-secure PRNG.
28+
/// n_bytes is the number of bytes provided to the RNG, the length of the string output varies by format
29+
/// The output string length and characters contained in each format is as follows:
30+
/// RUSTG_RNG_FORMAT_HEX: n_bytes * 2, [a-z0-9]
31+
/// RUSTG_RNG_FORMAT_ALPHANUMERIC: n_bytes, [A-Za-z0-9]
32+
/// RUSTG_RNG_FORMAT_BASE32: ceil(n_bytes / 5 * 8) [A-Z2-7]
33+
/// RUSTG_RNG_FORMAT_BASE32_PADDED: ceil(n_bytes / 5) * 8 [A-Z2-7=]
34+
/// RUSTG_RNG_FORMAT_BASE64: 4 * ceil(n_bytes/3), [A-Za-z0-9+/=]
35+
/// Outputs "ERROR: [reason]" if the format string provided is invalid, or n_bytes is not a positive non-zero integer
36+
#define rustg_prng_chacha20_seeded(format, n_bytes, seed) RUSTG_CALL(RUST_G, "prng_chacha20_seeded")(format, "[n_bytes]", seed)
37+
38+
#define RUSTG_RNG_FORMAT_HEX "hex"
39+
#define RUSTG_RNG_FORMAT_ALPHANUMERIC "alphanumeric"
40+
#define RUSTG_RNG_FORMAT_BASE32 "base32_rfc4648"
41+
#define RUSTG_RNG_FORMAT_BASE32_PADDED "base32_rfc4648_pad"
42+
#define RUSTG_RNG_FORMAT_BASE64 "base64"
543

644
#define RUSTG_HASH_MD5 "md5"
745
#define RUSTG_HASH_SHA1 "sha1"
846
#define RUSTG_HASH_SHA256 "sha256"
947
#define RUSTG_HASH_SHA512 "sha512"
1048
#define RUSTG_HASH_XXH64 "xxh64"
49+
#define RUSTG_HASH_BASE32 "base32_rfc4648"
50+
#define RUSTG_HASH_BASE32_PADDED "base32_rfc4648_pad"
1151
#define RUSTG_HASH_BASE64 "base64"
1252

1353
/// Encode a given string into base64
1454
#define rustg_encode_base64(str) rustg_hash_string(RUSTG_HASH_BASE64, str)
1555
/// Decode a given base64 string
1656
#define rustg_decode_base64(str) RUSTG_CALL(RUST_G, "decode_base64")(str)
1757

58+
/// Encode a given string into base32 (RFC4648)
59+
/// If padding set to FALSE, will not output padding characters.
60+
#define rustg_encode_base32(str, padding) rustg_hash_string(padding ? RUSTG_HASH_BASE32_PADDED : RUSTG_HASH_BASE32, str)
61+
/// Decode a given base32 (RFC4648) string
62+
/// If padding set to FALSE, decoding will not support padding characters.
63+
#define rustg_decode_base32(str, padding) RUSTG_CALL(RUST_G, "decode_base32")(str, "[padding ? 1 : 0]")
64+
1865
#ifdef RUSTG_OVERRIDE_BUILTINS
1966
#define md5(thing) (isfile(thing) ? rustg_hash_file(RUSTG_HASH_MD5, "[thing]") : rustg_hash_string(RUSTG_HASH_MD5, thing))
2067
#endif

‎src/error.rs‎

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,11 @@ pub enum Error {
6363
#[error(transparent)]
6464
Unzip(#[from] ZipError),
6565
#[cfg(feature = "hash")]
66-
#[error("Unable to decode hex value.")]
67-
HexDecode,
66+
#[error("TOTP seed is invalid length or not valid base32.")]
67+
BadSeed,
68+
#[cfg(feature = "hash")]
69+
#[error("TOTP may not be more than 8 digits.")]
70+
BadDigits,
6871
#[cfg(feature = "iconforge")]
6972
#[error("IconForge error: {0}")]
7073
IconForge(String),

0 commit comments

Comments
 (0)