Package: warcsigner
Tools to add and a verify a cryptographic signature to WARC (or any gzip-chunked) filesThis package provides complemetarywarc-signtool which signs WARC(s) with an RSA signature andwarc-verifywhich verifies that the WARC(s) have been signed.UsageInstall with:python setup.py installTests can be run with:python setup.py testTo sign a warc:warc-signprivatekey.pemmy-warc-file.warc.gzTo verify that a warc has been signed:warc-verifypublickey.pemmy-warc-file.warc.gzAPI Usagewarcsigner can be used from other scripts.
To sign a warc:from warcsigner.warcsigner import RSASigner

signer = RSASigner(private_key_file='privatekey.pem')

if signer.sign('my-warc-file.warc.gz'):
    # warc signed successfullyor to verify:from warcsigner.warcsigner import RSASigner

signer = RSASigner(public_key_file='publickey.pem')

if signer.verify('my-warc-file.warc.gz'):
    # signature verified
else:
    # signature not found/invalidthesignandverifymethods can take either a filename string or a file-like
stream object (an object with areadmethod)Additionally, upon verification, the signature can be removed:if signer.verify('my-warc-file.warc.gz', remove=True):
    # signature verified and removed

assert signer.verify('my-warc-file.warc.gz') == FalseIf the first verify succeeds, the signature will be removed and file truncated
to its previous pre-signature size. (The file is unaltered if the verification fails).
This may be useful if planning to append to the WARC and then resigning it.Streaming andseek()It is possible to use a file-like object which supports aread()instead of a filename.When a WARC is signed, the signature is appended to the end of the file.When verifying a file, theseek()may be used to determine the file size and the position of the signature.
However, if asize=param is added toverifyorverify_streamcalls, no seek() calls are made during
the verification and the file-like object is consumed linearly. This is specially useful
when streaming a file from a remote location andseek()is not available.
The total file size must be provided, though.Public/Private keys are expected to be in .PEM format
See thepython-rsa formats docfor more information
on supported key formats.Original StreamIn certain situations, it may be useful to return the original, unsigned stream from a signed stream.signer.get_unsigned_stream(stream, size)will return a wrapper forstreamwhich will not include the signature (if present). This is useful if concatenating WARCs without including a signature (and empty record) for each one.How it worksThepython-rsalibrary is used to sign and verify the signature.The signature is stored in an extra gzip chunk containing no data but usingcustom extra fieldto store the signature. This allows the verify tool to quickly access the signature by checking a fixed offset from the end of the WARC.When decompressing gzip chunks, there should be no detectable difference as most gzip tools ignore the extra gzip header.While this is designed for compressed WARCs, this can be used for any format consisting of concatenated gzip chunks, ARC files, etc…Note: since the signature is a gzip block, it makes less sense for uncompressed / plain text files.