Comments (7)
The task is to read more about crypthogrphy.io.
from internet-voting.
RSA can only encrypt data blocks that are shorter than the key length.
Usually, RSA is only used to transfer a symmetric key (at the start of the stream for example) and then the bulk data is encrypted with that key.
Asymmetric encryption isn't efficient enough to transfer a lot of data.
http://security.stackexchange.com/a/33445
from internet-voting.
Padding is a way to take data that may or may not be a multiple of the block size for a cipher and extend it out so that it is. This is required for many block cipher modes as they require the data to be encrypted to be an exact multiple of the block size.
https://cryptography.io/en/latest/hazmat/primitives/padding/
from internet-voting.
Very well explained what is RSA: http://unix.stackexchange.com/a/12265
It looks like we have to use RSA just to encrypt asymmetric key, and the whole message has to be encrypted using that asymmetric key. See https://cryptography.io/en/latest/fernet/
from internet-voting.
I just read more about PKI and yes, asymmetric algorithms usually are used only for symmetric key exchange. Then, rest of the encryption is done by symmetric algorithms using that exchanged key.
So your task will bet to encrypt message multiple time with list of given symmetric keys, using Fernet protocol. And the key exchange protocol is a different task.
from internet-voting.
After thinking more about this, I figured out, that you still need public keys. So the API stays the same:
envelope = create_envelope(nodes, content)
Here nodes
is a list of tuples, each tuple has mix-net node id (an int
) and public key instance.
When creating multi-layered envelope, for each layer you need a JSON list with two elements:
- Fernet key encoded with node's public key.
- The message encoded with Fernet key. Message should be JSON list with two elements:
- The inner envelope.
- Next node Id (
int
). Node Id of first layer should beNone
.
The envelope could look something like this (pseudocode):
envelope = json([
json([
node[1].public_key.encrypt(node[0].fernet_key),
node[1].fernet_key.encrypt(json([
json([
node[0].public_key.encrypt(node[0].fernet_key),
node[0].fernet_key.encrypt(message),
]),
node[0].id,
]))
]),
node[1].id,
])
Here node[0]
would be CEC.
For decoding envelope this API can be used:
content, next_node_id = decrypt_envelope(primary_key, envelope)
Here is what it should do:
- Deserialize envelope using
json.loads
. - Decrypt first element, using
primary_key
to get Fernet key. - Decrypt second element using decrypted Fernet key.
- Deserialize JSON to get
content
(inner envelope) andnext_node_id
(address).
For the serialization, I'm not sure if JSON is a good choice, since we will be dealing with binary data. Maybe we should use MessagePack instead of JSON?
from internet-voting.
Today decided to look into crypto things, and assembled set of functions, that should cover most of crypto needs. It would be good, if you wood put into some module and use these functions for your task.
import os
import json
import base64
import hashlib
import binascii
from cryptography.fernet import Fernet
from cryptography.exceptions import InvalidSignature
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.primitives.asymmetric import padding as asymmetric_padding
def generate(size: int=4096):
return rsa.generate_private_key(
public_exponent=65537,
key_size=size,
backend=default_backend(),
)
def dump_base64(data: bytes) -> str:
return base64.encodebytes(data).replace(b'\n', b'').decode('ascii')
def load_base64(data: str) -> bytes:
return base64.decodebytes(data.encode('ascii'))
def dump_private_key(private_key, password: str=None) -> str:
if password is None:
encryption_algorithm = serialization.NoEncryption()
else:
encryption_algorithm = serialization.BestAvailableEncryption(password.encode('utf-8'))
private_key_bytes = private_key.private_bytes(
encoding=serialization.Encoding.DER,
format=serialization.PrivateFormat.PKCS8,
encryption_algorithm=encryption_algorithm,
)
return dump_base64(private_key_bytes)
def load_private_key(private_key_data: str, password: str=None):
return serialization.load_der_private_key(
load_base64(private_key_data),
password=password.encode('utf-8'),
backend=default_backend()
)
def dump_public_key(public_key) -> str:
public_key_bytes = public_key.public_bytes(
encoding=serialization.Encoding.DER,
format=serialization.PublicFormat.SubjectPublicKeyInfo,
)
return dump_base64(public_key_bytes)
def load_public_key(public_key_data: str):
return serialization.load_der_public_key(
load_base64(public_key_data),
backend=default_backend(),
)
def public_key_fingerprint(public_key) -> str:
public_key_bytes = public_key.public_bytes(
encoding=serialization.Encoding.DER,
format=serialization.PublicFormat.SubjectPublicKeyInfo,
)
return hashlib.sha1(public_key_bytes).hexdigest()
def encrypt(public_key, message: str) -> (str, str):
key = Fernet.generate_key()
fernet = Fernet(key)
cipher = fernet.encrypt(message.encode('utf-8'))
key = public_key.encrypt(key, asymmetric_padding.OAEP(
mgf=asymmetric_padding.MGF1(algorithm=hashes.SHA1()),
algorithm=hashes.SHA1(),
label=None,
))
return dump_base64(key), cipher.decode('ascii')
def decrypt(private_key, key: str, cipher: str) -> str:
key = private_key.decrypt(load_base64(key), asymmetric_padding.OAEP(
mgf=asymmetric_padding.MGF1(algorithm=hashes.SHA1()),
algorithm=hashes.SHA1(),
label=None,
))
fernet = Fernet(key)
message = fernet.decrypt(cipher.encode('ascii'))
return message.decode('utf-8')
def sign(private_key, message: str) -> str:
signer = private_key.signer(
asymmetric_padding.PSS(
mgf=asymmetric_padding.MGF1(hashes.SHA256()),
salt_length=asymmetric_padding.PSS.MAX_LENGTH
),
hashes.SHA256()
)
signer.update(message.encode('utf-8'))
return dump_base64(signer.finalize())
def verify(public_key, message: str, signature: str) -> bool:
verifier = public_key.verifier(
load_base64(signature),
asymmetric_padding.PSS(
mgf=asymmetric_padding.MGF1(hashes.SHA256()),
salt_length=asymmetric_padding.PSS.MAX_LENGTH
),
hashes.SHA256()
)
verifier.update(message.encode('utf-8'))
try:
verifier.verify()
except InvalidSignature:
return False
else:
return True
def get_random_bytes(n: int) -> bytes:
return os.urandom(n)
def apply_hash_function(message: str, salt: bytes) -> str:
hash_bytes = hashlib.pbkdf2_hmac('sha1', message.encode('utf-8'), salt, 1000000)
return binascii.hexlify(hash_bytes).decode('utf-8')
def password_to_fernet_key(password: str, salt: bytes) -> bytes:
key = hashlib.pbkdf2_hmac('sha256', password.encode('utf-8'), salt, 1000000)
return base64.urlsafe_b64encode(key)
def fernet_encrypt(password: str, salt: bytes, data: str) -> bytes:
fernet = Fernet(password_to_fernet_key(password, salt))
return base64.urlsafe_b64decode(fernet.encrypt(data.encode('utf-8')).decode('ascii'))
def fernet_decrypt(password: str, salt: bytes, cipher: str) -> str:
fernet = Fernet(password_to_fernet_key(password, salt))
return fernet.decrypt(base64.urlsafe_b64encode(cipher)).decode('utf-8')
def dump_sensitive_data(password: str, data) -> bytes:
salt = get_random_bytes(32)
cipher = fernet_encrypt(password, salt, json.dumps(data))
return salt + cipher
def load_sensitive_data(password: str, cipher: bytes):
return json.loads(fernet_decrypt(password, cipher[:32], cipher[32:]))
from internet-voting.
Related Issues (10)
- Ability to publish public key by VRK representative
- Generate and serialize private and public keys
- Public key fingerprint
- Ability to publish public key for observer
- Ability to publish a public key for voters
- Ability for voters to prove their identity HOT 1
- Command line voting client argument parser HOT 1
- Incremental signing HOT 2
- Mix-net node deamon
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from internet-voting.