def testEncode6(self): # Two positive integers der = DerSequence() der.append(0x180L) der.append(0xFFL) self.assertEquals(der.encode(), b('0\x08\x02\x02\x01\x80\x02\x02\x00\xff')) self.failUnless(der.hasOnlyInts()) self.failUnless(der.hasOnlyInts(False)) # Two mixed integers der = DerSequence() der.append(2) der.append(-2) self.assertEquals(der.encode(), b('0\x06\x02\x01\x02\x02\x01\xFE')) self.assertEquals(der.hasInts(), 1) self.assertEquals(der.hasInts(False), 2) self.failIf(der.hasOnlyInts()) self.failUnless(der.hasOnlyInts(False)) # der.append(0x01) der[1:] = [9, 8] self.assertEquals(len(der), 3) self.assertEqual(der[1:], [9, 8]) self.assertEqual(der[1:-1], [9]) self.assertEquals(der.encode(), b('0\x09\x02\x01\x02\x02\x01\x09\x02\x01\x08'))
def exportKey(self, format='PEM'): """Export the RSA key. A string is returned with the encoded public or the private half under the selected format. format: 'DER' (PKCS#1) or 'PEM' (RFC1421) """ der = DerSequence() if self.has_private(): keyType = "RSA PRIVATE" der[:] = [ 0, self.n, self.e, self.d, self.p, self.q, self.d % (self.p-1), self.d % (self.q-1), self.u ] else: keyType = "PUBLIC" der.append(b('\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01\x05\x00')) bitmap = DerObject('BIT STRING') derPK = DerSequence() derPK[:] = [ self.n, self.e ] bitmap.payload = b('\x00') + derPK.encode() der.append(bitmap.encode()) if format=='DER': return der.encode() if format=='PEM': pem = b("-----BEGIN %s KEY-----\n" % keyType) binaryKey = der.encode() # Each BASE64 line can take up to 64 characters (=48 bytes of data) chunks = [ binascii.b2a_base64(binaryKey[i:i+48]) for i in range(0, len(binaryKey), 48) ] pem += b('').join(chunks) pem += b("-----END %s KEY-----" % keyType) return pem return ValueError("")
def exportKey(self, format='PEM', public=False, type=None): """Export the RSA key. A string is returned with the encoded public or the private half under the selected format. format: 'DER' (PKCS#1) or 'PEM' (RFC1421) """ if type == 'ssh-rsa' and public: return ''.join(binascii.b2a_base64('\x00\x00\x00\x07ssh-rsa\x00\x00\x00\x03' + '\x00\x00\x01\x01\x00'.join([long_to_bytes(self.e), long_to_bytes(self.n)])).split("\n")) der = DerSequence() if not public and self.has_private(): keyType = "RSA PRIVATE" der[:] = [ 0, self.n, self.e, self.d, self.p, self.q, self.d % (self.p-1), self.d % (self.q-1), self.u ] else: keyType = "PUBLIC" der.append('\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01\x05\x00') bitmap = DerObject('BIT STRING') derPK = DerSequence() derPK[:] = [ self.n, self.e ] bitmap.payload = '\x00' + derPK.encode() der.append(bitmap.encode()) if format=='DER': return der.encode() if format=='PEM': pem = "-----BEGIN %s KEY-----\n" % keyType binaryKey = der.encode() # Each BASE64 line can take up to 64 characters (=48 bytes of data) chunks = [ binascii.b2a_base64(binaryKey[i:i+48]) for i in range(0, len(binaryKey), 48) ] pem += ''.join(chunks) pem += "-----END %s KEY-----" % keyType return pem return ValueError("")
def generate_spoofed_key(pubkey): x = int(pubkey[0:96], 16) y = int(pubkey[96:], 16) # Generate rogue generator # Generate degenerate case rogue generator privkey = '\x01' rogueG = unhexlify(b"04" + hex2(x).encode() + hex2(y).encode()) # Generate the file with explicit parameters der = get_der(ec_key_template) # Replace private key octet_der = DerOctetString(privkey) der[1] = octet_der.encode() # Replace public key der[3] = b"\xa1\x64\x03b\x00" + unhexlify(b"04" + pubkey) # Replace the generator seq_der = DerSequence() seq_der.decode(der[2][4:]) s = seq_der._seq octet_der = DerOctetString(rogueG) s[3] = octet_der.encode() seq_der = DerSequence(s) der[2] = der[2][:4] + seq_der.encode() seq_der = DerSequence(der) return PEMHelper.PEMEncode(seq_der.encode(), 'EC PRIVATE KEY')
def exportKey(self, format="PEM"): """Export the RSA key. A string is returned with the encoded public or the private half under the selected format. format: 'DER' (PKCS#1) or 'PEM' (RFC1421) """ der = DerSequence() if self.has_private(): keyType = "RSA PRIVATE" der[:] = [0, self.n, self.e, self.d, self.p, self.q, self.d % (self.p - 1), self.d % (self.q - 1), self.u] else: keyType = "PUBLIC" der.append("\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01\x05\x00") bitmap = DerObject("BIT STRING") derPK = DerSequence() derPK[:] = [self.n, self.e] bitmap.payload = "\x00" + derPK.encode() der.append(bitmap.encode()) if format == "DER": return der.encode() if format == "PEM": pem = "-----BEGIN %s KEY-----\n" % keyType binaryKey = der.encode() # Each BASE64 line can take up to 64 characters (=48 bytes of data) chunks = [] for i in range(0, len(binaryKey), 48): chunks.append(binascii.b2a_base64(binaryKey[i : i + 48])) pem += "".join(chunks) pem += "-----END %s KEY-----" % keyType return pem if format == "SSH": # Create public key. ssh_rsa = "00000007" + base64.b16encode("ssh-rsa") # Exponent. exponent = "%x" % (self.key.e,) if len(exponent) % 2: exponent = "0" + exponent ssh_rsa += "%08x" % (len(exponent) / 2,) ssh_rsa += exponent modulus = "%x" % (self.key.n,) if len(modulus) % 2: modulus = "0" + modulus if modulus[0] in "89abcdef": modulus = "00" + modulus ssh_rsa += "%08x" % (len(modulus) / 2,) ssh_rsa += modulus return "ssh-rsa %s" % (base64.b64encode(base64.b16decode(ssh_rsa.upper())),) return ValueError("")
def testEncode1(self): # Empty sequence der = DerSequence() self.assertEqual(der.encode(), b('0\x00')) self.assertFalse(der.hasOnlyInts()) # One single-byte integer (zero) der.append(0) self.assertEqual(der.encode(), b('0\x03\x02\x01\x00')) self.assertTrue(der.hasOnlyInts()) # Invariant self.assertEqual(der.encode(), b('0\x03\x02\x01\x00'))
def testEncode1(self): # Empty sequence der = DerSequence() self.assertEqual(der.encode(), b('0\x00')) self.assertFalse(der.hasOnlyInts()) # One single-byte integer (zero) der.append(0) self.assertEqual(der.encode(), b('0\x03\x02\x01\x00')) self.assertTrue(der.hasOnlyInts()) # Invariant self.assertEqual(der.encode(), b('0\x03\x02\x01\x00'))
def get_pubkey_ssh2_fingerprint(pubkey): # This is the format that EC2 shows for public key fingerprints in its # KeyPair mgmt API if not pycrypto_available: raise RuntimeError('pycrypto is not available') k = importKey(pubkey) derPK = DerSequence([k.n, k.e]) bitmap = DerObject('BIT STRING') bitmap.payload = bchr(0x00) + derPK.encode() der = DerSequence([algorithmIdentifier, bitmap.encode()]) return _to_md5_fingerprint(der.encode())
def testEncode1(self): # Empty sequence der = DerSequence() self.assertEquals(der.encode(), '0\x00') self.failIf(der.hasOnlyInts()) # One single-byte integer (zero) der.append(0) self.assertEquals(der.encode(), '0\x03\x02\x01\x00') self.failUnless(der.hasOnlyInts()) # Invariant self.assertEquals(der.encode(), '0\x03\x02\x01\x00')
def get_pubkey_ssh2_fingerprint(pubkey): # This is the format that EC2 shows for public key fingerprints in its # KeyPair mgmt API if not pycrypto_available: raise RuntimeError('pycrypto is not available') k = importKey(pubkey) derPK = DerSequence([k.n, k.e]) bitmap = DerObject('BIT STRING') bitmap.payload = bchr(0x00) + derPK.encode() der = DerSequence([algorithmIdentifier, bitmap.encode()]) return _to_md5_fingerprint(der.encode())
def testEncode2(self): # Indexing der = DerSequence() der.append(0) der[0] = 1 self.assertEquals(len(der), 1) self.assertEquals(der[0], 1) self.assertEquals(der[-1], 1) self.assertEquals(der.encode(), b('0\x03\x02\x01\x01')) # der[:] = [1] self.assertEquals(len(der), 1) self.assertEquals(der[0], 1) self.assertEquals(der.encode(), b('0\x03\x02\x01\x01'))
def testEncode6(self): # Two integers der = DerSequence() der.append(0x180L) der.append(0xFFL) self.assertEquals(der.encode(), '0\x08\x02\x02\x01\x80\x02\x02\x00\xff') self.failUnless(der.hasOnlyInts()) # der.append(0x01) der[1:] = [9,8] self.assertEquals(len(der),3) self.assertEqual(der[1:],[9,8]) self.assertEqual(der[1:-1],[9]) self.assertEquals(der.encode(), '0\x0A\x02\x02\x01\x80\x02\x01\x09\x02\x01\x08')
def testEncode2(self): # Indexing der = DerSequence() der.append(0) der[0] = 1 self.assertEqual(len(der),1) self.assertEqual(der[0],1) self.assertEqual(der[-1],1) self.assertEqual(der.encode(), b('0\x03\x02\x01\x01')) # der[:] = [1] self.assertEqual(len(der),1) self.assertEqual(der[0],1) self.assertEqual(der.encode(), b('0\x03\x02\x01\x01'))
def EMSA_PKCS1_V1_5_ENCODE(hash, emLen): """ Implement the ``EMSA-PKCS1-V1_5-ENCODE`` function, as defined in PKCS#1 v2.1 (RFC3447, 9.2). ``EMSA-PKCS1-V1_5-ENCODE`` actually accepts the message ``M`` as input, and hash it internally. Here, we expect that the message has already been hashed instead. :Parameters: hash : hash object The hash object that holds the digest of the message being signed. emLen : int The length the final encoding must have, in bytes. :attention: the early standard (RFC2313) stated that ``DigestInfo`` had to be BER-encoded. This means that old signatures might have length tags in indefinite form, which is not supported in DER. Such encoding cannot be reproduced by this function. :attention: the same standard defined ``DigestAlgorithm`` to be of ``AlgorithmIdentifier`` type, where the PARAMETERS item is optional. Encodings for ``MD2/4/5`` without ``PARAMETERS`` cannot be reproduced by this function. :Return: An ``emLen`` byte long string that encodes the hash. """ # First, build the ASN.1 DER object DigestInfo: # # DigestInfo ::= SEQUENCE { # digestAlgorithm AlgorithmIdentifier, # digest OCTET STRING # } # # where digestAlgorithm identifies the hash function and shall be an # algorithm ID with an OID in the set PKCS1-v1-5DigestAlgorithms. # # PKCS1-v1-5DigestAlgorithms ALGORITHM-IDENTIFIER ::= { # { OID id-md2 PARAMETERS NULL }| # { OID id-md5 PARAMETERS NULL }| # { OID id-sha1 PARAMETERS NULL }| # { OID id-sha256 PARAMETERS NULL }| # { OID id-sha384 PARAMETERS NULL }| # { OID id-sha512 PARAMETERS NULL } # } # digestAlgo = DerSequence([hash.oid, DerNull().encode()]) digest = DerOctetString(hash.digest()) digestInfo = DerSequence([digestAlgo.encode(), digest.encode()]).encode() # We need at least 11 bytes for the remaining data: 3 fixed bytes and # at least 8 bytes of padding). if emLen < len(digestInfo) + 11: raise ValueError( "Selected hash algorith has a too long digest (%d bytes)." % len(digest)) PS = bchr(0xFF) * (emLen - len(digestInfo) - 3) return b("\x00\x01") + PS + bchr(0x00) + digestInfo
def testEncode4(self): # One very long integer der = DerSequence() der.append(2 ** 2048) self.assertEquals( der.encode(), b("0\x82\x01\x05") + b("\x02\x82\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00") + b("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00") + b("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00") + b("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00") + b("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00") + b("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00") + b("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00") + b("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00") + b("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00") + b("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00") + b("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00") + b("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00") + b("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00") + b("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00") + b("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00") + b("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00") + b("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00") + b("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00") + b("\x00\x00\x00\x00\x00\x00\x00\x00\x00"), )
def testEncode7(self): # One integer and another type (no matter what it is) der = DerSequence() der.append(0x180) der.append(b('\x00\x02\x00\x00')) self.assertEqual(der.encode(), b('0\x08\x02\x02\x01\x80\x00\x02\x00\x00')) self.assertFalse(der.hasOnlyInts())
def testEncode7(self): # One integer and another type (already encoded) der = DerSequence() der.append(0x180) der.append(b('0\x03\x02\x01\x05')) self.assertEqual(der.encode(), b('0\x09\x02\x02\x01\x800\x03\x02\x01\x05')) self.assertFalse(der.hasOnlyInts())
def testEncode7(self): # One integer and another type (already encoded) der = DerSequence() der.append(0x180) der.append(b('0\x03\x02\x01\x05')) self.assertEqual(der.encode(), b('0\x09\x02\x02\x01\x800\x03\x02\x01\x05')) self.assertFalse(der.hasOnlyInts())
def testEncode2(self): # One single-byte integer (non-zero) der = DerSequence() der.append(127) self.assertEquals(der.encode(), '0\x03\x02\x01\x7f') # Indexing der[0] = 1 self.assertEquals(len(der),1) self.assertEquals(der[0],1) self.assertEquals(der[-1],1) self.assertEquals(der.encode(), '0\x03\x02\x01\x01') # der[:] = [1] self.assertEquals(len(der),1) self.assertEquals(der[0],1) self.assertEquals(der.encode(), '0\x03\x02\x01\x01')
def testEncode8(self): # One integer and another type (yet to encode) der = DerSequence() der.append(0x180) der.append(DerSequence([5])) self.assertEqual(der.encode(), b('0\x09\x02\x02\x01\x800\x03\x02\x01\x05')) self.assertFalse(der.hasOnlyInts())
def testEncode8(self): # One integer and another type (yet to encode) der = DerSequence() der.append(0x180) der.append(DerSequence([5])) self.assertEquals(der.encode(), b('0\x09\x02\x02\x01\x800\x03\x02\x01\x05')) self.failIf(der.hasOnlyInts())
def testEncode6(self): # One integer and another type (no matter what it is) der = DerSequence() der.append(0x180L) der.append('\x00\x02\x00\x00') self.assertEquals(der.encode(), '0\x08\x02\x02\x01\x80\x00\x02\x00\x00') self.failIf(der.hasOnlyInts())
def csr_pem_to_der(csr_cert): certificate_key_der = DerSequence() certificate_key_der.decode( OpenSSL.crypto.dump_certificate_request(OpenSSL.crypto.FILETYPE_ASN1, csr_cert)) certificate_der = certificate_key_der.encode() return certificate_der
def testEncode4(self): # One very long integer der = DerSequence() der.append(2L**2048) self.assertEquals( der.encode(), b('0\x82\x01\x05') + b('\x02\x82\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00') + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00'))
def testEncode7(self): # One integer and another type (no matter what it is) der = DerSequence() der.append(0x180) der.append(b('\x00\x02\x00\x00')) self.assertEqual(der.encode(), b('0\x08\x02\x02\x01\x80\x00\x02\x00\x00')) self.assertFalse(der.hasOnlyInts())
def _create_subject_public_key_info(algo_oid, secret_key, params=None): if params is None: params = DerNull() spki = DerSequence([ DerSequence([DerObjectId(algo_oid), params]), DerBitString(secret_key) ]) return spki.encode()
def _create_subject_public_key_info(algo_oid, public_key, params): if params is None: algorithm = DerSequence([DerObjectId(algo_oid)]) else: algorithm = DerSequence([DerObjectId(algo_oid), params]) spki = DerSequence([algorithm, DerBitString(public_key) ]) return spki.encode()
def _create_subject_public_key_info(algo_oid, secret_key, params=None): if params is None: params = DerNull() spki = DerSequence([ DerSequence([ DerObjectId(algo_oid), params]), DerBitString(secret_key) ]) return spki.encode()
def CRYPTO_EMSA_PKCS1_V1_5_ENCODE(M, emLen): msg_hash = SHA256.new(M) digestAlgo = DerSequence([DerObjectId(msg_hash.oid).encode()]) print(digestAlgo) digestAlgo.append(DerNull().encode()) digest = DerOctetString(msg_hash.digest()) digestInfo = DerSequence([digestAlgo.encode(), digest.encode()]).encode() print("%x" % int.from_bytes(digestInfo, byteorder='big')) print("%x" % int.from_bytes(digestAlgo.encode(), byteorder='big')) print("%x" % int.from_bytes(digest.encode(), byteorder='big')) print("%x" % int.from_bytes(msg_hash.digest(), byteorder='big')) #b91d0b7a09f57c109926a449647283adb5dc213c0fdb0cf2b219e064cc132273 2004 00 0501020403650148866009060d30 3130 # 501020403650148866009060d30 #b91d0b7a09f57c109926a449647283adb5dc213c0fdb0cf2b219e064cc132273 2004 #b91d0b7a09f57c109926a449647283adb5dc213c0fdb0cf2b219e064cc132273 #b91d0b7a09f57c109926a449647283adb5dc213c0fdb0cf2b219e064cc1322732004000501020403650148866009060d30313000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0100 #3031 300d06096086480165030402010500 0420 732213cc64e019b2f20cdb0f3c21dcb5ad83726449a42699107cf5097a0b1db9 # 300d06096086480165030402010500 # 0420 732213cc64e019b2f20cdb0f3c21dcb5ad83726449a42699107cf5097a0b1db9 # 732213cc64e019b2f20cdb0f3c21dcb5ad83726449a42699107cf5097a0b1db9 #0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003031300d060960864801650304020105000420732213cc64e019b2f20cdb0f3c21dcb5ad83726449a42699107cf5097a0b1db9 # We need at least 11 bytes for the remaining data: 3 fixed bytes and # at least 8 bytes of padding). if emLen < len(digestInfo) + 11: raise TypeError( "Selected hash algorith has a too long digest (%d bytes)." % len(digest)) PS = b'\xFF' * (emLen - len(digestInfo) - 3) out = b'\x00\x01' + PS + b'\x00' + digestInfo print("%x" % int.from_bytes(out, byteorder='big')) return out
def testEncode6(self): # Two positive integers der = DerSequence() der.append(0x180) der.append(0xFF) self.assertEqual(der.encode(), b('0\x08\x02\x02\x01\x80\x02\x02\x00\xff')) self.assertTrue(der.hasOnlyInts()) self.assertTrue(der.hasOnlyInts(False)) # Two mixed integers der = DerSequence() der.append(2) der.append(-2) self.assertEqual(der.encode(), b('0\x06\x02\x01\x02\x02\x01\xFE')) self.assertEqual(der.hasInts(), 1) self.assertEqual(der.hasInts(False), 2) self.assertFalse(der.hasOnlyInts()) self.assertTrue(der.hasOnlyInts(False)) # der.append(0x01) der[1:] = [9,8] self.assertEqual(len(der),3) self.assertEqual(der[1:],[9,8]) self.assertEqual(der[1:-1],[9]) self.assertEqual(der.encode(), b('0\x09\x02\x01\x02\x02\x01\x09\x02\x01\x08'))
def sign(self, msg_hash): """Produce the DSS signature of a message. :Parameters: msg_hash : hash object The hash that was carried out over the message. The object belongs to the `Crypto.Hash` package. Under mode *'fips-186-3'*, the hash must be a FIPS approved secure hash (SHA-1 or a member of the SHA-2 family). :Return: The signature encoded as a byte string. :Raise ValueError: If the hash algorithm is incompatible to the DSA key. :Raise TypeError: If the DSA key has no private half. """ # Generate the nonce k (critical!) if self._deterministic: nonce = self._compute_nonce(msg_hash) else: if self._n > msg_hash.digest_size * 8: raise ValueError("Hash is not long enough") if not hash_is_shs(msg_hash): raise ValueError("Hash does not belong to SHS") rng = StrongRandom(randfunc=self._randfunc) nonce = rng.randint(1, self._key.q - 1) # Perform signature using the raw API z = bytes_to_long(msg_hash.digest()[:self._n]) sig_pair = self._key._sign(z, nonce) # Encode the signature into a single byte string if self._encoding == 'binary': output = b("").join([long_to_bytes(x, self._n) for x in sig_pair]) else: # Dss-sig ::= SEQUENCE { # r OCTET STRING, # s OCTET STRING # } der_seq = DerSequence(sig_pair) output = der_seq.encode() return output
def sign(self, msg_hash): """Produce the DSS signature of a message. :Parameters: msg_hash : hash object The hash that was carried out over the message. The object belongs to the `Crypto.Hash` package. Under mode *'fips-186-3'*, the hash must be a FIPS approved secure hash (SHA-1 or a member of the SHA-2 family). :Return: The signature encoded as a byte string. :Raise ValueError: If the hash algorithm is incompatible to the DSA key. :Raise TypeError: If the DSA key has no private half. """ # Generate the nonce k (critical!) if self._deterministic: nonce = self._compute_nonce(msg_hash) else: if self._n > msg_hash.digest_size * 8: raise ValueError("Hash is not long enough") if not msg_hash.name.upper().startswith("SHA"): raise ValueError("Hash %s does not belong to SHS" % msg_hash.name) rng = StrongRandom(randfunc=self._randfunc) nonce = rng.randint(1, self._key.q - 1) # Perform signature using the raw API z = bytes_to_long(msg_hash.digest()[:self._n]) sig_pair = self._key._sign(z, nonce) # Encode the signature into a single byte string if self._encoding == 'binary': output = b("").join([long_to_bytes(x, self._n) for x in sig_pair]) else: # Dss-sig ::= SEQUENCE { # r OCTET STRING, # s OCTET STRING # } der_seq = DerSequence(sig_pair) output = der_seq.encode() return output
def pkcs1_v1_5_encode(msg_hash: SHA256.SHA256Hash, emLen: int) -> bytes: # this code is copied from EMSA_PKCS1_V1_5_ENCODE # https://github.com/dlitz/pycrypto/blob/v2.7a1/lib/Crypto/Signature/PKCS1_v1_5.py#L173 digestAlgo = DerSequence([ DerObjectId(msg_hash.oid).encode() ]) #if with_hash_parameters: if True: digestAlgo.append(DerNull().encode()) digest = DerOctetString(msg_hash.digest()) digestInfo = DerSequence([ digestAlgo.encode(), digest.encode() ]).encode() # We need at least 11 bytes for the remaining data: 3 fixed bytes and # at least 8 bytes of padding). if emLen<len(digestInfo)+11: raise TypeError("Selected hash algorith has a too long digest (%d bytes)." % len(digest)) PS = b'\xFF' * (emLen - len(digestInfo) - 3) return b'\x00\x01' + PS + b'\x00' + digestInfo
def sign_bytes_dsa(byte_array, path_to_private_key_pem_file): # Use this method for DSA keys key = open(path_to_private_key_pem_file, 'r').read() # Import the key dsa_key = DSA.importKey(key) # Create a digest of nonce + cnonce # This only seems to work with SHA1 (SHA256 gives us a 401 error) buf = buffer(byte_array) digest = SHA1.new(buf).digest() # Digitally sign the digest with our private key # The corresponding public key is in our admin handle on the server k = random.StrongRandom().randint(1, dsa_key.q-1) sign = dsa_key.sign(digest, k) # Signature bytes from a DSA key need to be DER-encoded # This signature is in two parts (r and s) seq = DerSequence() seq.append(sign[0]) seq.append(sign[1]) return seq.encode()
def sign_bytes_dsa(byte_array, path_to_private_key_pem_file): # Use this method for DSA keys key = open(path_to_private_key_pem_file, 'r').read() # Import the key dsa_key = DSA.importKey(key) # Create a digest of nonce + cnonce # This only seems to work with SHA1 (SHA256 gives us a 401 error) buf = buffer(byte_array) digest = SHA1.new(buf).digest() # Digitally sign the digest with our private key # The corresponding public key is in our admin handle on the server k = random.StrongRandom().randint(1, dsa_key.q - 1) sign = dsa_key.sign(digest, k) # Signature bytes from a DSA key need to be DER-encoded # This signature is in two parts (r and s) seq = DerSequence() seq.append(sign[0]) seq.append(sign[1]) return seq.encode()
def testEncode4(self): # One very long integer der = DerSequence() der.append(2**2048) self.assertEqual(der.encode(), b('0\x82\x01\x05')+ b('\x02\x82\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ b('\x00\x00\x00\x00\x00\x00\x00\x00\x00'))
def generatePublicKey(cert_file): osw = OpenSSLWrapper() cert_str = osw.read_str_from_file(cert_file) cert = crypto.load_certificate(crypto.FILETYPE_PEM, cert_str) pub_key = cert.get_pubkey() src = crypto.dump_privatekey(crypto.FILETYPE_ASN1, pub_key) pub_der = DerSequence() pub_der.decode(src) pub_key_rsa = RSA.construct((long(pub_der._seq[1]), long(pub_der._seq[2]))) pemSeq = DerSequence() pemSeq[:] = [pub_key_rsa.key.n, pub_key_rsa.key.e] s = pub_key_str = b64encode(pemSeq.encode()) pem_src = '-----BEGIN RSA PUBLIC KEY-----\n' while True: pem_src += s[:64] + '\n' s = s[64:] if s == '': break pem_src += '-----END RSA PUBLIC KEY-----' jwks = { "keys": [{ "use": "enc", "e": "AQAB", "kty": "RSA", "n": pub_key_str }, { "use": "sig", "e": "AQAB", "kty": "RSA", "n": pub_key_str }] } jwks_str = json.dumps(jwks) osw.write_str_to_file("./static/jwks.json", jwks_str)
def testEncode5(self): # One single-byte integer (looks negative) der = DerSequence() der.append(0xFFL) self.assertEquals(der.encode(), '0\x04\x02\x02\x00\xff')
def testEncode3(self): # One multi-byte integer (non-zero) der = DerSequence() der.append(0x180L) self.assertEquals(der.encode(), '0\x04\x02\x02\x01\x80')
def generateCert(cert_info=None): cert_info_ca = { "cn": "localhost", "country_code": "se", "state": "ac", "city": "Test", "organization": "Test org", "organization_unit": "Testers" } if cert_info is not None: cert_info_ca = cert_info osw = OpenSSLWrapper() sn = 1 try: sn = osw.read_str_from_file("sn.txt") if len(sn) > 0: sn = int(sn) sn += 1 else: sn = 1 except: pass ca_cert1, ca_key1 = osw.create_certificate(cert_info_ca, request=False, write_to_file=True, cert_dir="./httpsCert", sn=sn) sn += 1 ca_cert2, ca_key2 = osw.create_certificate(cert_info_ca, request=False, write_to_file=True, cert_dir="./idp_cert", sn=sn) sn += 1 ca_cert3, ca_key3 = osw.create_certificate(cert_info_ca, request=False, write_to_file=True, cert_dir="./sp_cert", sn=sn) sn += 1 ca_cert4, ca_key4 = osw.create_certificate(cert_info_ca, request=False, write_to_file=True, cert_dir="./opKeys", sn=sn, key_length=2048) cert_str = osw.read_str_from_file(ca_cert4) cert = crypto.load_certificate(crypto.FILETYPE_PEM, cert_str) pub_key = cert.get_pubkey() src = crypto.dump_privatekey(crypto.FILETYPE_ASN1, pub_key) pub_der = DerSequence() pub_der.decode(src) pub_key_rsa = RSA.construct((long(pub_der._seq[1]), long(pub_der._seq[2]))) pemSeq = DerSequence() pemSeq[:] = [pub_key_rsa.key.n, pub_key_rsa.key.e] s = pub_key_str = b64encode(pemSeq.encode()) pem_src = '-----BEGIN RSA PUBLIC KEY-----\n' while True: pem_src += s[:64] + '\n' s = s[64:] if s == '': break pem_src += '-----END RSA PUBLIC KEY-----' jwks = {"keys": [{"use": "enc", "e": "AQAB", "kty": "RSA", "n": pub_key_str}, {"use": "sig", "e": "AQAB", "kty": "RSA", "n": pub_key_str}]} jwks_str = json.dumps(jwks) osw.write_str_to_file("./static/jwks.json", jwks_str) sn += 1 osw.write_str_to_file("sn.txt", str(sn)) return sn
def exportKey(self, format='PEM', passphrase=None, pkcs=1): """Export this RSA key. :Parameter format: The format to use for wrapping the key. - *'DER'*. Binary encoding, always unencrypted. - *'PEM'*. Textual encoding, done according to `RFC1421`_/`RFC1423`_. Unencrypted (default) or encrypted. - *'OpenSSH'*. Textual encoding, done according to OpenSSH specification. Only suitable for public keys (not private keys). :Type format: string :Parameter passphrase: In case of PEM, the pass phrase to derive the encryption key from. :Type passphrase: string :Parameter pkcs: The PKCS standard to follow for assembling the key. You have two choices: - with **1**, the public key is embedded into an X.509 `SubjectPublicKeyInfo` DER SEQUENCE. The private key is embedded into a `PKCS#1`_ `RSAPrivateKey` DER SEQUENCE. This mode is the default. - with **8**, the private key is embedded into a `PKCS#8`_ `PrivateKeyInfo` DER SEQUENCE. This mode is not available for public keys. PKCS standards are not relevant for the *OpenSSH* format. :Type pkcs: integer :Return: A byte string with the encoded public or private half. :Raise ValueError: When the format is unknown. .. _RFC1421: http://www.ietf.org/rfc/rfc1421.txt .. _RFC1423: http://www.ietf.org/rfc/rfc1423.txt .. _`PKCS#1`: http://www.ietf.org/rfc/rfc3447.txt .. _`PKCS#8`: http://www.ietf.org/rfc/rfc5208.txt """ if passphrase is not None: passphrase = tobytes(passphrase) if format=='OpenSSH': eb = long_to_bytes(self.e) nb = long_to_bytes(self.n) if bord(eb[0]) & 0x80: eb=bchr(0x00)+eb if bord(nb[0]) & 0x80: nb=bchr(0x00)+nb keyparts = [ b('ssh-rsa'), eb, nb ] keystring = b('').join([ struct.pack(">I",len(kp))+kp for kp in keyparts]) return b('ssh-rsa ')+binascii.b2a_base64(keystring)[:-1] # DER format is always used, even in case of PEM, which simply # encodes it into BASE64. der = DerSequence() if self.has_private(): keyType= { 1: 'RSA PRIVATE', 8: 'PRIVATE' }[pkcs] der[:] = [ 0, self.n, self.e, self.d, self.p, self.q, self.d % (self.p-1), self.d % (self.q-1), inverse(self.q, self.p) ] if pkcs==8: derkey = der.encode() der = DerSequence([0]) der.append(algorithmIdentifier) der.append(DerObject('OCTET STRING', derkey).encode()) else: keyType = "PUBLIC" der.append(algorithmIdentifier) bitmap = DerObject('BIT STRING') derPK = DerSequence( [ self.n, self.e ] ) bitmap.payload = bchr(0x00) + derPK.encode() der.append(bitmap.encode()) if format=='DER': return der.encode() if format=='PEM': pem = b("-----BEGIN " + keyType + " KEY-----\n") objenc = None if passphrase and keyType.endswith('PRIVATE'): # We only support 3DES for encryption import Crypto.Hash.MD5 from Crypto.Cipher import DES3 from Crypto.Protocol.KDF import PBKDF1 salt = self._randfunc(8) key = PBKDF1(passphrase, salt, 16, 1, Crypto.Hash.MD5) key += PBKDF1(key+passphrase, salt, 8, 1, Crypto.Hash.MD5) objenc = DES3.new(key, Crypto.Cipher.DES3.MODE_CBC, salt) pem += b('Proc-Type: 4,ENCRYPTED\n') pem += b('DEK-Info: DES-EDE3-CBC,') + binascii.b2a_hex(salt).upper() + b('\n\n') binaryKey = der.encode() if objenc: # Add PKCS#7-like padding padding = objenc.block_size-len(binaryKey)%objenc.block_size binaryKey = objenc.encrypt(binaryKey+bchr(padding)*padding) # Each BASE64 line can take up to 64 characters (=48 bytes of data) chunks = [ binascii.b2a_base64(binaryKey[i:i+48]) for i in range(0, len(binaryKey), 48) ] pem += b('').join(chunks) pem += b("-----END " + keyType + " KEY-----") return pem return ValueError("Unknown key format '%s'. Cannot export the RSA key." % format)
def testInit1(self): der = DerSequence([1, DerInteger(2), b('0\x00')]) self.assertEqual(der.encode(), b('0\x08\x02\x01\x01\x02\x01\x020\x00'))
def EMSA_PKCS1_V1_5_ENCODE(hash, emLen): """ Implement the ``EMSA-PKCS1-V1_5-ENCODE`` function, as defined in PKCS#1 v2.1 (RFC3447, 9.2). ``EMSA-PKCS1-V1_5-ENCODE`` actually accepts the message ``M`` as input, and hash it internally. Here, we expect that the message has already been hashed instead. :Parameters: hash : hash object The hash object that holds the digest of the message being signed. emLen : int The length the final encoding must have, in bytes. :attention: the early standard (RFC2313) stated that ``DigestInfo`` had to be BER-encoded. This means that old signatures might have length tags in indefinite form, which is not supported in DER. Such encoding cannot be reproduced by this function. :attention: the same standard defined ``DigestAlgorithm`` to be of ``AlgorithmIdentifier`` type, where the PARAMETERS item is optional. Encodings for ``MD2/4/5`` without ``PARAMETERS`` cannot be reproduced by this function. :Return: An ``emLen`` byte long string that encodes the hash. """ # First, build the ASN.1 DER object DigestInfo: # # DigestInfo ::= SEQUENCE { # digestAlgorithm AlgorithmIdentifier, # digest OCTET STRING # } # # where digestAlgorithm identifies the hash function and shall be an # algorithm ID with an OID in the set PKCS1-v1-5DigestAlgorithms. # # PKCS1-v1-5DigestAlgorithms ALGORITHM-IDENTIFIER ::= { # { OID id-md2 PARAMETERS NULL }| # { OID id-md5 PARAMETERS NULL }| # { OID id-sha1 PARAMETERS NULL }| # { OID id-sha256 PARAMETERS NULL }| # { OID id-sha384 PARAMETERS NULL }| # { OID id-sha512 PARAMETERS NULL } # } # digestAlgo = DerSequence([hash.oid, DerNull().encode()]) digest = DerOctetString(hash.digest()) digestInfo = DerSequence([ digestAlgo.encode(), digest.encode() ]).encode() # We need at least 11 bytes for the remaining data: 3 fixed bytes and # at least 8 bytes of padding). if emLen < len(digestInfo) + 11: raise ValueError("Selected hash algorith has a too long digest (%d bytes)." % len(digest)) PS = bchr(0xFF) * (emLen - len(digestInfo) - 3) return b("\x00\x01") + PS + bchr(0x00) + digestInfo
def wrap(private_key, key_oid, passphrase=None, protection=None, prot_params=None, key_params=None, randfunc=None): """Wrap a private key into a PKCS#8 blob (clear or encrypted). :Parameters: private_key : byte string The private key encoded in binary form. The actual encoding is algorithm specific. In most cases, it is DER. key_oid : string The object identifier (OID) of the private key to wrap. It is a dotted string, like "``1.2.840.113549.1.1.1``" (for RSA keys). passphrase : (binary) string The secret passphrase from which the wrapping key is derived. Set it only if encryption is required. protection : string The identifier of the algorithm to use for securely wrapping the key. The default value is '``PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC``'. prot_params : dictionary Parameters for the protection algorithm. +------------------+-----------------------------------------------+ | Key | Description | +==================+===============================================+ | iteration_count | The KDF algorithm is repeated several times to| | | slow down brute force attacks on passwords | | | (called *N* or CPU/memory cost in scrypt). | | | | | | The default value for PBKDF2 is 1 000. | | | The default value for scrypt is 16 384. | +------------------+-----------------------------------------------+ | salt_size | Salt is used to thwart dictionary and rainbow | | | attacks on passwords. The default value is 8 | | | bytes. | +------------------+-----------------------------------------------+ | block_size | *(scrypt only)* Memory-cost (r). The default | | | value is 8. | +------------------+-----------------------------------------------+ | parallelization | *(scrypt only)* CPU-cost (p). The default | | | value is 1. | +------------------+-----------------------------------------------+ key_params : DER object The algorithm parameters associated to the private key. It is required for algorithms like DSA, but not for others like RSA. randfunc : callable Random number generation function; it should accept a single integer N and return a string of random data, N bytes long. If not specified, a new RNG will be instantiated from ``Crypto.Random``. :Return: The PKCS#8-wrapped private key (possibly encrypted), as a binary string. """ if key_params is None: key_params = DerNull() # # PrivateKeyInfo ::= SEQUENCE { # version Version, # privateKeyAlgorithm PrivateKeyAlgorithmIdentifier, # privateKey PrivateKey, # attributes [0] IMPLICIT Attributes OPTIONAL # } # pk_info = DerSequence([ 0, DerSequence([ DerObjectId(key_oid), key_params ]), DerOctetString(private_key) ]) pk_info_der = pk_info.encode() if passphrase is None: return pk_info_der if not passphrase: raise ValueError("Empty passphrase") # Encryption with PBES2 passphrase = tobytes(passphrase) if protection is None: protection = 'PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC' return PBES2.encrypt(pk_info_der, passphrase, protection, prot_params, randfunc)
def _EMSA_PKCS1_V1_5_ENCODE(msg_hash, emLen, with_hash_parameters=True): """ Implement the ``EMSA-PKCS1-V1_5-ENCODE`` function, as defined in PKCS#1 v2.1 (RFC3447, 9.2). ``_EMSA-PKCS1-V1_5-ENCODE`` actually accepts the message ``M`` as input, and hash it internally. Here, we expect that the message has already been hashed instead. :Parameters: msg_hash : hash object The hash object that holds the digest of the message being signed. emLen : int The length the final encoding must have, in bytes. with_hash_parameters : bool If True (default), include NULL parameters for the hash algorithm in the ``digestAlgorithm`` SEQUENCE. :attention: the early standard (RFC2313) stated that ``DigestInfo`` had to be BER-encoded. This means that old signatures might have length tags in indefinite form, which is not supported in DER. Such encoding cannot be reproduced by this function. :Return: An ``emLen`` byte long string that encodes the hash. """ # First, build the ASN.1 DER object DigestInfo: # # DigestInfo ::= SEQUENCE { # digestAlgorithm AlgorithmIdentifier, # digest OCTET STRING # } # # where digestAlgorithm identifies the hash function and shall be an # algorithm ID with an OID in the set PKCS1-v1-5DigestAlgorithms. # # PKCS1-v1-5DigestAlgorithms ALGORITHM-IDENTIFIER ::= { # { OID id-md2 PARAMETERS NULL }| # { OID id-md5 PARAMETERS NULL }| # { OID id-sha1 PARAMETERS NULL }| # { OID id-sha256 PARAMETERS NULL }| # { OID id-sha384 PARAMETERS NULL }| # { OID id-sha512 PARAMETERS NULL } # } # # Appendix B.1 also says that for SHA-1/-2 algorithms, the parameters # should be omitted. They may be present, but when they are, they shall # have NULL value. digestAlgo = DerSequence([ DerObjectId(msg_hash.oid).encode() ]) if with_hash_parameters: digestAlgo.append(DerNull().encode()) digest = DerOctetString(msg_hash.digest()) digestInfo = DerSequence([ digestAlgo.encode(), digest.encode() ]).encode() # We need at least 11 bytes for the remaining data: 3 fixed bytes and # at least 8 bytes of padding). if emLen<len(digestInfo)+11: raise TypeError("Selected hash algorith has a too long digest (%d bytes)." % len(digest)) PS = b'\xFF' * (emLen - len(digestInfo) - 3) return b'\x00\x01' + PS + b'\x00' + digestInfo
def testEncode5(self): der = DerSequence() der += 1 der += b('\x30\x00') self.assertEquals(der.encode(), b('\x30\x05\x02\x01\x01\x30\x00'))
def wrap(private_key, key_oid, passphrase=None, protection=None, prot_params=None, key_params=None, randfunc=None): """Wrap a private key into a PKCS#8 blob (clear or encrypted). :Parameters: private_key : byte string The private key encoded in binary form. The actual encoding is algorithm specific. In most cases, it is DER. key_oid : string The object identifier (OID) of the private key to wrap. It is a dotted string, like "``1.2.840.113549.1.1.1``" (for RSA keys). passphrase : (binary) string The secret passphrase from which the wrapping key is derived. Set it only if encryption is required. protection : string The identifier of the algorithm to use for securely wrapping the key. The default value is '``PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC``'. prot_params : dictionary Parameters for the protection algorithm. +------------------+-----------------------------------------------+ | Key | Description | +==================+===============================================+ | iteration_count | The KDF algorithm is repeated several times to| | | slow down brute force attacks on passwords | | | (called *N* or CPU/memory cost in scrypt). | | | | | | The default value for PBKDF2 is 1 000. | | | The default value for scrypt is 16 384. | +------------------+-----------------------------------------------+ | salt_size | Salt is used to thwart dictionary and rainbow | | | attacks on passwords. The default value is 8 | | | bytes. | +------------------+-----------------------------------------------+ | block_size | *(scrypt only)* Memory-cost (r). The default | | | value is 8. | +------------------+-----------------------------------------------+ | parallelization | *(scrypt only)* CPU-cost (p). The default | | | value is 1. | +------------------+-----------------------------------------------+ key_params : DER object The algorithm parameters associated to the private key. It is required for algorithms like DSA, but not for others like RSA. randfunc : callable Random number generation function; it should accept a single integer N and return a string of random data, N bytes long. If not specified, a new RNG will be instantiated from ``Crypto.Random``. :Return: The PKCS#8-wrapped private key (possibly encrypted), as a binary string. """ if key_params is None: key_params = DerNull() # # PrivateKeyInfo ::= SEQUENCE { # version Version, # privateKeyAlgorithm PrivateKeyAlgorithmIdentifier, # privateKey PrivateKey, # attributes [0] IMPLICIT Attributes OPTIONAL # } # pk_info = DerSequence([ 0, DerSequence([DerObjectId(key_oid), key_params]), DerOctetString(private_key) ]) pk_info_der = pk_info.encode() if passphrase is None: return pk_info_der if not passphrase: raise ValueError("Empty passphrase") # Encryption with PBES2 passphrase = tobytes(passphrase) if protection is None: protection = 'PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC' return PBES2.encrypt(pk_info_der, passphrase, protection, prot_params, randfunc)
def testEncode5(self): der = DerSequence() der += 1 der += b('\x30\x00') self.assertEqual(der.encode(), b('\x30\x05\x02\x01\x01\x30\x00'))
def encrypt(data, passphrase, protection, prot_params=None, randfunc=None): """Encrypt a piece of data using a passphrase and *PBES2*. :Parameters: data : byte string The piece of data to encrypt. passphrase : byte string The passphrase to use for encrypting the data. protection : string The identifier of the encryption algorithm to use. The default value is '``PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC``'. prot_params : dictionary Parameters of the protection algorithm. +------------------+-----------------------------------------------+ | Key | Description | +==================+===============================================+ | iteration_count | The KDF algorithm is repeated several times to| | | slow down brute force attacks on passwords | | | (called *N* or CPU/memory cost in scrypt). | | | | | | The default value for PBKDF2 is 1 000. | | | The default value for scrypt is 16 384. | +------------------+-----------------------------------------------+ | salt_size | Salt is used to thwart dictionary and rainbow | | | attacks on passwords. The default value is 8 | | | bytes. | +------------------+-----------------------------------------------+ | block_size | *(scrypt only)* Memory-cost (r). The default | | | value is 8. | +------------------+-----------------------------------------------+ | parallelization | *(scrypt only)* CPU-cost (p). The default | | | value is 1. | +------------------+-----------------------------------------------+ randfunc : callable Random number generation function; it should accept a single integer N and return a string of random data, N bytes long. If not specified, a new RNG will be instantiated from ``Crypto.Random``. :Returns: The encrypted data, as a binary string. """ if prot_params is None: prot_params = {} if randfunc is None: randfunc = Random.new().read if protection == 'PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC': key_size = 24 module = DES3 cipher_mode = DES3.MODE_CBC enc_oid = "1.2.840.113549.3.7" elif protection in ('PBKDF2WithHMAC-SHA1AndAES128-CBC', 'scryptAndAES128-CBC'): key_size = 16 module = AES cipher_mode = AES.MODE_CBC enc_oid = "2.16.840.1.101.3.4.1.2" elif protection in ('PBKDF2WithHMAC-SHA1AndAES192-CBC', 'scryptAndAES192-CBC'): key_size = 24 module = AES cipher_mode = AES.MODE_CBC enc_oid = "2.16.840.1.101.3.4.1.22" elif protection in ('PBKDF2WithHMAC-SHA1AndAES256-CBC', 'scryptAndAES256-CBC'): key_size = 32 module = AES cipher_mode = AES.MODE_CBC enc_oid = "2.16.840.1.101.3.4.1.42" else: raise ValueError("Unknown PBES2 mode") # Get random data iv = randfunc(module.block_size) salt = randfunc(prot_params.get("salt_size", 8)) # Derive key from password if protection.startswith('PBKDF2'): count = prot_params.get("iteration_count", 1000) key = PBKDF2(passphrase, salt, key_size, count) kdf_info = DerSequence([ DerObjectId("1.2.840.113549.1.5.12"), # PBKDF2 DerSequence([ DerOctetString(salt), DerInteger(count) ]) ]) else: # It must be scrypt count = prot_params.get("iteration_count", 16384) scrypt_r = prot_params.get('block_size', 8) scrypt_p = prot_params.get('parallelization', 1) key = scrypt(passphrase, salt, key_size, count, scrypt_r, scrypt_p) kdf_info = DerSequence([ DerObjectId("1.3.6.1.4.1.11591.4.11"), # scrypt DerSequence([ DerOctetString(salt), DerInteger(count), DerInteger(scrypt_r), DerInteger(scrypt_p) ]) ]) # Create cipher and use it cipher = module.new(key, cipher_mode, iv) encrypted_data = cipher.encrypt(pad(data, cipher.block_size)) enc_info = DerSequence([ DerObjectId(enc_oid), DerOctetString(iv) ]) # Result enc_private_key_info = DerSequence([ # encryptionAlgorithm DerSequence([ DerObjectId("1.2.840.113549.1.5.13"), # PBES2 DerSequence([ kdf_info, enc_info ]), ]), DerOctetString(encrypted_data) ]) return enc_private_key_info.encode()
def testInit1(self): der = DerSequence([1, DerInteger(2), b('0\x00')]) self.assertEquals(der.encode(), b('0\x08\x02\x01\x01\x02\x01\x020\x00'))