hmac.rs 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. /* This file is part of DarkFi (https://dark.fi)
  2. *
  3. * Copyright (C) 2020-2023 Dyne.org foundation
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU Affero General Public License as
  7. * published by the Free Software Foundation, either version 3 of the
  8. * License, or (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU Affero General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU Affero General Public License
  16. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  17. */
  18. //! HMAC simplementation.
  19. //! https://en.wikipedia.org/wiki/Hmac
  20. use digest::{
  21. core_api::Block, crypto_common::BlockSizeUser, Digest, FixedOutput, Output, OutputSizeUser,
  22. Update,
  23. };
  24. const IPAD: u8 = 0x36;
  25. const OPAD: u8 = 0x5C;
  26. fn get_der_key<D: Digest + BlockSizeUser + Clone>(key: &[u8]) -> Block<D> {
  27. let mut der_key = Block::<D>::default();
  28. // The key that HMAC processes must be the same as the block size
  29. // of the underlying hash function. If the provided key is smaller
  30. // than that, we just pad it with zeroes. If it's larger, we hash
  31. // it and then pad it with zeroes.
  32. if key.len() <= der_key.len() {
  33. der_key[..key.len()].copy_from_slice(key);
  34. return der_key
  35. }
  36. let hash = D::digest(key);
  37. // All commonly used hash functions have block size bigger than
  38. // output hash size, but to be extra rigorous we handle the
  39. // potential uncommon cases as well. The condition is calculated
  40. // at compile time, so this branch gets removed from final binary.
  41. if hash.len() <= der_key.len() {
  42. der_key[..hash.len()].copy_from_slice(&hash);
  43. } else {
  44. let n = der_key.len();
  45. der_key.copy_from_slice(&hash[..n]);
  46. }
  47. der_key
  48. }
  49. /// HMAC for arbitrary hash functions that implement `Digest`
  50. /// and `BlockSizeUser` traits.
  51. #[derive(Clone)]
  52. pub struct Hmac<D: Digest + BlockSizeUser + Clone> {
  53. digest: D,
  54. opad_key: Block<D>,
  55. }
  56. impl<D: Digest + BlockSizeUser + Clone> Hmac<D> {
  57. /// Initialize a new `Hmac` with the given key.
  58. #[inline]
  59. pub fn new_from_slice(key: &[u8]) -> Self {
  60. let der_key = get_der_key::<D>(key);
  61. let mut ipad_key = der_key.clone();
  62. for b in ipad_key.iter_mut() {
  63. *b ^= IPAD;
  64. }
  65. let mut digest = D::new();
  66. digest.update(&ipad_key);
  67. let mut opad_key = der_key;
  68. for b in opad_key.iter_mut() {
  69. *b ^= OPAD;
  70. }
  71. Self { digest, opad_key }
  72. }
  73. /// Finalize the HMAC
  74. pub fn finalize(self) -> Output<D> {
  75. Output::<D>::clone_from_slice(&self.finalize_fixed())
  76. }
  77. }
  78. impl<D: Digest + BlockSizeUser + Clone> FixedOutput for Hmac<D> {
  79. fn finalize_into(self, out: &mut Output<Self>) {
  80. let mut h = D::new();
  81. h.update(&self.opad_key);
  82. h.update(&self.digest.finalize());
  83. h.finalize_into(out);
  84. }
  85. }
  86. impl<D: Digest + BlockSizeUser + Clone> OutputSizeUser for Hmac<D> {
  87. type OutputSize = D::OutputSize;
  88. }
  89. impl<D: Digest + BlockSizeUser + Clone> Update for Hmac<D> {
  90. /// Update the HMAC with the given data.
  91. fn update(&mut self, data: &[u8]) {
  92. self.digest.update(data);
  93. }
  94. }