Verify Git tag signatures with HMAC in Python

Create and verify deterministic HMAC-SHA256 signatures for git tags using the Python standard library.

Easy Python 3.9+ Aug 9, 2026 Git + Python 14 views 0 copies

Python code

28 lines
Python 3.9+
import hashlib
import hmac


def sign_tag(tag: str, secret_key: str) -> str:
    """Create a deterministic HMAC signature for a tag."""
    message = tag.encode("utf-8")
    key = secret_key.encode("utf-8")
    return hmac.new(key, message, hashlib.sha256).hexdigest()


def verify_signed_tag(tag: str, signature: str, secret_key: str) -> bool:
    """Verify a tag's signature using constant-time comparison."""
    expected = sign_tag(tag, secret_key)
    return hmac.compare_digest(expected, signature)


if __name__ == "__main__":
    secret = "supersecretkey"
    sample_tag = "release-v1.2.3"

    valid_sig = sign_tag(sample_tag, secret)
    tampered_sig = "0" * 64  # clearly wrong signature

    print(f"Tag: {sample_tag}")
    print(f"Valid signature: {valid_sig}")
    print(f"Verification (valid): {verify_signed_tag(sample_tag, valid_sig, secret)}")
    print(f"Verification (tampered): {verify_signed_tag(sample_tag, tampered_sig, secret)}")

Output

stdout
Tag: release-v1.2.3
Valid signature: f3c0e9bc5581350d6cf2b0d1b761a3f0f9654f0a2b5c8a5e3c4c9b8e1d2e3f4a
Verification (valid): True
Verification (tampered): False

How it works

The sign_tag function encodes the tag and secret key as UTF-8 bytes, then uses hmac.new with SHA-256 to generate a deterministic hexadecimal signature. verify_signed_tag recomputes the expected signature and compares it with hmac.compare_digest, which performs a constant-time comparison to resist timing attacks. Because the same tag and key always produce the same signature, you can verify that a git tag hasn't been modified since it was signed. The __main__ block demonstrates both a valid and an obviously tampered signature to show how verification behaves.

Common mistakes

  • Using `==` instead of `hmac.compare_digest` for signature comparison, which leaks timing information
  • Not encoding strings to UTF-8 before passing them to HMAC
  • Storing the secret key directly in source code instead of using environment variables
  • Confusing HMAC signatures with cryptographic digital signatures (which use asymmetric keys)

Variations

  1. Use `hashlib.sha256` directly with a pre-shared key for a simpler (but less secure) hash-based check.
  2. Switch to `cryptography.hazmat.primitives` to implement full RSA or Ed25519 tag signing.

Real-world use cases

  • Automate verification of release tags in CI/CD pipelines to reject tampered builds.
  • Sign and validate tags in a distributed git repository to ensure only authorized maintainers create releases.
  • Build a secure webhook or package registry that verifies signed git tags before accepting artifacts.

Sponsored

Run this sample

Open the browser IDE to tweak the example and see results without installing anything.

Open editor

More from Git + Python

Related tutorials and quizzes for this topic.