Port skybot hash plugin as a module
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
b312ff0338
commit
d9e279d8ed
4 changed files with 333 additions and 4 deletions
250
src/bot/modules/hash.rs
Normal file
250
src/bot/modules/hash.rs
Normal file
|
|
@ -0,0 +1,250 @@
|
|||
use crate::bot::module::{Action, Command, CommandSpec, Module};
|
||||
|
||||
pub struct Hash;
|
||||
|
||||
const COMMANDS: &[CommandSpec] = &[
|
||||
CommandSpec { name: "md5", usage: "md5 <text>", about: "MD5 hex digest of <text>" },
|
||||
CommandSpec { name: "sha1", usage: "sha1 <text>", about: "SHA1 hex digest of <text>" },
|
||||
CommandSpec { name: "sha256", usage: "sha256 <text>", about: "SHA256 hex digest of <text>" },
|
||||
CommandSpec { name: "hash", usage: "hash <text>", about: "md5, sha1 and sha256 of <text>" },
|
||||
];
|
||||
|
||||
impl Module for Hash {
|
||||
fn name(&self) -> &'static str {
|
||||
"hash"
|
||||
}
|
||||
|
||||
fn commands(&self) -> &'static [CommandSpec] {
|
||||
COMMANDS
|
||||
}
|
||||
|
||||
fn on_command(&mut self, cmd: &Command) -> Vec<Action> {
|
||||
let input = cmd.args.join(" ");
|
||||
if input.is_empty() {
|
||||
return vec![Action::reply(format!("usage: {}{} <text>", cmd.prefix, cmd.name))];
|
||||
}
|
||||
let b = input.as_bytes();
|
||||
let reply = match cmd.name {
|
||||
"md5" => md5(b),
|
||||
"sha1" => sha1(b),
|
||||
"sha256" => sha256(b),
|
||||
"hash" => format!("md5: {}, sha1: {}, sha256: {}", md5(b), sha1(b), sha256(b)),
|
||||
_ => return vec![],
|
||||
};
|
||||
vec![Action::reply(reply)]
|
||||
}
|
||||
}
|
||||
|
||||
fn pad(data: &[u8], little_endian_len: bool) -> Vec<u8> {
|
||||
let bits = (data.len() as u64).wrapping_mul(8);
|
||||
let mut m = data.to_vec();
|
||||
m.push(0x80);
|
||||
while m.len() % 64 != 56 {
|
||||
m.push(0);
|
||||
}
|
||||
if little_endian_len {
|
||||
m.extend_from_slice(&bits.to_le_bytes());
|
||||
} else {
|
||||
m.extend_from_slice(&bits.to_be_bytes());
|
||||
}
|
||||
m
|
||||
}
|
||||
|
||||
fn to_hex(bytes: &[u8]) -> String {
|
||||
let mut s = String::with_capacity(bytes.len() * 2);
|
||||
for b in bytes {
|
||||
s.push_str(&format!("{b:02x}"));
|
||||
}
|
||||
s
|
||||
}
|
||||
|
||||
pub fn md5(data: &[u8]) -> String {
|
||||
const S: [u32; 64] = [
|
||||
7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 5, 9, 14, 20, 5, 9, 14, 20, 5,
|
||||
9, 14, 20, 5, 9, 14, 20, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 6, 10,
|
||||
15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21,
|
||||
];
|
||||
const K: [u32; 64] = [
|
||||
0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a, 0xa8304613,
|
||||
0xfd469501, 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, 0x6b901122, 0xfd987193,
|
||||
0xa679438e, 0x49b40821, 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, 0xd62f105d,
|
||||
0x02441453, 0xd8a1e681, 0xe7d3fbc8, 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
|
||||
0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, 0xfffa3942, 0x8771f681, 0x6d9d6122,
|
||||
0xfde5380c, 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, 0x289b7ec6, 0xeaa127fa,
|
||||
0xd4ef3085, 0x04881d05, 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, 0xf4292244,
|
||||
0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
|
||||
0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, 0xf7537e82, 0xbd3af235, 0x2ad7d2bb,
|
||||
0xeb86d391,
|
||||
];
|
||||
|
||||
let (mut a0, mut b0, mut c0, mut d0) =
|
||||
(0x67452301u32, 0xefcdab89u32, 0x98badcfeu32, 0x10325476u32);
|
||||
let msg = pad(data, true);
|
||||
for chunk in msg.chunks(64) {
|
||||
let mut m = [0u32; 16];
|
||||
for (i, word) in m.iter_mut().enumerate() {
|
||||
*word = u32::from_le_bytes([
|
||||
chunk[i * 4],
|
||||
chunk[i * 4 + 1],
|
||||
chunk[i * 4 + 2],
|
||||
chunk[i * 4 + 3],
|
||||
]);
|
||||
}
|
||||
let (mut a, mut b, mut c, mut d) = (a0, b0, c0, d0);
|
||||
for i in 0..64 {
|
||||
let (f, g) = if i < 16 {
|
||||
((b & c) | (!b & d), i)
|
||||
} else if i < 32 {
|
||||
((d & b) | (!d & c), (5 * i + 1) % 16)
|
||||
} else if i < 48 {
|
||||
(b ^ c ^ d, (3 * i + 5) % 16)
|
||||
} else {
|
||||
(c ^ (b | !d), (7 * i) % 16)
|
||||
};
|
||||
let f = f.wrapping_add(a).wrapping_add(K[i]).wrapping_add(m[g]);
|
||||
a = d;
|
||||
d = c;
|
||||
c = b;
|
||||
b = b.wrapping_add(f.rotate_left(S[i]));
|
||||
}
|
||||
a0 = a0.wrapping_add(a);
|
||||
b0 = b0.wrapping_add(b);
|
||||
c0 = c0.wrapping_add(c);
|
||||
d0 = d0.wrapping_add(d);
|
||||
}
|
||||
|
||||
let mut out = Vec::with_capacity(16);
|
||||
for v in [a0, b0, c0, d0] {
|
||||
out.extend_from_slice(&v.to_le_bytes());
|
||||
}
|
||||
to_hex(&out)
|
||||
}
|
||||
|
||||
pub fn sha1(data: &[u8]) -> String {
|
||||
let (mut h0, mut h1, mut h2, mut h3, mut h4) = (
|
||||
0x67452301u32,
|
||||
0xEFCDAB89u32,
|
||||
0x98BADCFEu32,
|
||||
0x10325476u32,
|
||||
0xC3D2E1F0u32,
|
||||
);
|
||||
let msg = pad(data, false);
|
||||
for chunk in msg.chunks(64) {
|
||||
let mut w = [0u32; 80];
|
||||
for i in 0..16 {
|
||||
w[i] = u32::from_be_bytes([
|
||||
chunk[i * 4],
|
||||
chunk[i * 4 + 1],
|
||||
chunk[i * 4 + 2],
|
||||
chunk[i * 4 + 3],
|
||||
]);
|
||||
}
|
||||
for i in 16..80 {
|
||||
w[i] = (w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]).rotate_left(1);
|
||||
}
|
||||
let (mut a, mut b, mut c, mut d, mut e) = (h0, h1, h2, h3, h4);
|
||||
for (i, &word) in w.iter().enumerate() {
|
||||
let (f, k) = if i < 20 {
|
||||
((b & c) | (!b & d), 0x5A827999u32)
|
||||
} else if i < 40 {
|
||||
(b ^ c ^ d, 0x6ED9EBA1u32)
|
||||
} else if i < 60 {
|
||||
((b & c) | (b & d) | (c & d), 0x8F1BBCDCu32)
|
||||
} else {
|
||||
(b ^ c ^ d, 0xCA62C1D6u32)
|
||||
};
|
||||
let temp = a
|
||||
.rotate_left(5)
|
||||
.wrapping_add(f)
|
||||
.wrapping_add(e)
|
||||
.wrapping_add(k)
|
||||
.wrapping_add(word);
|
||||
e = d;
|
||||
d = c;
|
||||
c = b.rotate_left(30);
|
||||
b = a;
|
||||
a = temp;
|
||||
}
|
||||
h0 = h0.wrapping_add(a);
|
||||
h1 = h1.wrapping_add(b);
|
||||
h2 = h2.wrapping_add(c);
|
||||
h3 = h3.wrapping_add(d);
|
||||
h4 = h4.wrapping_add(e);
|
||||
}
|
||||
|
||||
let mut out = Vec::with_capacity(20);
|
||||
for v in [h0, h1, h2, h3, h4] {
|
||||
out.extend_from_slice(&v.to_be_bytes());
|
||||
}
|
||||
to_hex(&out)
|
||||
}
|
||||
|
||||
pub fn sha256(data: &[u8]) -> String {
|
||||
const K: [u32; 64] = [
|
||||
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4,
|
||||
0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe,
|
||||
0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f,
|
||||
0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
|
||||
0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc,
|
||||
0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b,
|
||||
0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116,
|
||||
0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
|
||||
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7,
|
||||
0xc67178f2,
|
||||
];
|
||||
|
||||
let mut h: [u32; 8] = [
|
||||
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab,
|
||||
0x5be0cd19,
|
||||
];
|
||||
let msg = pad(data, false);
|
||||
for chunk in msg.chunks(64) {
|
||||
let mut w = [0u32; 64];
|
||||
for i in 0..16 {
|
||||
w[i] = u32::from_be_bytes([
|
||||
chunk[i * 4],
|
||||
chunk[i * 4 + 1],
|
||||
chunk[i * 4 + 2],
|
||||
chunk[i * 4 + 3],
|
||||
]);
|
||||
}
|
||||
for i in 16..64 {
|
||||
let s0 = w[i - 15].rotate_right(7) ^ w[i - 15].rotate_right(18) ^ (w[i - 15] >> 3);
|
||||
let s1 = w[i - 2].rotate_right(17) ^ w[i - 2].rotate_right(19) ^ (w[i - 2] >> 10);
|
||||
w[i] = w[i - 16]
|
||||
.wrapping_add(s0)
|
||||
.wrapping_add(w[i - 7])
|
||||
.wrapping_add(s1);
|
||||
}
|
||||
let mut v = h;
|
||||
for i in 0..64 {
|
||||
let s1 = v[4].rotate_right(6) ^ v[4].rotate_right(11) ^ v[4].rotate_right(25);
|
||||
let ch = (v[4] & v[5]) ^ (!v[4] & v[6]);
|
||||
let temp1 = v[7]
|
||||
.wrapping_add(s1)
|
||||
.wrapping_add(ch)
|
||||
.wrapping_add(K[i])
|
||||
.wrapping_add(w[i]);
|
||||
let s0 = v[0].rotate_right(2) ^ v[0].rotate_right(13) ^ v[0].rotate_right(22);
|
||||
let maj = (v[0] & v[1]) ^ (v[0] & v[2]) ^ (v[1] & v[2]);
|
||||
let temp2 = s0.wrapping_add(maj);
|
||||
v[7] = v[6];
|
||||
v[6] = v[5];
|
||||
v[5] = v[4];
|
||||
v[4] = v[3].wrapping_add(temp1);
|
||||
v[3] = v[2];
|
||||
v[2] = v[1];
|
||||
v[1] = v[0];
|
||||
v[0] = temp1.wrapping_add(temp2);
|
||||
}
|
||||
for i in 0..8 {
|
||||
h[i] = h[i].wrapping_add(v[i]);
|
||||
}
|
||||
}
|
||||
|
||||
let mut out = Vec::with_capacity(32);
|
||||
for v in h {
|
||||
out.extend_from_slice(&v.to_be_bytes());
|
||||
}
|
||||
to_hex(&out)
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
pub mod builtins;
|
||||
pub mod dice;
|
||||
pub mod hash;
|
||||
pub mod weather;
|
||||
|
||||
use super::module::Module;
|
||||
|
|
@ -8,6 +9,7 @@ pub fn all(network: &str) -> Vec<Box<dyn Module>> {
|
|||
vec![
|
||||
Box::new(builtins::Builtins),
|
||||
Box::new(dice::Dice::new()),
|
||||
Box::new(hash::Hash),
|
||||
Box::new(weather::Weather::new(network)),
|
||||
]
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue