def test_secretKeys_known_good_keys(): # test data was obtained by adding debug messages to {"commit":"188b28f","source":"https://github.com/mozilla/send/","version":"v1.2.4"} testdata = { 'secretKey': b'q\xd94B\xa1&\x03\xa5<8\xddk\xee.\xea&', 'encryptKey': b'\xc4\x979\xaa\r\n\xeb\xc7\xa16\xa4%\xfd\xa6\x91\t', 'authKey': b'5\xa0@\xef\xd0}f\xc7o{S\x05\xe4,\xe1\xe4\xc2\x8cE\xa1\xfat\xc1\x11\x94e[L\x89%\xf5\x8b\xfc\xb5\x9b\x87\x9a\xf2\xc3\x0eKt\xdeL\xab\xa4\xa6%t\xa6"4\r\x07\xb3\xf5\xf6\xb9\xec\xcc\x08\x80}\xea', 'metaKey': b'\xd5\x9dF\x05\x86\x1a\xfdi\xaeK+\xe7\x8e\x7f\xf2\xfd', 'password': '******', 'url': 'http://192.168.254.87:1443/download/fa4cd959de/#cdk0QqEmA6U8ON1r7i7qJg', 'newAuthKey': b'U\x02F\x19\x1b\xc1W\x03q\x86q\xbc\xe7\x84WB\xa7(\x0f\x8a\x0f\x17\\\xb9y\xfaZT\xc1\xbf\xb2\xd48\x82\xa7\t\x9a\xb1\x1e{cg\n\xc6\x995+\x0f\xd3\xf4\xb3kd\x93D\xca\xf9\xa1(\xdf\xcb_^\xa3', } # generate all keys keys = secretKeys(secretKey=testdata['secretKey'], password=testdata['password'], url=testdata['url']) # Check every key has the expected value assert keys.secretKey == testdata['secretKey'] assert keys.encryptKey == testdata['encryptKey'] assert keys.authKey == testdata['authKey'] assert keys.metaKey == testdata['metaKey'] assert keys.password == testdata['password'] assert keys.url == testdata['url'] assert keys.newAuthKey == testdata['newAuthKey']
def send_file(service, file, fileName=None, password=None, ignoreVersion=False): if checkServerVersion(service, ignoreVersion=ignoreVersion) == False: print( '\033[1;41m!!! Potentially incompatible server version !!!\033[0m') ''' Encrypt & Upload a file to send and return the download URL''' fileName = fileName if fileName != None else os.path.basename(file.name) print('Encrypting data from "' + fileName + '"') keys = secretKeys() encData = encrypt_file(file, keys) encMeta = encrypt_metadata(keys, fileName) print('Uploading "' + fileName + '"') secretUrl, fileId, fileNonce, delete_token = api_upload( service, encData, encMeta, keys) if password != None: print('Setting password') set_password(service, keys, secretUrl, fileId, password, fileNonce) return secretUrl, delete_token
def send_urlToFile(url, password=None, ignoreVersion=False): service, fileId, key = splitkeyurl(url) if checkServerVersion(service, ignoreVersion) == False: raise Exception('Potentially incompatible server version, use --ignore-version to disable version checks') passwordRequired = check_for_password(service + 'download/' + str(fileId) + '/') rawKey = unpadded_urlsafe_b64decode(key) if passwordRequired == False and password == None: keys = secretKeys(rawKey) elif passwordRequired == True and password != None: keys = secretKeys(rawKey, password=password, url=url) keys.authKey = keys.newAuthKey elif passwordRequired and password == None: print("A password is required, please enter it now") password = getpass.getpass() keys = secretKeys(rawKey, password=password, url=url) keys.authKey = keys.newAuthKey elif passwordRequired == False and password != None: raise Exception('A password was provided but none is required') print('Checking if file exists...') passwordRequired = check_for_password(service + 'download/' + fileId) if password == None and passwordRequired == True: raise Exception('This Send url requires a password') nonce = get_nonce(service + 'download/' + str(fileId) + '/') authorisation = sign_nonce(keys.authKey, nonce) print('Fetching metadata...') jsonMeta, nonce = api_metadata(service, fileId, authorisation) encMeta = unpadded_urlsafe_b64decode(jsonMeta['metadata']) metadata = decrypt_metadata(encMeta, keys) keys.encryptIV = unpadded_urlsafe_b64decode(metadata['iv']) print('The file wishes to be called \'' + metadata['name'] + '\' and is ' + str(jsonMeta['size'] - 16) + ' bytes in size') print('Downloading ' + url) authorisation = sign_nonce(keys.authKey, nonce) data = api_download(service, fileId, authorisation) print('Decrypting to temp file') tmpfile = decrypt_filedata(data, keys) return tmpfile, metadata['name']
def test_secretKeys_random_key_lengths(): # test key generation without providing the master secretKey keys = secretKeys() assert len(keys.secretKey) == 16 assert len(keys.encryptKey) == 16 assert len(keys.encryptIV) == 12 assert len(keys.authKey) == 64 assert len(keys.metaKey) == 16 assert len(keys.deriveNewAuthKey('drowssap', 'https://send.server/download/aFileID/#someSecretKey' )) == 64
def encrypt_file(file, keys=secretKeys()): '''Encrypt file data with the same method as the Send browser/js client''' key = keys.encryptKey iv = keys.encryptIV encData = tempfile.SpooledTemporaryFile(max_size=SPOOL_SIZE, mode='w+b') cipher = Cryptodome.Cipher.AES.new(key, Cryptodome.Cipher.AES.MODE_GCM, iv) pbar = progbar(fileSize(file)) for chunk in iter(lambda: file.read(CHUNK_SIZE), b''): encData.write(cipher.encrypt(chunk)) pbar.update(len(chunk)) pbar.close() encData.write(cipher.digest()) file.close() encData.seek(0) return encData