def Verify(self, data, sig): """ Verifies whether the signature corresponds to the given data. This is a stanard signature (i.e. HMAC-SHA1, RSA-SHA1, DSA-SHA1) that contains no version information, so this will try to verify with each key in a keyset. @param data: message that has been signed with sig @type data: string @param sig: Base64 string formatted as Header|Signature @type sig: string @return: True if sig corresponds to data, False otherwise. @rtype: boolean """ sig_bytes = util.Base64WSDecode(sig) for version in self.versions: key = self._keys[version] # Try to verify with each key result = key.Verify(util.RawBytes(data), sig_bytes) if result: return True # None of the keys verified the signature return False
def AttachedVerify(self, signed_data, nonce): """ Verifies the signature in the signed blob corresponds to the data in the signed blob and the provided nonce, and returns the data. @param signed_data: the blob, produced by AttachedSign, containing data and signature. @type signed_data: string @param nonce: Nonce string that was used when the signature was generated. If the provided value doesn't match, verification will fail. @type sig: string @return: If verification succeeds, the extracted data will be returned, otherwise, None @rtype: string """ decoded_data = util.Base64WSDecode(signed_data) reader = util.BytesReader(decoded_data) writer, getoutput = util.BytesWriter() nonce = util.RawBytes(nonce) if self.AttachedVerifyIO(reader, writer, nonce): return util.RawString(getoutput()) return None
def __simulateReflow(self, data): """Helper to simulate reflowing of data""" endings = [b'\n', b'\r', b'\r\n'] reflowed_data = b'' bdata = util.RawBytes(data) for c in [bdata[x:x + 5] for x in range(0, len(bdata), 5)]: d = bytes(bytearray(c)) reflowed_data += random.choice(endings) + d return reflowed_data
def AttachedSign(self, data, nonce): """ Sign given data and nonce and return a blob containing both data and signature For message M, and nonce N, outputs Header|len(M)|M|Sig(Header|M|N). @param data: message to be signed @type data: string @param nonce: nonce to be included in the signature @type nonce: string @return: signature on the data encoded as a Base64 string @rtype: string """ return util.Base64WSEncode( self.primary_key.Header() + util.PackByteArray(util.RawBytes(data)) + self.__InternalSign(util.RawBytes(data), util.RawBytes(nonce)))
def testBadAesCiphertextsStream(self): crypter = keyczar.Crypter.Read(os.path.join(TEST_DATA, "aes")) ciphertext = util.Base64WSDecode(crypter.Encrypt(self.input_data)) bad = util.Base64WSEncode(b'0x00') char = bytes([bytearray(ciphertext)[2] ^ 44]) ciphertext = util.Base64WSEncode(ciphertext[:2] + char + ciphertext[3:]) try: stream = io.BytesIO(util.RawBytes(bad)) decryption_stream = crypter.CreateDecryptingStreamReader(stream) self.__readFromStream(decryption_stream) except errors.ShortCiphertextError: pass try: stream = io.BytesIO(util.RawBytes(ciphertext)) decryption_stream = crypter.CreateDecryptingStreamReader(stream) self.__readFromStream(decryption_stream) except errors.KeyNotFoundError: pass
def testSimulateDecrypter(self): enc_data = util.RawBytes( 'AJehaFGwoOrkzpDCnF1zqIi721eCOMYWRmLyRyn3hxyhh_mYwpnDN6jKN057gr5lz' \ 'APFYhq9zoDwFMaGMEipEl__ECOZGeaxWw') expected_result = util.Base64WSDecode(enc_data) stream = util.IncrementalBase64WSStreamReader(io.BytesIO(enc_data)) result = stream.read(5) result += stream.read(15) read_data = True while read_data: read_data = stream.read(4096) result += read_data self.assertEqual(result, expected_result)
def Sign(self, data): """ Sign given data and return corresponding signature. For message M, outputs the signature as Header|Sig(Header.M). @param data: message to be signed @type data: string @return: signature on the data encoded as a Base64 string @rtype: string """ return util.Base64WSEncode(self.primary_key.Header() + self.__InternalSign(util.RawBytes(data)))
def Sign(self, data): """ Sign given data and return corresponding signature. This signature contains no header or version information. For message M, outputs the signature as Sig(M). @param data: message to be signed @type data: string @return: signature on the data encoded as a Base64 string @rtype: string """ signing_key = self.primary_key if signing_key is None: raise errors.NoPrimaryKeyError() return util.Base64WSEncode(signing_key.Sign(util.RawBytes(data)))
def testStreamDecryptHandlesIOModuleBlockingExceptionRaised(self): """ Test for input streams that conform to the blocking I/O module spec wrt buffered blocking, i.e. if the underlying raw stream is in non blocking-mode, a BlockingIOError is raised indicate no data available, but not EOF """ crypter = keyczar.Crypter.Read(os.path.join(TEST_DATA, 'aes')) ciphertext = crypter.Encrypt(self.input_data) class PseudoBlockingStream(object): """ A 'stream' that raises BlockingIOError every 2nd call to read() to simultate buffered blocking """ def __init__(self, string): self.current_posn = 0 self.string = string self.raise_exception = True def read(self, size=-1): result = None start = self.current_posn if not self.raise_exception: if size < 0: end = size self.current_posn = len(self.string) else: end = (start + size) self.current_posn = end result = self.string[start:end] else: if start > len(self.string): result = b'' else: self.raise_exception = False raise io.BlockingIOError(1, 'Dummy error', self.current_posn) self.raise_exception = not self.raise_exception return result decryption_stream = crypter.CreateDecryptingStreamReader( PseudoBlockingStream(util.RawBytes(ciphertext))) result = self.__readFromStream(decryption_stream, len_to_read=-1) self.assertEqual(self.input_data, result)
def Verify(self, data, sig): """ Verifies whether the signature corresponds to the given data. @param data: message that has been signed with sig @type data: string @param sig: Base64 string formatted as Header|Signature @type sig: string @return: True if sig corresponds to data, False otherwise. @rtype: boolean """ sig_bytes = util.Base64WSDecode(sig) if len(sig_bytes) < constants.HEADER_SIZE: raise errors.ShortSignatureError(len(sig_bytes)) return self.__InternalVerify(sig_bytes[:constants.HEADER_SIZE], sig_bytes[constants.HEADER_SIZE:], util.RawBytes(data))
def testStreamDecryptHandlesIOModuleBlockingNoneReturned(self): """ Test for input streams that conform to the blocking I/O module spec, i.e. read() returns None to indicate no data available, but not EOF """ crypter = keyczar.Crypter.Read(os.path.join(TEST_DATA, 'aes')) ciphertext = crypter.Encrypt(self.input_data) class PseudoBlockingStream(object): """ A 'stream' that blocks every 2nd call to read() to simultate blocking i/o """ def __init__(self, string): self.current_posn = 0 self.string = string self.return_none = False def read(self, size=-1): result = None start = self.current_posn if not self.return_none: if size < 0: end = size self.current_posn = len(self.string) else: end = (start + size) self.current_posn = end result = self.string[start:end] else: if start > len(self.string): result = b'' self.return_none = not self.return_none return result decryption_stream = crypter.CreateDecryptingStreamReader( PseudoBlockingStream(util.RawBytes(ciphertext))) result = self.__readFromStream(decryption_stream, len_to_read=-1) self.assertEqual(self.input_data, result)
def __testStandardEncryptAndStreamDecrypt(self, subdir, input_data, stream_buffer_size, len_to_read, stream_source): crypter = keyczar.Crypter.Read(os.path.join(TEST_DATA, subdir)) ciphertext = crypter.Encrypt(input_data) ciphertext_stream = io.BytesIO(util.RawBytes(ciphertext)) if stream_source is None: decoder = None ciphertext_stream = io.BytesIO(util.Base64WSDecode(ciphertext)) else: decoder = util.IncrementalBase64WSStreamReader decryption_stream = crypter.CreateDecryptingStreamReader( ciphertext_stream, decoder=decoder, buffer_size=stream_buffer_size) plaintext = self.__readFromStream(decryption_stream, len_to_read) self.assertEqual( len(input_data), len(plaintext), 'Wrong length for buffer:%d, read len:%d' % (stream_buffer_size, len_to_read)) self.assertEqual( input_data, plaintext, 'Not equals for buffer:%d, read len:%d' % (stream_buffer_size, len_to_read))
def Sign(self, data, expire_date): """ Sign given data and return corresponding signature. For message M, outputs the signature as Header|Sig(Header.M). @param data: message to be signed @type data: string @param expire_date: datetime when signature expires @type expire_date: datetime (UTC) @return: signature on the data encoded as a Base64 string @rtype: string """ expire_milli = util.UnixTimeMilliseconds(expire_date) expire_bytes = util.LongLongToBytes(expire_milli) return util.Base64WSEncode(self.primary_key.Header() + expire_bytes + self.__InternalSign(expire_bytes + util.RawBytes(data)))
def Encrypt(self, data, encoder=util.Base64WSEncode): """ Encrypt the data and return the ciphertext. @param data: message to encrypt @type data: string @param encoder: function to perform final encoding. Defaults to Base64, use None for no encoding. @type encoder: function @return: ciphertext, by default Base64 encoded @rtype: string @raise NoPrimaryKeyError: if no primary key can be found to encrypt """ reader = io.BufferedReader(io.BytesIO(util.RawBytes(data))) output = io.BytesIO() writer = io.BufferedWriter(output) self.EncryptIO(reader, writer) ciphertext = output.getvalue() return encoder(ciphertext) if encoder else ciphertext
def __testRead(self, input_data, expected_result): for size in [1, 5, 4096, 99999, -1]: stream = util.IncrementalBase64WSStreamReader(io.BytesIO(util.RawBytes(input_data))) self.assertEqual(util.RawString(self.__readStream(stream, size)), util.RawString(expected_result))