oauth1_request/signature_method/
hmac_sha1.rs1use core::fmt::{self, Debug, Display, Formatter, Write};
8
9use digest::core_api::BlockSizeUser;
10use digest::generic_array::sequence::GenericSequence;
11use digest::generic_array::GenericArray;
12use digest::OutputSizeUser;
13use hmac::{Hmac, Mac};
14use sha1::{Digest, Sha1};
15
16use super::digest_common::{Base64PercentEncodeDisplay, UpdateSign};
17use super::{write_signing_key, Sign, SignatureMethod};
18
19#[derive(Clone, Copy, Default)]
21pub struct HmacSha1 {
22 _priv: (),
23}
24
25#[derive(Clone, Debug)]
27pub struct HmacSha1Sign {
28 inner: UpdateSign<Hmac<Sha1>>,
29}
30
31pub struct HmacSha1Signature {
33 inner: Base64PercentEncodeDisplay<GenericArray<u8, <Sha1 as OutputSizeUser>::OutputSize>>,
34}
35
36pub const HMAC_SHA1: HmacSha1 = HmacSha1::new();
38
39#[derive(Clone)]
40enum SigningKey {
41 Key {
42 buf: GenericArray<u8, <Sha1 as BlockSizeUser>::BlockSize>,
43 pos: usize,
44 },
45 Digest(Sha1),
46}
47
48impl HmacSha1 {
49 pub const fn new() -> Self {
51 HmacSha1 { _priv: () }
52 }
53}
54
55impl Debug for HmacSha1 {
56 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
57 #[derive(Debug)]
58 struct HmacSha1;
59 HmacSha1.fmt(f)
60 }
61}
62
63impl SignatureMethod for HmacSha1 {
64 type Sign = HmacSha1Sign;
65
66 fn sign_with(self, client_secret: &str, token_secret: Option<&str>) -> HmacSha1Sign {
67 let mut key = SigningKey::new();
68 write_signing_key(&mut key, client_secret, token_secret).unwrap();
69 HmacSha1Sign {
70 inner: UpdateSign(key.into_hmac()),
71 }
72 }
73}
74
75impl Sign for HmacSha1Sign {
76 type Signature = HmacSha1Signature;
77
78 fn get_signature_method_name(&self) -> &'static str {
79 "HMAC-SHA1"
80 }
81
82 fn request_method(&mut self, method: &str) {
83 self.inner.request_method(method);
84 }
85
86 fn uri<T: Display>(&mut self, uri: T) {
87 self.inner.uri(uri);
88 }
89
90 fn parameter<V: Display>(&mut self, key: &str, value: V) {
91 self.inner.parameter(key, value);
92 }
93
94 fn delimiter(&mut self) {
95 self.inner.delimiter();
96 }
97
98 fn end(self) -> HmacSha1Signature {
99 HmacSha1Signature {
100 inner: Base64PercentEncodeDisplay(self.inner.0.finalize().into_bytes()),
101 }
102 }
103}
104
105impl Display for HmacSha1Signature {
106 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
107 self.inner.fmt(f)
108 }
109}
110
111impl SigningKey {
112 fn new() -> Self {
113 SigningKey::Key {
114 buf: GenericArray::generate(|_| 0),
115 pos: 0,
116 }
117 }
118
119 fn write(&mut self, input: &[u8]) {
120 *self = match *self {
121 SigningKey::Key {
122 ref mut buf,
123 ref mut pos,
124 } => {
125 if input.len() > buf.len() - *pos {
126 let mut digest = Sha1::default();
127 digest.update(&buf[..*pos]);
128 digest.update(input);
129 SigningKey::Digest(digest)
130 } else {
131 buf[*pos..(*pos + input.len())].copy_from_slice(input);
132 *pos += input.len();
133 return;
134 }
135 }
136 SigningKey::Digest(ref mut digest) => {
137 digest.update(input);
138 return;
139 }
140 };
141 }
142
143 fn into_hmac(self) -> Hmac<Sha1> {
144 match self {
145 SigningKey::Key { ref buf, pos } => Hmac::new_from_slice(&buf[..pos]).unwrap(),
146 SigningKey::Digest(digest) => Hmac::new_from_slice(&digest.finalize()).unwrap(),
147 }
148 }
149}
150
151impl Write for SigningKey {
152 fn write_str(&mut self, s: &str) -> fmt::Result {
153 self.write(s.as_bytes());
154 Ok(())
155 }
156}
157
158#[cfg(test)]
159mod tests {
160 extern crate alloc;
161
162 use alloc::vec::Vec;
163
164 use digest::generic_array::typenum::Unsigned;
165
166 use super::*;
167
168 #[test]
169 fn signing_key() {
170 let mut sk = SigningKey::new();
171 let mut k = Vec::new();
172
173 for _ in 0..=<Sha1 as BlockSizeUser>::BlockSize::to_usize() + 1 {
174 sk.write(&[1]);
175 k.extend(&[1]);
176
177 let mut skm = sk.clone().into_hmac();
178 let mut m = Hmac::<Sha1>::new_from_slice(&k).unwrap();
179 skm.update(b"test");
180 m.update(b"test");
181
182 assert_eq!(skm.finalize().into_bytes(), m.finalize().into_bytes());
183 }
184 }
185}