SHA-based encryption function in Python

Paul Rubin phr-n2002a at nightsong.com
Thu Apr 25 07:33:25 EDT 2002


Richard Parker <richard at electrophobia.com> writes:
> > Currently I'm using
> > 
> > K1 = H('auth1' + K)
> > K2 = H('auth2' + K)
> > MAC = H(K1 + H(K2 + ciphertext))
> > 
> > which I hope is at least as good as HMAC (the keys are more
> > independent) and it uses fewer interpreter operations (though more SHA
> > calls).  It's speed isn't too bad, but I always like to look for
> > improvements.
> 
> I like that idea.  I do, however, recommend that as a precaution you choose
> values for the two constants that differ by more than one bit.

Hmm, that's my instinct too, but I just finished making myself get
over it in order to believe that counter mode AES encryption is ok,
and now I'm supposed to change back?  ;-)

>  While more expensive than HMAC in the theoretical sense, this HMAC
> variant looks secure and I'm not surprised to hear that it is
> actually faster in Python.  I can't see any attack that wouldn't
> also imply the ability to crack the hash function, which is the same
> level of security offered by HMAC.  If you are using the MAC more
> than once with same key you could improve performance by only
> computing the values of K1 and K2 once (this optimization would also
> apply to HMAC).

K in this system is derived from the password and nonce, which in turn
depends on the password, the plaintext, and a random value.

It bugs me that HMAC goes out of its way to make sure the compression
function runs separately for the key and message for both of its
hashes, and my variant doesn't.  There must be a reason for that.  So
maybe I should read the paper and/or bite the bullet and use HMAC.

Anyway, I begin to miss my original scheme of hashing under the
encryption (MAC-then-encrypt):

  ciphertext = encrypt(plaintext + H(plaintext))

The Bellare/Namprempre article list this scheme as insecure but I
don't understand the reasons yet.  I'll have to read the article more
carefully (it's a good article--thanks).  I don't see what problems it
causes, and as we've seen it avoids some problems and may be a little
faster.

Btw, here's my current hmac implementation, which should be faster
than the 2.2 library version on short strings, but I still have to do
some comparative timing.

# sha-1 hmac, RFC 2104

from array import array
import sha
from string import translate

def _setup():
    global _ipad, _opad, _itrans, _otrans
    _itrans = array('B',[0]*256)
    _otrans = array('B',[0]*256)    
    for i in xrange(256):
        _itrans[i] = i ^ 0x36
        _otrans[i] = i ^ 0x5c
    _itrans = _itrans.tostring()
    _otrans = _otrans.tostring()

    _ipad = '\x36'*64
    _opad = '\x5c'*64

_setup()  # initialize constants

def hmac_str(key, msg, digestmod=sha):
    if len(key) > 64:
        key = digestmod.new(key).digest()
    ki = (translate(key,_itrans)+_ipad)[:64] # inner
    ko = (translate(key,_otrans)+_opad)[:64] # outer
    return digestmod.new(ko+digestmod.new(ki+msg).digest()).digest()



More information about the Python-list mailing list