chksum_sha1/
lib.rs

1//! This crate provides an implementation of the SHA-1 hash function with a straightforward interface for computing digests of bytes, files, directories, and more.
2//!
3//! For a low-level interface, you can explore the [`chksum_hash_sha1`] crate.
4//!
5//! # Setup
6//!
7//! To use this crate, add the following entry to your `Cargo.toml` file in the `dependencies` section:
8//!
9//! ```toml
10//! [dependencies]
11//! chksum-sha1 = "0.1.0"
12//! ```
13//!
14//! Alternatively, you can use the [`cargo add`](https://doc.rust-lang.org/cargo/commands/cargo-add.html) subcommand:
15//!
16//! ```sh
17//! cargo add chksum-sha1
18//! ```     
19//!
20//! # Usage
21//!
22//! Use the [`chksum`] function to calculate digest of file, directory and so on.
23//!
24//! ```rust
25//! # use std::path::Path;
26//! use std::fs::File;
27//!
28//! # use chksum_sha1::Result;
29//! use chksum_sha1 as sha1;
30//!
31//! # fn wrapper(path: &Path) -> Result<()> {
32//! let file = File::open(path)?;
33//! let digest = sha1::chksum(file)?;
34//! assert_eq!(
35//!     digest.to_hex_lowercase(),
36//!     "9fc42adac31303d68b444e6129f13f6093a0e045"
37//! );
38//! # Ok(())
39//! # }
40//! ```
41//!
42//! ## Asynchronous Runtime
43//!
44//! Use the [`async_chksum`] function to calculate digest of file, directory and so on.
45//!
46//! ```rust
47//! # #[cfg(feature = "async-runtime-tokio")]
48//! # {
49//! # use std::path::Path;
50//! # use chksum_sha1::Result;
51//! use chksum_sha1 as sha1;
52//! use tokio::fs::File;
53//!
54//! # async fn wrapper(path: &Path) -> Result<()> {
55//! let file = File::open(path).await?;
56//! let digest = sha1::async_chksum(file).await?;
57//! assert_eq!(
58//!     digest.to_hex_lowercase(),
59//!     "9fc42adac31303d68b444e6129f13f6093a0e045"
60//! );
61//! # Ok(())
62//! # }
63//! # }
64//! ```
65//!
66//! # Input Types
67//!
68//! ## Bytes
69//!
70//! ### Array
71//!
72//! ```rust
73//! # use chksum_sha1::Result;
74//! use chksum_sha1 as sha1;
75//!
76//! # fn wrapper() -> Result<()> {
77//! let data = [0, 1, 2, 3];
78//! let digest = sha1::chksum(data)?;
79//! assert_eq!(
80//!     digest.to_hex_lowercase(),
81//!     "9fc42adac31303d68b444e6129f13f6093a0e045"
82//! );
83//! # Ok(())
84//! # }
85//! ```
86//!
87//! ### Vec
88//!
89//! ```rust
90//! # use chksum_sha1::Result;
91//! use chksum_sha1 as sha1;
92//!
93//! # fn wrapper() -> Result<()> {
94//! let data = vec![0, 1, 2, 3];
95//! let digest = sha1::chksum(data)?;
96//! assert_eq!(
97//!     digest.to_hex_lowercase(),
98//!     "9fc42adac31303d68b444e6129f13f6093a0e045"
99//! );
100//! # Ok(())
101//! # }
102//! ```
103//!
104//! ### Slice
105//!
106//! ```rust
107//! # use chksum_sha1::Result;
108//! use chksum_sha1 as sha1;
109//!
110//! # fn wrapper() -> Result<()> {
111//! let data = &[0, 1, 2, 3];
112//! let digest = sha1::chksum(data)?;
113//! assert_eq!(
114//!     digest.to_hex_lowercase(),
115//!     "9fc42adac31303d68b444e6129f13f6093a0e045"
116//! );
117//! # Ok(())
118//! # }
119//! ```
120//!
121//! ## Strings
122//!
123//! ### str
124//!
125//! ```rust
126//! # use chksum_sha1::Result;
127//! use chksum_sha1 as sha1;
128//!
129//! # fn wrapper() -> Result<()> {
130//! let data = "&str";
131//! let digest = sha1::chksum(data)?;
132//! assert_eq!(
133//!     digest.to_hex_lowercase(),
134//!     "9fc42adac31303d68b444e6129f13f6093a0e045"
135//! );
136//! # Ok(())
137//! # }
138//! ```
139//!
140//! ### String
141//!
142//! ```rust
143//! # use chksum_sha1::Result;
144//! use chksum_sha1 as sha1;
145//!
146//! # fn wrapper() -> Result<()> {
147//! let data = String::from("String");
148//! let digest = sha1::chksum(data)?;
149//! assert_eq!(
150//!     digest.to_hex_lowercase(),
151//!     "9fc42adac31303d68b444e6129f13f6093a0e045"
152//! );
153//! # Ok(())
154//! # }
155//! ```
156//!
157//! ## File
158//!
159//! ```rust
160//! # use std::path::Path;
161//! use std::fs::File;
162//!
163//! # use chksum_sha1::Result;
164//! use chksum_sha1 as sha1;
165//!
166//! # fn wrapper(path: &Path) -> Result<()> {
167//! let file = File::open(path)?;
168//! let digest = sha1::chksum(file)?;
169//! assert_eq!(
170//!     digest.to_hex_lowercase(),
171//!     "9fc42adac31303d68b444e6129f13f6093a0e045"
172//! );
173//! # Ok(())
174//! # }
175//! ```
176//!
177//! ## Directory
178//!
179//! ```rust
180//! # use std::path::Path;
181//! use std::fs::read_dir;
182//!
183//! # use chksum_sha1::Result;
184//! use chksum_sha1 as sha1;
185//!
186//! # fn wrapper(path: &Path) -> Result<()> {
187//! let readdir = read_dir(path)?;
188//! let digest = sha1::chksum(readdir)?;
189//! assert_eq!(
190//!     digest.to_hex_lowercase(),
191//!     "9fc42adac31303d68b444e6129f13f6093a0e045"
192//! );
193//! # Ok(())
194//! # }
195//! ```
196//!
197//! ## Path
198//!
199//! ```rust
200//! # use std::path::Path;
201//! use std::path::PathBuf;
202//!
203//! # use chksum_sha1::Result;
204//! use chksum_sha1 as sha1;
205//!
206//! # fn wrapper(path: &Path) -> Result<()> {
207//! let path = PathBuf::from(path);
208//! let digest = sha1::chksum(path)?;
209//! assert_eq!(
210//!     digest.to_hex_lowercase(),
211//!     "9fc42adac31303d68b444e6129f13f6093a0e045"
212//! );
213//! # Ok(())
214//! # }
215//! ```
216//!
217//! ## Standard Input
218//!
219//! ```rust
220//! use std::io::stdin;
221//!
222//! # use chksum_sha1::Result;
223//! use chksum_sha1 as sha1;
224//!
225//! # fn wrapper() -> Result<()> {
226//! let stdin = stdin();
227//! let digest = sha1::chksum(stdin)?;
228//! assert_eq!(
229//!     digest.to_hex_lowercase(),
230//!     "9fc42adac31303d68b444e6129f13f6093a0e045"
231//! );
232//! # Ok(())
233//! # }
234//! ```
235//!
236//! # Features
237//!
238//! Cargo features are utilized to enable extra options.
239//!
240//! * `reader` enables the [`reader`] module with the [`Reader`] struct.
241//! * `writer` enables the [`writer`] module with the [`Writer`] struct.
242//!
243//! By default, neither of these features is enabled.
244//!
245//! To customize your setup, disable the default features and enable only those that you need in your `Cargo.toml` file:
246//!
247//! ```toml
248//! [dependencies]
249//! chksum-sha1 = { version = "0.1.0", features = ["reader", "writer"] }
250//! ```
251//!
252//! Alternatively, you can use the [`cargo add`](https://doc.rust-lang.org/cargo/commands/cargo-add.html) subcommand:
253//!
254//! ```shell
255//! cargo add chksum-sha1 --features reader,writer
256//! ```
257//!
258//! ## Asynchronous Runtime
259//!
260//! * `async-runtime-tokio`: Enables async interface for Tokio runtime.
261//!
262//! By default, neither of these features is enabled.
263//!
264//! # Disclaimer
265//!
266//! The SHA-1 hash function should be used only for backward compatibility due to security issues.
267//!
268//! Check [RFC 6194: Security Considerations for the SHA-0 and SHA-1 Message-Digest Algorithms](https://www.rfc-editor.org/rfc/rfc6194) for more details.
269//!
270//! # License
271//!
272//! This crate is licensed under the MIT License.
273
274#![cfg_attr(docsrs, feature(doc_auto_cfg))]
275#![forbid(unsafe_code)]
276
277#[cfg(feature = "reader")]
278pub mod reader;
279#[cfg(feature = "writer")]
280pub mod writer;
281
282use std::fmt::{self, Display, Formatter, LowerHex, UpperHex};
283
284use chksum_core as core;
285#[cfg(feature = "async-runtime-tokio")]
286#[doc(no_inline)]
287pub use chksum_core::AsyncChksumable;
288#[doc(no_inline)]
289pub use chksum_core::{Chksumable, Error, Hash, Hashable, Result};
290#[doc(no_inline)]
291pub use chksum_hash_sha1 as hash;
292
293#[cfg(all(feature = "reader", feature = "async-runtime-tokio"))]
294#[doc(inline)]
295pub use crate::reader::AsyncReader;
296#[cfg(feature = "reader")]
297#[doc(inline)]
298pub use crate::reader::Reader;
299#[cfg(all(feature = "writer", feature = "async-runtime-tokio"))]
300#[doc(inline)]
301pub use crate::writer::AsyncWriter;
302#[cfg(feature = "writer")]
303#[doc(inline)]
304pub use crate::writer::Writer;
305
306/// Creates a new hash.
307///
308/// # Example
309///
310/// ```rust
311/// use chksum_sha1 as sha1;
312///
313/// let mut hash = sha1::new();
314/// hash.update(b"example data");
315/// let digest = hash.digest();
316/// assert_eq!(
317///     digest.to_hex_lowercase(),
318///     "9fc42adac31303d68b444e6129f13f6093a0e045"
319/// );
320/// ```
321#[must_use]
322pub fn new() -> SHA1 {
323    SHA1::new()
324}
325
326/// Creates a default hash.
327///
328/// # Example
329///
330/// ```rust
331/// use chksum_sha1 as sha1;
332///
333/// let mut hash = sha1::default();
334/// hash.update(b"example data");
335/// let digest = hash.digest();
336/// assert_eq!(
337///     digest.to_hex_lowercase(),
338///     "9fc42adac31303d68b444e6129f13f6093a0e045"
339/// );
340/// ```
341#[must_use]
342pub fn default() -> SHA1 {
343    core::default()
344}
345
346/// Computes the hash of the given input.
347///
348/// # Example
349///
350/// ```rust
351/// use chksum_sha1 as sha1;
352///
353/// let data = b"example data";
354/// let digest = sha1::hash(data);
355/// assert_eq!(
356///     digest.to_hex_lowercase(),
357///     "9fc42adac31303d68b444e6129f13f6093a0e045"
358/// );
359/// ```
360pub fn hash(data: impl core::Hashable) -> Digest {
361    core::hash::<SHA1>(data)
362}
363
364/// Computes the hash of the given input.
365///
366/// # Example
367///
368/// ```rust
369/// use chksum_sha1 as sha1;
370///
371/// let data = b"example data";
372/// if let Ok(digest) = sha1::chksum(data) {
373///     assert_eq!(
374///         digest.to_hex_lowercase(),
375///         "9fc42adac31303d68b444e6129f13f6093a0e045"
376///     );
377/// }
378/// ```
379pub fn chksum(data: impl core::Chksumable) -> Result<Digest> {
380    core::chksum::<SHA1>(data)
381}
382
383/// Computes the hash of the given input.
384///
385/// # Example
386///
387/// ```rust
388/// use chksum_sha1 as sha1;
389///
390/// # async fn wrapper() {
391/// let data = b"example data";
392/// if let Ok(digest) = sha1::async_chksum(data).await {
393///     assert_eq!(
394///         digest.to_hex_lowercase(),
395///         "9fc42adac31303d68b444e6129f13f6093a0e045"
396///     );
397/// }
398/// # }
399/// ```
400#[cfg(feature = "async-runtime-tokio")]
401pub async fn async_chksum(data: impl core::AsyncChksumable) -> Result<Digest> {
402    core::async_chksum::<SHA1>(data).await
403}
404
405/// The SHA-1 hash instance.
406#[derive(Clone, Debug, Default, PartialEq, Eq)]
407pub struct SHA1 {
408    inner: hash::Update,
409}
410
411impl SHA1 {
412    /// Calculates the hash digest of an input data.
413    ///
414    /// # Example
415    ///
416    /// ```rust
417    /// use chksum_sha1::SHA1;
418    ///
419    /// let data = b"example data";
420    /// let digest = SHA1::hash(data);
421    /// assert_eq!(
422    ///     digest.to_hex_lowercase(),
423    ///     "9fc42adac31303d68b444e6129f13f6093a0e045"
424    /// );
425    /// ```
426    #[must_use]
427    pub fn hash<T>(data: T) -> Digest
428    where
429        T: AsRef<[u8]>,
430    {
431        let mut hash = Self::new();
432        hash.update(data);
433        hash.digest()
434    }
435
436    /// Creates a new hash.
437    ///
438    /// # Example
439    ///
440    /// ```rust
441    /// use chksum_sha1::SHA1;
442    ///
443    /// let mut hash = SHA1::new();
444    /// hash.update(b"example data");
445    /// let digest = hash.digest();
446    /// assert_eq!(
447    ///     digest.to_hex_lowercase(),
448    ///     "9fc42adac31303d68b444e6129f13f6093a0e045"
449    /// );
450    /// ```
451    #[must_use]
452    pub fn new() -> Self {
453        let inner = hash::Update::new();
454        Self { inner }
455    }
456
457    /// Updates the hash state with an input data.
458    ///
459    /// # Example
460    ///
461    /// ```rust
462    /// use chksum_sha1::SHA1;
463    ///
464    /// let mut hash = SHA1::new();
465    /// hash.update(b"example");
466    /// hash.update(" ");
467    /// hash.update("data");
468    /// let digest = hash.digest();
469    /// assert_eq!(
470    ///     digest.to_hex_lowercase(),
471    ///     "9fc42adac31303d68b444e6129f13f6093a0e045"
472    /// );
473    /// ```
474    pub fn update<T>(&mut self, data: T)
475    where
476        T: AsRef<[u8]>,
477    {
478        self.inner.update(data);
479    }
480
481    /// Resets the hash state to its initial state.
482    ///
483    /// # Example
484    ///
485    /// ```rust
486    /// use chksum_sha1::SHA1;
487    ///
488    /// let mut hash = SHA1::new();
489    /// hash.update(b"example data");
490    /// hash.reset();
491    /// let digest = hash.digest();
492    /// assert_eq!(
493    ///     digest.to_hex_lowercase(),
494    ///     "da39a3ee5e6b4b0d3255bfef95601890afd80709"
495    /// );
496    /// ```
497    pub fn reset(&mut self) {
498        self.inner.reset();
499    }
500
501    /// Produces the hash digest.
502    ///
503    /// # Example
504    ///
505    /// ```
506    /// use chksum_sha1::SHA1;
507    ///
508    /// let mut hash = SHA1::new();
509    /// let digest = hash.digest();
510    /// assert_eq!(
511    ///     digest.to_hex_lowercase(),
512    ///     "da39a3ee5e6b4b0d3255bfef95601890afd80709"
513    /// );
514    /// ```
515    #[must_use]
516    pub fn digest(&self) -> Digest {
517        self.inner.digest().into()
518    }
519}
520
521impl core::Hash for SHA1 {
522    type Digest = Digest;
523
524    fn update<T>(&mut self, data: T)
525    where
526        T: AsRef<[u8]>,
527    {
528        self.update(data);
529    }
530
531    fn reset(&mut self) {
532        self.reset();
533    }
534
535    fn digest(&self) -> Self::Digest {
536        self.digest()
537    }
538}
539
540/// A hash digest.
541pub struct Digest(hash::Digest);
542
543impl Digest {
544    /// Creates a new digest.
545    #[must_use]
546    pub const fn new(digest: [u8; hash::DIGEST_LENGTH_BYTES]) -> Self {
547        let inner = hash::Digest::new(digest);
548        Self(inner)
549    }
550
551    /// Returns a byte slice of the digest's contents.
552    #[must_use]
553    pub const fn as_bytes(&self) -> &[u8] {
554        let Self(inner) = self;
555        inner.as_bytes()
556    }
557
558    /// Consumes the digest, returning the digest bytes.
559    #[must_use]
560    pub fn into_inner(self) -> [u8; hash::DIGEST_LENGTH_BYTES] {
561        let Self(inner) = self;
562        inner.into_inner()
563    }
564
565    /// Returns a string in the lowercase hexadecimal representation.
566    ///
567    /// # Example
568    ///
569    /// ```rust
570    /// use chksum_sha1 as sha1;
571    ///
572    /// #[rustfmt::skip]
573    /// let digest = [
574    ///     0xDA, 0x39, 0xA3, 0xEE,
575    ///     0x5E, 0x6B, 0x4B, 0x0D,
576    ///     0x32, 0x55, 0xBF, 0xEF,
577    ///     0x95, 0x60, 0x18, 0x90,
578    ///     0xAF, 0xD8, 0x07, 0x09,
579    /// ];
580    /// let digest = sha1::Digest::new(digest);
581    /// assert_eq!(
582    ///     digest.to_hex_lowercase(),
583    ///     "da39a3ee5e6b4b0d3255bfef95601890afd80709"
584    /// );
585    /// ```
586    #[must_use]
587    pub fn to_hex_lowercase(&self) -> String {
588        let Self(inner) = self;
589        inner.to_hex_lowercase()
590    }
591
592    /// Returns a string in the uppercase hexadecimal representation.
593    ///
594    /// # Example
595    ///
596    /// ```rust
597    /// use chksum_sha1 as sha1;
598    ///
599    /// #[rustfmt::skip]
600    /// let digest = [
601    ///     0xDA, 0x39, 0xA3, 0xEE,
602    ///     0x5E, 0x6B, 0x4B, 0x0D,
603    ///     0x32, 0x55, 0xBF, 0xEF,
604    ///     0x95, 0x60, 0x18, 0x90,
605    ///     0xAF, 0xD8, 0x07, 0x09,
606    /// ];
607    /// let digest = sha1::Digest::new(digest);
608    /// assert_eq!(
609    ///     digest.to_hex_uppercase(),
610    ///     "DA39A3EE5E6B4B0D3255BFEF95601890AFD80709"
611    /// );
612    /// ```
613    #[must_use]
614    pub fn to_hex_uppercase(&self) -> String {
615        let Self(inner) = self;
616        inner.to_hex_uppercase()
617    }
618}
619
620impl core::Digest for Digest {}
621
622impl AsRef<[u8]> for Digest {
623    fn as_ref(&self) -> &[u8] {
624        let Self(inner) = self;
625        inner.as_bytes()
626    }
627}
628
629impl Display for Digest {
630    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
631        let Self(inner) = self;
632        Display::fmt(inner, f)
633    }
634}
635
636impl LowerHex for Digest {
637    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
638        let Self(inner) = self;
639        LowerHex::fmt(inner, f)
640    }
641}
642
643impl UpperHex for Digest {
644    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
645        let Self(inner) = self;
646        UpperHex::fmt(inner, f)
647    }
648}
649
650impl From<[u8; hash::DIGEST_LENGTH_BYTES]> for Digest {
651    fn from(digest: [u8; hash::DIGEST_LENGTH_BYTES]) -> Self {
652        Self::new(digest)
653    }
654}
655
656impl From<hash::Digest> for Digest {
657    fn from(digest: hash::Digest) -> Self {
658        Self(digest)
659    }
660}