From: Brian Warner Date: Tue, 4 Dec 2007 00:27:46 +0000 (-0700) Subject: use AES from pycryptopp instead of pycrypto, also truncate the keys slightly differently X-Git-Url: https://git.rkrishnan.org/architecture.txt?a=commitdiff_plain;h=0bf5a762a995f17aeb60d1576d610ad2207da64f;p=tahoe-lafs%2Ftahoe-lafs.git use AES from pycryptopp instead of pycrypto, also truncate the keys slightly differently --- diff --git a/calcdeps.py b/calcdeps.py index d5adc975..53c1358a 100644 --- a/calcdeps.py +++ b/calcdeps.py @@ -24,7 +24,7 @@ except ImportError: install_requires=["zfec >= 1.0.3", "foolscap >= 0.1.6", "simplejson >= 1.4", - "pycryptopp >= 0.2.6", + "pycryptopp >= 0.2.8", ] diff --git a/docs/mutable.txt b/docs/mutable.txt index ee01d044..858f8043 100644 --- a/docs/mutable.txt +++ b/docs/mutable.txt @@ -99,10 +99,11 @@ encrypted child names to rw-URI/ro-URI pairs. Each SDMF slot is created with a public/private key pair. The public key is known as the "verification key", while the private key is called the -"signature key". The private key is hashed to form the "write key" (an AES -symmetric key). The write key is then hashed to form the "read key". The read -key is hashed to form the "storage index" (a unique string used as an index -to locate stored data). +"signature key". The private key is hashed and truncated to 16 bytes to form +the "write key" (an AES symmetric key). The write key is then hashed and +truncated to form the "read key". The read key is hashed and truncated to +form the 16-byte "storage index" (a unique string used as an index to locate +stored data). The public key is hashed by itself to form the "verification key hash". diff --git a/src/allmydata/dirnode2.py b/src/allmydata/dirnode2.py index 5a1cecdb..9b5e630d 100644 --- a/src/allmydata/dirnode2.py +++ b/src/allmydata/dirnode2.py @@ -11,7 +11,7 @@ from allmydata.interfaces import IMutableFileNode, IDirectoryNode,\ from allmydata.util import hashutil from allmydata.util.hashutil import netstring from allmydata.uri import NewDirectoryURI -from allmydata.Crypto.Cipher import AES +from pycryptopp.cipher.aes import AES from allmydata.mutable import MutableFileNode @@ -79,9 +79,8 @@ class NewDirectoryNode: assert isinstance(rwcap, str) IV = os.urandom(16) key = hashutil.mutable_rwcap_key_hash(IV, self._node.get_writekey()) - counterstart = "\x00"*16 - cryptor = AES.new(key=key, mode=AES.MODE_CTR, counterstart=counterstart) - crypttext = cryptor.encrypt(rwcap) + cryptor = AES(key) + crypttext = cryptor.process(rwcap) mac = hashutil.hmac(key, IV + crypttext) assert len(mac) == 32 return IV + crypttext + mac @@ -93,9 +92,8 @@ class NewDirectoryNode: key = hashutil.mutable_rwcap_key_hash(IV, self._node.get_writekey()) if mac != hashutil.hmac(key, IV+crypttext): raise hashutil.IntegrityCheckError("HMAC does not match, crypttext is corrupted") - counterstart = "\x00"*16 - cryptor = AES.new(key=key, mode=AES.MODE_CTR, counterstart=counterstart) - plaintext = cryptor.decrypt(crypttext) + cryptor = AES(key) + plaintext = cryptor.process(crypttext) return plaintext def _create_node(self, child_uri): diff --git a/src/allmydata/download.py b/src/allmydata/download.py index 88834667..a0a0367e 100644 --- a/src/allmydata/download.py +++ b/src/allmydata/download.py @@ -10,9 +10,9 @@ from foolscap.eventual import eventually from allmydata.util import idlib, mathutil, hashutil from allmydata.util.assertutil import _assert from allmydata import codec, hashtree, storage, uri -from allmydata.Crypto.Cipher import AES from allmydata.interfaces import IDownloadTarget, IDownloader, IFileURI from allmydata.encode import NotEnoughPeersError +from pycryptopp.cipher.aes import AES class HaveAllPeersError(Exception): # we use this to jump out of the loop @@ -31,8 +31,7 @@ class DownloadStopped(Exception): class Output: def __init__(self, downloadable, key, total_length): self.downloadable = downloadable - self._decryptor = AES.new(key=key, mode=AES.MODE_CTR, - counterstart="\x00"*16) + self._decryptor = AES(key) self._crypttext_hasher = hashutil.crypttext_hasher() self._plaintext_hasher = hashutil.plaintext_hasher() self.length = 0 @@ -59,7 +58,7 @@ class Output: crypttext_leaves = {self._segment_number: ch.digest()} self._crypttext_hash_tree.set_hashes(leaves=crypttext_leaves) - plaintext = self._decryptor.decrypt(crypttext) + plaintext = self._decryptor.process(crypttext) del crypttext # now we're back down to 1*segment_size. diff --git a/src/allmydata/mutable.py b/src/allmydata/mutable.py index c8fa347f..29e1ba2a 100644 --- a/src/allmydata/mutable.py +++ b/src/allmydata/mutable.py @@ -8,10 +8,10 @@ from foolscap.eventual import eventually from allmydata.interfaces import IMutableFileNode, IMutableFileURI from allmydata.util import hashutil, mathutil, idlib, log from allmydata.uri import WriteableSSKFileURI -from allmydata.Crypto.Cipher import AES from allmydata import hashtree, codec from allmydata.encode import NotEnoughPeersError from pycryptopp.publickey import rsa +from pycryptopp.cipher.aes import AES class NotMutableError(Exception): @@ -400,6 +400,7 @@ class Retrieve: if not self._pubkey: fingerprint = hashutil.ssk_pubkey_fingerprint_hash(pubkey_s) + assert len(fingerprint) == 32 if fingerprint != self._node._fingerprint: raise CorruptShareError(peerid, shnum, "pubkey doesn't match fingerprint") @@ -682,8 +683,8 @@ class Retrieve: def _decrypt(self, crypttext, IV, seqnum, root_hash): key = hashutil.ssk_readkey_data_hash(IV, self._readkey) - decryptor = AES.new(key=key, mode=AES.MODE_CTR, counterstart="\x00"*16) - plaintext = decryptor.decrypt(crypttext) + decryptor = AES(key) + plaintext = decryptor.process(crypttext) # it worked, so record the seqnum and root_hash for next time self._node._populate_seqnum(seqnum) self._node._populate_root_hash(root_hash) @@ -1016,8 +1017,8 @@ class Publish: self.log("_encrypt_and_encode") key = hashutil.ssk_readkey_data_hash(IV, readkey) - enc = AES.new(key=key, mode=AES.MODE_CTR, counterstart="\x00"*16) - crypttext = enc.encrypt(newdata) + enc = AES(key) + crypttext = enc.process(newdata) assert len(crypttext) == len(newdata) # now apply FEC @@ -1320,13 +1321,13 @@ class MutableFileNode: return d def _encrypt_privkey(self, writekey, privkey): - enc = AES.new(key=writekey, mode=AES.MODE_CTR, counterstart="\x00"*16) - crypttext = enc.encrypt(privkey) + enc = AES(writekey) + crypttext = enc.process(privkey) return crypttext def _decrypt_privkey(self, enc_privkey): - enc = AES.new(key=self._writekey, mode=AES.MODE_CTR, counterstart="\x00"*16) - privkey = enc.decrypt(enc_privkey) + enc = AES(self._writekey) + privkey = enc.process(enc_privkey) return privkey def _populate(self, stuff): diff --git a/src/allmydata/upload.py b/src/allmydata/upload.py index 496568c7..972de770 100644 --- a/src/allmydata/upload.py +++ b/src/allmydata/upload.py @@ -13,7 +13,7 @@ from allmydata.util.hashutil import file_renewal_secret_hash, \ from allmydata import encode, storage, hashtree, uri from allmydata.util import idlib, mathutil from allmydata.interfaces import IUploadable, IUploader, IEncryptedUploadable -from allmydata.Crypto.Cipher import AES +from pycryptopp.cipher.aes import AES from cStringIO import StringIO @@ -329,7 +329,7 @@ class EncryptAnUploadable: d = self.original.get_encryption_key() def _got(key): - e = AES.new(key=key, mode=AES.MODE_CTR, counterstart="\x00"*16) + e = AES(key) self._encryptor = e storage_index = storage_index_chk_hash(key) @@ -390,7 +390,7 @@ class EncryptAnUploadable: chunk = data.pop(0) self._plaintext_hasher.update(chunk) self._update_segment_hash(chunk) - cryptdata.append(self._encryptor.encrypt(chunk)) + cryptdata.append(self._encryptor.process(chunk)) del chunk return cryptdata d.addCallback(_got) diff --git a/src/allmydata/util/hashutil.py b/src/allmydata/util/hashutil.py index 5bac1ae2..98d5f151 100644 --- a/src/allmydata/util/hashutil.py +++ b/src/allmydata/util/hashutil.py @@ -123,9 +123,9 @@ def hmac(tag, data): return h2 def mutable_rwcap_key_hash(iv, writekey): - return tagged_pair_hash("allmydata_mutable_rwcap_key_v1", iv, writekey) + return tagged_pair_hash("allmydata_mutable_rwcap_key_v1", iv, writekey)[:16] def ssk_writekey_hash(privkey): - return tagged_hash("allmydata_mutable_writekey_v1", privkey) + return tagged_hash("allmydata_mutable_writekey_v1", privkey)[:16] def ssk_write_enabler_master_hash(writekey): return tagged_hash("allmydata_mutable_write_enabler_master_v1", writekey) def ssk_write_enabler_hash(writekey, peerid): @@ -137,8 +137,8 @@ def ssk_pubkey_fingerprint_hash(pubkey): return tagged_hash("allmydata_mutable_pubkey_v1", pubkey) def ssk_readkey_hash(writekey): - return tagged_hash("allmydata_mutable_readkey_v1", writekey) + return tagged_hash("allmydata_mutable_readkey_v1", writekey)[:16] def ssk_readkey_data_hash(IV, readkey): - return tagged_pair_hash("allmydata_mutable_readkey_data_v1", IV, readkey) + return tagged_pair_hash("allmydata_mutable_readkey_data_v1", IV, readkey)[:16] def ssk_storage_index_hash(readkey): return tagged_hash("allmydata_mutable_storage_index_v1", readkey)[:16]