tencentcloud_cls_sdk_rust/
sign.rs1extern crate chrono;
2extern crate rustc_serialize;
3extern crate sha1;
4extern crate url;
5
6use std::collections::HashMap;
7
8use rustc_serialize::hex::ToHex;
9
10pub const SHA1_DIGEST_BYTES: usize = 20;
11const SHA1_KEY_BYTES: usize = 64;
12
13pub fn cal_sha1_sum(msg: &str) -> String {
14 sha1::Sha1::from(msg).digest().to_string()
15}
16
17pub fn cal_sha1_hmac_digest(key: &[u8], message: &[u8]) -> [u8; SHA1_DIGEST_BYTES] {
18 let inner_pad_byte: u8 = 0x36;
19 let outer_pad_byte: u8 = 0x5c;
20 let key_pad_byte: u8 = 0x00;
21
22 let mut sha1_ctx = sha1::Sha1::new();
23 let auth_key: &mut [u8; SHA1_KEY_BYTES] = &mut [key_pad_byte; SHA1_KEY_BYTES];
24
25 if key.len() > SHA1_KEY_BYTES {
26 sha1_ctx.update(key);
27 auth_key[..SHA1_DIGEST_BYTES].copy_from_slice(&(sha1_ctx.digest().bytes()));
28 sha1_ctx.reset();
29 } else {
30 auth_key[..key.len()].copy_from_slice(key);
31 }
32
33 let mut inner_padding: [u8; SHA1_KEY_BYTES] = [inner_pad_byte; SHA1_KEY_BYTES];
34 let mut outer_padding: [u8; SHA1_KEY_BYTES] = [outer_pad_byte; SHA1_KEY_BYTES];
35
36 for offset in 0..auth_key.len() {
37 inner_padding[offset] ^= auth_key[offset];
38 outer_padding[offset] ^= auth_key[offset];
39 }
40 sha1_ctx.update(&inner_padding);
41 sha1_ctx.update(message);
42 let inner_hash = sha1_ctx.digest().bytes();
43 sha1_ctx.reset();
44 sha1_ctx.update(&outer_padding);
45 sha1_ctx.update(&inner_hash);
46 sha1_ctx.digest().bytes()
47}
48
49pub fn signature(
50 secret_id: &str,
51 secret_key: &str,
52 method: &str,
53 path: &str,
54 params: &HashMap<String, String>,
55 headers: &HashMap<String, String>,
56 expire: i64,
57) -> String {
58 let mut signed_header_list: Vec<String> = vec![];
59 let mut signed_parameter_list: Vec<String> = vec![];
60
61 let mut hs = url::form_urlencoded::Serializer::new(String::new());
62 for (key, val) in headers {
63 let lower_key = key.to_lowercase();
64 if lower_key == "content-type"
65 || lower_key == "content-md5"
66 || lower_key == "host"
67 || lower_key.starts_with('x')
68 {
69 hs.append_pair(lower_key.as_str(), val.as_str());
70 signed_header_list.push(lower_key.clone());
71 }
72 }
73 signed_header_list.sort();
74 let format_headers = hs.finish().as_str().to_string();
75
76 let mut ps = url::form_urlencoded::Serializer::new(String::new());
77 for (key, val) in params {
78 let lower_key = key.to_lowercase();
79 ps.append_pair(lower_key.as_str(), val.as_str());
80 signed_parameter_list.push(lower_key.clone());
81 }
82 let format_parameters = ps.finish().as_str().to_string();
83 signed_parameter_list.sort();
84 let format_string = format!(
85 "{}\n{}\n{}\n{}\n",
86 method.to_lowercase(),
87 path,
88 format_parameters,
89 format_headers
90 );
91
92 let sign_time = format!(
93 "{};{}",
94 chrono::Local::now().timestamp() - 60,
95 chrono::Local::now().timestamp() + expire
96 );
97 let string_to_sign = format!(
98 "sha1\n{}\n{}\n",
99 sign_time.clone(),
100 cal_sha1_sum(format_string.as_str())
101 );
102
103 let sign_key = cal_sha1_hmac_digest(secret_key.as_bytes(), sign_time.as_bytes()).to_hex();
104 let signature = cal_sha1_hmac_digest(sign_key.as_bytes(), string_to_sign.as_bytes()).to_hex();
105
106 vec![
107 "q-sign-algorithm=sha1".to_string(),
108 format!("q-ak={}", secret_id),
109 format!("q-sign-time={}", sign_time),
110 format!("q-key-time={}", sign_time),
111 format!("q-header-list={}", signed_header_list.join(";")),
112 format!("q-url-param-list={}", signed_parameter_list.join(";")),
113 format!("q-signature={}", signature),
114 ]
115 .join("&")
116}
117
118#[cfg(test)]
119mod tests {
120 use std::collections::HashMap;
121
122 use crate::sign::signature;
123
124 #[test]
125 fn test_url_encode() {
126 let mut headers: HashMap<String, String> = HashMap::new();
127 let params: HashMap<String, String> = HashMap::new();
128 headers.insert(
129 "Host".to_string(),
130 "ap-shanghai.cls.myqcloud.com".to_string(),
131 );
132 headers.insert("User-Agent".to_string(), "AuthSDK".to_string());
133 headers.insert("Content-Type".to_string(), "application/json".to_string());
134 headers.insert(
135 "Content-MD5".to_string(),
136 "f9c7fc33c7eab68dfa8a52508d1f4659".to_string(),
137 );
138
139 let data = signature(
145 "SecretIdExample_XXXXXXXXXXXXXXXXXXXXX",
146 "SecretKeyExample_XXXXXXXXXXXXXXXX",
147 "GET",
148 "/logset",
149 ¶ms,
150 &headers,
151 300,
152 );
153 println!("{}", data)
154 }
155}