#!/usr/bin/env python # # /* zx8 (ps) - Stream Cipher Algorithm/Source Code */ # # /* # Copyright (c) 2012, Karl-Uwe Frank # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are # met: # # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS # IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED # TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A # PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED # TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # #** zx8 (ps) algorithm developed by Karl-Uwe Frank # */ # # ### zx8 Message/File Encryption using File Hash for IV ### # # P = Plaintext # K = memorable Keyword # C = Ciphertext # # P_h = File Content Hash # seed = keyed HMAC_md5 # dkLen = 64 byte (512 bit) # #i = Iteration # # R = Pseudo-random Data from external Source # time = POSIX Timestamp with Millisecond Precision # HMAC = with MD5Digest # PRF = HMAC # KBF = Keystream Byte Function # # key = Intermediate Key for KBF seeding to derive Ckey and Mkey # Ckey = Plaintext/Ciphertext Encryption/Decryption Key # Mkey = Message Authentication Key # # || = Concatenation of Strings # # # Encryption # ========== # P_h = MD5(P) # seed = HMAC(P_h, netinfo || fileinfo || time || R) || R # IV = KBF(zx8, seed, 1024, dkLen) # # key = PBKDF2(PRF, K, IV, #i, dkLen) # Ckey = KBF(zx8, key, 1024, dkLen) # Mkey = KBF(zx8, key, 2048, dkLen) # C = zx8(Ckey, P) # MAC = HMAC(Mkey, IV || C) # # # Decryption # ========== # key = PBKDF2(PRF, K, IV, #i, dkLen) # Ckey = KBF(zx8, key, 1024, dkLen) # Mkey = KBF(zx8, key, 2048, dkLen) # MAC = HMAC(Mkey, IV || C)) # P = zx8(Ckey, C) # # # # # KBF Function Description: # ========================= # KBF(Algorithm, Key, Drop, Byte) # # Algorithm = zx8 Stream Cipher # Key = defined Keyword # Drop = Byte to drop after KSA # Byte = Amount of Byte captured from generated Keystream # r = Return Value # # zx8_KSA(Key) # # for i=1 to Drop # zx8_PRGA() # next # # for i=1 to Byte # r = r || zx8_PRGA() # next # import sys, os # ----------------------------------------- # # Global Functions # import zx8_ftCrypto_fn as fn #----------------------------------------- # def ShowUsage(ThisName): fn.printf ("\nUsage: %s -e InFile OutFile for encryption\n" % ThisName) fn.printf ("Usage: %s -d InFile OutFile for decryption\n\n" % ThisName) fn.printf ("\nexample: pypy %s -e ~/Public/zero_1MB.bin ~/Public/zero_1MB.bin.zx8 keyword\n\n" % ThisName) fn.printf (" pypy %s -d ~/Public/zero_1MB.bin.zx8 ~/Public/zero_1MB-out.bin keyword\n\n" % ThisName) # ----------------------------------------- # # Show some Process Details # def StatusInfo(Direction, InFile, OutFile): if (Direction == "-e"): fn.printf("\n===================================================\n") fn.printf("Encrypting: %s\nto file : %s\n" % (InFile, OutFile)) fn.printf("===================================================\n") else: fn.printf("\n===================================================\n") fn.printf("Decrypting: %s\nto file : %s\n" % (InFile, OutFile)) fn.printf("===================================================\n") # ----------------------------------------- # # Main # def main(): # # Check if a Parameter are passed through PrgName = InFile = OutFile = Direction = str('') PrgName = sys.argv[0] if (len(sys.argv) < 4): ShowUsage(PrgName) sys.exit() else: Direction = sys.argv[1] if ( (Direction != "-e") and (Direction != "-d") ): ShowUsage(PrgName) sys.exit() # Set InFile and OutFile Name InFile = sys.argv[2] OutFile = sys.argv[3] if (len(sys.argv) == 5): PassedKey = sys.argv[4] else: PassedKey = False # ----------------------------------------- # Declare Variables # Algorithm = 'ps' Version = 'b1' nKeyByte = 64 # Byte Length (512 bit) of the Crypto_Key and MAC_Key KDF_Rounds = 32 # 32*256 = 8192 nDropKSA = 8 # 8*256 = 2048 HashType = "m" # m=md5 s=sha nHMACHashSize = 7 # md5=(2**7) sha256=(2**8) sha512=(2**9) bVal = int(Version[1:2]) # Value to set zx8 Index Pointer Value for b nMACsize = pow(2, nHMACHashSize)/8 # Length of the Hash Hex-String # if MD5 or SHA1 then use two concatenated Hashes as IV if ((nMACsize*8) < 256): IV_Length = nMACsize*4 else: IV_Length = nMACsize*2 IV = str('') Crypto_Key = str('') MAC_Key = str('') HeaderInfo = str('') seekPos = int(0) # ----------------------------------------- # First try to open the Input File # fIn = fn.OpenInFile(InFile) fIn.seek(0,2) # EOF inFileSize = fIn.tell() fIn.seek(0,0) # rewind # ----------------------------------------- # Read the Encryption Keyword # KeyWord = bytearray(256) KeyLen = int(0) fn.ReadKeyword(KeyWord, KeyLen, PassedKey, Direction) from time import time start = time() # ----------------------------------------- # # Encryption # # ----------------------------------------- # # Generate the IV if (Direction == "-e"): # # HMac of Plaintext Hash and Unix timestamp # in order to generate an always unique IV # IV = fn.IV__MD5_file(KeyWord, nKeyByte, InFile, nDropKSA, KDF_Rounds, IV_Length, bVal) # Derive the Keys and return MAC_Key for later use MAC_Key = fn.DeriveKeys(KeyWord, IV, Crypto_Key, MAC_Key, nKeyByte, nDropKSA, KDF_Rounds, bVal) # Prepend the Algorithm Info HeaderInfo += Algorithm # Prepend the Algorithm Version HeaderInfo += Version # Prepend the Length of Key Byte HeaderInfo += chr(nKeyByte) # Prepend the Value for the KDF Rounds HeaderInfo += chr(KDF_Rounds) # Prepend how may Byte to drop after the KSA HeaderInfo += chr(nDropKSA) # Prepend the Hash Identifier and Value for the HMac Rounds HeaderInfo += HashType HeaderInfo += chr(nHMACHashSize) # Add 11 Byte as Placeholder for later Extensions # because HeaderInfo has alway 20 Byte # before the IV for i in range(0,11): HeaderInfo = HeaderInfo + chr(0) # Prepend the IV for i in range(0,IV_Length): HeaderInfo += IV[i] # Try to create and open a new Output File fOut = fn.NewOutFile(OutFile) # Write HeaderInfo to Output File for i in range(0,len(HeaderInfo)): fOut.write(HeaderInfo[i]) inFileSeekPos = 0 # ----------------------------------------- # # Decryption # # ----------------------------------------- # # Read the IV and other Information from the File Header else: # Now the encrypted File Algorithm = fIn.read(2) Version = fIn.read(2) nKeyByte = ord(fIn.read(1)) KDF_Rounds = ord(fIn.read(1)) nDropKSA = ord(fIn.read(1)) HashType = fIn.read(1) nHMACHashSize = ord(fIn.read(1)) bVal = int(Version[1:2]) # Value to set zx8 Index Pointer Value for b # Skip the next empty 11 Placeholder Byte # because HeaderInfo has alway 20 Byte # before the IV fIn.seek( fIn.tell() +11) # Length of the Hash Hex-String nMACsize = pow(2, nHMACHashSize)/8 # if MD5 or SHA1 then use two concatenated Hashes as IV if ((nMACsize*8) < 256): IV_Length = nMACsize*4 else: IV_Length = nMACsize*2 # Get the IV for i in range(0,IV_Length): IV += fIn.read(1) # Calculate File Pointer Position were the encrypted Data begin inFileSeekPos = fIn.tell() # Addjust to Size of relevant Data inFileSize = (inFileSize - nMACsize) # Derive the Keys and return MAC_Key for later use MAC_Key = fn.DeriveKeys(KeyWord, IV, Crypto_Key, MAC_Key, nKeyByte, nDropKSA, KDF_Rounds, bVal) # Get the Message Authentication Code fn.CompareMAC(InFile, inFileSize, MAC_Key, nMACsize) # Try to create and open a new Output File fOut = fn.NewOutFile(OutFile) # # # ----------------------------------------- # Show some Details StatusInfo(Direction, InFile, OutFile) # Encrypt/Decrypt Binary File (unbuffered Read/Write) fIn.close() fOut.close() fn.Encrypt_Decrypt(InFile, OutFile, inFileSize, inFileSeekPos, MAC_Key, Direction) end = time() fn.printf ("Time: %f\n" % (end - start) ) # # # ----------------------------------------- try: raise SystemExit(main()) except KeyboardInterrupt: raise SystemExit("Aborted by user request.")