Skip to content

Commit d60cd8a

Browse files
Merge pull request #227 from Tcode-Motion/code-health-extract-crypto-2408439689701466053
🧹 [Extract cryptographic functions]
2 parents 896d5fb + 36aad4b commit d60cd8a

1 file changed

Lines changed: 127 additions & 142 deletions

File tree

‎stdlib/src/crypto.rs‎

Lines changed: 127 additions & 142 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,129 @@ use std::collections::HashMap;
1010
use std::rc::Rc;
1111
use techscript_runtime::{error::RuntimeError, error::RuntimeErrorKind, value::RuntimeValue};
1212

13+
fn helper_aes_encrypt(args: &[RuntimeValue]) -> Result<RuntimeValue, RuntimeError> {
14+
let key_str = args[0].try_into_string()?;
15+
let text = args[1].try_into_string()?;
16+
17+
// Derive a 32-byte key from key_str using Sha256
18+
let mut hasher = sha2::Sha256::new();
19+
hasher.update(key_str.as_bytes());
20+
let hashed_key = hasher.finalize();
21+
22+
let cipher = Aes256Gcm::new_from_slice(&hashed_key).map_err(|e| {
23+
RuntimeError::new(
24+
RuntimeErrorKind::InvalidOperation(format!("AES key init error: {}", e)),
25+
None,
26+
None,
27+
)
28+
})?;
29+
30+
// Generate a random 12-byte nonce for secure encryption
31+
let mut nonce_bytes = [0u8; 12];
32+
rand::thread_rng().fill(&mut nonce_bytes);
33+
let nonce = Nonce::from_slice(&nonce_bytes);
34+
35+
let ciphertext = cipher.encrypt(nonce, text.as_bytes()).map_err(|e| {
36+
RuntimeError::new(
37+
RuntimeErrorKind::InvalidOperation(format!("AES encryption error: {}", e)),
38+
None,
39+
None,
40+
)
41+
})?;
42+
43+
// Prepend nonce to ciphertext
44+
let mut combined = nonce_bytes.to_vec();
45+
combined.extend_from_slice(&ciphertext);
46+
47+
// Hex encode ciphertext
48+
// ⚡ Bolt Performance Optimization: Replaced iterative format! with hex::encode for single-allocation hex string conversion.
49+
let hex_ciphertext = hex::encode(combined);
50+
Ok(RuntimeValue::Str(hex_ciphertext))
51+
}
52+
53+
fn helper_aes_decrypt(args: &[RuntimeValue]) -> Result<RuntimeValue, RuntimeError> {
54+
let key_str = args[0].try_into_string()?;
55+
let hex_ciphertext = args[1].try_into_string()?;
56+
57+
// Decode hex string
58+
// ⚡ Bolt Performance Optimization: Replaced manual hex decoding with hex::decode for zero-allocation decoding.
59+
let ciphertext = hex::decode(&hex_ciphertext).map_err(|_| {
60+
RuntimeError::new(
61+
RuntimeErrorKind::InvalidOperation("Invalid hex ciphertext".to_string()),
62+
None,
63+
None,
64+
)
65+
})?;
66+
67+
let mut hasher = sha2::Sha256::new();
68+
hasher.update(key_str.as_bytes());
69+
let hashed_key = hasher.finalize();
70+
71+
let cipher = Aes256Gcm::new_from_slice(&hashed_key).map_err(|e| {
72+
RuntimeError::new(
73+
RuntimeErrorKind::InvalidOperation(format!("AES key init error: {}", e)),
74+
None,
75+
None,
76+
)
77+
})?;
78+
79+
if ciphertext.len() < 12 {
80+
return Err(RuntimeError::new(
81+
RuntimeErrorKind::InvalidOperation("Ciphertext too short (missing nonce)".to_string()),
82+
None,
83+
None,
84+
));
85+
}
86+
87+
let nonce_bytes = &ciphertext[0..12];
88+
let actual_ciphertext = &ciphertext[12..];
89+
let nonce = Nonce::from_slice(nonce_bytes);
90+
91+
let plaintext_bytes = cipher.decrypt(nonce, actual_ciphertext).map_err(|e| {
92+
RuntimeError::new(
93+
RuntimeErrorKind::InvalidOperation(format!("AES decryption error: {}", e)),
94+
None,
95+
None,
96+
)
97+
})?;
98+
99+
let plaintext = String::from_utf8(plaintext_bytes).map_err(|e| {
100+
RuntimeError::new(
101+
RuntimeErrorKind::InvalidOperation(format!("Invalid UTF-8 in plaintext: {}", e)),
102+
None,
103+
None,
104+
)
105+
})?;
106+
107+
Ok(RuntimeValue::Str(plaintext))
108+
}
109+
110+
fn helper_bcrypt_hash(args: &[RuntimeValue]) -> Result<RuntimeValue, RuntimeError> {
111+
let password = args[0].try_into_string()?;
112+
let cost = args[1].try_into_int()? as u32;
113+
let hashed = bcrypt::hash(&password, cost).map_err(|e| {
114+
RuntimeError::new(
115+
RuntimeErrorKind::InvalidOperation(format!("Bcrypt hash error: {}", e)),
116+
None,
117+
None,
118+
)
119+
})?;
120+
Ok(RuntimeValue::Str(hashed))
121+
}
122+
123+
fn helper_bcrypt_verify(args: &[RuntimeValue]) -> Result<RuntimeValue, RuntimeError> {
124+
let password = args[0].try_into_string()?;
125+
let hash = args[1].try_into_string()?;
126+
let matches = bcrypt::verify(&password, &hash).map_err(|e| {
127+
RuntimeError::new(
128+
RuntimeErrorKind::InvalidOperation(format!("Bcrypt verify error: {}", e)),
129+
None,
130+
None,
131+
)
132+
})?;
133+
Ok(RuntimeValue::Bool(matches))
134+
}
135+
13136
impl StdlibRegistry {
14137
pub fn register_crypto(&mut self) {
15138
let mut exports: HashMap<String, Rc<dyn techscript_runtime::function::Callable>> =
@@ -20,51 +143,7 @@ impl StdlibRegistry {
20143
Rc::new(StdFunction {
21144
name: "aes_encrypt".to_string(),
22145
arity: 2,
23-
callback: |_ctx, args| {
24-
let key_str = args[0].try_into_string()?;
25-
let text = args[1].try_into_string()?;
26-
27-
// Derive a 32-byte key from key_str using Sha256
28-
let mut hasher = sha2::Sha256::new();
29-
hasher.update(key_str.as_bytes());
30-
let hashed_key = hasher.finalize();
31-
32-
let cipher = Aes256Gcm::new_from_slice(&hashed_key).map_err(|e| {
33-
RuntimeError::new(
34-
RuntimeErrorKind::InvalidOperation(format!(
35-
"AES key init error: {}",
36-
e
37-
)),
38-
None,
39-
None,
40-
)
41-
})?;
42-
43-
// Generate a random 12-byte nonce for secure encryption
44-
let mut nonce_bytes = [0u8; 12];
45-
rand::thread_rng().fill(&mut nonce_bytes);
46-
let nonce = Nonce::from_slice(&nonce_bytes);
47-
48-
let ciphertext = cipher.encrypt(nonce, text.as_bytes()).map_err(|e| {
49-
RuntimeError::new(
50-
RuntimeErrorKind::InvalidOperation(format!(
51-
"AES encryption error: {}",
52-
e
53-
)),
54-
None,
55-
None,
56-
)
57-
})?;
58-
59-
// Prepend nonce to ciphertext
60-
let mut combined = nonce_bytes.to_vec();
61-
combined.extend_from_slice(&ciphertext);
62-
63-
// Hex encode ciphertext
64-
// ⚡ Bolt Performance Optimization: Replaced iterative format! with hex::encode for single-allocation hex string conversion.
65-
let hex_ciphertext = hex::encode(combined);
66-
Ok(RuntimeValue::Str(hex_ciphertext))
67-
},
146+
callback: |_ctx, args| helper_aes_encrypt(args),
68147
}),
69148
);
70149

@@ -73,76 +152,7 @@ impl StdlibRegistry {
73152
Rc::new(StdFunction {
74153
name: "aes_decrypt".to_string(),
75154
arity: 2,
76-
callback: |_ctx, args| {
77-
let key_str = args[0].try_into_string()?;
78-
let hex_ciphertext = args[1].try_into_string()?;
79-
80-
// Decode hex string
81-
// ⚡ Bolt Performance Optimization: Replaced manual hex decoding with hex::decode for zero-allocation decoding.
82-
let ciphertext = hex::decode(&hex_ciphertext).map_err(|_| {
83-
RuntimeError::new(
84-
RuntimeErrorKind::InvalidOperation(
85-
"Invalid hex ciphertext".to_string(),
86-
),
87-
None,
88-
None,
89-
)
90-
})?;
91-
92-
let mut hasher = sha2::Sha256::new();
93-
hasher.update(key_str.as_bytes());
94-
let hashed_key = hasher.finalize();
95-
96-
let cipher = Aes256Gcm::new_from_slice(&hashed_key).map_err(|e| {
97-
RuntimeError::new(
98-
RuntimeErrorKind::InvalidOperation(format!(
99-
"AES key init error: {}",
100-
e
101-
)),
102-
None,
103-
None,
104-
)
105-
})?;
106-
107-
if ciphertext.len() < 12 {
108-
return Err(RuntimeError::new(
109-
RuntimeErrorKind::InvalidOperation(
110-
"Ciphertext too short (missing nonce)".to_string(),
111-
),
112-
None,
113-
None,
114-
));
115-
}
116-
117-
let nonce_bytes = &ciphertext[0..12];
118-
let actual_ciphertext = &ciphertext[12..];
119-
let nonce = Nonce::from_slice(nonce_bytes);
120-
121-
let plaintext_bytes =
122-
cipher.decrypt(nonce, actual_ciphertext).map_err(|e| {
123-
RuntimeError::new(
124-
RuntimeErrorKind::InvalidOperation(format!(
125-
"AES decryption error: {}",
126-
e
127-
)),
128-
None,
129-
None,
130-
)
131-
})?;
132-
133-
let plaintext = String::from_utf8(plaintext_bytes).map_err(|e| {
134-
RuntimeError::new(
135-
RuntimeErrorKind::InvalidOperation(format!(
136-
"Invalid UTF-8 in plaintext: {}",
137-
e
138-
)),
139-
None,
140-
None,
141-
)
142-
})?;
143-
144-
Ok(RuntimeValue::Str(plaintext))
145-
},
155+
callback: |_ctx, args| helper_aes_decrypt(args),
146156
}),
147157
);
148158

@@ -151,18 +161,7 @@ impl StdlibRegistry {
151161
Rc::new(StdFunction {
152162
name: "bcrypt_hash".to_string(),
153163
arity: 2,
154-
callback: |_ctx, args| {
155-
let password = args[0].try_into_string()?;
156-
let cost = args[1].try_into_int()? as u32;
157-
let hashed = bcrypt::hash(&password, cost).map_err(|e| {
158-
RuntimeError::new(
159-
RuntimeErrorKind::InvalidOperation(format!("Bcrypt hash error: {}", e)),
160-
None,
161-
None,
162-
)
163-
})?;
164-
Ok(RuntimeValue::Str(hashed))
165-
},
164+
callback: |_ctx, args| helper_bcrypt_hash(args),
166165
}),
167166
);
168167

@@ -171,21 +170,7 @@ impl StdlibRegistry {
171170
Rc::new(StdFunction {
172171
name: "bcrypt_verify".to_string(),
173172
arity: 2,
174-
callback: |_ctx, args| {
175-
let password = args[0].try_into_string()?;
176-
let hash = args[1].try_into_string()?;
177-
let matches = bcrypt::verify(&password, &hash).map_err(|e| {
178-
RuntimeError::new(
179-
RuntimeErrorKind::InvalidOperation(format!(
180-
"Bcrypt verify error: {}",
181-
e
182-
)),
183-
None,
184-
None,
185-
)
186-
})?;
187-
Ok(RuntimeValue::Bool(matches))
188-
},
173+
callback: |_ctx, args| helper_bcrypt_verify(args),
189174
}),
190175
);
191176

0 commit comments

Comments
 (0)