SHA-1

Header: #include <cryptopp/sha.h> | Namespace: CryptoPP Since: Crypto++ 1.0 Thread Safety: Not thread-safe per instance; use separate instances per thread

⚠️

SHA-1 is cryptographically broken and should not be used for security purposes.

SHA-1 has known collision attacks (SHAttered, 2017) and should only be used for:

  • Legacy system compatibility
  • Non-security checksums
  • Git commit hashes (being phased out)

For new applications, use SHA-256, SHA-3, or BLAKE3.

SHA-1 (Secure Hash Algorithm 1) is a 160-bit cryptographic hash function designed by the NSA. While once widely used, it is now considered broken for security applications due to practical collision attacks.

Quick Example

#include <cryptopp/sha.h>
#include <cryptopp/hex.h>
#include <cryptopp/filters.h>
#include <iostream>

int main() {
    using namespace CryptoPP;

    // WARNING: SHA-1 is deprecated for security use
    SHA1 hash;
    std::string message = "Hello, World!";
    std::string digest, hexOutput;

    StringSource(message, true,
        new HashFilter(hash,
            new StringSink(digest)
        )
    );

    StringSource(digest, true,
        new HexEncoder(new StringSink(hexOutput))
    );

    std::cout << "SHA-1: " << hexOutput << std::endl;
    // Output: 0A0A9F2A6772942557AB5355D76AF442F8F65E01

    return 0;
}

When SHA-1 Is Still Used

Despite being broken, SHA-1 remains in use for:

Use CaseStatusRecommendation
Git commits⚠️ LegacyGit moving to SHA-256
HMAC-SHA1⚠️ Still secure*Prefer HMAC-SHA256
Legacy TLS⚠️ DeprecatedUpgrade to TLS 1.3
Code signing❌ InsecureUse SHA-256
Certificates❌ RejectedUse SHA-256+
Checksums (non-security)⚠️ OKConsider faster alternatives

*HMAC construction doesn’t require collision resistance, but migration is recommended.

Class: SHA1

Constants

static const int DIGESTSIZE = 20;   // 160 bits (20 bytes)
static const int BLOCKSIZE = 64;    // 512 bits (64 bytes)

Methods

Update()

void Update(const byte* input, size_t length);

Add data to hash computation.

Final()

void Final(byte* digest);

Finalize and get 20-byte digest.

Restart()

void Restart();

Reset to initial state.

CalculateDigest() - Static

static void CalculateDigest(byte* digest,
                            const byte* input,
                            size_t length);

One-shot hashing.

VerifyDigest() - Static

static bool VerifyDigest(const byte* digest,
                         const byte* input,
                         size_t length);

Verify hash (constant-time comparison).

Complete Example: Legacy Compatibility

#include <cryptopp/sha.h>
#include <cryptopp/hex.h>
#include <cryptopp/filters.h>
#include <iostream>

using namespace CryptoPP;

// Only use for legacy system compatibility!
std::string sha1Hash(const std::string& input) {
    SHA1 hash;
    std::string digest, hexDigest;

    StringSource(input, true,
        new HashFilter(hash,
            new StringSink(digest)
        )
    );

    StringSource(digest, true,
        new HexEncoder(new StringSink(hexDigest))
    );

    return hexDigest;
}

int main() {
    // Legacy compatibility example
    std::string hash = sha1Hash("test data");
    std::cout << "SHA-1 (legacy): " << hash << std::endl;

    // WARNING: Do not use for:
    // - Digital signatures
    // - Certificate fingerprints
    // - Password hashing
    // - Any security-critical application

    return 0;
}

Security

Known Attacks

AttackYearComplexityImpact
Theoretical collision20052^69Academic
SHAttered collision20172^63Practical
Chosen-prefix collision20202^63Practical

SHAttered Attack (2017)

Google and CWI Amsterdam demonstrated a practical collision attack, creating two different PDF files with the same SHA-1 hash:

PDF 1: SHA-1 = 38762cf7f55934b34d179ae6a4c80cadccbb7f0a
PDF 2: SHA-1 = 38762cf7f55934b34d179ae6a4c80cadccbb7f0a (same!)

This attack cost approximately 110 GPU-years and is feasible for well-resourced attackers.

What’s Still Safe

  • HMAC-SHA1: The HMAC construction doesn’t require collision resistance. HMAC-SHA1 remains secure, though migration to HMAC-SHA256 is recommended.
  • Non-security checksums: If collision resistance isn’t needed (e.g., cache keys), SHA-1 works but faster alternatives exist.

What’s Broken

  • Digital signatures: An attacker can create two documents with the same hash
  • Certificate fingerprints: Collision attacks enable certificate forgery
  • Git commits: Potential for malicious commit collision (being addressed)
  • File integrity: Attacker can substitute files with same hash

Migration Guide

Replace SHA-1 with SHA-256

// OLD (insecure)
#include <cryptopp/sha.h>
SHA1 hash;

// NEW (secure)
#include <cryptopp/sha.h>
SHA256 hash;

// The API is identical - just change the class name

Replace HMAC-SHA1 with HMAC-SHA256

// OLD
#include <cryptopp/hmac.h>
#include <cryptopp/sha.h>
HMAC<SHA1> hmac(key, keyLen);

// NEW
#include <cryptopp/hmac.h>
#include <cryptopp/sha.h>
HMAC<SHA256> hmac(key, keyLen);

Performance

Benchmarks (Approximate)

AlgorithmSpeed (MB/s)Digest SizeSecurity
SHA-1400-80020 bytes❌ Broken
SHA-256200-40032 bytes✅ Secure
SHA-256 (SHA-NI)1000-200032 bytes✅ Secure
BLAKE33000-600032 bytes✅ Secure

Note: SHA-1’s speed advantage is not worth the security risk. Modern CPUs with SHA-NI make SHA-256 faster than SHA-1 anyway.

SHA-1 vs Modern Alternatives

PropertySHA-1SHA-256BLAKE3
Security❌ Broken✅ ~128-bit✅ ~128-bit
Collision resistance❌ ~63-bit✅ ~128-bit✅ ~128-bit
SpeedMediumMediumFast
Hardware accel❌ Rare✅ SHA-NI❌ No
RecommendationLegacy onlyGeneral usePerformance

When to Use SHA-1

⚠️ Only use SHA-1 for:

  1. Legacy Compatibility - Interfacing with old systems
  2. HMAC-SHA1 - When required by protocol (but prefer HMAC-SHA256)
  3. Git Compatibility - Until SHA-256 migration complete
  4. Non-Security Checksums - Where collisions don’t matter

❌ Never use SHA-1 for:

  1. Digital Signatures - Use SHA-256 or stronger
  2. Certificates - Major browsers/CAs reject SHA-1
  3. Password Hashing - Use Argon2 or bcrypt
  4. New Protocols - Always use SHA-256+
  5. File Integrity - Where security matters

Test Vector

// SHA-1("abc") = a9993e364706816aba3e25717850c26c9cd0d89d
std::string message = "abc";
SHA1 hash;
byte digest[SHA1::DIGESTSIZE];

hash.Update((const byte*)message.data(), message.size());
hash.Final(digest);

byte expected[] = {
    0xa9, 0x99, 0x3e, 0x36, 0x47, 0x06, 0x81, 0x6a,
    0xba, 0x3e, 0x25, 0x71, 0x78, 0x50, 0xc2, 0x6c,
    0x9c, 0xd0, 0xd8, 0x9d
};

assert(std::memcmp(digest, expected, 20) == 0);

Exceptions

None thrown under normal operation.

See Also

  • SHA-256 - Recommended replacement
  • SHA-512 - Higher security margin
  • BLAKE3 - Fastest secure hash
  • HMAC - Message authentication