Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/usr/bin/python3
- """
- Password-Encrypt File
- Usage:
- pef encrypt {password} {plainfile} {outputfile}
- pef decrypt {password} {encryptedfile} {outputfile}
- pef verify {password} {encryptedfile}
- If {password} is an empty string, the user will be prompted for a password.
- This script is useful for encrypting and decrypting important files to
- be stored in insecure (or untrusted) environments in a way that makes it
- easy to recover the data on a platform with Python3 and default libraries
- installed only. If this script is lost, the data can easily be recovered
- with the aid of cryptographic libraries and analysis of the file headers.
- The encryption is AES-128-GCM with a random 96-bit initialisation vector.
- The password-based key derivation function is PBKDF2 with HMAC-SHA-256,
- a 256-bit random salt, 5000 iterations, producing a 128-bit (16 byte) key.
- The appended authentication tag is 128 bits (16 bytes) in length.
- """
- #-------------------------------------------------------------------------------
- # Imports
- #-------------------------------------------------------------------------------
- import sys
- import os
- import traceback
- import io
- import binascii
- import getpass
- #-------------------------------------------------------------------------------
- # Exceptions
- #-------------------------------------------------------------------------------
- class Error (Exception):
- pass
- class ArgError (Error):
- pass
- class FileError(Error):
- pass
- class CmdError(Error):
- pass
- #-------------------------------------------------------------------------------
- # Bit fiddling functions
- #-------------------------------------------------------------------------------
- def XorAWithB(A, B):
- for i, x in enumerate(B):
- A[i] ^= x
- #-------------------------------------------------------------------------------
- def BytesToIntBE(X):
- """
- Read a big-endian byte array as a native integer.
- """
- Result = 0
- for b in X:
- Result = (Result << 8) + b
- return Result
- #-------------------------------------------------------------------------------
- def IntToBytesBE(x, Length):
- """
- Return a big-endian byte array from a native integer.
- """
- Result = bytearray(Length)
- RIx = Length
- a = x
- while a != 0:
- RIx -= 1
- Result[RIx] = a & 0xFF
- a >>= 8
- return Result
- #-------------------------------------------------------------------------------
- # Stream functions
- #-------------------------------------------------------------------------------
- class Substream (io.RawIOBase):
- def __init__(self, instream, start=None, length=None):
- self._instream = instream
- if instream.seekable():
- pos = instream.tell()
- end = instream.seek(0, io.SEEK_END)
- pos = instream.seek(pos, io.SEEK_SET)
- self._start = pos if start is None else start
- self._length = end - self._start if length is None else length
- else:
- self._start = None
- self._length = length
- self._closed = instream.closed
- self._pos = 0
- pass
- @property
- def closed(self):
- self._closed = self._closed or _instream.closed
- return self.closed
- def close(self):
- self._closed = True
- def readable(self):
- return self._instream.readable() and not self._closed
- def seek(self, offset, whence=io.SEEK_SET):
- if not self._instream.seekable():
- raise FileError("This Substream is not seekable.")
- if whence == io.SEEK_SET:
- x = offset
- elif whence == io.SEEK_CUR:
- x = self._pos + offset
- elif whence == io.SEEK_END:
- x = self._length - offset
- else:
- raise FileError("Invalid seek origin for Substream.")
- self._pos = x
- return self._pos
- def seekable(self):
- return seek._instream.seekable()
- def tell(self):
- if not self._instream.seekable():
- raise FileError("This Substream is not seekable, so no tell().")
- return self._pos
- def writable(self):
- return False
- def readinto(self, b):
- l = len(b)
- readsize = min(max(0, self._length - self._pos), l)
- if readsize > 0:
- if self._instream.seekable():
- self._instream.seek(self._start + self._pos, io.SEEK_SET)
- output = self._instream.read(readsize)
- if output is None:
- return None
- readsize = len(output)
- b[:readsize] = output
- self._pos += readsize
- return readsize
- def write(self, size):
- raise FileError("Substream is not writable.")
- #-------------------------------------------------------------------------------
- class StreamSansTail (io.RawIOBase):
- def __init__(self, InStream, TailLength):
- self.TailLength = TailLength
- self.TailBuffer = b''
- self.InStream = InStream
- def readable(self):
- return True
- def readinto(self, b):
- n = len(b)
- NumBytesNeeded = n + self.TailLength - len(self.TailBuffer)
- if self.InStream is not None:
- if NumBytesNeeded > 0:
- Chunk = self.InStream.read(NumBytesNeeded)
- if Chunk is None:
- self.InStream = None
- self.TailBuffer += Chunk
- NumBytesToOutput = min(n, len(self.TailBuffer) - self.TailLength)
- Output = self.TailBuffer[:NumBytesToOutput]
- self.TailBuffer = self.TailBuffer[NumBytesToOutput:]
- b[:len(Output)] = Output
- return len(Output)
- def readtail(self):
- return self.TailBuffer[-self.TailLength:]
- #-------------------------------------------------------------------------------
- def StreamAsBlocks(Stream, BlockSize):
- Length = 0
- HaveEOF = False
- Buffer = bytes()
- while not HaveEOF:
- S = Stream.read(2 * BlockSize - len(Buffer))
- if len(S) > 0:
- Length += len(S)
- Buffer += S
- else:
- HaveEOF = True
- while len(Buffer) >= BlockSize:
- Block = Buffer[:BlockSize]
- Buffer = Buffer[BlockSize:]
- yield Block
- if len(Buffer) > 0:
- yield Buffer
- #-------------------------------------------------------------------------------
- def IterableToStream(iterable, buffer_size=io.DEFAULT_BUFFER_SIZE):
- class IterStream (io.RawIOBase):
- def __init__(self):
- self.inbuf = b''
- def readable(self):
- return True
- def readinto(self, b):
- try:
- chunk = self.inbuf or next(iterable)
- n = len(b)
- output = chunk[:n]
- self.inbuf = chunk[n:]
- b[:len(output)] = output
- return len(output)
- except StopIteration:
- return 0
- return io.BufferedReader(IterStream(), buffer_size=buffer_size)
- #-------------------------------------------------------------------------------
- # AES
- #-------------------------------------------------------------------------------
- SBox = bytes([
- 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5,
- 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76,
- 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0,
- 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0,
- 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC,
- 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15,
- 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A,
- 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75,
- 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0,
- 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84,
- 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B,
- 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF,
- 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85,
- 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8,
- 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5,
- 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2,
- 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17,
- 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73,
- 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88,
- 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB,
- 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C,
- 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79,
- 0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9,
- 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08,
- 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6,
- 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A,
- 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E,
- 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E,
- 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94,
- 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,
- 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68,
- 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16
- ])
- RoundConstantBytes = bytes([
- 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40,
- 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a
- ])
- InvSBox = bytes([
- 0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38,
- 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB,
- 0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87,
- 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB,
- 0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D,
- 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E,
- 0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2,
- 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25,
- 0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16,
- 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92,
- 0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA,
- 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84,
- 0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A,
- 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06,
- 0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02,
- 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B,
- 0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA,
- 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73,
- 0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85,
- 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E,
- 0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89,
- 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B,
- 0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20,
- 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4,
- 0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31,
- 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F,
- 0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D,
- 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF,
- 0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0,
- 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61,
- 0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26,
- 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D
- ])
- GMul0E = bytes([
- 0x00, 0x0E, 0x1C, 0x12, 0x38, 0x36, 0x24, 0x2A,
- 0x70, 0x7E, 0x6C, 0x62, 0x48, 0x46, 0x54, 0x5A,
- 0xE0, 0xEE, 0xFC, 0xF2, 0xD8, 0xD6, 0xC4, 0xCA,
- 0x90, 0x9E, 0x8C, 0x82, 0xA8, 0xA6, 0xB4, 0xBA,
- 0xDB, 0xD5, 0xC7, 0xC9, 0xE3, 0xED, 0xFF, 0xF1,
- 0xAB, 0xA5, 0xB7, 0xB9, 0x93, 0x9D, 0x8F, 0x81,
- 0x3B, 0x35, 0x27, 0x29, 0x03, 0x0D, 0x1F, 0x11,
- 0x4B, 0x45, 0x57, 0x59, 0x73, 0x7D, 0x6F, 0x61,
- 0xAD, 0xA3, 0xB1, 0xBF, 0x95, 0x9B, 0x89, 0x87,
- 0xDD, 0xD3, 0xC1, 0xCF, 0xE5, 0xEB, 0xF9, 0xF7,
- 0x4D, 0x43, 0x51, 0x5F, 0x75, 0x7B, 0x69, 0x67,
- 0x3D, 0x33, 0x21, 0x2F, 0x05, 0x0B, 0x19, 0x17,
- 0x76, 0x78, 0x6A, 0x64, 0x4E, 0x40, 0x52, 0x5C,
- 0x06, 0x08, 0x1A, 0x14, 0x3E, 0x30, 0x22, 0x2C,
- 0x96, 0x98, 0x8A, 0x84, 0xAE, 0xA0, 0xB2, 0xBC,
- 0xE6, 0xE8, 0xFA, 0xF4, 0xDE, 0xD0, 0xC2, 0xCC,
- 0x41, 0x4F, 0x5D, 0x53, 0x79, 0x77, 0x65, 0x6B,
- 0x31, 0x3F, 0x2D, 0x23, 0x09, 0x07, 0x15, 0x1B,
- 0xA1, 0xAF, 0xBD, 0xB3, 0x99, 0x97, 0x85, 0x8B,
- 0xD1, 0xDF, 0xCD, 0xC3, 0xE9, 0xE7, 0xF5, 0xFB,
- 0x9A, 0x94, 0x86, 0x88, 0xA2, 0xAC, 0xBE, 0xB0,
- 0xEA, 0xE4, 0xF6, 0xF8, 0xD2, 0xDC, 0xCE, 0xC0,
- 0x7A, 0x74, 0x66, 0x68, 0x42, 0x4C, 0x5E, 0x50,
- 0x0A, 0x04, 0x16, 0x18, 0x32, 0x3C, 0x2E, 0x20,
- 0xEC, 0xE2, 0xF0, 0xFE, 0xD4, 0xDA, 0xC8, 0xC6,
- 0x9C, 0x92, 0x80, 0x8E, 0xA4, 0xAA, 0xB8, 0xB6,
- 0x0C, 0x02, 0x10, 0x1E, 0x34, 0x3A, 0x28, 0x26,
- 0x7C, 0x72, 0x60, 0x6E, 0x44, 0x4A, 0x58, 0x56,
- 0x37, 0x39, 0x2B, 0x25, 0x0F, 0x01, 0x13, 0x1D,
- 0x47, 0x49, 0x5B, 0x55, 0x7F, 0x71, 0x63, 0x6D,
- 0xD7, 0xD9, 0xCB, 0xC5, 0xEF, 0xE1, 0xF3, 0xFD,
- 0xA7, 0xA9, 0xBB, 0xB5, 0x9F, 0x91, 0x83, 0x8D
- ])
- GMul09 = bytes([
- 0x00, 0x09, 0x12, 0x1B, 0x24, 0x2D, 0x36, 0x3F,
- 0x48, 0x41, 0x5A, 0x53, 0x6C, 0x65, 0x7E, 0x77,
- 0x90, 0x99, 0x82, 0x8B, 0xB4, 0xBD, 0xA6, 0xAF,
- 0xD8, 0xD1, 0xCA, 0xC3, 0xFC, 0xF5, 0xEE, 0xE7,
- 0x3B, 0x32, 0x29, 0x20, 0x1F, 0x16, 0x0D, 0x04,
- 0x73, 0x7A, 0x61, 0x68, 0x57, 0x5E, 0x45, 0x4C,
- 0xAB, 0xA2, 0xB9, 0xB0, 0x8F, 0x86, 0x9D, 0x94,
- 0xE3, 0xEA, 0xF1, 0xF8, 0xC7, 0xCE, 0xD5, 0xDC,
- 0x76, 0x7F, 0x64, 0x6D, 0x52, 0x5B, 0x40, 0x49,
- 0x3E, 0x37, 0x2C, 0x25, 0x1A, 0x13, 0x08, 0x01,
- 0xE6, 0xEF, 0xF4, 0xFD, 0xC2, 0xCB, 0xD0, 0xD9,
- 0xAE, 0xA7, 0xBC, 0xB5, 0x8A, 0x83, 0x98, 0x91,
- 0x4D, 0x44, 0x5F, 0x56, 0x69, 0x60, 0x7B, 0x72,
- 0x05, 0x0C, 0x17, 0x1E, 0x21, 0x28, 0x33, 0x3A,
- 0xDD, 0xD4, 0xCF, 0xC6, 0xF9, 0xF0, 0xEB, 0xE2,
- 0x95, 0x9C, 0x87, 0x8E, 0xB1, 0xB8, 0xA3, 0xAA,
- 0xEC, 0xE5, 0xFE, 0xF7, 0xC8, 0xC1, 0xDA, 0xD3,
- 0xA4, 0xAD, 0xB6, 0xBF, 0x80, 0x89, 0x92, 0x9B,
- 0x7C, 0x75, 0x6E, 0x67, 0x58, 0x51, 0x4A, 0x43,
- 0x34, 0x3D, 0x26, 0x2F, 0x10, 0x19, 0x02, 0x0B,
- 0xD7, 0xDE, 0xC5, 0xCC, 0xF3, 0xFA, 0xE1, 0xE8,
- 0x9F, 0x96, 0x8D, 0x84, 0xBB, 0xB2, 0xA9, 0xA0,
- 0x47, 0x4E, 0x55, 0x5C, 0x63, 0x6A, 0x71, 0x78,
- 0x0F, 0x06, 0x1D, 0x14, 0x2B, 0x22, 0x39, 0x30,
- 0x9A, 0x93, 0x88, 0x81, 0xBE, 0xB7, 0xAC, 0xA5,
- 0xD2, 0xDB, 0xC0, 0xC9, 0xF6, 0xFF, 0xE4, 0xED,
- 0x0A, 0x03, 0x18, 0x11, 0x2E, 0x27, 0x3C, 0x35,
- 0x42, 0x4B, 0x50, 0x59, 0x66, 0x6F, 0x74, 0x7D,
- 0xA1, 0xA8, 0xB3, 0xBA, 0x85, 0x8C, 0x97, 0x9E,
- 0xE9, 0xE0, 0xFB, 0xF2, 0xCD, 0xC4, 0xDF, 0xD6,
- 0x31, 0x38, 0x23, 0x2A, 0x15, 0x1C, 0x07, 0x0E,
- 0x79, 0x70, 0x6B, 0x62, 0x5D, 0x54, 0x4F, 0x46
- ])
- GMul0D = bytes([
- 0x00, 0x0D, 0x1A, 0x17, 0x34, 0x39, 0x2E, 0x23,
- 0x68, 0x65, 0x72, 0x7F, 0x5C, 0x51, 0x46, 0x4B,
- 0xD0, 0xDD, 0xCA, 0xC7, 0xE4, 0xE9, 0xFE, 0xF3,
- 0xB8, 0xB5, 0xA2, 0xAF, 0x8C, 0x81, 0x96, 0x9B,
- 0xBB, 0xB6, 0xA1, 0xAC, 0x8F, 0x82, 0x95, 0x98,
- 0xD3, 0xDE, 0xC9, 0xC4, 0xE7, 0xEA, 0xFD, 0xF0,
- 0x6B, 0x66, 0x71, 0x7C, 0x5F, 0x52, 0x45, 0x48,
- 0x03, 0x0E, 0x19, 0x14, 0x37, 0x3A, 0x2D, 0x20,
- 0x6D, 0x60, 0x77, 0x7A, 0x59, 0x54, 0x43, 0x4E,
- 0x05, 0x08, 0x1F, 0x12, 0x31, 0x3C, 0x2B, 0x26,
- 0xBD, 0xB0, 0xA7, 0xAA, 0x89, 0x84, 0x93, 0x9E,
- 0xD5, 0xD8, 0xCF, 0xC2, 0xE1, 0xEC, 0xFB, 0xF6,
- 0xD6, 0xDB, 0xCC, 0xC1, 0xE2, 0xEF, 0xF8, 0xF5,
- 0xBE, 0xB3, 0xA4, 0xA9, 0x8A, 0x87, 0x90, 0x9D,
- 0x06, 0x0B, 0x1C, 0x11, 0x32, 0x3F, 0x28, 0x25,
- 0x6E, 0x63, 0x74, 0x79, 0x5A, 0x57, 0x40, 0x4D,
- 0xDA, 0xD7, 0xC0, 0xCD, 0xEE, 0xE3, 0xF4, 0xF9,
- 0xB2, 0xBF, 0xA8, 0xA5, 0x86, 0x8B, 0x9C, 0x91,
- 0x0A, 0x07, 0x10, 0x1D, 0x3E, 0x33, 0x24, 0x29,
- 0x62, 0x6F, 0x78, 0x75, 0x56, 0x5B, 0x4C, 0x41,
- 0x61, 0x6C, 0x7B, 0x76, 0x55, 0x58, 0x4F, 0x42,
- 0x09, 0x04, 0x13, 0x1E, 0x3D, 0x30, 0x27, 0x2A,
- 0xB1, 0xBC, 0xAB, 0xA6, 0x85, 0x88, 0x9F, 0x92,
- 0xD9, 0xD4, 0xC3, 0xCE, 0xED, 0xE0, 0xF7, 0xFA,
- 0xB7, 0xBA, 0xAD, 0xA0, 0x83, 0x8E, 0x99, 0x94,
- 0xDF, 0xD2, 0xC5, 0xC8, 0xEB, 0xE6, 0xF1, 0xFC,
- 0x67, 0x6A, 0x7D, 0x70, 0x53, 0x5E, 0x49, 0x44,
- 0x0F, 0x02, 0x15, 0x18, 0x3B, 0x36, 0x21, 0x2C,
- 0x0C, 0x01, 0x16, 0x1B, 0x38, 0x35, 0x22, 0x2F,
- 0x64, 0x69, 0x7E, 0x73, 0x50, 0x5D, 0x4A, 0x47,
- 0xDC, 0xD1, 0xC6, 0xCB, 0xE8, 0xE5, 0xF2, 0xFF,
- 0xB4, 0xB9, 0xAE, 0xA3, 0x80, 0x8D, 0x9A, 0x97
- ])
- GMul0B = bytes([
- 0x00, 0x0B, 0x16, 0x1D, 0x2C, 0x27, 0x3A, 0x31,
- 0x58, 0x53, 0x4E, 0x45, 0x74, 0x7F, 0x62, 0x69,
- 0xB0, 0xBB, 0xA6, 0xAD, 0x9C, 0x97, 0x8A, 0x81,
- 0xE8, 0xE3, 0xFE, 0xF5, 0xC4, 0xCF, 0xD2, 0xD9,
- 0x7B, 0x70, 0x6D, 0x66, 0x57, 0x5C, 0x41, 0x4A,
- 0x23, 0x28, 0x35, 0x3E, 0x0F, 0x04, 0x19, 0x12,
- 0xCB, 0xC0, 0xDD, 0xD6, 0xE7, 0xEC, 0xF1, 0xFA,
- 0x93, 0x98, 0x85, 0x8E, 0xBF, 0xB4, 0xA9, 0xA2,
- 0xF6, 0xFD, 0xE0, 0xEB, 0xDA, 0xD1, 0xCC, 0xC7,
- 0xAE, 0xA5, 0xB8, 0xB3, 0x82, 0x89, 0x94, 0x9F,
- 0x46, 0x4D, 0x50, 0x5B, 0x6A, 0x61, 0x7C, 0x77,
- 0x1E, 0x15, 0x08, 0x03, 0x32, 0x39, 0x24, 0x2F,
- 0x8D, 0x86, 0x9B, 0x90, 0xA1, 0xAA, 0xB7, 0xBC,
- 0xD5, 0xDE, 0xC3, 0xC8, 0xF9, 0xF2, 0xEF, 0xE4,
- 0x3D, 0x36, 0x2B, 0x20, 0x11, 0x1A, 0x07, 0x0C,
- 0x65, 0x6E, 0x73, 0x78, 0x49, 0x42, 0x5F, 0x54,
- 0xF7, 0xFC, 0xE1, 0xEA, 0xDB, 0xD0, 0xCD, 0xC6,
- 0xAF, 0xA4, 0xB9, 0xB2, 0x83, 0x88, 0x95, 0x9E,
- 0x47, 0x4C, 0x51, 0x5A, 0x6B, 0x60, 0x7D, 0x76,
- 0x1F, 0x14, 0x09, 0x02, 0x33, 0x38, 0x25, 0x2E,
- 0x8C, 0x87, 0x9A, 0x91, 0xA0, 0xAB, 0xB6, 0xBD,
- 0xD4, 0xDF, 0xC2, 0xC9, 0xF8, 0xF3, 0xEE, 0xE5,
- 0x3C, 0x37, 0x2A, 0x21, 0x10, 0x1B, 0x06, 0x0D,
- 0x64, 0x6F, 0x72, 0x79, 0x48, 0x43, 0x5E, 0x55,
- 0x01, 0x0A, 0x17, 0x1C, 0x2D, 0x26, 0x3B, 0x30,
- 0x59, 0x52, 0x4F, 0x44, 0x75, 0x7E, 0x63, 0x68,
- 0xB1, 0xBA, 0xA7, 0xAC, 0x9D, 0x96, 0x8B, 0x80,
- 0xE9, 0xE2, 0xFF, 0xF4, 0xC5, 0xCE, 0xD3, 0xD8,
- 0x7A, 0x71, 0x6C, 0x67, 0x56, 0x5D, 0x40, 0x4B,
- 0x22, 0x29, 0x34, 0x3F, 0x0E, 0x05, 0x18, 0x13,
- 0xCA, 0xC1, 0xDC, 0xD7, 0xE6, 0xED, 0xF0, 0xFB,
- 0x92, 0x99, 0x84, 0x8F, 0xBE, 0xB5, 0xA8, 0xA3
- ])
- #-------------------------------------------------------------------------------
- def SubstituteAndShift(State):
- State[0] = SBox[State[0]]
- State[4] = SBox[State[4]]
- State[8] = SBox[State[8]]
- State[12] = SBox[State[12]]
- a = State[1]
- State[1] = SBox[State[5]]
- State[5] = SBox[State[9]]
- State[9] = SBox[State[13]]
- State[13] = SBox[a]
- a = State[2]
- State[2] = SBox[State[10]]
- State[10] = SBox[a]
- a = State[6]
- State[6] = SBox[State[14]]
- State[14] = SBox[a]
- a = State[15]
- State[15] = SBox[State[11]]
- State[11] = SBox[State[7]]
- State[7] = SBox[State[3]]
- State[3] = SBox[a]
- #-------------------------------------------------------------------------------
- def InvSubstituteAndShift(State):
- State[0] = InvSBox[State[0]]
- State[4] = InvSBox[State[4]]
- State[8] = InvSBox[State[8]]
- State[12] = InvSBox[State[12]]
- a = State[13]
- State[13] = InvSBox[State[9]]
- State[9] = InvSBox[State[5]]
- State[5] = InvSBox[State[1]]
- State[1] = InvSBox[a]
- a = State[2]
- State[2] = InvSBox[State[10]]
- State[10] = InvSBox[a]
- a = State[6]
- State[6] = InvSBox[State[14]]
- State[14] = InvSBox[a]
- a = State[3]
- State[3] = InvSBox[State[7]]
- State[7] = InvSBox[State[11]]
- State[11] = InvSBox[State[15]]
- State[15] = InvSBox[a]
- #-------------------------------------------------------------------------------
- def MixColumns(State):
- def gmul2(x):
- return x << 1 if x < 128 else ((x << 1) & 255) ^ 0x1b
- def gmul3(x):
- return ((x << 1) ^ x) if x < 128 else ((x << 1) & 255) ^ x ^ 0x1b
- def MixColumn(State, c):
- Offset = 4 * c
- a = State[Offset + 0]
- b = State[Offset + 1]
- c = State[Offset + 2]
- d = State[Offset + 3]
- State[Offset + 0] = gmul2(a) ^ gmul3(b) ^ c ^ d
- State[Offset + 1] = a ^ gmul2(b) ^ gmul3(c) ^ d
- State[Offset + 2] = a ^ b ^ gmul2(c) ^ gmul3(d)
- State[Offset + 3] = gmul3(a) ^ b ^ c ^ gmul2(d)
- for i in range(4):
- MixColumn(State, i)
- #-------------------------------------------------------------------------------
- def InvMixColumns(State):
- def gmulE(x):
- return GMul0E[x]
- def gmul9(x):
- return GMul09[x]
- def gmulD(x):
- return GMul0D[x]
- def gmulB(x):
- return GMul0B[x]
- def MixColumn(State, c):
- Offset = 4 * c
- a = State[Offset + 0]
- b = State[Offset + 1]
- c = State[Offset + 2]
- d = State[Offset + 3]
- State[Offset + 0] = gmulE(a) ^ gmulB(b) ^ gmulD(c) ^ gmul9(d)
- State[Offset + 1] = gmul9(a) ^ gmulE(b) ^ gmulB(c) ^ gmulD(d)
- State[Offset + 2] = gmulD(a) ^ gmul9(b) ^ gmulE(c) ^ gmulB(d)
- State[Offset + 3] = gmulB(a) ^ gmulD(b) ^ gmul9(c) ^ gmulE(d)
- for i in range(4):
- MixColumn(State, i)
- #-------------------------------------------------------------------------------
- def AdvanceRoundKey(Key, NextRoundNumber):
- a = RoundConstantBytes[NextRoundNumber]
- a ^= SBox[Key[13]]
- b = SBox[Key[14]]
- c = SBox[Key[15]]
- d = SBox[Key[12]]
- Offset = 0
- for j in range(4):
- a ^= Key[Offset + 0]
- b ^= Key[Offset + 1]
- c ^= Key[Offset + 2]
- d ^= Key[Offset + 3]
- Key[Offset + 0] = a
- Key[Offset + 1] = b
- Key[Offset + 2] = c
- Key[Offset + 3] = d
- Offset += 4
- #-------------------------------------------------------------------------------
- def AddRoundKey(Key, State):
- for i in range(16):
- State[i] ^= Key[i]
- #-------------------------------------------------------------------------------
- def AESEncryptBlock(Key, Block):
- Result = bytearray(Block)
- W = bytearray(Key)
- AddRoundKey(W, Result)
- for i in range(1, 11):
- AdvanceRoundKey(W, i)
- SubstituteAndShift(Result)
- if i < 10:
- MixColumns(Result)
- AddRoundKey(W, Result)
- return Result
- #-------------------------------------------------------------------------------
- def AESDecryptBlock(Key, Block):
- Result = bytearray(Block)
- W = bytearray(Key)
- for j in range(1, 11):
- AdvanceRoundKey(W, j)
- AddRoundKey(W, Result)
- for i in range(10, 0, -1):
- W = bytearray(Key)
- for j in range(1, i):
- AdvanceRoundKey(W, j)
- InvSubstituteAndShift(Result)
- AddRoundKey(W, Result)
- if i > 1:
- InvMixColumns(Result)
- return Result
- #-------------------------------------------------------------------------------
- def NextRoundKey(KeyN, RoundNPlus1):
- r = bytearray(KeyN)
- g = [SBox[x] for x in KeyN[13:16] + KeyN[12:13]]
- g[0] ^= RoundConstantBytes[RoundNPlus1]
- for i in range(4):
- r[i] = KeyN[i] ^ g[i]
- d = i
- for j in range(3):
- r[d + 4] = r[d] ^ KeyN[d + 4]
- d += 4
- return r
- #-------------------------------------------------------------------------------
- def AESECBEncryptMessage(Key, Message):
- Result = bytearray(len(Message))
- Addr = 0
- while Addr < len(Message):
- M = bytearray(Message[Addr : Addr + 16])
- M.extend(bytearray(16 - len(M)))
- E = AESEncryptBlock(Key, M)
- Result[Addr : Addr + 16] = E
- Addr += 16
- return Result
- #-------------------------------------------------------------------------------
- def AESECBDecryptMessage(Key, Message, Length=None):
- if Length is None:
- Length = len(Message)
- Result = bytearray(Length)
- Addr = 0
- while Addr + 16 <= len(Message):
- M = bytearray(Message[Addr : Addr + 16])
- D = AESDecryptBlock(Key, M)
- DLength = min(16, Length - Addr)
- D = D[:DLength]
- Result[Addr : Addr + DLength] = D
- Addr += 16
- return Result
- #-------------------------------------------------------------------------------
- def CMACSubKeys(Key):
- """
- Generate subkeys K1 and K2 for use on the final block.
- K1 is used on a whole final block. K2 is used on a short final block which
- has been padded with a bit 1 and a run of zero or more bit 0s.
- """
- def NextSubKey(Key):
- Result = bytearray(16)
- c = 0
- for i in reversed(range(len(Result))):
- e = (Key[i] << 1) | c
- c = e >> 8
- Result[i] = e & 255
- if c:
- Result[15] ^= 0x87
- return Result
- X = AESEncryptBlock(Key, bytearray(16))
- K1 = NextSubKey(X)
- K2 = NextSubKey(K1)
- return K1, K2
- #-------------------------------------------------------------------------------
- def AESCMAC(Message, Key, Debug=False):
- K1, K2 = CMACSubKeys(Key)
- T = bytearray(16)
- BlockEndIx = 16
- while BlockEndIx < len(Message):
- Mi = bytearray(Message[BlockEndIx - 16 : BlockEndIx])
- XorAWithB(T, Mi)
- T = AESEncryptBlock(Key, T)
- BlockEndIx += 16
- if BlockEndIx == len(Message):
- Mi = bytearray(Message[BlockEndIx - 16 : BlockEndIx])
- XorAWithB(T, Mi)
- XorAWithB(T, K1)
- T = AESEncryptBlock(Key, T)
- else:
- Mi = bytearray(Message[BlockEndIx - 16:])
- PaddingLength = 16 - len(Mi)
- Mi.extend(bytearray([0x80]))
- Mi.extend(bytearray(PaddingLength - 1))
- XorAWithB(T, Mi)
- XorAWithB(T, K2)
- T = AESEncryptBlock(Key, T)
- return T
- #-------------------------------------------------------------------------------
- # GCM functions
- #-------------------------------------------------------------------------------
- def GaloisMultInt128(X, Y):
- """
- Multiply X and Y using Galois multiplation in GF(2^8).
- X and Y are integers rather than byte arrays.
- """
- R = 0b11100001 << 120
- Z = 0
- V = Y
- Mask = 1 << 127
- for i in range(128):
- if X & Mask:
- Z ^= V
- if V & 1:
- V = (V >> 1) ^ R
- else:
- V >>= 1
- Mask >>= 1
- return Z
- #-------------------------------------------------------------------------------
- # AES in GCM mode
- #-------------------------------------------------------------------------------
- class AESGCMCipher (object):
- def __init__(self, Key, IV):
- self.CipherFn = AESEncryptBlock
- NumTagBits = 128 # May be 128, 120, 112, 104, 96, 64 or 32
- self.NumTagBytes = (NumTagBits + 7) >> 3
- self.Key = bytes(Key)
- self.IV = bytes(IV)
- self.AuthTag = None
- def IncrementalGHash(self, H, Y, Block):
- # H is the hash subkey as a 128-bit integer and
- # Y is the hash accumulator as a 128-bit integer.
- # Block is an array of 16 bytes.
- X = BytesToIntBE(Block)
- NextY = GaloisMultInt128(Y ^ X, H)
- return NextY
- def IntGHash(H, Data):
- Y = 0
- for Addr in range(0, len(Data) - 15, 16):
- Y = IncrementalGHash(H, Y, Data[Addr : Addr + 16])
- return Y
- def OutputBytes(self, AADStream, MsgStream, Mode):
- # Mode is 1 for encryption, 2 for decryption and 3 for verification.
- def Inc32BE(X):
- c = (X[-4] << 24) + (X[-3] << 16) + (X[-2] << 8) + X[-1] + 1
- X[-4:] = [(c >> 24) & 0xFF, (c >> 16) & 0xFF, (c >> 8) & 0xFF, c & 0xFF]
- H = BytesToIntBE(self.CipherFn(self.Key, bytes(16)))
- if len(self.IV) == 12: # 96 bits
- J0 = self.IV + b"\x00\x00\x00\x01"
- else:
- # Pad (our copy of) IV to a multiple of 128 bits (16 bytes),
- # then 64 bits (8 bytes) of zeros, followed by the length of
- # IV in bits as a 64 bit big-endian integer.
- p = (16 - len(self.IV)) & 15
- IV1 = self.IV + bytes(p + 8) + IntToBytesBE(len(IV) * 8, 8)
- J0 = IntToBytesBE(IntGHash(H, IV1), 16)
- AADLength = 0
- Y = 0
- if AADStream is not None:
- for Block in StreamAsBlocks(AADStream, 16):
- A = Block
- if len(A) > 0:
- AADLength += len(A)
- if len(A) < 16:
- A = A + bytes(16 - len(A))
- Y = self.IncrementalGHash(H, Y, A)
- MsgLength = 0
- CB = bytearray(J0)
- if MsgStream is not None:
- for Block in StreamAsBlocks(MsgStream, 16):
- A = bytearray(Block)
- if len(A) > 0:
- MsgLength += len(A)
- Inc32BE(CB)
- B = self.CipherFn(self.Key, CB)
- if Mode == 1:
- XorAWithB(A, B[:len(A)])
- Y = self.IncrementalGHash(H, Y, A + bytes(16 - len(A)))
- else:
- Y = self.IncrementalGHash(H, Y, A + bytes(16 - len(A)))
- XorAWithB(A, B[:len(A)])
- if Mode != 3:
- yield A
- A = IntToBytesBE(AADLength * 8, 8) + IntToBytesBE(MsgLength * 8, 8)
- Y = self.IncrementalGHash(H, Y, A)
- A = self.CipherFn(self.Key, J0)
- XorAWithB(A, IntToBytesBE(Y, 16))
- self.AuthTag = bytes(A[:self.NumTagBytes])
- if Mode == 3:
- yield self.AuthTag
- def Encrypt(self, AADStream, PlainStream):
- self.AuthTag = None
- B = self.OutputBytes(AADStream, PlainStream, 1)
- S = IterableToStream(B)
- return S
- def Decrypt(self, AADStream, CipherStream):
- self.AuthTag = None
- B = self.OutputBytes(AADStream, CipherStream, 2)
- S = IterableToStream(B)
- return S
- def Verify(self, AADStream, CipherStream, AuthTag):
- self.AuthTag = None
- B = self.OutputBytes(AADStream, CipherStream, 3)
- T = next(B)
- IsValid = T == AuthTag
- return IsValid
- def GMAC(self, AADStream):
- self.AuthTag = None
- B = self.OutputBytes(AADStream, None, 3)
- G = next(B)
- return G
- #-------------------------------------------------------------------------------
- # Hash functions
- #-------------------------------------------------------------------------------
- def SHA_256(Message):
- """
- Compute the SHA-256 hash of a message.
- """
- WMask = 0xFFFFFFFF
- def PaddedMsgBlocks(Message):
- # The padding is such that the padded message is always a multiple of
- # 512 bits (64 bytes) and the padding contains a bit one followed by
- # zero or more bit zeros, terminated by a 64-bit (8 byte) big-endian
- # representation of the unpadded message length in bits.
- Addr = 0
- while Addr + 64 <= len(Message):
- yield bytes(Message[Addr : Addr + 64])
- Addr += 64
- Appendix = (b'\x80' + bytes((56 - len(Message) - 1) & 63) +
- IntToBytesBE(len(Message) * 8, 8))
- FinalBlockOrTwo = bytes(Message[Addr:]) + Appendix
- yield FinalBlockOrTwo[:64]
- if len(FinalBlockOrTwo) > 64:
- yield FinalBlockOrTwo[64:]
- def rr(x, n):
- return ((x >> n) | (x << (32 - n))) & WMask
- # Hash values, initialised to the first 32 bits of the fractional parts of
- # the square roots of the first eight primes, {2, 3, 5, 7, 11, 13, 17, 19}
- H = [
- 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
- 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
- ]
- # Round constants (first 32 bits of the fractional parts of the cube roots
- # of the first sixty-four primes)
- K = (
- 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
- 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
- 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
- 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
- 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
- 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
- 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
- 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
- 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
- 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
- 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
- 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
- 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
- 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
- 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
- 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
- )
- # Message schedule of 64 words of 32 bits each.
- W = list([None] * 64)
- for B in PaddedMsgBlocks(Message):
- # Stuff the message block into the first 16 entries.
- for i in range(16):
- j = i << 2
- W[i] = (B[j] << 24) + (B[j + 1] << 16) + (B[j + 2] << 8) + B[j + 3]
- # Fill the rest of the schedule with big and little sigma
- for i in range(16, 64):
- x = W[i - 15]
- s0 = rr(x, 7) ^ rr(x, 18) ^ (x >> 3)
- x = W[i - 2]
- s1 = rr(x, 17) ^ rr(x, 19) ^ (x >> 10)
- W[i] = (W[i - 16] + s0 + W[i - 7] + s1) & WMask
- # Initialise the working variables.
- a, b, c, d, e, f, g, h = H[0], H[1], H[2], H[3], H[4], H[5], H[6], H[7]
- # Compression
- for i in range(64):
- S1 = rr(e, 6) ^ rr(e, 11) ^ rr(e, 25)
- Ch = (e & f) ^ (~e & g)
- T1 = h + S1 + Ch + K[i] + W[i]
- S0 = rr(a, 2) ^ rr(a, 13) ^ rr(a, 22)
- Maj = (a & b) ^ (a & c) ^ (b & c)
- T2 = S0 + Maj
- h, g, f, e = g, f, e, (d + T1) & WMask
- d, c, b, a = c, b, a, (T1 + T2) & WMask
- # Arithmetically add the working variables to the 32-bit hash values.
- for i, x in enumerate((a, b, c, d, e, f, g, h)):
- H[i] = (H[i] + x) & WMask
- Result = bytearray()
- for x in H:
- Result.extend(IntToBytesBE(x, 4))
- return bytes(Result)
- #-------------------------------------------------------------------------------
- def HMAC_SHA_256(Key, Message):
- """
- Compute a keyed-hash message authentication code.
- """
- # The block size for SHA-256 is 512 bits (64 bytes).
- BlockSizeInBytes = 64
- # Procrastinate.
- if len(Key) > BlockSizeInBytes:
- KeyToUse = SHA_256(Key)
- else:
- KeyToUse = bytes(Key) + bytes(BlockSizeInBytes - len(Key))
- InnerKeyPad = bytearray(b'\x36' * BlockSizeInBytes)
- XorAWithB(InnerKeyPad, KeyToUse)
- OuterKeyPad = bytearray(b'\x5C' * BlockSizeInBytes)
- XorAWithB(OuterKeyPad, KeyToUse)
- Result = SHA_256(OuterKeyPad + SHA_256(InnerKeyPad + bytes(Message)))
- # The hash size is 256 bit (32 bytes).
- return Result
- #-------------------------------------------------------------------------------
- def PBKDF2(PRF, Password, Salt, Count, DerivedKeyLength):
- """
- Derive an encryption key from a password.
- """
- HashLength = len(PRF(b"", b""))
- def F(P, S, Count, i):
- U = PRF(P, S + IntToBytesBE(i, 4))
- Result = bytearray(U)
- for j in range(2, Count + 1):
- U = PRF(P, U)
- XorAWithB(Result, U)
- return Result
- if DerivedKeyLength >= (1 << 32):
- raise Exception("The derived key length is too long!")
- if DerivedKeyLength < 1:
- raise Exception("The derived key length must be at least 1 byte.")
- if Count < 1:
- raise Exception("The PBKDF2 interation count must be at least 1.")
- Result = bytes()
- P = bytes(Password)
- S = bytes(Salt)
- i = 1
- DKLengthRemaining = DerivedKeyLength
- while len(Result) < DerivedKeyLength:
- Ti = F(P, S, Count, i)
- if DKLengthRemaining < HashLength:
- Ti = Ti[:DKLengthRemaining]
- Result = Result + Ti
- DKLengthRemaining -= HashLength
- i += 1
- return Result
- #-------------------------------------------------------------------------------
- # File encryption
- #-------------------------------------------------------------------------------
- def Encrypt(Password, AAD, PlainStream, OutputStream):
- IV = os.urandom(12)
- Salt = os.urandom(32)
- NumIterations = 5000
- Key = PBKDF2(HMAC_SHA_256, Password.encode("utf8"), Salt, NumIterations, 16)
- AADLength = 0 if AAD is None else len(AAD)
- HdrLines = [
- "#ENCRYPTED#",
- "[File]",
- "HDRSIZE=",
- "AADSIZE={}".format(AADLength),
- "FORMAT=CONCATENATED ACT",
- "VERSION=1.0",
- "[Password]",
- "KDF=PBKDF2",
- "PRF=HMAC-SHA-256",
- "ITERATIONS={}".format(NumIterations),
- "SALT={}".format(binascii.hexlify(Salt).decode("utf8")),
- "[Cipher]",
- "CIPHER=AES-128",
- "MODE=GCM",
- "IV=" + binascii.hexlify(IV).decode("utf8")
- ]
- L0 = sum((len(Line.encode("utf8")) + 1 for Line in HdrLines)) + 1
- L = L0
- LastL = -1
- while L != LastL:
- LastL = L
- L = L0 + len(str(LastL))
- HdrLines[HdrLines.index("HDRSIZE=")] += str(L)
- Hdr = chr(10).join(HdrLines + [chr(0)]).encode("utf8")
- Cipher = AESGCMCipher(Key, IV)
- AADStream = None if AAD is None or AAD == b"" else io.BytesIO(AAD)
- S = Cipher.Encrypt(AADStream, PlainStream)
- OutputStream.write(Hdr)
- if AAD is not None:
- OutputStream.write(AAD)
- HaveEOF = False
- while not HaveEOF:
- Chunk = S.read(65536)
- if len(Chunk) > 0:
- OutputStream.write(Chunk)
- else:
- HaveEOF = True
- S.close()
- OutputStream.write(Cipher.AuthTag)
- #-------------------------------------------------------------------------------
- def Decrypt(Password, InputStream, OutputStream):
- Result = None
- HdrBytesRead = 0
- MagicLine = b"#ENCRYPTED#\x0A"
- Magic = InputStream.read(len(MagicLine))
- if Magic != MagicLine:
- raise FileError("The encrypted file is in an unrecognised format.")
- HdrBytesRead += len(MagicLine)
- Assertions = {
- "FILE": {
- "FORMAT": "CONCATENATED ACT",
- "VERSION": "1.0",
- "HDRSIZE": None,
- "AADSIZE": None
- },
- "PASSWORD": {
- "KDF": "PBKDF2",
- "PRF": "HMAC-SHA-256",
- "ITERATIONS": None,
- "SALT": None
- },
- "CIPHER": {
- "CIPHER": "AES-128",
- "MODE": "GCM",
- "IV": None
- }
- }
- Sections = {
- "FILE": {},
- "PASSWORD": {},
- "CIPHER": {},
- "OTHER": {},
- }
- Section = Sections["OTHER"]
- IsInHeader = True
- while IsInHeader:
- LineBytes = bytearray()
- IsEOL = False
- while not IsEOL:
- Ch = InputStream.read(1)
- HdrBytesRead += 1
- if Ch == b'\x0A':
- IsEOL = True
- elif Ch == b'\x00':
- IsEOL = True
- IsInHeader = False
- else:
- LineBytes.append(ord(Ch))
- Line = LineBytes.decode("utf8").strip()
- if Line[:1] + Line[-1:] == "[]":
- SectionName = Line[1:-1].upper()
- if SectionName in Sections:
- Section = Sections[SectionName]
- else:
- Section = Sections["OTHER"]
- elif '=' in Line:
- K, V = Line.split('=', 1)
- K = K.strip().upper()
- V = V.strip()
- Section[K] = V
- for ASectionName, ASection in Assertions.items():
- if ASectionName in Sections:
- Section = Sections[ASectionName]
- for AK, AV in ASection.items():
- if AK in Section:
- if AV is not None:
- V = Section[AK]
- if V != AV:
- raise FileError(("Section {} requires {} to be " +
- "set to {}.").format(ASectionName, AK, AV))
- else:
- if AV is not None:
- raise FileError(("Section {} requires " +
- "{}={}.").format(ASectionName, AK, AV))
- else:
- raise FileError(("Section {} requires {} to be " +
- "defined.").format(ASectionName, AK))
- else:
- raise FileError(("INTERNAL: Required section {} " +
- "is missiong.").format(ASectionName))
- HLStr = Sections["FILE"]["HDRSIZE"]
- try:
- HdrLength = int(HLStr)
- except (ValueError) as E:
- raise FileError("Bad HDRSIZE: " + str(E))
- if HdrBytesRead != HdrLength:
- raise FileError("HDRSIZE not consistent with measured length: " + str(E))
- ALStr = Sections["FILE"]["AADSIZE"]
- try:
- AADLength = int(ALStr)
- except (ValueError) as E:
- raise FileError("Bad AADSIZE: " + str(E))
- if not (0 <= AADLength <= (1 << 30)):
- raise FileError("AADSIZE is given as {}, " +
- "an outrageous value.".format(AADLength))
- NIStr = Sections["PASSWORD"]["ITERATIONS"]
- try:
- NumIterations = int(NIStr)
- except (binascii.Error) as E:
- raise FileError("Bad ITERATIONS: " + str(E))
- SaltStr = Sections["PASSWORD"]["SALT"]
- try:
- Salt = binascii.unhexlify(SaltStr.encode("utf8"))
- except (binascii.Error) as E:
- raise FileError("Bad SALT: " + str(E))
- IVStr = Sections["CIPHER"]["IV"]
- try:
- IV = binascii.unhexlify(IVStr.encode("utf8"))
- except (binascii.Error) as E:
- raise FileError("Bad IV: " + str(E))
- if OutputStream is not None:
- try:
- OutputStream.seek(0)
- OutputStream.write(b"?")
- OutputStream.seek(0)
- OutputStream.truncate()
- except (Exception) as E:
- raise FileError('Unable to write to output file: ' + E)
- AADStart = HdrLength
- TagLength = 16 # 128 bits
- CipherStart = AADStart + AADLength
- AADStream = Substream(InputStream, AADStart, AADLength)
- CipherAndTagStream = Substream(InputStream, CipherStart)
- CipherStreamTB = StreamSansTail(CipherAndTagStream, TagLength)
- Key = PBKDF2(HMAC_SHA_256, Password.encode("utf8"), Salt, NumIterations, 16)
- Cipher = AESGCMCipher(Key, IV)
- CStream = Cipher.Decrypt(AADStream, CipherStreamTB)
- HaveEOF = False
- while not HaveEOF:
- Chunk = CStream.read(65536)
- if len(Chunk) > 0:
- if OutputStream is not None:
- OutputStream.write(Chunk)
- else:
- HaveEOF = True
- CStream.close()
- Tag = CipherStreamTB.readtail()
- if Tag != Cipher.AuthTag:
- if OutputStream is not None:
- OutputStream.seek(0)
- OutputStream.truncate()
- return None
- else:
- AADStream.seek(0)
- return AADStream
- #-------------------------------------------------------------------------------
- # Diagnostics
- #-------------------------------------------------------------------------------
- def PrintMessage(Message, Name):
- def SafeChr(Code):
- return chr(Code) if 32 <= Code <= 126 else '.'
- print(("State:" if Name is None else Name) + ":")
- if Message is not None:
- M = bytearray(Message)
- for i in range((len(M) + 15) >> 4):
- Addr = 16 * i
- Row = M[Addr : Addr + 16]
- LWs = [Row[4 * j : 4 * (j + 1)] for j in range(4) if 4 * j < len(Row)]
- RowHex = ".".join(["".join(["{:02x}".format(x) for x in L]) for L in LWs])
- RowChr = "".join(SafeChr(x) for x in Row)
- print(" {:04x}: {:35} {:16}".format(Addr, RowHex, RowChr))
- print(" {:04x}:".format((len(M))))
- else:
- print(" [None]")
- #-------------------------------------------------------------------------------
- def Test():
- XBytes = binascii.unhexlify
- def HexBStr(M):
- if len(M) > 0:
- return binascii.hexlify(M).decode("utf8")
- else:
- return "(empty string)"
- def MatchStr(M, Ref):
- if M == Ref:
- return "\x1b[32;1mOK\x1b[39;22m"
- else:
- return "\x1b[31;1mFAIL\x1b[39;22m"
- def HexLines(Block, Name=None, NameFieldWidth=None):
- Lines = []
- fw = NameFieldWidth if NameFieldWidth is not None else 0
- if Name is not None and len(Name) > 0:
- L = Name + ":"
- if NameFieldWidth is None:
- L = L + " "
- L = "{:<{}}".format(L, fw)
- else:
- L = " " * fw
- Blanks = " " * len(L)
- w = 16
- p = 0
- if len(Block) > 0:
- while p < len(Block):
- B = HexBStr(Block[p : p + w])
- Padding = " " * (2 * w - len(B))
- Lines.append(L + B + Padding)
- L = Blanks
- p += w
- else:
- B = HexBStr(Block[p : p + w])
- Padding = " " * (2 * w - len(B))
- Lines.append(L + B + Padding)
- return Lines
- def PrintBlock(Block, Name=None, NameFieldWidth=None):
- print("\n".join(HexLines(Block, Name, NameFieldWidth)))
- def PrintAndCheckBlock(Block, Ref, Name=None, NameFieldWidth=None):
- Lines = HexLines(Block, Name, NameFieldWidth)
- Lines[-1] += " " + MatchStr(Block, Ref)
- print("\n".join(Lines))
- if Block != Ref:
- Lines = HexLines(Ref, Name, NameFieldWidth)
- Lines[0] = "\x1b[36m" + Lines[0]
- Lines[-1] += " Ref\x1b[39;22m"
- print("\n".join(Lines))
- print("AES-128\n")
- # Example from FIPS PUBS 197
- # C.1: AES-128 (Nk=4, Nr=10)
- M = XBytes("00112233445566778899aabbccddeeff")
- K = XBytes("000102030405060708090a0b0c0d0e0f")
- RefC = XBytes("69c4e0d86a7b0430d8cdb78070b4c55a")
- w = 12
- PrintBlock(K, "Key", w)
- PrintBlock(M, "Message", w)
- C = AESEncryptBlock(K, M)
- PrintAndCheckBlock(C, RefC, "Encrypted", w)
- R = AESDecryptBlock(K, RefC)
- PrintAndCheckBlock(R, M, "Decrypted", w)
- print("\nCMAC Subkeys\n")
- # Example from NIST Special Publication 800-38B
- # D.1: AES-128, Subkey Generation
- K = XBytes("2b7e151628aed2a6abf7158809cf4f3c")
- RefZ = XBytes("7df76b0c1ab899b33e42f047b91b546f")
- RefK1 = XBytes("fbeed618357133667c85e08f7236a8de")
- RefK2 = XBytes("f7ddac306ae266ccf90bc11ee46d513b")
- w = 12
- PrintBlock(K, "Key", w)
- Z = AESEncryptBlock(K, b"\x00" * 16)
- PrintAndCheckBlock(Z, RefZ, "CIPH_K(0)", w)
- K1, K2 = CMACSubKeys(K)
- PrintAndCheckBlock(K1, RefK1, "K1", w)
- PrintAndCheckBlock(K2, RefK2, "K2", w)
- print("\nAES-128 CMAC\n")
- # Example from NIST Special Publication 800-38B
- # D.1: AES-128, Examples 1 to 4
- K = XBytes("2b7e151628aed2a6abf7158809cf4f3c")
- w = 8
- PrintBlock(K, "Key", w)
- Examples = [
- ("0", XBytes(""),
- XBytes("bb1d6929e95937287fa37d129b756746")),
- ("128", XBytes("6bc1bee22e409f96e93d7e117393172a"),
- XBytes("070a16b46b4d4144f79bdd9dd04a287c")),
- ("320", XBytes("6bc1bee22e409f96e93d7e117393172a"
- "ae2d8a571e03ac9c9eb76fac45af8e51"
- "30c81c46a35ce411"),
- XBytes("dfa66747de9ae63030ca32611497c827")),
- ("512", XBytes("6bc1bee22e409f96e93d7e117393172a"
- "ae2d8a571e03ac9c9eb76fac45af8e51"
- "30c81c46a35ce411e5fbc1191a0a52ef"
- "f69f2445df4f9b17ad2b417be66c3710"),
- XBytes("51f0bebf7e3b9d92fc49741779363cfe"))
- ]
- for StrName, M, RefT in Examples:
- PrintBlock(M, "M" + StrName, w)
- T = AESCMAC(M, K)
- PrintAndCheckBlock(T, RefT, "T" + StrName, w)
- print("\nAES-128 GCM\n ")
- # Example from MACsec GCM-AES Test Vectors (April 11, 2011)
- # 2.4.1: 54-byte Packet Encryption Using GCM-AES-128
- K = XBytes("071B113B0CA743FECCCF3D051F737382")
- IV = XBytes("F0761E8DCD3D000176D457ED")
- A = XBytes("E20106D7CD0DF0761E8DCD3D88E54C2A76D457ED")
- P = XBytes("08000F101112131415161718191A1B1C"
- "1D1E1F202122232425262728292A2B2C"
- "2D2E2F30313233340004")
- RefC = XBytes("13B4C72B389DC5018E72A171DD85A5D3"
- "752274D3A019FBCAED09A425CD9B2E1C"
- "9B72EEE7C9DE7D52B3F3")
- RefT = XBytes("D6A5284F4A6D3FE22A5D6C2B960494C3")
- w = 8
- PrintBlock(K, "K", w)
- PrintBlock(IV, "IV", w)
- PrintBlock(A, "A", w)
- PrintBlock(P, "P", w)
- Cipher = AESGCMCipher(K, IV)
- # Encrypt
- AADStream = io.BytesIO(A)
- PlainStream = io.BytesIO(P)
- S = Cipher.Encrypt(AADStream, PlainStream)
- OutputStream = io.BytesIO()
- HaveEOF = False
- while not HaveEOF:
- Chunk = S.read(65536)
- if len(Chunk) > 0:
- OutputStream.write(Chunk)
- else:
- HaveEOF = True
- S.close()
- OutputStream.seek(0)
- C = OutputStream.read()
- OutputStream.close()
- T = Cipher.AuthTag
- PrintAndCheckBlock(C, RefC, "C", w)
- PrintAndCheckBlock(T, RefT, "T", w)
- # Decrypt
- AADStream.seek(0)
- CipherStream = io.BytesIO(RefC)
- S = Cipher.Decrypt(AADStream, CipherStream)
- OutputStream = io.BytesIO()
- HaveEOF = False
- while not HaveEOF:
- Chunk = S.read(65536)
- if len(Chunk) > 0:
- OutputStream.write(Chunk)
- else:
- HaveEOF = True
- S.close()
- OutputStream.seek(0)
- R = OutputStream.read()
- OutputStream.close()
- T = Cipher.AuthTag
- PrintAndCheckBlock(R, P, "P'", w)
- PrintAndCheckBlock(T, RefT, "T'", w)
- # Verify
- AADStream.seek(0)
- CipherStream.seek(0)
- IsOK = Cipher.Verify(AADStream, CipherStream, RefT)
- print("Cipher.Verify() returned {}.".format(IsOK))
- print("\nAES-128 GMAC\n ")
- # Example from MACsec GCM-AES Test Vectors (April 11, 2011)
- # 2.1.1: 54-byte Packet Authentication Using GCM-AES-128
- K = XBytes("AD7A2BD03EAC835A6F620FDCB506B345")
- IV = XBytes("12153524C0895E81B2C28465")
- A = XBytes("D609B1F056637A0D46DF998D88E5222A"
- "B2C2846512153524C0895E8108000F10"
- "1112131415161718191A1B1C1D1E1F20"
- "2122232425262728292A2B2C2D2E2F30"
- "313233340001")
- RefG = XBytes("F09478A9B09007D06F46E9B6A1DA25DD")
- w = 8
- PrintBlock(K, "K", w)
- PrintBlock(IV, "IV", w)
- PrintBlock(A, "A", w)
- AADStream = io.BytesIO(A)
- Cipher = AESGCMCipher(K, IV)
- G = Cipher.GMAC(AADStream)
- PrintAndCheckBlock(G, RefG, "GMAC", w)
- print("\nSHA-256\n ")
- w = 8
- Examples = [
- ("0", XBytes(""),
- XBytes("e3b0c44298fc1c149afbf4c8996fb924"
- "27ae41e4649b934ca495991b7852b855")),
- ("abc", b"abc",
- XBytes("BA7816BF8F01CFEA414140DE5DAE2223"
- "B00361A396177A9CB410FF61F20015AD"))
- ]
- for StrName, M, RefH in Examples:
- PrintBlock(M, "M" + StrName, w)
- H = SHA_256(M)
- PrintAndCheckBlock(H, RefH, "H" + StrName, w)
- print("\nHMAC-SHA-256\n ")
- w = 8
- Examples = [
- ("0", b"", b"",
- XBytes("b613679a0814d9ec772f95d778c35fc5"
- "ff1697c493715653c6c712144292c5ad")),
- ("qbf", b"key", b"The quick brown fox jumps over the lazy dog",
- XBytes("f7bc83f430538424b13298e6aa6fb143"
- "ef4d59a14946175997479dbc2d1a3cd8"))
- ]
- for StrName, K, M, RefH in Examples:
- PrintBlock(K, "K" + StrName, w)
- PrintBlock(M, "M" + StrName, w)
- H = HMAC_SHA_256(K, M)
- PrintAndCheckBlock(H, RefH, "H" + StrName, w)
- print("PBKDF2")
- w = 10
- #PBKDF2(PRF, Password, Salt, Count, DerivedKeyLength)
- Examples = [
- ("1", b"password", b"salt", 1, 32,
- XBytes("120fb6cffcf8b32c43e7225256c4f837"
- "a86548c92ccc35480805987cb70be17b")),
- ("2", b"passwordPASSWORDpassword",
- b"saltSALTsaltSALTsaltSALTsaltSALTsalt", 4096, 40,
- XBytes("348c89dbcbd32b2f32d814b8116e84cf"
- "2b17347ebc1800181c4e2a1fb8dd53e1"
- "c635518c7dac47e9"))
- ]
- for StrName, P, S, c, dkLen, RefDK in Examples:
- PrintBlock(P, "P" + StrName, w)
- PrintBlock(S, "S" + StrName, w)
- print("{:<{}}{}".format("c" + StrName + ":", w, c))
- print("{:<{}}{}".format("dkLen" + StrName + ":", w, dkLen))
- DK = PBKDF2(HMAC_SHA_256, P, S, c, dkLen)
- PrintAndCheckBlock(DK, RefDK, "DK" + StrName, w)
- # Encryption example
- #
- # Password = "boojum"
- # KDF = PBKDF2
- # PRF = HMAC-SHA-256
- # Iterations = 5000
- # Salt = 40c8298595ff6e6d876fae82f0a498b167194c89bad4695fb35428ccb6b8da9d
- #
- # Cipher = AES-128
- # Mode = GCM
- # IV = 8c3b8c4f4af83514139351ad
- #
- # AAD = (empty string)
- #
- # plain.txt:
- # 0000: 22 4a 75 73 74 20 74 68 65 20 70 6c 61 63 65 20 |"Just the place |
- # 0010: 66 6f 72 20 61 20 53 6e 61 72 6b 21 22 20 74 68 |for a Snark!" th|
- # 0020: 65 20 42 65 6c 6c 6d 61 6e 20 63 72 69 65 64 2c |e Bellman cried,|
- # 0030: 0a 41 73 20 68 65 20 6c 61 6e 64 65 64 20 68 69 |.As he landed hi|
- # 0040: 73 20 63 72 65 77 20 77 69 74 68 20 63 61 72 65 |s crew with care|
- # 0050: 3b 0a 53 75 70 70 6f 72 74 69 6e 67 20 65 61 63 |;.Supporting eac|
- # 0060: 68 20 6d 61 6e 20 6f 6e 20 74 68 65 20 74 6f 70 |h man on the top|
- # 0070: 20 6f 66 20 74 68 65 20 74 69 64 65 0a 42 79 20 | of the tide.By |
- # 0080: 61 20 66 69 6e 67 65 72 20 65 6e 74 77 69 6e 65 |a finger entwine|
- # 0090: 64 20 69 6e 20 68 69 73 20 68 61 69 72 2e 0a |d in his hair..|
- # 009f:
- #
- # encrypted.bin
- # 0000: 23 45 4e 43 52 59 50 54 45 44 23 0a 5b 46 69 6c |#ENCRYPTED#.[Fil|
- # 0010: 65 5d 0a 48 44 52 53 49 5a 45 3d 32 36 34 0a 41 |e].HDRSIZE=264.A|
- # 0020: 41 44 53 49 5a 45 3d 30 0a 46 4f 52 4d 41 54 3d |ADSIZE=0.FORMAT=|
- # 0030: 43 4f 4e 43 41 54 45 4e 41 54 45 44 20 41 43 54 |CONCATENATED ACT|
- # 0040: 0a 56 45 52 53 49 4f 4e 3d 31 2e 30 0a 5b 50 61 |.VERSION=1.0.[Pa|
- # 0050: 73 73 77 6f 72 64 5d 0a 4b 44 46 3d 50 42 4b 44 |ssword].KDF=PBKD|
- # 0060: 46 32 0a 50 52 46 3d 48 4d 41 43 2d 53 48 41 2d |F2.PRF=HMAC-SHA-|
- # 0070: 32 35 36 0a 49 54 45 52 41 54 49 4f 4e 53 3d 35 |256.ITERATIONS=5|
- # 0080: 30 30 30 0a 53 41 4c 54 3d 34 30 63 38 32 39 38 |000.SALT=40c8298|
- # 0090: 35 39 35 66 66 36 65 36 64 38 37 36 66 61 65 38 |595ff6e6d876fae8|
- # 00a0: 32 66 30 61 34 39 38 62 31 36 37 31 39 34 63 38 |2f0a498b167194c8|
- # 00b0: 39 62 61 64 34 36 39 35 66 62 33 35 34 32 38 63 |9bad4695fb35428c|
- # 00c0: 63 62 36 62 38 64 61 39 64 0a 5b 43 69 70 68 65 |cb6b8da9d.[Ciphe|
- # 00d0: 72 5d 0a 43 49 50 48 45 52 3d 41 45 53 2d 31 32 |r].CIPHER=AES-12|
- # 00e0: 38 0a 4d 4f 44 45 3d 47 43 4d 0a 49 56 3d 38 63 |8.MODE=GCM.IV=8c|
- # 00f0: 33 62 38 63 34 66 34 61 66 38 33 35 31 34 31 33 |3b8c4f4af8351413|
- # 0100: 39 33 35 31 61 64 0a 00 3a 9f 9f e8 2c e3 53 81 |9351ad..:...,.S.|
- # 0110: 4f cf 2b 47 82 88 c3 4d c3 1d 78 59 5b ab 36 83 |O.+G...M..xY[.6.|
- # 0120: 94 b3 74 5e bd 70 ea ee ab 41 f1 fd e0 ce 93 36 |..t^.p...A.....6|
- # 0130: dd b0 b0 48 49 84 7b b4 bf 43 2c 23 34 35 48 aa |...HI.{..C,#45H.|
- # 0140: 5d b3 54 5a d2 84 d0 8b e2 d7 93 ae 18 0d ec 1d |].TZ............|
- # 0150: ae 0a 12 05 6a 7c 3d 40 73 5a 9f 78 eb 52 db 04 |....j|=@sZ.x.R..|
- # 0160: 50 ec 7c b5 21 31 7f 03 73 8e 99 40 08 93 5e 14 |P.|.!1..s..@..^.|
- # 0170: 12 ef c2 72 f8 8a f3 54 3a e9 49 ce 27 e8 9c 52 |...r...T:.I.'..R|
- # 0180: d6 02 a4 45 77 ca d4 c5 fd 1c dc 00 c7 e1 47 b6 |...Ew.........G.|
- # 0190: 5c 20 bb 25 75 0b 61 7e 5e db 78 d0 0c f1 08 b1 |\ .%u.a~^.x.....|
- # 01a0: b3 5c 15 60 65 c5 1a 9a 8a 85 73 71 66 23 0f 54 |.\.`e.....sqf#.T|
- # 01b0: dd 5b 88 f5 50 57 db |.[..PW.|
- # 01b7:
- #
- # Tag = 9a8a85737166230f54dd5b88f55057db
- print("Done")
- #-------------------------------------------------------------------------------
- # Main
- #-------------------------------------------------------------------------------
- def main(Args):
- """
- Usage:
- pef encrypt {password} {plainfile} {outputfile}
- pef decrypt {password} {encryptedfile} {outputfile}
- pef verify {password} {file}
- If {password} is an empty string, the user will be prompted for a password.
- """
- Result = 0
- ErrMsg = ""
- InFile = None
- OutFile = None
- CmdName = os.path.basename(sys.argv[0])
- try:
- CmdArg = None if len(Args) < 2 else Args[1]
- KeyArg = None if len(Args) < 3 else Args[2]
- CmdArgLC = None if CmdArg is None else CmdArg.lower()
- Cmd = None
- if CmdArgLC in ("encrypt", "decrypt", "verify"):
- Cmd = CmdArgLC
- else:
- if CmdArg is None:
- raise ArgError('Command argument required: ' +
- '"encrypt", "decrypt" or "verify".')
- else:
- raise ArgError('Unknown command "' + CmdArg + '".')
- if Cmd == 'encrypt':
- if len(Args) != 5:
- raise ArgError(
- 'Expected arguments: encrypt {password} ' +
- '{plainfile} {outputfile}')
- Password, InFileName, OutFileName = Args[2:]
- Password = Password or getpass.getpass()
- InFile = open(InFileName, "rb")
- OutFile = open(OutFileName, "wb")
- AADStr = ""
- AAD = (AADStr).encode("utf8")
- Encrypt(Password, AAD, InFile, OutFile)
- elif Cmd == 'decrypt':
- if len(Args) != 5:
- raise ArgError(
- 'Expected arguments: decrypt {password} ' +
- '{encryptedfile} {outputfile}')
- Password, InFileName, OutFileName = Args[2:]
- Password = Password or getpass.getpass()
- OFExistedAlready = os.path.isfile(OutFileName)
- InFile = open(InFileName, "rb")
- OutFile = open(OutFileName, "wb")
- AAD = Decrypt(Password, InFile, OutFile)
- if AAD is None:
- if not OFExistedAlready:
- os.remove(OutFileName)
- raise FileError('Authenticity check failed.')
- elif Cmd == 'verify':
- Password, InFileName = Args[2:]
- Password = Password or getpass.getpass()
- InFile = open(InFileName, "rb")
- AAD = Decrypt(Password, InFile, None)
- if AAD is None:
- raise FileError('Authenticity check failed.')
- else:
- print("OK")
- else:
- raise ArgError('INTERNAL: Command."' + Cmd + '" not handled.')
- except (ArgError) as E:
- ErrMsg = "error: " + str(E)
- Result = 2
- except (FileError) as E:
- ErrMsg = str(E)
- Result = 3
- except (Exception) as E:
- exc_type, exc_value, exc_traceback = sys.exc_info()
- ErrLines = traceback.format_exc().splitlines()
- ErrMsg = "Unhandled exception:\n" + "\n".join(ErrLines)
- Result = 1
- finally:
- if InFile is not None:
- InFile.close()
- if OutFile is not None:
- OutFile.close()
- if ErrMsg != "":
- print(CmdName + ": " + ErrMsg, file=sys.stderr)
- return Result
- #-------------------------------------------------------------------------------
- if __name__ == '__main__':
- sys.exit(main(sys.argv))
- #-------------------------------------------------------------------------------
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement