def sign(self, data): privateKeyNum = bytesToNumber(self.rawPrivateKey) hash = Digest.SHA256(data) g = generator_256 n = g.order() x = bytesToNumber(self.rawPublicKey[:32]) y = bytesToNumber(self.rawPublicKey[32:]) pubkey = Public_key(g, Point(g.curve(), x, y)) privkey = Private_key(pubkey, privateKeyNum) # Generating random nonce k per FIPS 186-3 B.5.1: # (except we use 32 extra bytes instead of 8 before reduction) # Random bytes taken from os.urandom as well as HMAC(privkey,hash) # REVIEW THIS CAREFULLY!!! CHANGE AT YOUR PERIL!!! # 64 random bytes and HMAC(rawPrivateKey,hash) are used as key for an # HMAC PRF to generate a 64-byte value which is reduced modulo # n to produce the nonce # # The use of HMAC(rawPrivateKey,hash) means this construction # will be secure even if os.urandom fails, however we include # os.urandom anyways out of an excess of caution randBytes0 = bytearray(os.urandom(64)) randBytes0 += Digest.HMAC_SHA256(self.rawPrivateKey, hash) randBytes = Digest.HMAC_SHA256(randBytes0, bytearray([1])) randBytes += Digest.HMAC_SHA256(randBytes0, bytearray([2])) c = bytesToNumber(randBytes) k = (c % (n - 1)) + 1 hashNum = bytesToNumber(hash) sig = privkey.sign(hashNum, k) sigBytes = numberToBytes(sig.r, 32) + numberToBytes(sig.s, 32) # Double-check the signature before returning assert (Python_ECPublicKey(self.rawPublicKey).verify(data, sigBytes)) return sigBytes
def _encryptKey(self, password, salt, iter_count, public_key, private_key): encKey, authKey = self._deriveKeys(password, salt, iter_count) ciphertext = AES(encKey, bytearray(16)).encrypt(private_key.getRawKey()) macData = ciphertext + public_key.getRawKey() mac = Digest.HMAC_SHA256(authKey, macData) return ciphertext, mac
def hmac_sha256(password, salt, iter_count): m = salt + bytearray([0, 0, 0, 1]) result = bytearray(32) for c in range(iter_count): m = Digest.HMAC_SHA256(bytearray(password, "ascii"), m) result = PBKDF2._xorbytes(m, result) return result
def _encrypt(self, password): encKey, authKey = self._deriveKeys(password, self.salt, self.iter_count) ciphertext = AES.create(encKey, bytearray(16)).encrypt( self.private_key.getRawKey()) macData = ciphertext + self.public_key.getRawKey() mac = Digest.HMAC_SHA256(authKey, macData) self.ciphertext = ciphertext self.mac = mac
def _decrypt(self, password): encKey, authKey = self._deriveKeys(password, self.salt, self.iter_count) macData = self.ciphertext + self.public_key.getRawKey() calcMac = Digest.HMAC_SHA256(authKey, macData) if not Util.constTimeCompare(calcMac, self.mac): raise InvalidPasswordException("Bad password") return AES.create(encKey, bytearray(16)).decrypt(self.ciphertext)
def _deriveKeys(self, password, salt, iter_count): assert (iter_count > 0) masterKey = PBKDF2.hmac_sha256(password, salt, iter_count) encKey = Digest.HMAC_SHA256(masterKey, bytearray([1])) authKey = Digest.HMAC_SHA256(masterKey, bytearray([2])) return encKey, authKey