I saw a request for Koji to use a stronger cryptographic hash function such as SHA256 
( https://fedorahosted.org/koji/ticket/119 ) on RPM packages. I took some time in reading how the 
RPMTAG_SIGMD5 is calculated and implemented some Python code to hash the same RPM data 
using hashlib's SHA256 module. The outputted SHA256 digest can be stored in Koji's DB and 
also retrieved/calculated/checked with any new packages that are being submitted. 


$ rpm -q --queryformat '%{RPMTAG_SIGMD5}' -p "gcc-4.6.2-1.fc17.1.src.rpm"
c88e96685e7eb3a124a5707b1bc41333
$ python sha2pay.py gcc-4.6.2-1.fc17.1.src.rpm
['c88e96685e7eb3a124a5707b1bc41333', 'c729d818d5468f8b1147cb70b266992f92f58c9dace218417c7582427d1e5561']


Source code:



import hashlib
import os
import struct
import subprocess
import sys


def sha2pay(fn):
# http://www.iagora.com/~espel/rpm2cpio

nel = 0
f = open(fn, "r")

rpm = f.read(96)
if (len(rpm) != 96):
#print("error reading lead 96.0")
return None
nel += len(rpm)

# http://perldoc.perl.org/functions/pack.html
# http://docs.python.org/library/struct.html

(magic, major, minor, rest) = struct.unpack(">LBB90s", rpm)

if (magic != 0xedabeedb):
#print("incorrect lead magic")
return None

if ((major != 3) and (major != 4)):
#print("incorrect lead major")
return None

# http://docs.python.org/library/stdtypes.html

while (1):
pos = nel
rpm = f.read(16)
if (len(rpm) != 16):
#print("error reading header 16.0")
return None
nel += len(rpm)
(smagic, rest) = struct.unpack(">H14s", rpm)
if ((smagic == 0x1f8b) or (smagic == 0x425a)):
break
if (pos & 0x7):
pos += 7
pos &= (~0x7)
f.seek(pos, 0)
nel = pos
rpm = f.read(16)
if (len(rpm) != 16):
#print("error reading header 16.1")
return None
nel += len(rpm)
left = (len(rpm) - 16)
(magic, data, sections, bytes, rest) = struct.unpack(">4L" + str(left) + "s", rpm)
if (magic != 0x8eade801):
#print("incorrect header magic")
return None
# beg custom
f.seek(pos + 16, 0)
tmp = f.read((16 * sections) + bytes)
head = (rpm + tmp)
# end custom
pos += 16
pos += (16 * sections)
pos += bytes
f.seek(pos, 0)
nel = pos

if ((smagic != 0x1f8b) and (smagic != 0x425a)):
#print("unknown compression format")
return None

while (1):
tmp = f.read(16384)

if (not tmp):
break

rpm += tmp

f.close()
return [hashlib.md5(head + rpm).hexdigest(), hashlib.sha256(head + rpm).hexdigest()]