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