hkdf.rs 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. //! https://tools.ietf.org/html/rfc5869
  2. use core::fmt;
  3. use sha2::{
  4. digest::{crypto_common::BlockSizeUser, typenum::Unsigned, Output, OutputSizeUser, Update},
  5. Digest,
  6. };
  7. use super::hmac::Hmac;
  8. #[derive(Copy, Clone, Debug)]
  9. pub struct InvalidPrkLength;
  10. impl fmt::Display for InvalidPrkLength {
  11. fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
  12. f.write_str("invalid pseudorandom key length, too short")
  13. }
  14. }
  15. // Structure for InvalidLength, used for output error handling.
  16. #[derive(Copy, Clone, Debug)]
  17. pub struct InvalidLength;
  18. impl fmt::Display for InvalidLength {
  19. fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
  20. f.write_str("invalid number of blocks, too large output")
  21. }
  22. }
  23. #[derive(Clone)]
  24. pub struct HkdfExtract<H: Digest + BlockSizeUser + Clone> {
  25. hmac: Hmac<H>,
  26. }
  27. impl<H: Digest + BlockSizeUser + Clone> HkdfExtract<H> {
  28. pub fn new(salt: &[u8]) -> Self {
  29. Self { hmac: Hmac::<H>::new_from_slice(salt) }
  30. }
  31. pub fn input_ikm(&mut self, ikm: &[u8]) {
  32. self.hmac.update(ikm);
  33. }
  34. pub fn finalize(self) -> (Output<H>, Hkdf<H>) {
  35. let prk = self.hmac.finalize();
  36. let hkdf = Hkdf::from_prk(&prk).expect("PRK size is correct");
  37. (prk, hkdf)
  38. }
  39. }
  40. #[derive(Clone)]
  41. pub struct Hkdf<H: Digest + BlockSizeUser + Clone> {
  42. hmac: Hmac<H>,
  43. }
  44. impl<H: Digest + BlockSizeUser + Clone> Hkdf<H> {
  45. pub fn new(salt: &[u8], ikm: &[u8]) -> Self {
  46. let (_, hkdf) = Self::extract(salt, ikm);
  47. hkdf
  48. }
  49. pub fn extract(salt: &[u8], ikm: &[u8]) -> (Output<H>, Self) {
  50. let mut extract_ctx = HkdfExtract::new(salt);
  51. extract_ctx.input_ikm(ikm);
  52. extract_ctx.finalize()
  53. }
  54. pub fn from_prk(prk: &[u8]) -> Result<Self, InvalidPrkLength> {
  55. if prk.len() < <H as OutputSizeUser>::OutputSize::to_usize() {
  56. return Err(InvalidPrkLength)
  57. }
  58. Ok(Self { hmac: Hmac::<H>::new_from_slice(prk) })
  59. }
  60. pub fn expand(&self, info: &[u8], okm: &mut [u8]) -> Result<(), InvalidLength> {
  61. self.expand_multi_info(&[info], okm)
  62. }
  63. pub fn expand_multi_info(&self, infos: &[&[u8]], okm: &mut [u8]) -> Result<(), InvalidLength> {
  64. let mut prev: Option<Output<H>> = None;
  65. let chunk_len = <H as OutputSizeUser>::OutputSize::USIZE;
  66. if okm.len() > chunk_len * 255 {
  67. return Err(InvalidLength)
  68. }
  69. for (block_n, block) in okm.chunks_mut(chunk_len).enumerate() {
  70. let mut hmac = self.hmac.clone();
  71. if let Some(ref prev) = prev {
  72. hmac.update(prev);
  73. }
  74. // Feed in the info components in sequence. This is equivalent
  75. // to feeding in the concatenation of all the info components.
  76. for info in infos {
  77. hmac.update(info);
  78. }
  79. hmac.update(&[block_n as u8 + 1]);
  80. let output = hmac.finalize();
  81. let block_len = block.len();
  82. block.copy_from_slice(&output[..block_len]);
  83. prev = Some(output);
  84. }
  85. Ok(())
  86. }
  87. }