You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@warble.apache.org by hu...@apache.org on 2018/06/25 22:35:11 UTC

[incubator-warble-node] 02/07: Add a basic crypto lib

This is an automated email from the ASF dual-hosted git repository.

humbedooh pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-warble-node.git

commit 114c371c5971032db6337c5a08f0c11689099f91
Author: Daniel Gruno <hu...@apache.org>
AuthorDate: Mon Jun 25 16:56:30 2018 -0500

    Add a basic crypto lib
---
 plugins/basics/__init__.py |   1 +
 plugins/basics/crypto.py   | 163 +++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 164 insertions(+)

diff --git a/plugins/basics/__init__.py b/plugins/basics/__init__.py
index 8f21a81..c9184a3 100644
--- a/plugins/basics/__init__.py
+++ b/plugins/basics/__init__.py
@@ -1,5 +1,6 @@
 import plugins.basics.socket
 import plugins.basics.misc
+import plugins.basics.crypto
 
 __all__ = [
     'misc',
diff --git a/plugins/basics/crypto.py b/plugins/basics/crypto.py
new file mode 100644
index 0000000..9902c54
--- /dev/null
+++ b/plugins/basics/crypto.py
@@ -0,0 +1,163 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+ #the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+""" This is the library for basic cryptographic features in
+    Apache Warble (incubating) nodes. It includes wrappers for
+    encrypting, decrypting, signing and verifying using RSA async key
+    pairs.
+    
+    NB: Ideally we'd use SHA256 for hashing, but as that still isn't
+    widely supported, we're resorting to SHA1 for now.
+"""
+
+import cryptography.hazmat.backends
+import cryptography.hazmat.primitives
+import cryptography.hazmat.primitives.asymmetric.rsa
+import cryptography.hazmat.primitives.asymmetric.utils
+import cryptography.hazmat.primitives.asymmetric.padding
+import cryptography.hazmat.primitives.hashes
+
+def keypair(bits = 4096):
+    """ Generate a private+public key pair for encryption/signing """
+    private_key = cryptography.hazmat.primitives.asymmetric.rsa.generate_private_key(
+        public_exponent=65537,
+        key_size=bits, # Minimum hould be 4096, puhlease.
+        backend=cryptography.hazmat.backends.default_backend()
+    )
+    return private_key
+
+def decrypt(key, text):
+    """ Decrypt a message encrypted with the public key, by using the private key on-disk """
+    retval = b""
+    i = 0
+    txtl = len(text)
+    ks = int(key.key_size / 8) # bits -> bytes, room for padding
+    # Process the data in chunks the size of the key, as per the encryption
+    # model used below.
+    while i < txtl:
+        chunk = text[i:i+ks]
+        i += ks
+        ciphertext = key.decrypt(
+            chunk,
+            cryptography.hazmat.primitives.asymmetric.padding.OAEP(
+                mgf=cryptography.hazmat.primitives.asymmetric.padding.MGF1(
+                    algorithm=cryptography.hazmat.primitives.hashes.SHA1()
+                    ),
+                algorithm=cryptography.hazmat.primitives.hashes.SHA1(),
+                label=None
+            )
+        )
+        retval += ciphertext
+    return retval
+
+def encrypt(key, text):
+    """ Encrypt a message using the public key, for decryption with the private key """
+    retval = b""
+    i = 0
+    txtl = len(text)
+    ks = int(key.key_size / 8) - 64 # bits -> bytes, room for padding
+    # Process data in chunks no larger than the key, leave some room for padding.
+    while i < txtl:
+        chunk = text[i:i+ks-1]
+        i += ks
+        ciphertext = key.encrypt(
+            chunk.encode('utf-8'),
+            cryptography.hazmat.primitives.asymmetric.padding.OAEP(
+                mgf=cryptography.hazmat.primitives.asymmetric.padding.MGF1(
+                    algorithm=cryptography.hazmat.primitives.hashes.SHA1()
+                    ),
+                algorithm=cryptography.hazmat.primitives.hashes.SHA1(),
+                label=None
+            )
+        )
+        retval += ciphertext
+    return retval
+
+
+def sign(key, text):
+    """ Signs a string with the private key """
+    hashver = cryptography.hazmat.primitives.hashes.SHA1()
+    hasher = cryptography.hazmat.primitives.hashes.Hash(hashver, cryptography.hazmat.backends.default_backend())
+    retval = b""
+    i = 0
+    txtl = len(text)
+    ks = int(key.key_size / 8)
+    while i < txtl:
+        chunk = text[i:i+ks-1]
+        i += ks
+        hasher.update(chunk.encode('utf-8'))
+    digest = hasher.finalize()
+    sig = key.sign(
+        digest,
+        cryptography.hazmat.primitives.asymmetric.padding.PSS(
+            mgf=cryptography.hazmat.primitives.asymmetric.padding.MGF1(cryptography.hazmat.primitives.hashes.SHA1()),
+            salt_length=cryptography.hazmat.primitives.asymmetric.padding.PSS.MAX_LENGTH
+        ),
+        cryptography.hazmat.primitives.asymmetric.utils.Prehashed(hashver)
+    )
+    return sig
+
+def verify(key, sig, text):
+    """ Verifies a signature of a text using the public key """
+    hashver = cryptography.hazmat.primitives.hashes.SHA1()
+    hasher = cryptography.hazmat.primitives.hashes.Hash(hashver, cryptography.hazmat.backends.default_backend())
+    retval = b""
+    i = 0
+    txtl = len(text)
+    ks = int(key.key_size / 8)
+    while i < txtl:
+        chunk = text[i:i+ks-1]
+        i += ks
+        hasher.update(chunk.encode('utf-8'))
+    digest = hasher.finalize()
+    try:
+        key.verify(
+            sig,
+            digest,
+            cryptography.hazmat.primitives.asymmetric.padding.PSS(
+                mgf=cryptography.hazmat.primitives.asymmetric.padding.MGF1(cryptography.hazmat.primitives.hashes.SHA1()),
+                salt_length=cryptography.hazmat.primitives.asymmetric.padding.PSS.MAX_LENGTH
+            ),
+            cryptography.hazmat.primitives.asymmetric.utils.Prehashed(hashver)
+        )
+        return True
+    except cryptography.exceptions.InvalidSignature as err:
+        return False
+
+def test():
+    """ Tests for the crypto lib """
+    
+    # Generate a key pair, agree on a string to test with
+    privkey = keypair()
+    pubkey = privkey.public_key()
+    mystring = "Bob was here, his burgers were great."
+    
+    # Test encrypting
+    etxt = encrypt(pubkey, mystring)
+    
+    # Test decrypting
+    dtxt = decrypt(privkey, etxt)
+    assert(mystring == str(dtxt, 'utf-8'))
+    
+    # Test signing
+    xx = sign(privkey, mystring)
+    
+    # Test verification
+    assert( verify(pubkey, xx, mystring))
+    
+    print("Crypto lib works as intended!")
+


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@warble.apache.org
For additional commands, e-mail: commits-help@warble.apache.org