@@ -10,6 +10,129 @@ use std::collections::HashMap;
1010use std:: rc:: Rc ;
1111use 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+
13136impl 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