#############################################################################
# Documentation #
#############################################################################
# Author: Todd Whiteman
# Date: 7th May, 2003
# Verion: 1.1
# Homepage: http://h...content-available-to-author-only...t.au/~twhitema/des.html
#
# Modifications to 3des CBC code by Matt Johnston 2004 <matt at ucc asn au>
#
# This algorithm is a pure python implementation of the DES algorithm.
# It is in pure python to avoid portability issues, since most DES
# implementations are programmed in C (for performance reasons).
#
# Triple DES class is also implemented, utilising the DES base. Triple DES
# is either DES-EDE3 with a 24 byte key, or DES-EDE2 with a 16 byte key.
#
# See the README.txt that should come with this python module for the
# implementation methods used.
"""A pure python implementation of the DES and TRIPLE DES encryption algorithms
pyDes.des(key, [mode], [IV])
pyDes.triple_des(key, [mode], [IV])
key -> String containing the encryption key. 8 bytes for DES, 16 or 24 bytes
for Triple DES
mode -> Optional argument for encryption type, can be either
pyDes.ECB (Electronic Code Book) or pyDes.CBC (Cypher Block Chaining)
IV -> Optional argument, must be supplied if using CBC mode. Must be 8 bytes
Example:
from pyDes import *
data = "Please encrypt my string"
k = des("DESCRYPT", " ", CBC, "\0 \0 \0 \0 \0 \0 \0 \0 ")
d = k.encrypt(data)
print "Encypted string: " + d
print "Decypted string: " + k.decrypt(d)
See the module source (pyDes.py) for more examples of use.
You can slo run the pyDes.py file without and arguments to see a simple test.
Note: This code was not written for high-end systems needing a fast
implementation, but rather a handy portable solution with small usage.
"""
# Modes of crypting / cyphering
ECB = 0
CBC = 1
#############################################################################
# DES #
#############################################################################
class des:
"""DES encryption/decrytpion class
Supports ECB (Electronic Code Book) and CBC (Cypher Block Chaining) modes.
pyDes.des(key,[mode], [IV])
key -> The encryption key string, must be exactly 8 bytes
mode -> Optional argument for encryption type, can be either pyDes.ECB
(Electronic Code Book), pyDes.CBC (Cypher Block Chaining)
IV -> Optional string argument, must be supplied if using CBC mode.
Must be 8 bytes in length.
"""
# Permutation and translation tables for DES
__pc1 = [ 56 , 48 , 40 , 32 , 24 , 16 , 8 ,
0 , 57 , 49 , 41 , 33 , 25 , 17 ,
9 , 1 , 58 , 50 , 42 , 34 , 26 ,
18 , 10 , 2 , 59 , 51 , 43 , 35 ,
62 , 54 , 46 , 38 , 30 , 22 , 14 ,
6 , 61 , 53 , 45 , 37 , 29 , 21 ,
13 , 5 , 60 , 52 , 44 , 36 , 28 ,
20 , 12 , 4 , 27 , 19 , 11 , 3
]
# number left rotations of pc1
__left_rotations = [
1 , 1 , 2 , 2 , 2 , 2 , 2 , 2 , 1 , 2 , 2 , 2 , 2 , 2 , 2 , 1
]
# permuted choice key (table 2)
__pc2 = [
13 , 16 , 10 , 23 , 0 , 4 ,
2 , 27 , 14 , 5 , 20 , 9 ,
22 , 18 , 11 , 3 , 25 , 7 ,
15 , 6 , 26 , 19 , 12 , 1 ,
40 , 51 , 30 , 36 , 46 , 54 ,
29 , 39 , 50 , 44 , 32 , 47 ,
43 , 48 , 38 , 55 , 33 , 52 ,
45 , 41 , 49 , 35 , 28 , 31
]
# initial permutation IP
__ip = [ 57 , 49 , 41 , 33 , 25 , 17 , 9 , 1 ,
59 , 51 , 43 , 35 , 27 , 19 , 11 , 3 ,
61 , 53 , 45 , 37 , 29 , 21 , 13 , 5 ,
63 , 55 , 47 , 39 , 31 , 23 , 15 , 7 ,
56 , 48 , 40 , 32 , 24 , 16 , 8 , 0 ,
58 , 50 , 42 , 34 , 26 , 18 , 10 , 2 ,
60 , 52 , 44 , 36 , 28 , 20 , 12 , 4 ,
62 , 54 , 46 , 38 , 30 , 22 , 14 , 6
]
# Expansion table for turning 32 bit blocks into 48 bits
__expansion_table = [
31 , 0 , 1 , 2 , 3 , 4 ,
3 , 4 , 5 , 6 , 7 , 8 ,
7 , 8 , 9 , 10 , 11 , 12 ,
11 , 12 , 13 , 14 , 15 , 16 ,
15 , 16 , 17 , 18 , 19 , 20 ,
19 , 20 , 21 , 22 , 23 , 24 ,
23 , 24 , 25 , 26 , 27 , 28 ,
27 , 28 , 29 , 30 , 31 , 0
]
# The (in)famous S-boxes
__sbox = [
# S1
[ 14 , 4 , 13 , 1 , 2 , 15 , 11 , 8 , 3 , 10 , 6 , 12 , 5 , 9 , 0 , 7 ,
0 , 15 , 7 , 4 , 14 , 2 , 13 , 1 , 10 , 6 , 12 , 11 , 9 , 5 , 3 , 8 ,
4 , 1 , 14 , 8 , 13 , 6 , 2 , 11 , 15 , 12 , 9 , 7 , 3 , 10 , 5 , 0 ,
15 , 12 , 8 , 2 , 4 , 9 , 1 , 7 , 5 , 11 , 3 , 14 , 10 , 0 , 6 , 13 ] ,
# S2
[ 15 , 1 , 8 , 14 , 6 , 11 , 3 , 4 , 9 , 7 , 2 , 13 , 12 , 0 , 5 , 10 ,
3 , 13 , 4 , 7 , 15 , 2 , 8 , 14 , 12 , 0 , 1 , 10 , 6 , 9 , 11 , 5 ,
0 , 14 , 7 , 11 , 10 , 4 , 13 , 1 , 5 , 8 , 12 , 6 , 9 , 3 , 2 , 15 ,
13 , 8 , 10 , 1 , 3 , 15 , 4 , 2 , 11 , 6 , 7 , 12 , 0 , 5 , 14 , 9 ] ,
# S3
[ 10 , 0 , 9 , 14 , 6 , 3 , 15 , 5 , 1 , 13 , 12 , 7 , 11 , 4 , 2 , 8 ,
13 , 7 , 0 , 9 , 3 , 4 , 6 , 10 , 2 , 8 , 5 , 14 , 12 , 11 , 15 , 1 ,
13 , 6 , 4 , 9 , 8 , 15 , 3 , 0 , 11 , 1 , 2 , 12 , 5 , 10 , 14 , 7 ,
1 , 10 , 13 , 0 , 6 , 9 , 8 , 7 , 4 , 15 , 14 , 3 , 11 , 5 , 2 , 12 ] ,
# S4
[ 7 , 13 , 14 , 3 , 0 , 6 , 9 , 10 , 1 , 2 , 8 , 5 , 11 , 12 , 4 , 15 ,
13 , 8 , 11 , 5 , 6 , 15 , 0 , 3 , 4 , 7 , 2 , 12 , 1 , 10 , 14 , 9 ,
10 , 6 , 9 , 0 , 12 , 11 , 7 , 13 , 15 , 1 , 3 , 14 , 5 , 2 , 8 , 4 ,
3 , 15 , 0 , 6 , 10 , 1 , 13 , 8 , 9 , 4 , 5 , 11 , 12 , 7 , 2 , 14 ] ,
# S5
[ 2 , 12 , 4 , 1 , 7 , 10 , 11 , 6 , 8 , 5 , 3 , 15 , 13 , 0 , 14 , 9 ,
14 , 11 , 2 , 12 , 4 , 7 , 13 , 1 , 5 , 0 , 15 , 10 , 3 , 9 , 8 , 6 ,
4 , 2 , 1 , 11 , 10 , 13 , 7 , 8 , 15 , 9 , 12 , 5 , 6 , 3 , 0 , 14 ,
11 , 8 , 12 , 7 , 1 , 14 , 2 , 13 , 6 , 15 , 0 , 9 , 10 , 4 , 5 , 3 ] ,
# S6
[ 12 , 1 , 10 , 15 , 9 , 2 , 6 , 8 , 0 , 13 , 3 , 4 , 14 , 7 , 5 , 11 ,
10 , 15 , 4 , 2 , 7 , 12 , 9 , 5 , 6 , 1 , 13 , 14 , 0 , 11 , 3 , 8 ,
9 , 14 , 15 , 5 , 2 , 8 , 12 , 3 , 7 , 0 , 4 , 10 , 1 , 13 , 11 , 6 ,
4 , 3 , 2 , 12 , 9 , 5 , 15 , 10 , 11 , 14 , 1 , 7 , 6 , 0 , 8 , 13 ] ,
# S7
[ 4 , 11 , 2 , 14 , 15 , 0 , 8 , 13 , 3 , 12 , 9 , 7 , 5 , 10 , 6 , 1 ,
13 , 0 , 11 , 7 , 4 , 9 , 1 , 10 , 14 , 3 , 5 , 12 , 2 , 15 , 8 , 6 ,
1 , 4 , 11 , 13 , 12 , 3 , 7 , 14 , 10 , 15 , 6 , 8 , 0 , 5 , 9 , 2 ,
6 , 11 , 13 , 8 , 1 , 4 , 10 , 7 , 9 , 5 , 0 , 15 , 14 , 2 , 3 , 12 ] ,
# S8
[ 13 , 2 , 8 , 4 , 6 , 15 , 11 , 1 , 10 , 9 , 3 , 14 , 5 , 0 , 12 , 7 ,
1 , 15 , 13 , 8 , 10 , 3 , 7 , 4 , 12 , 5 , 6 , 11 , 0 , 14 , 9 , 2 ,
7 , 11 , 4 , 1 , 9 , 12 , 14 , 2 , 0 , 6 , 10 , 13 , 15 , 3 , 5 , 8 ,
2 , 1 , 14 , 7 , 4 , 10 , 8 , 13 , 15 , 12 , 9 , 0 , 3 , 5 , 6 , 11 ] ,
]
# 32-bit permutation function P used on the output of the S-boxes
__p = [
15 , 6 , 19 , 20 , 28 , 11 ,
27 , 16 , 0 , 14 , 22 , 25 ,
4 , 17 , 30 , 9 , 1 , 7 ,
23 , 13 , 31 , 26 , 2 , 8 ,
18 , 12 , 29 , 5 , 21 , 10 ,
3 , 24
]
# final permutation IP^-1
__fp = [
39 , 7 , 47 , 15 , 55 , 23 , 63 , 31 ,
38 , 6 , 46 , 14 , 54 , 22 , 62 , 30 ,
37 , 5 , 45 , 13 , 53 , 21 , 61 , 29 ,
36 , 4 , 44 , 12 , 52 , 20 , 60 , 28 ,
35 , 3 , 43 , 11 , 51 , 19 , 59 , 27 ,
34 , 2 , 42 , 10 , 50 , 18 , 58 , 26 ,
33 , 1 , 41 , 9 , 49 , 17 , 57 , 25 ,
32 , 0 , 40 , 8 , 48 , 16 , 56 , 24
]
# Type of crypting being done
ENCRYPT = 0x00
DECRYPT = 0x01
# Initialisation
def __init__ ( self , key, mode= ECB, IV= None ) :
if len ( key) != 8 :
raise ValueError ( "Invalid DES key size. Key must be exactly 8 bytes long." )
self .block_size = 8
self .key_size = 8
self .__padding = ''
# Set the passed in variables
self .setMode ( mode)
if IV:
self .setIV ( IV)
self .L = [ ]
self .R = [ ]
self .Kn = [ [ 0 ] * 48 ] * 16 # 16 48-bit keys (K1 - K16)
self .final = [ ]
self .setKey ( key)
def getKey( self ) :
"""getKey() -> string"""
return self .__key
def setKey( self , key) :
"""Will set the crypting key for this object. Must be 8 bytes."""
self .__key = key
self .__create_sub_keys( )
def getMode( self ) :
"""getMode() -> pyDes.ECB or pyDes.CBC"""
return self .__mode
def setMode( self , mode) :
"""Sets the type of crypting mode, pyDes.ECB or pyDes.CBC"""
self .__mode = mode
def getIV( self ) :
"""getIV() -> string"""
return self .__iv
def setIV( self , IV) :
"""Will set the Initial Value, used in conjunction with CBC mode"""
if not IV or len ( IV) != self .block_size :
raise ValueError ( "Invalid Initial Value (IV), must be a multiple of " + str ( self .block_size ) + " bytes" )
self .__iv = IV
def getPadding( self ) :
"""getPadding() -> string of length 1. Padding character."""
return self .__padding
def __String_to_BitList( self , data) :
"""Turn the string data, into a list of bits (1, 0)'s"""
l = len ( data) * 8
result = [ 0 ] * l
pos = 0
for c in data:
i = 7
ch = ord ( c)
while i >= 0 :
if ch & ( 1 << i) != 0 :
result[ pos] = 1
else :
result[ pos] = 0
pos += 1
i -= 1
return result
def __BitList_to_String( self , data) :
"""Turn the list of bits -> data, into a string"""
result = ''
pos = 0
c = 0
while pos < len ( data) :
c += data[ pos] << ( 7 - ( pos % 8 ) )
if ( pos % 8 ) == 7 :
result += chr ( c)
c = 0
pos += 1
return result
def __permutate( self , table, block) :
"""Permutate this block with the specified table"""
return map ( lambda x: block[ x] , table)
# Transform the secret key, so that it is ready for data processing
# Create the 16 subkeys, K[1] - K[16]
def __create_sub_keys( self ) :
"""Create the 16 subkeys K[1] to K[16] from the given key"""
key = self .__permutate( des.__pc1, self .__String_to_BitList( self .getKey ( ) ) )
i = 0
# Split into Left and Right sections
self .L = key[ :28 ]
self .R = key[ 28 :]
while i < 16 :
j = 0
# Perform circular left shifts
while j < des.__left_rotations[ i] :
self .L .append ( self .L [ 0 ] )
del self .L [ 0 ]
self .R .append ( self .R [ 0 ] )
del self .R [ 0 ]
j += 1
# Create one of the 16 subkeys through pc2 permutation
self .Kn [ i] = self .__permutate( des.__pc2, self .L + self .R )
i += 1
# Main part of the encryption algorithm, the number cruncher :)
def __des_crypt( self , block, crypt_type) :
"""Crypt the block of data through DES bit-manipulation"""
block = self .__permutate( des.__ip, block)
self .L = block[ :32 ]
self .R = block[ 32 :]
# Encryption starts from Kn[1] through to Kn[16]
if crypt_type == des.ENCRYPT :
iteration = 0
iteration_adjustment = 1
# Decryption starts from Kn[16] down to Kn[1]
else :
iteration = 15
iteration_adjustment = -1
i = 0
while i < 16 :
# Make a copy of R[i-1], this will later become L[i]
tempR = self .R [ :]
# Permutate R[i - 1] to start creating R[i]
self .R = self .__permutate( des.__expansion_table, self .R )
# Exclusive or R[i - 1] with K[i], create B[1] to B[8] whilst here
self .R = map ( lambda x, y: x ^ y, self .R , self .Kn [ iteration] )
B = [ self .R [ :6 ] , self .R [ 6 :12 ] , self .R [ 12 :18 ] , self .R [ 18 :24 ] , self .R [ 24 :30 ] , self .R [ 30 :36 ] , self .R [ 36 :42 ] , self .R [ 42 :] ]
# Optimization: Replaced below commented code with above
#j = 0
#B = []
#while j < len(self.R):
# self.R[j] = self.R[j] ^ self.Kn[iteration][j]
# j += 1
# if j % 6 == 0:
# B.append(self.R[j-6:j])
# Permutate B[1] to B[8] using the S-Boxes
j = 0
Bn = [ 0 ] * 32
pos = 0
while j < 8 :
# Work out the offsets
m = ( B[ j] [ 0 ] << 1 ) + B[ j] [ 5 ]
n = ( B[ j] [ 1 ] << 3 ) + ( B[ j] [ 2 ] << 2 ) + ( B[ j] [ 3 ] << 1 ) + B[ j] [ 4 ]
# Find the permutation value
v = des.__sbox[ j] [ ( m << 4 ) + n]
# Turn value into bits, add it to result: Bn
Bn[ pos] = ( v & 8 ) >> 3
Bn[ pos + 1 ] = ( v & 4 ) >> 2
Bn[ pos + 2 ] = ( v & 2 ) >> 1
Bn[ pos + 3 ] = v & 1
pos += 4
j += 1
# Permutate the concatination of B[1] to B[8] (Bn)
self .R = self .__permutate( des.__p, Bn)
# Xor with L[i - 1]
self .R = map ( lambda x, y: x ^ y, self .R , self .L )
# Optimization: This now replaces the below commented code
#j = 0
#while j < len(self.R):
# self.R[j] = self.R[j] ^ self.L[j]
# j += 1
# L[i] becomes R[i - 1]
self .L = tempR
i += 1
iteration += iteration_adjustment
# Final permutation of R[16]L[16]
self .final = self .__permutate( des.__fp, self .R + self .L )
return self .final
# Data to be encrypted/decrypted
def crypt ( self , data, crypt_type) :
"""Crypt the data in blocks, running it through des_crypt()"""
# Error check the data
if not data:
return ''
if len ( data) % self .block_size != 0 :
if crypt_type == des.DECRYPT : # Decryption must work on 8 byte blocks
raise ValueError ( "Invalid data length, data must be a multiple of " + str ( self .block_size ) + " bytes\n ." )
if not self .getPadding ( ) :
raise ValueError ( "Invalid data length, data must be a multiple of " + str ( self .block_size ) + " bytes\n . Try setting the optional padding character" )
else :
data += ( self .block_size - ( len ( data) % self .block_size ) ) * self .getPadding ( )
# print "Len of data: %f" % (len(data) / self.block_size)
if self .getMode ( ) == CBC:
if self .getIV ( ) :
iv = self .__String_to_BitList( self .getIV ( ) )
else :
raise ValueError ( "For CBC mode, you must supply the Initial Value (IV) for ciphering" )
# Split the data into blocks, crypting each one seperately
i = 0
dict = { }
result = [ ]
#cached = 0
#lines = 0
while i < len ( data) :
# Test code for caching encryption results
#lines += 1
#if dict.has_key(data[i:i+8]):
#print "Cached result for: %s" % data[i:i+8]
# cached += 1
# result.append(dict[data[i:i+8]])
# i += 8
# continue
block = self .__String_to_BitList( data[ i:i+8 ] )
# Xor with IV if using CBC mode
if self .getMode ( ) == CBC:
if crypt_type == des.ENCRYPT :
block = map ( lambda x, y: x ^ y, block, iv)
#j = 0
#while j < len(block):
# block[j] = block[j] ^ iv[j]
# j += 1
processed_block = self .__des_crypt( block, crypt_type)
if crypt_type == des.DECRYPT :
processed_block = map ( lambda x, y: x ^ y, processed_block, iv)
#j = 0
#while j < len(processed_block):
# processed_block[j] = processed_block[j] ^ iv[j]
# j += 1
iv = block
else :
iv = processed_block
else :
processed_block = self .__des_crypt( block, crypt_type)
# Add the resulting crypted block to our list
#d = self.__BitList_to_String(processed_block)
#result.append(d)
result.append ( self .__BitList_to_String( processed_block) )
#dict[data[i:i+8]] = d
i += 8
# print "Lines: %d, cached: %d" % (lines, cached)
# Remove the padding from the last block
if crypt_type == des.DECRYPT and self .getPadding ( ) :
#print "Removing decrypt pad"
s = result[ -1 ]
while s[ -1 ] == self .getPadding ( ) :
s = s[ :-1 ]
result[ -1 ] = s
# Return the full crypted string
return '' .join ( result)
def encrypt( self , data, pad= '' ) :
"""encrypt(data, [pad]) -> string
data : String to be encrypted
pad : Optional argument for encryption padding. Must only be one byte
The data must be a multiple of 8 bytes and will be encrypted
with the already specified key. Data does not have to be a
multiple of 8 bytes if the padding character is supplied, the
data will then be padded to a multiple of 8 bytes with this
pad character.
"""
self .__padding = pad
return self .crypt ( data, des.ENCRYPT )
def decrypt( self , data, pad= '' ) :
"""decrypt(data, [pad]) -> string
data : String to be encrypted
pad : Optional argument for decryption padding. Must only be one byte
The data must be a multiple of 8 bytes and will be decrypted
with the already specified key. If the optional padding character
is supplied, then the un-encypted data will have the padding characters
removed from the end of the string. This pad removal only occurs on the
last 8 bytes of the data (last data block).
"""
self .__padding = pad
return self .crypt ( data, des.DECRYPT )
#############################################################################
# Triple DES #
#############################################################################
class triple_des:
"""Triple DES encryption/decrytpion class
This algorithm uses the DES-EDE3 (when a 24 byte key is supplied) or
the DES-EDE2 (when a 16 byte key is supplied) encryption methods.
Supports ECB (Electronic Code Book) and CBC (Cypher Block Chaining) modes.
pyDes.des(key, [mode], [IV])
key -> The encryption key string, must be either 16 or 24 bytes long
mode -> Optional argument for encryption type, can be either pyDes.ECB
(Electronic Code Book), pyDes.CBC (Cypher Block Chaining)
IV -> Optional string argument, must be supplied if using CBC mode.
Must be 8 bytes in length.
"""
def __init__ ( self , key, mode= ECB, IV= None ) :
self .block_size = 8
self .setMode ( mode)
self .__padding = ''
self .__iv = IV
self .setKey ( key)
def getKey( self ) :
"""getKey() -> string"""
return self .__key
def setKey( self , key) :
"""Will set the crypting key for this object. Either 16 or 24 bytes long."""
self .key_size = 24 # Use DES-EDE3 mode
if len ( key) != self .key_size :
if len ( key) == 16 : # Use DES-EDE2 mode
self .key_size = 16
else :
raise ValueError ( "Invalid triple DES key size. Key must be either 16 or 24 bytes long" )
if self .getMode ( ) == CBC and ( not self .getIV ( ) or len ( self .getIV ( ) ) != self .block_size ) :
raise ValueError ( "Invalid IV, must be 8 bytes in length" ) ## TODO: Check this
# modes get handled later, since CBC goes on top of the triple-des
self .__key1 = des( key[ :8 ] )
self .__key2 = des( key[ 8 :16 ] )
if self .key_size == 16 :
self .__key3 = self .__key1
else :
self .__key3 = des( key[ 16 :] )
self .__key = key
def getMode( self ) :
"""getMode() -> pyDes.ECB or pyDes.CBC"""
return self .__mode
def setMode( self , mode) :
"""Sets the type of crypting mode, pyDes.ECB or pyDes.CBC"""
self .__mode = mode
def getIV( self ) :
"""getIV() -> string"""
return self .__iv
def setIV( self , IV) :
"""Will set the Initial Value, used in conjunction with CBC mode"""
self .__iv = IV
def xorstr( self , x, y ) :
"""Returns the bitwise xor of the bytes in two strings"""
if len ( x) != len ( y) :
raise "string lengths differ %d %d" % ( len ( x) , len ( y) )
ret = ''
for i in range ( len ( x) ) :
ret += chr ( ord ( x[ i] ) ^ ord ( y[ i] ) )
return ret
def encrypt( self , data, pad= '' ) :
"""encrypt(data, [pad]) -> string
data : String to be encrypted
pad : Optional argument for encryption padding. Must only be one byte
The data must be a multiple of 8 bytes and will be encrypted
with the already specified key. Data does not have to be a
multiple of 8 bytes if the padding character is supplied, the
data will then be padded to a multiple of 8 bytes with this
pad character.
"""
if self .getMode ( ) == ECB:
# simple
data = self .__key1.encrypt ( data, pad)
data = self .__key2.decrypt ( data)
return self .__key3.encrypt ( data)
if self .getMode ( ) == CBC:
raise "This code hasn't been tested yet"
if len ( data) % self .block_size != 0 :
raise "CBC mode needs datalen to be a multiple of blocksize (ignoring padding for now)"
# simple
lastblock = self .getIV ( )
retdata = ''
for i in range ( 0 , len ( data) , self .block_size ) :
thisblock = data[ i:i+self .block_size ]
# the XOR for CBC
thisblock = self .xorstr ( lastblock, thisblock )
thisblock = self .__key1.encrypt ( thisblock)
thisblock = self .__key2.decrypt ( thisblock)
lastblock = self .__key3.encrypt ( thisblock)
retdata += lastblock
return retdata
raise "Not reached"
def decrypt( self , data, pad= '' ) :
"""decrypt(data, [pad]) -> string
data : String to be encrypted
pad : Optional argument for decryption padding. Must only be one byte
The data must be a multiple of 8 bytes and will be decrypted
with the already specified key. If the optional padding character
is supplied, then the un-encypted data will have the padding characters
removed from the end of the string. This pad removal only occurs on the
last 8 bytes of the data (last data block).
"""
if self .getMode ( ) == ECB:
# simple
data = self .__key3.decrypt ( data)
data = self .__key2.encrypt ( data)
return self .__key1.decrypt ( data, pad)
if self .getMode ( ) == CBC:
if len ( data) % self .block_size != 0 :
raise "Can only decrypt multiples of blocksize"
lastblock = self .getIV ( )
retdata = ''
for i in range ( 0 , len ( data) , self .block_size ) :
# can I arrange this better? probably...
cipherchunk = data[ i:i+self .block_size ]
thisblock = self .__key3.decrypt ( cipherchunk)
thisblock = self .__key2.encrypt ( thisblock)
thisblock = self .__key1.decrypt ( thisblock)
retdata += self .xorstr ( lastblock, thisblock )
lastblock = cipherchunk
return retdata
raise "Not reached"
#############################################################################
# Examples #
#############################################################################
def example_triple_des( ) :
from time import time
# Utility module
from binascii import unhexlify as unhex
# example shows triple-des encryption using the des class
print "Example of triple DES encryption in default ECB mode (DES-EDE3)\n "
print "Triple des using the des class (3 times)"
t = time ( )
k1 = des( unhex( "133457799BBCDFF1" ) )
k2 = des( unhex( "1122334455667788" ) )
k3 = des( unhex( "77661100DD223311" ) )
d = "Triple DES test string, to be encrypted and decrypted..."
print "Key1: %s" % k1.getKey ( )
print "Key2: %s" % k2.getKey ( )
print "Key3: %s" % k3.getKey ( )
print "Data: %s" % d
e1 = k1.encrypt ( d)
e2 = k2.decrypt ( e1)
e3 = k3.encrypt ( e2)
print "Encrypted: " + e3
d3 = k3.decrypt ( e3)
d2 = k2.encrypt ( d3)
d1 = k1.decrypt ( d2)
print "Decrypted: " + d1
print "DES time taken: %f (%d crypt operations)" % ( time ( ) - t, 6 * ( len ( d) / 8 ) )
print ""
# Example below uses the triple-des class to achieve the same as above
print "Now using triple des class"
t = time ( )
t1 = triple_des( unhex( "133457799BBCDFF1112233445566778877661100DD223311" ) )
print "Key: %s" % t1.getKey ( )
print "Data: %s" % d
td1 = t1.encrypt ( d)
print "Encrypted: " + td1
td2 = t1.decrypt ( td1)
print "Decrypted: " + td2
print "Triple DES time taken: %f (%d crypt operations)" % ( time ( ) - t, 6 * ( len ( d) / 8 ) )
def example_des( ) :
from time import time
# example of DES encrypting in CBC mode with the IV of "\0\0\0\0\0\0\0\0"
print "Example of DES encryption using CBC mode\n "
t = time ( )
k = des( "DESCRYPT" , CBC, "\0 \0 \0 \0 \0 \0 \0 \0 " )
data = "DES encryption algorithm"
print "Key : " + k.getKey ( )
print "Data : " + data
d = k.encrypt ( data)
print "Encrypted: " + d
d = k.decrypt ( d)
print "Decrypted: " + d
print "DES time taken: %f (6 crypt operations)" % ( time ( ) - t)
print ""
def __test__( ) :
example_des( )
example_triple_des( )
def __fulltest__( ) :
# This should not produce any unexpected errors or exceptions
from binascii import unhexlify as unhex
from binascii import hexlify as dohex
__test__( )
print ""
k = des( "\0 \0 \0 \0 \0 \0 \0 \0 " , CBC, "\0 \0 \0 \0 \0 \0 \0 \0 " )
d = k.encrypt ( "DES encryption algorithm" )
if k.decrypt ( d) != "DES encryption algorithm" :
print "Test 1 Error: Unencypted data block does not match start data"
k = des( "\0 \0 \0 \0 \0 \0 \0 \0 " , CBC, "\0 \0 \0 \0 \0 \0 \0 \0 " )
d = k.encrypt ( "Default string of text" , '*' )
if k.decrypt ( d, "*" ) != "Default string of text" :
print "Test 2 Error: Unencypted data block does not match start data"
k = des( "\r \n \t ABC\r \n " )
d = k.encrypt ( "String to Pad" , '*' )
if k.decrypt ( d) != "String to Pad***" :
print "'%s'" % k.decrypt ( d)
print "Test 3 Error: Unencypted data block does not match start data"
k = des( "\r \n \t ABC\r \n " )
d = k.encrypt ( unhex( "000102030405060708FF8FDCB04080" ) , unhex( "44" ) )
if k.decrypt ( d, unhex( "44" ) ) != unhex( "000102030405060708FF8FDCB04080" ) :
print "Test 4a Error: Unencypted data block does not match start data"
if k.decrypt ( d) != unhex( "000102030405060708FF8FDCB0408044" ) :
print "Test 4b Error: Unencypted data block does not match start data"
k = triple_des( "MyDesKey\r \n \t ABC\r \n 0987*543" )
d = k.encrypt ( unhex( "000102030405060708FF8FDCB04080000102030405060708FF8FDCB04080000102030405060708FF8FDCB04080000102030405060708FF8FDCB04080000102030405060708FF8FDCB04080000102030405060708FF8FDCB04080000102030405060708FF8FDCB04080000102030405060708FF8FDCB04080" ) )
if k.decrypt ( d) != unhex( "000102030405060708FF8FDCB04080000102030405060708FF8FDCB04080000102030405060708FF8FDCB04080000102030405060708FF8FDCB04080000102030405060708FF8FDCB04080000102030405060708FF8FDCB04080000102030405060708FF8FDCB04080000102030405060708FF8FDCB04080" ) :
print "Test 5 Error: Unencypted data block does not match start data"
k = triple_des( "\r \n \t ABC\r \n 0987*543" )
d = k.encrypt ( unhex( "000102030405060708FF8FDCB04080000102030405060708FF8FDCB04080000102030405060708FF8FDCB04080000102030405060708FF8FDCB04080000102030405060708FF8FDCB04080000102030405060708FF8FDCB04080000102030405060708FF8FDCB04080000102030405060708FF8FDCB04080" ) )
if k.decrypt ( d) != unhex( "000102030405060708FF8FDCB04080000102030405060708FF8FDCB04080000102030405060708FF8FDCB04080000102030405060708FF8FDCB04080000102030405060708FF8FDCB04080000102030405060708FF8FDCB04080000102030405060708FF8FDCB04080000102030405060708FF8FDCB04080" ) :
print "Test 6 Error: Unencypted data block does not match start data"
def __filetest__( ) :
from time import time
f = open ( "pyDes.py" , "rb+" )
d = f.read ( )
f.close ( )
t = time ( )
k = des( "MyDESKey" )
d = k.encrypt ( d, " " )
f = open ( "pyDes.py.enc" , "wb+" )
f.write ( d)
f.close ( )
d = k.decrypt ( d, " " )
f = open ( "pyDes.py.dec" , "wb+" )
f.write ( d)
f.close ( )
print "DES file test time: %f" % ( time ( ) - t)
def __profile__( ) :
import profile
profile .run ( '__fulltest__()' )
#profile.run('__filetest__()')
#if __name__ == '__main__':
__test__( )
#__fulltest__()
#__filetest__()
#__profile__()
IyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKIyAJCQkJRG9jdW1lbnRhdGlvbgkJCQkgICAgIwojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwojIEF1dGhvcjogICBUb2RkIFdoaXRlbWFuCiMgRGF0ZTogICAgIDd0aCBNYXksIDIwMDMKIyBWZXJpb246ICAgMS4xCiMgSG9tZXBhZ2U6IGh0dHA6Ly9oLi4uY29udGVudC1hdmFpbGFibGUtdG8tYXV0aG9yLW9ubHkuLi50LmF1L350d2hpdGVtYS9kZXMuaHRtbAojCiMgTW9kaWZpY2F0aW9ucyB0byAzZGVzIENCQyBjb2RlIGJ5IE1hdHQgSm9obnN0b24gMjAwNCA8bWF0dCBhdCB1Y2MgYXNuIGF1PgojCiMgVGhpcyBhbGdvcml0aG0gaXMgYSBwdXJlIHB5dGhvbiBpbXBsZW1lbnRhdGlvbiBvZiB0aGUgREVTIGFsZ29yaXRobS4KIyBJdCBpcyBpbiBwdXJlIHB5dGhvbiB0byBhdm9pZCBwb3J0YWJpbGl0eSBpc3N1ZXMsIHNpbmNlIG1vc3QgREVTIAojIGltcGxlbWVudGF0aW9ucyBhcmUgcHJvZ3JhbW1lZCBpbiBDIChmb3IgcGVyZm9ybWFuY2UgcmVhc29ucykuCiMKIyBUcmlwbGUgREVTIGNsYXNzIGlzIGFsc28gaW1wbGVtZW50ZWQsIHV0aWxpc2luZyB0aGUgREVTIGJhc2UuIFRyaXBsZSBERVMKIyBpcyBlaXRoZXIgREVTLUVERTMgd2l0aCBhIDI0IGJ5dGUga2V5LCBvciBERVMtRURFMiB3aXRoIGEgMTYgYnl0ZSBrZXkuCiMKIyBTZWUgdGhlIFJFQURNRS50eHQgdGhhdCBzaG91bGQgY29tZSB3aXRoIHRoaXMgcHl0aG9uIG1vZHVsZSBmb3IgdGhlCiMgaW1wbGVtZW50YXRpb24gbWV0aG9kcyB1c2VkLgoiIiJBIHB1cmUgcHl0aG9uIGltcGxlbWVudGF0aW9uIG9mIHRoZSBERVMgYW5kIFRSSVBMRSBERVMgZW5jcnlwdGlvbiBhbGdvcml0aG1zCnB5RGVzLmRlcyhrZXksIFttb2RlXSwgW0lWXSkKcHlEZXMudHJpcGxlX2RlcyhrZXksIFttb2RlXSwgW0lWXSkKa2V5ICAtPiBTdHJpbmcgY29udGFpbmluZyB0aGUgZW5jcnlwdGlvbiBrZXkuIDggYnl0ZXMgZm9yIERFUywgMTYgb3IgMjQgYnl0ZXMKCWZvciBUcmlwbGUgREVTCm1vZGUgLT4gT3B0aW9uYWwgYXJndW1lbnQgZm9yIGVuY3J5cHRpb24gdHlwZSwgY2FuIGJlIGVpdGhlcgogICAgICAgIHB5RGVzLkVDQiAoRWxlY3Ryb25pYyBDb2RlIEJvb2spIG9yIHB5RGVzLkNCQyAoQ3lwaGVyIEJsb2NrIENoYWluaW5nKQpJViAgIC0+IE9wdGlvbmFsIGFyZ3VtZW50LCBtdXN0IGJlIHN1cHBsaWVkIGlmIHVzaW5nIENCQyBtb2RlLiBNdXN0IGJlIDggYnl0ZXMKRXhhbXBsZToKZnJvbSBweURlcyBpbXBvcnQgKgpkYXRhID0gIlBsZWFzZSBlbmNyeXB0IG15IHN0cmluZyIKayA9IGRlcygiREVTQ1JZUFQiLCAiICIsIENCQywgIlwwXDBcMFwwXDBcMFwwXDAiKQpkID0gay5lbmNyeXB0KGRhdGEpCnByaW50ICJFbmN5cHRlZCBzdHJpbmc6ICIgKyBkCnByaW50ICJEZWN5cHRlZCBzdHJpbmc6ICIgKyBrLmRlY3J5cHQoZCkKU2VlIHRoZSBtb2R1bGUgc291cmNlIChweURlcy5weSkgZm9yIG1vcmUgZXhhbXBsZXMgb2YgdXNlLgpZb3UgY2FuIHNsbyBydW4gdGhlIHB5RGVzLnB5IGZpbGUgd2l0aG91dCBhbmQgYXJndW1lbnRzIHRvIHNlZSBhIHNpbXBsZSB0ZXN0LgpOb3RlOiBUaGlzIGNvZGUgd2FzIG5vdCB3cml0dGVuIGZvciBoaWdoLWVuZCBzeXN0ZW1zIG5lZWRpbmcgYSBmYXN0CiAgICAgIGltcGxlbWVudGF0aW9uLCBidXQgcmF0aGVyIGEgaGFuZHkgcG9ydGFibGUgc29sdXRpb24gd2l0aCBzbWFsbCB1c2FnZS4KIiIiCiMgTW9kZXMgb2YgY3J5cHRpbmcgLyBjeXBoZXJpbmcKRUNCID0JMApDQkMgPQkxCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiMgCQkJCSAgICBERVMJCQkJCSAgICAjCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCmNsYXNzIGRlczoKCSIiIkRFUyBlbmNyeXB0aW9uL2RlY3J5dHBpb24gY2xhc3MKCVN1cHBvcnRzIEVDQiAoRWxlY3Ryb25pYyBDb2RlIEJvb2spIGFuZCBDQkMgKEN5cGhlciBCbG9jayBDaGFpbmluZykgbW9kZXMuCglweURlcy5kZXMoa2V5LFttb2RlXSwgW0lWXSkKCWtleSAgLT4gVGhlIGVuY3J5cHRpb24ga2V5IHN0cmluZywgbXVzdCBiZSBleGFjdGx5IDggYnl0ZXMKCW1vZGUgLT4gT3B0aW9uYWwgYXJndW1lbnQgZm9yIGVuY3J5cHRpb24gdHlwZSwgY2FuIGJlIGVpdGhlciBweURlcy5FQ0IKCQkoRWxlY3Ryb25pYyBDb2RlIEJvb2spLCBweURlcy5DQkMgKEN5cGhlciBCbG9jayBDaGFpbmluZykKCUlWICAgLT4gT3B0aW9uYWwgc3RyaW5nIGFyZ3VtZW50LCBtdXN0IGJlIHN1cHBsaWVkIGlmIHVzaW5nIENCQyBtb2RlLgoJCU11c3QgYmUgOCBieXRlcyBpbiBsZW5ndGguCgkiIiIKCSMgUGVybXV0YXRpb24gYW5kIHRyYW5zbGF0aW9uIHRhYmxlcyBmb3IgREVTCglfX3BjMSA9IFs1NiwgNDgsIDQwLCAzMiwgMjQsIDE2LCAgOCwKCQkgIDAsIDU3LCA0OSwgNDEsIDMzLCAyNSwgMTcsCgkJICA5LCAgMSwgNTgsIDUwLCA0MiwgMzQsIDI2LAoJCSAxOCwgMTAsICAyLCA1OSwgNTEsIDQzLCAzNSwKCQkgNjIsIDU0LCA0NiwgMzgsIDMwLCAyMiwgMTQsCgkJICA2LCA2MSwgNTMsIDQ1LCAzNywgMjksIDIxLAoJCSAxMywgIDUsIDYwLCA1MiwgNDQsIDM2LCAyOCwKCQkgMjAsIDEyLCAgNCwgMjcsIDE5LCAxMSwgIDMKCV0KCSMgbnVtYmVyIGxlZnQgcm90YXRpb25zIG9mIHBjMQoJX19sZWZ0X3JvdGF0aW9ucyA9IFsKCQkxLCAxLCAyLCAyLCAyLCAyLCAyLCAyLCAxLCAyLCAyLCAyLCAyLCAyLCAyLCAxCgldCgkjIHBlcm11dGVkIGNob2ljZSBrZXkgKHRhYmxlIDIpCglfX3BjMiA9IFsKCQkxMywgMTYsIDEwLCAyMywgIDAsICA0LAoJCSAyLCAyNywgMTQsICA1LCAyMCwgIDksCgkJMjIsIDE4LCAxMSwgIDMsIDI1LCAgNywKCQkxNSwgIDYsIDI2LCAxOSwgMTIsICAxLAoJCTQwLCA1MSwgMzAsIDM2LCA0NiwgNTQsCgkJMjksIDM5LCA1MCwgNDQsIDMyLCA0NywKCQk0MywgNDgsIDM4LCA1NSwgMzMsIDUyLAoJCTQ1LCA0MSwgNDksIDM1LCAyOCwgMzEKCV0KCSMgaW5pdGlhbCBwZXJtdXRhdGlvbiBJUAoJX19pcCA9IFs1NywgNDksIDQxLCAzMywgMjUsIDE3LCA5LCAgMSwKCQk1OSwgNTEsIDQzLCAzNSwgMjcsIDE5LCAxMSwgMywKCQk2MSwgNTMsIDQ1LCAzNywgMjksIDIxLCAxMywgNSwKCQk2MywgNTUsIDQ3LCAzOSwgMzEsIDIzLCAxNSwgNywKCQk1NiwgNDgsIDQwLCAzMiwgMjQsIDE2LCA4LCAgMCwKCQk1OCwgNTAsIDQyLCAzNCwgMjYsIDE4LCAxMCwgMiwKCQk2MCwgNTIsIDQ0LCAzNiwgMjgsIDIwLCAxMiwgNCwKCQk2MiwgNTQsIDQ2LCAzOCwgMzAsIDIyLCAxNCwgNgoJXQoJIyBFeHBhbnNpb24gdGFibGUgZm9yIHR1cm5pbmcgMzIgYml0IGJsb2NrcyBpbnRvIDQ4IGJpdHMKCV9fZXhwYW5zaW9uX3RhYmxlID0gWwoJCTMxLCAgMCwgIDEsICAyLCAgMywgIDQsCgkJIDMsICA0LCAgNSwgIDYsICA3LCAgOCwKCQkgNywgIDgsICA5LCAxMCwgMTEsIDEyLAoJCTExLCAxMiwgMTMsIDE0LCAxNSwgMTYsCgkJMTUsIDE2LCAxNywgMTgsIDE5LCAyMCwKCQkxOSwgMjAsIDIxLCAyMiwgMjMsIDI0LAoJCTIzLCAyNCwgMjUsIDI2LCAyNywgMjgsCgkJMjcsIDI4LCAyOSwgMzAsIDMxLCAgMAoJXQoJIyBUaGUgKGluKWZhbW91cyBTLWJveGVzCglfX3Nib3ggPSBbCgkJIyBTMQoJCVsxNCwgNCwgMTMsIDEsIDIsIDE1LCAxMSwgOCwgMywgMTAsIDYsIDEyLCA1LCA5LCAwLCA3LAoJCSAwLCAxNSwgNywgNCwgMTQsIDIsIDEzLCAxLCAxMCwgNiwgMTIsIDExLCA5LCA1LCAzLCA4LAoJCSA0LCAxLCAxNCwgOCwgMTMsIDYsIDIsIDExLCAxNSwgMTIsIDksIDcsIDMsIDEwLCA1LCAwLAoJCSAxNSwgMTIsIDgsIDIsIDQsIDksIDEsIDcsIDUsIDExLCAzLCAxNCwgMTAsIDAsIDYsIDEzXSwKCQkjIFMyCgkJWzE1LCAxLCA4LCAxNCwgNiwgMTEsIDMsIDQsIDksIDcsIDIsIDEzLCAxMiwgMCwgNSwgMTAsCgkJIDMsIDEzLCA0LCA3LCAxNSwgMiwgOCwgMTQsIDEyLCAwLCAxLCAxMCwgNiwgOSwgMTEsIDUsCgkJIDAsIDE0LCA3LCAxMSwgMTAsIDQsIDEzLCAxLCA1LCA4LCAxMiwgNiwgOSwgMywgMiwgMTUsCgkJIDEzLCA4LCAxMCwgMSwgMywgMTUsIDQsIDIsIDExLCA2LCA3LCAxMiwgMCwgNSwgMTQsIDldLAoJCSMgUzMKCQlbMTAsIDAsIDksIDE0LCA2LCAzLCAxNSwgNSwgMSwgMTMsIDEyLCA3LCAxMSwgNCwgMiwgOCwKCQkgMTMsIDcsIDAsIDksIDMsIDQsIDYsIDEwLCAyLCA4LCA1LCAxNCwgMTIsIDExLCAxNSwgMSwKCQkgMTMsIDYsIDQsIDksIDgsIDE1LCAzLCAwLCAxMSwgMSwgMiwgMTIsIDUsIDEwLCAxNCwgNywKCQkgMSwgMTAsIDEzLCAwLCA2LCA5LCA4LCA3LCA0LCAxNSwgMTQsIDMsIDExLCA1LCAyLCAxMl0sCgkJIyBTNAoJCVs3LCAxMywgMTQsIDMsIDAsIDYsIDksIDEwLCAxLCAyLCA4LCA1LCAxMSwgMTIsIDQsIDE1LAoJCSAxMywgOCwgMTEsIDUsIDYsIDE1LCAwLCAzLCA0LCA3LCAyLCAxMiwgMSwgMTAsIDE0LCA5LAoJCSAxMCwgNiwgOSwgMCwgMTIsIDExLCA3LCAxMywgMTUsIDEsIDMsIDE0LCA1LCAyLCA4LCA0LAoJCSAzLCAxNSwgMCwgNiwgMTAsIDEsIDEzLCA4LCA5LCA0LCA1LCAxMSwgMTIsIDcsIDIsIDE0XSwKCQkjIFM1CgkJWzIsIDEyLCA0LCAxLCA3LCAxMCwgMTEsIDYsIDgsIDUsIDMsIDE1LCAxMywgMCwgMTQsIDksCgkJIDE0LCAxMSwgMiwgMTIsIDQsIDcsIDEzLCAxLCA1LCAwLCAxNSwgMTAsIDMsIDksIDgsIDYsCgkJIDQsIDIsIDEsIDExLCAxMCwgMTMsIDcsIDgsIDE1LCA5LCAxMiwgNSwgNiwgMywgMCwgMTQsCgkJIDExLCA4LCAxMiwgNywgMSwgMTQsIDIsIDEzLCA2LCAxNSwgMCwgOSwgMTAsIDQsIDUsIDNdLAoJCSMgUzYKCQlbMTIsIDEsIDEwLCAxNSwgOSwgMiwgNiwgOCwgMCwgMTMsIDMsIDQsIDE0LCA3LCA1LCAxMSwKCQkgMTAsIDE1LCA0LCAyLCA3LCAxMiwgOSwgNSwgNiwgMSwgMTMsIDE0LCAwLCAxMSwgMywgOCwKCQkgOSwgMTQsIDE1LCA1LCAyLCA4LCAxMiwgMywgNywgMCwgNCwgMTAsIDEsIDEzLCAxMSwgNiwKCQkgNCwgMywgMiwgMTIsIDksIDUsIDE1LCAxMCwgMTEsIDE0LCAxLCA3LCA2LCAwLCA4LCAxM10sCgkJIyBTNwoJCVs0LCAxMSwgMiwgMTQsIDE1LCAwLCA4LCAxMywgMywgMTIsIDksIDcsIDUsIDEwLCA2LCAxLAoJCSAxMywgMCwgMTEsIDcsIDQsIDksIDEsIDEwLCAxNCwgMywgNSwgMTIsIDIsIDE1LCA4LCA2LAoJCSAxLCA0LCAxMSwgMTMsIDEyLCAzLCA3LCAxNCwgMTAsIDE1LCA2LCA4LCAwLCA1LCA5LCAyLAoJCSA2LCAxMSwgMTMsIDgsIDEsIDQsIDEwLCA3LCA5LCA1LCAwLCAxNSwgMTQsIDIsIDMsIDEyXSwKCQkjIFM4CgkJWzEzLCAyLCA4LCA0LCA2LCAxNSwgMTEsIDEsIDEwLCA5LCAzLCAxNCwgNSwgMCwgMTIsIDcsCgkJIDEsIDE1LCAxMywgOCwgMTAsIDMsIDcsIDQsIDEyLCA1LCA2LCAxMSwgMCwgMTQsIDksIDIsCgkJIDcsIDExLCA0LCAxLCA5LCAxMiwgMTQsIDIsIDAsIDYsIDEwLCAxMywgMTUsIDMsIDUsIDgsCgkJIDIsIDEsIDE0LCA3LCA0LCAxMCwgOCwgMTMsIDE1LCAxMiwgOSwgMCwgMywgNSwgNiwgMTFdLAoJXQoJIyAzMi1iaXQgcGVybXV0YXRpb24gZnVuY3Rpb24gUCB1c2VkIG9uIHRoZSBvdXRwdXQgb2YgdGhlIFMtYm94ZXMKCV9fcCA9IFsKCQkxNSwgNiwgMTksIDIwLCAyOCwgMTEsCgkJMjcsIDE2LCAwLCAxNCwgMjIsIDI1LAoJCTQsIDE3LCAzMCwgOSwgMSwgNywKCQkyMywxMywgMzEsIDI2LCAyLCA4LAoJCTE4LCAxMiwgMjksIDUsIDIxLCAxMCwKCQkzLCAyNAoJXQoJIyBmaW5hbCBwZXJtdXRhdGlvbiBJUF4tMQoJX19mcCA9IFsKCQkzOSwgIDcsIDQ3LCAxNSwgNTUsIDIzLCA2MywgMzEsCgkJMzgsICA2LCA0NiwgMTQsIDU0LCAyMiwgNjIsIDMwLAoJCTM3LCAgNSwgNDUsIDEzLCA1MywgMjEsIDYxLCAyOSwKCQkzNiwgIDQsIDQ0LCAxMiwgNTIsIDIwLCA2MCwgMjgsCgkJMzUsICAzLCA0MywgMTEsIDUxLCAxOSwgNTksIDI3LAoJCTM0LCAgMiwgNDIsIDEwLCA1MCwgMTgsIDU4LCAyNiwKCQkzMywgIDEsIDQxLCAgOSwgNDksIDE3LCA1NywgMjUsCgkJMzIsICAwLCA0MCwgIDgsIDQ4LCAxNiwgNTYsIDI0CgldCgkjIFR5cGUgb2YgY3J5cHRpbmcgYmVpbmcgZG9uZQoJRU5DUllQVCA9CTB4MDAKCURFQ1JZUFQgPQkweDAxCgkjIEluaXRpYWxpc2F0aW9uCglkZWYgX19pbml0X18oc2VsZiwga2V5LCBtb2RlPUVDQiwgSVY9Tm9uZSk6CgkJaWYgbGVuKGtleSkgIT0gODoKCQkJcmFpc2UgVmFsdWVFcnJvcigiSW52YWxpZCBERVMga2V5IHNpemUuIEtleSBtdXN0IGJlIGV4YWN0bHkgOCBieXRlcyBsb25nLiIpCgkJc2VsZi5ibG9ja19zaXplID0gOAoJCXNlbGYua2V5X3NpemUgPSA4CgkJc2VsZi5fX3BhZGRpbmcgPSAnJwoJCSMgU2V0IHRoZSBwYXNzZWQgaW4gdmFyaWFibGVzCgkJc2VsZi5zZXRNb2RlKG1vZGUpCgkJaWYgSVY6CgkJCXNlbGYuc2V0SVYoSVYpCgkJc2VsZi5MID0gW10KCQlzZWxmLlIgPSBbXQoJCXNlbGYuS24gPSBbIFswXSAqIDQ4IF0gKiAxNgkjIDE2IDQ4LWJpdCBrZXlzIChLMSAtIEsxNikKCQlzZWxmLmZpbmFsID0gW10KCQlzZWxmLnNldEtleShrZXkpCglkZWYgZ2V0S2V5KHNlbGYpOgoJCSIiImdldEtleSgpIC0+IHN0cmluZyIiIgoJCXJldHVybiBzZWxmLl9fa2V5CglkZWYgc2V0S2V5KHNlbGYsIGtleSk6CgkJIiIiV2lsbCBzZXQgdGhlIGNyeXB0aW5nIGtleSBmb3IgdGhpcyBvYmplY3QuIE11c3QgYmUgOCBieXRlcy4iIiIKCQlzZWxmLl9fa2V5ID0ga2V5CgkJc2VsZi5fX2NyZWF0ZV9zdWJfa2V5cygpCglkZWYgZ2V0TW9kZShzZWxmKToKCQkiIiJnZXRNb2RlKCkgLT4gcHlEZXMuRUNCIG9yIHB5RGVzLkNCQyIiIgoJCXJldHVybiBzZWxmLl9fbW9kZQoJZGVmIHNldE1vZGUoc2VsZiwgbW9kZSk6CgkJIiIiU2V0cyB0aGUgdHlwZSBvZiBjcnlwdGluZyBtb2RlLCBweURlcy5FQ0Igb3IgcHlEZXMuQ0JDIiIiCgkJc2VsZi5fX21vZGUgPSBtb2RlCglkZWYgZ2V0SVYoc2VsZik6CgkJIiIiZ2V0SVYoKSAtPiBzdHJpbmciIiIKCQlyZXR1cm4gc2VsZi5fX2l2CglkZWYgc2V0SVYoc2VsZiwgSVYpOgoJCSIiIldpbGwgc2V0IHRoZSBJbml0aWFsIFZhbHVlLCB1c2VkIGluIGNvbmp1bmN0aW9uIHdpdGggQ0JDIG1vZGUiIiIKCQlpZiBub3QgSVYgb3IgbGVuKElWKSAhPSBzZWxmLmJsb2NrX3NpemU6CgkJCXJhaXNlIFZhbHVlRXJyb3IoIkludmFsaWQgSW5pdGlhbCBWYWx1ZSAoSVYpLCBtdXN0IGJlIGEgbXVsdGlwbGUgb2YgIiArIHN0cihzZWxmLmJsb2NrX3NpemUpICsgIiBieXRlcyIpCgkJc2VsZi5fX2l2ID0gSVYKCWRlZiBnZXRQYWRkaW5nKHNlbGYpOgoJCSIiImdldFBhZGRpbmcoKSAtPiBzdHJpbmcgb2YgbGVuZ3RoIDEuIFBhZGRpbmcgY2hhcmFjdGVyLiIiIgoJCXJldHVybiBzZWxmLl9fcGFkZGluZwoJZGVmIF9fU3RyaW5nX3RvX0JpdExpc3Qoc2VsZiwgZGF0YSk6CgkJIiIiVHVybiB0aGUgc3RyaW5nIGRhdGEsIGludG8gYSBsaXN0IG9mIGJpdHMgKDEsIDApJ3MiIiIKCQlsID0gbGVuKGRhdGEpICogOAoJCXJlc3VsdCA9IFswXSAqIGwKCQlwb3MgPSAwCgkJZm9yIGMgaW4gZGF0YToKCQkJaSA9IDcKCQkJY2ggPSBvcmQoYykKCQkJd2hpbGUgaSA+PSAwOgoJCQkJaWYgY2ggJiAoMSA8PCBpKSAhPSAwOgoJCQkJCXJlc3VsdFtwb3NdID0gMQoJCQkJZWxzZToKCQkJCQlyZXN1bHRbcG9zXSA9IDAKCQkJCXBvcyArPSAxCgkJCQlpIC09IDEKCQlyZXR1cm4gcmVzdWx0CglkZWYgX19CaXRMaXN0X3RvX1N0cmluZyhzZWxmLCBkYXRhKToKCQkiIiJUdXJuIHRoZSBsaXN0IG9mIGJpdHMgLT4gZGF0YSwgaW50byBhIHN0cmluZyIiIgoJCXJlc3VsdCA9ICcnCgkJcG9zID0gMAoJCWMgPSAwCgkJd2hpbGUgcG9zIDwgbGVuKGRhdGEpOgoJCQljICs9IGRhdGFbcG9zXSA8PCAoNyAtIChwb3MgJSA4KSkKCQkJaWYgKHBvcyAlIDgpID09IDc6CgkJCQlyZXN1bHQgKz0gY2hyKGMpCgkJCQljID0gMAoJCQlwb3MgKz0gMQoJCXJldHVybiByZXN1bHQKCWRlZiBfX3Blcm11dGF0ZShzZWxmLCB0YWJsZSwgYmxvY2spOgoJCSIiIlBlcm11dGF0ZSB0aGlzIGJsb2NrIHdpdGggdGhlIHNwZWNpZmllZCB0YWJsZSIiIgoJCXJldHVybiBtYXAobGFtYmRhIHg6IGJsb2NrW3hdLCB0YWJsZSkKCQkJIyBUcmFuc2Zvcm0gdGhlIHNlY3JldCBrZXksIHNvIHRoYXQgaXQgaXMgcmVhZHkgZm9yIGRhdGEgcHJvY2Vzc2luZwoJIyBDcmVhdGUgdGhlIDE2IHN1YmtleXMsIEtbMV0gLSBLWzE2XQoJZGVmIF9fY3JlYXRlX3N1Yl9rZXlzKHNlbGYpOgoJCSIiIkNyZWF0ZSB0aGUgMTYgc3Via2V5cyBLWzFdIHRvIEtbMTZdIGZyb20gdGhlIGdpdmVuIGtleSIiIgoJCWtleSA9IHNlbGYuX19wZXJtdXRhdGUoZGVzLl9fcGMxLCBzZWxmLl9fU3RyaW5nX3RvX0JpdExpc3Qoc2VsZi5nZXRLZXkoKSkpCgkJaSA9IDAKCQkjIFNwbGl0IGludG8gTGVmdCBhbmQgUmlnaHQgc2VjdGlvbnMKCQlzZWxmLkwgPSBrZXlbOjI4XQoJCXNlbGYuUiA9IGtleVsyODpdCgkJd2hpbGUgaSA8IDE2OgoJCQlqID0gMAoJCQkjIFBlcmZvcm0gY2lyY3VsYXIgbGVmdCBzaGlmdHMKCQkJd2hpbGUgaiA8IGRlcy5fX2xlZnRfcm90YXRpb25zW2ldOgoJCQkJc2VsZi5MLmFwcGVuZChzZWxmLkxbMF0pCgkJCQlkZWwgc2VsZi5MWzBdCgkJCQlzZWxmLlIuYXBwZW5kKHNlbGYuUlswXSkKCQkJCWRlbCBzZWxmLlJbMF0KCQkJCWogKz0gMQoJCQkjIENyZWF0ZSBvbmUgb2YgdGhlIDE2IHN1YmtleXMgdGhyb3VnaCBwYzIgcGVybXV0YXRpb24KCQkJc2VsZi5LbltpXSA9IHNlbGYuX19wZXJtdXRhdGUoZGVzLl9fcGMyLCBzZWxmLkwgKyBzZWxmLlIpCgkJCWkgKz0gMQoJIyBNYWluIHBhcnQgb2YgdGhlIGVuY3J5cHRpb24gYWxnb3JpdGhtLCB0aGUgbnVtYmVyIGNydW5jaGVyIDopCglkZWYgX19kZXNfY3J5cHQoc2VsZiwgYmxvY2ssIGNyeXB0X3R5cGUpOgoJCSIiIkNyeXB0IHRoZSBibG9jayBvZiBkYXRhIHRocm91Z2ggREVTIGJpdC1tYW5pcHVsYXRpb24iIiIKCQlibG9jayA9IHNlbGYuX19wZXJtdXRhdGUoZGVzLl9faXAsIGJsb2NrKQoJCXNlbGYuTCA9IGJsb2NrWzozMl0KCQlzZWxmLlIgPSBibG9ja1szMjpdCgkJIyBFbmNyeXB0aW9uIHN0YXJ0cyBmcm9tIEtuWzFdIHRocm91Z2ggdG8gS25bMTZdCgkJaWYgY3J5cHRfdHlwZSA9PSBkZXMuRU5DUllQVDoKCQkJaXRlcmF0aW9uID0gMAoJCQlpdGVyYXRpb25fYWRqdXN0bWVudCA9IDEKCQkjIERlY3J5cHRpb24gc3RhcnRzIGZyb20gS25bMTZdIGRvd24gdG8gS25bMV0KCQllbHNlOgoJCQlpdGVyYXRpb24gPSAxNQoJCQlpdGVyYXRpb25fYWRqdXN0bWVudCA9IC0xCgkJaSA9IDAKCQl3aGlsZSBpIDwgMTY6CgkJCSMgTWFrZSBhIGNvcHkgb2YgUltpLTFdLCB0aGlzIHdpbGwgbGF0ZXIgYmVjb21lIExbaV0KCQkJdGVtcFIgPSBzZWxmLlJbOl0KCQkJIyBQZXJtdXRhdGUgUltpIC0gMV0gdG8gc3RhcnQgY3JlYXRpbmcgUltpXQoJCQlzZWxmLlIgPSBzZWxmLl9fcGVybXV0YXRlKGRlcy5fX2V4cGFuc2lvbl90YWJsZSwgc2VsZi5SKQoJCQkjIEV4Y2x1c2l2ZSBvciBSW2kgLSAxXSB3aXRoIEtbaV0sIGNyZWF0ZSBCWzFdIHRvIEJbOF0gd2hpbHN0IGhlcmUKCQkJc2VsZi5SID0gbWFwKGxhbWJkYSB4LCB5OiB4IF4geSwgc2VsZi5SLCBzZWxmLktuW2l0ZXJhdGlvbl0pCgkJCUIgPSBbc2VsZi5SWzo2XSwgc2VsZi5SWzY6MTJdLCBzZWxmLlJbMTI6MThdLCBzZWxmLlJbMTg6MjRdLCBzZWxmLlJbMjQ6MzBdLCBzZWxmLlJbMzA6MzZdLCBzZWxmLlJbMzY6NDJdLCBzZWxmLlJbNDI6XV0KCQkJIyBPcHRpbWl6YXRpb246IFJlcGxhY2VkIGJlbG93IGNvbW1lbnRlZCBjb2RlIHdpdGggYWJvdmUKCQkJI2ogPSAwCgkJCSNCID0gW10KCQkJI3doaWxlIGogPCBsZW4oc2VsZi5SKToKCQkJIwlzZWxmLlJbal0gPSBzZWxmLlJbal0gXiBzZWxmLktuW2l0ZXJhdGlvbl1bal0KCQkJIwlqICs9IDEKCQkJIwlpZiBqICUgNiA9PSAwOgoJCQkjCQlCLmFwcGVuZChzZWxmLlJbai02OmpdKQoJCQkjIFBlcm11dGF0ZSBCWzFdIHRvIEJbOF0gdXNpbmcgdGhlIFMtQm94ZXMKCQkJaiA9IDAKCQkJQm4gPSBbMF0gKiAzMgoJCQlwb3MgPSAwCgkJCXdoaWxlIGogPCA4OgoJCQkJIyBXb3JrIG91dCB0aGUgb2Zmc2V0cwoJCQkJbSA9IChCW2pdWzBdIDw8IDEpICsgQltqXVs1XQoJCQkJbiA9IChCW2pdWzFdIDw8IDMpICsgKEJbal1bMl0gPDwgMikgKyAoQltqXVszXSA8PCAxKSArIEJbal1bNF0KCQkJCSMgRmluZCB0aGUgcGVybXV0YXRpb24gdmFsdWUKCQkJCXYgPSBkZXMuX19zYm94W2pdWyhtIDw8IDQpICsgbl0KCQkJCSMgVHVybiB2YWx1ZSBpbnRvIGJpdHMsIGFkZCBpdCB0byByZXN1bHQ6IEJuCgkJCQlCbltwb3NdID0gKHYgJiA4KSA+PiAzCgkJCQlCbltwb3MgKyAxXSA9ICh2ICYgNCkgPj4gMgoJCQkJQm5bcG9zICsgMl0gPSAodiAmIDIpID4+IDEKCQkJCUJuW3BvcyArIDNdID0gdiAmIDEKCQkJCXBvcyArPSA0CgkJCQlqICs9IDEKCQkJIyBQZXJtdXRhdGUgdGhlIGNvbmNhdGluYXRpb24gb2YgQlsxXSB0byBCWzhdIChCbikKCQkJc2VsZi5SID0gc2VsZi5fX3Blcm11dGF0ZShkZXMuX19wLCBCbikKCQkJIyBYb3Igd2l0aCBMW2kgLSAxXQoJCQlzZWxmLlIgPSBtYXAobGFtYmRhIHgsIHk6IHggXiB5LCBzZWxmLlIsIHNlbGYuTCkKCQkJIyBPcHRpbWl6YXRpb246IFRoaXMgbm93IHJlcGxhY2VzIHRoZSBiZWxvdyBjb21tZW50ZWQgY29kZQoJCQkjaiA9IDAKCQkJI3doaWxlIGogPCBsZW4oc2VsZi5SKToKCQkJIwlzZWxmLlJbal0gPSBzZWxmLlJbal0gXiBzZWxmLkxbal0KCQkJIwlqICs9IDEKCQkJIyBMW2ldIGJlY29tZXMgUltpIC0gMV0KCQkJc2VsZi5MID0gdGVtcFIKCQkJaSArPSAxCgkJCWl0ZXJhdGlvbiArPSBpdGVyYXRpb25fYWRqdXN0bWVudAoJCQkjIEZpbmFsIHBlcm11dGF0aW9uIG9mIFJbMTZdTFsxNl0KCQlzZWxmLmZpbmFsID0gc2VsZi5fX3Blcm11dGF0ZShkZXMuX19mcCwgc2VsZi5SICsgc2VsZi5MKQoJCXJldHVybiBzZWxmLmZpbmFsCgkjIERhdGEgdG8gYmUgZW5jcnlwdGVkL2RlY3J5cHRlZAoJZGVmIGNyeXB0KHNlbGYsIGRhdGEsIGNyeXB0X3R5cGUpOgoJCSIiIkNyeXB0IHRoZSBkYXRhIGluIGJsb2NrcywgcnVubmluZyBpdCB0aHJvdWdoIGRlc19jcnlwdCgpIiIiCgkJIyBFcnJvciBjaGVjayB0aGUgZGF0YQoJCWlmIG5vdCBkYXRhOgoJCQlyZXR1cm4gJycKCQlpZiBsZW4oZGF0YSkgJSBzZWxmLmJsb2NrX3NpemUgIT0gMDoKCQkJaWYgY3J5cHRfdHlwZSA9PSBkZXMuREVDUllQVDogIyBEZWNyeXB0aW9uIG11c3Qgd29yayBvbiA4IGJ5dGUgYmxvY2tzCgkJCQlyYWlzZSBWYWx1ZUVycm9yKCJJbnZhbGlkIGRhdGEgbGVuZ3RoLCBkYXRhIG11c3QgYmUgYSBtdWx0aXBsZSBvZiAiICsgc3RyKHNlbGYuYmxvY2tfc2l6ZSkgKyAiIGJ5dGVzXG4uIikKCQkJaWYgbm90IHNlbGYuZ2V0UGFkZGluZygpOgoJCQkJcmFpc2UgVmFsdWVFcnJvcigiSW52YWxpZCBkYXRhIGxlbmd0aCwgZGF0YSBtdXN0IGJlIGEgbXVsdGlwbGUgb2YgIiArIHN0cihzZWxmLmJsb2NrX3NpemUpICsgIiBieXRlc1xuLiBUcnkgc2V0dGluZyB0aGUgb3B0aW9uYWwgcGFkZGluZyBjaGFyYWN0ZXIiKQoJCQllbHNlOgoJCQkJZGF0YSArPSAoc2VsZi5ibG9ja19zaXplIC0gKGxlbihkYXRhKSAlIHNlbGYuYmxvY2tfc2l6ZSkpICogc2VsZi5nZXRQYWRkaW5nKCkKCQkJIyBwcmludCAiTGVuIG9mIGRhdGE6ICVmIiAlIChsZW4oZGF0YSkgLyBzZWxmLmJsb2NrX3NpemUpCgkJaWYgc2VsZi5nZXRNb2RlKCkgPT0gQ0JDOgoJCQlpZiBzZWxmLmdldElWKCk6CgkJCQlpdiA9IHNlbGYuX19TdHJpbmdfdG9fQml0TGlzdChzZWxmLmdldElWKCkpCgkJCWVsc2U6CgkJCQlyYWlzZSBWYWx1ZUVycm9yKCJGb3IgQ0JDIG1vZGUsIHlvdSBtdXN0IHN1cHBseSB0aGUgSW5pdGlhbCBWYWx1ZSAoSVYpIGZvciBjaXBoZXJpbmciKQoJCSMgU3BsaXQgdGhlIGRhdGEgaW50byBibG9ja3MsIGNyeXB0aW5nIGVhY2ggb25lIHNlcGVyYXRlbHkKCQlpID0gMAoJCWRpY3QgPSB7fQoJCXJlc3VsdCA9IFtdCgkJI2NhY2hlZCA9IDAKCQkjbGluZXMgPSAwCgkJd2hpbGUgaSA8IGxlbihkYXRhKToKCQkJIyBUZXN0IGNvZGUgZm9yIGNhY2hpbmcgZW5jcnlwdGlvbiByZXN1bHRzCgkJCSNsaW5lcyArPSAxCgkJCSNpZiBkaWN0Lmhhc19rZXkoZGF0YVtpOmkrOF0pOgoJCQkJI3ByaW50ICJDYWNoZWQgcmVzdWx0IGZvcjogJXMiICUgZGF0YVtpOmkrOF0KCQkJIwljYWNoZWQgKz0gMQoJCQkjCXJlc3VsdC5hcHBlbmQoZGljdFtkYXRhW2k6aSs4XV0pCgkJCSMJaSArPSA4CgkJCSMJY29udGludWUKCQkJCQkJYmxvY2sgPSBzZWxmLl9fU3RyaW5nX3RvX0JpdExpc3QoZGF0YVtpOmkrOF0pCgkJCSMgWG9yIHdpdGggSVYgaWYgdXNpbmcgQ0JDIG1vZGUKCQkJaWYgc2VsZi5nZXRNb2RlKCkgPT0gQ0JDOgoJCQkJaWYgY3J5cHRfdHlwZSA9PSBkZXMuRU5DUllQVDoKCQkJCQlibG9jayA9IG1hcChsYW1iZGEgeCwgeTogeCBeIHksIGJsb2NrLCBpdikKCQkJCQkjaiA9IDAKCQkJCQkjd2hpbGUgaiA8IGxlbihibG9jayk6CgkJCQkJIwlibG9ja1tqXSA9IGJsb2NrW2pdIF4gaXZbal0KCQkJCQkjCWogKz0gMQoJCQkJcHJvY2Vzc2VkX2Jsb2NrID0gc2VsZi5fX2Rlc19jcnlwdChibG9jaywgY3J5cHRfdHlwZSkKCQkJCWlmIGNyeXB0X3R5cGUgPT0gZGVzLkRFQ1JZUFQ6CgkJCQkJcHJvY2Vzc2VkX2Jsb2NrID0gbWFwKGxhbWJkYSB4LCB5OiB4IF4geSwgcHJvY2Vzc2VkX2Jsb2NrLCBpdikKCQkJCQkjaiA9IDAKCQkJCQkjd2hpbGUgaiA8IGxlbihwcm9jZXNzZWRfYmxvY2spOgoJCQkJCSMJcHJvY2Vzc2VkX2Jsb2NrW2pdID0gcHJvY2Vzc2VkX2Jsb2NrW2pdIF4gaXZbal0KCQkJCQkjCWogKz0gMQoJCQkJCWl2ID0gYmxvY2sKCQkJCWVsc2U6CgkJCQkJaXYgPSBwcm9jZXNzZWRfYmxvY2sKCQkJZWxzZToKCQkJCXByb2Nlc3NlZF9ibG9jayA9IHNlbGYuX19kZXNfY3J5cHQoYmxvY2ssIGNyeXB0X3R5cGUpCgkJCSMgQWRkIHRoZSByZXN1bHRpbmcgY3J5cHRlZCBibG9jayB0byBvdXIgbGlzdAoJCQkjZCA9IHNlbGYuX19CaXRMaXN0X3RvX1N0cmluZyhwcm9jZXNzZWRfYmxvY2spCgkJCSNyZXN1bHQuYXBwZW5kKGQpCgkJCXJlc3VsdC5hcHBlbmQoc2VsZi5fX0JpdExpc3RfdG9fU3RyaW5nKHByb2Nlc3NlZF9ibG9jaykpCgkJCSNkaWN0W2RhdGFbaTppKzhdXSA9IGQKCQkJaSArPSA4CgkJIyBwcmludCAiTGluZXM6ICVkLCBjYWNoZWQ6ICVkIiAlIChsaW5lcywgY2FjaGVkKQoJCSMgUmVtb3ZlIHRoZSBwYWRkaW5nIGZyb20gdGhlIGxhc3QgYmxvY2sKCQlpZiBjcnlwdF90eXBlID09IGRlcy5ERUNSWVBUIGFuZCBzZWxmLmdldFBhZGRpbmcoKToKCQkJI3ByaW50ICJSZW1vdmluZyBkZWNyeXB0IHBhZCIKCQkJcyA9IHJlc3VsdFstMV0KCQkJd2hpbGUgc1stMV0gPT0gc2VsZi5nZXRQYWRkaW5nKCk6CgkJCQlzID0gc1s6LTFdCgkJCXJlc3VsdFstMV0gPSBzCgkJIyBSZXR1cm4gdGhlIGZ1bGwgY3J5cHRlZCBzdHJpbmcKCQlyZXR1cm4gJycuam9pbihyZXN1bHQpCglkZWYgZW5jcnlwdChzZWxmLCBkYXRhLCBwYWQ9JycpOgoJCSIiImVuY3J5cHQoZGF0YSwgW3BhZF0pIC0+IHN0cmluZwoJCWRhdGEgOiBTdHJpbmcgdG8gYmUgZW5jcnlwdGVkCgkJcGFkICA6IE9wdGlvbmFsIGFyZ3VtZW50IGZvciBlbmNyeXB0aW9uIHBhZGRpbmcuIE11c3Qgb25seSBiZSBvbmUgYnl0ZQoJCVRoZSBkYXRhIG11c3QgYmUgYSBtdWx0aXBsZSBvZiA4IGJ5dGVzIGFuZCB3aWxsIGJlIGVuY3J5cHRlZAoJCXdpdGggdGhlIGFscmVhZHkgc3BlY2lmaWVkIGtleS4gRGF0YSBkb2VzIG5vdCBoYXZlIHRvIGJlIGEKCQltdWx0aXBsZSBvZiA4IGJ5dGVzIGlmIHRoZSBwYWRkaW5nIGNoYXJhY3RlciBpcyBzdXBwbGllZCwgdGhlCgkJZGF0YSB3aWxsIHRoZW4gYmUgcGFkZGVkIHRvIGEgbXVsdGlwbGUgb2YgOCBieXRlcyB3aXRoIHRoaXMKCQlwYWQgY2hhcmFjdGVyLgoJCSIiIgoJCXNlbGYuX19wYWRkaW5nID0gcGFkCgkJcmV0dXJuIHNlbGYuY3J5cHQoZGF0YSwgZGVzLkVOQ1JZUFQpCglkZWYgZGVjcnlwdChzZWxmLCBkYXRhLCBwYWQ9JycpOgoJCSIiImRlY3J5cHQoZGF0YSwgW3BhZF0pIC0+IHN0cmluZwoJCWRhdGEgOiBTdHJpbmcgdG8gYmUgZW5jcnlwdGVkCgkJcGFkICA6IE9wdGlvbmFsIGFyZ3VtZW50IGZvciBkZWNyeXB0aW9uIHBhZGRpbmcuIE11c3Qgb25seSBiZSBvbmUgYnl0ZQoJCVRoZSBkYXRhIG11c3QgYmUgYSBtdWx0aXBsZSBvZiA4IGJ5dGVzIGFuZCB3aWxsIGJlIGRlY3J5cHRlZAoJCXdpdGggdGhlIGFscmVhZHkgc3BlY2lmaWVkIGtleS4gSWYgdGhlIG9wdGlvbmFsIHBhZGRpbmcgY2hhcmFjdGVyCgkJaXMgc3VwcGxpZWQsIHRoZW4gdGhlIHVuLWVuY3lwdGVkIGRhdGEgd2lsbCBoYXZlIHRoZSBwYWRkaW5nIGNoYXJhY3RlcnMKCQlyZW1vdmVkIGZyb20gdGhlIGVuZCBvZiB0aGUgc3RyaW5nLiBUaGlzIHBhZCByZW1vdmFsIG9ubHkgb2NjdXJzIG9uIHRoZQoJCWxhc3QgOCBieXRlcyBvZiB0aGUgZGF0YSAobGFzdCBkYXRhIGJsb2NrKS4KCQkiIiIKCQlzZWxmLl9fcGFkZGluZyA9IHBhZAoJCXJldHVybiBzZWxmLmNyeXB0KGRhdGEsIGRlcy5ERUNSWVBUKQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwojIAkJCQlUcmlwbGUgREVTCQkJCSAgICAjCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCmNsYXNzIHRyaXBsZV9kZXM6CgkiIiJUcmlwbGUgREVTIGVuY3J5cHRpb24vZGVjcnl0cGlvbiBjbGFzcwoJVGhpcyBhbGdvcml0aG0gdXNlcyB0aGUgREVTLUVERTMgKHdoZW4gYSAyNCBieXRlIGtleSBpcyBzdXBwbGllZCkgb3IKCXRoZSBERVMtRURFMiAod2hlbiBhIDE2IGJ5dGUga2V5IGlzIHN1cHBsaWVkKSBlbmNyeXB0aW9uIG1ldGhvZHMuCglTdXBwb3J0cyBFQ0IgKEVsZWN0cm9uaWMgQ29kZSBCb29rKSBhbmQgQ0JDIChDeXBoZXIgQmxvY2sgQ2hhaW5pbmcpIG1vZGVzLgoJcHlEZXMuZGVzKGtleSwgW21vZGVdLCBbSVZdKQoJa2V5ICAtPiBUaGUgZW5jcnlwdGlvbiBrZXkgc3RyaW5nLCBtdXN0IGJlIGVpdGhlciAxNiBvciAyNCBieXRlcyBsb25nCgltb2RlIC0+IE9wdGlvbmFsIGFyZ3VtZW50IGZvciBlbmNyeXB0aW9uIHR5cGUsIGNhbiBiZSBlaXRoZXIgcHlEZXMuRUNCCgkJKEVsZWN0cm9uaWMgQ29kZSBCb29rKSwgcHlEZXMuQ0JDIChDeXBoZXIgQmxvY2sgQ2hhaW5pbmcpCglJViAgIC0+IE9wdGlvbmFsIHN0cmluZyBhcmd1bWVudCwgbXVzdCBiZSBzdXBwbGllZCBpZiB1c2luZyBDQkMgbW9kZS4KCQlNdXN0IGJlIDggYnl0ZXMgaW4gbGVuZ3RoLgoJIiIiCglkZWYgX19pbml0X18oc2VsZiwga2V5LCBtb2RlPUVDQiwgSVY9Tm9uZSk6CgkJc2VsZi5ibG9ja19zaXplID0gOAoJCXNlbGYuc2V0TW9kZShtb2RlKQoJCXNlbGYuX19wYWRkaW5nID0gJycKCQlzZWxmLl9faXYgPSBJVgoJCXNlbGYuc2V0S2V5KGtleSkKCWRlZiBnZXRLZXkoc2VsZik6CgkJIiIiZ2V0S2V5KCkgLT4gc3RyaW5nIiIiCgkJcmV0dXJuIHNlbGYuX19rZXkKCWRlZiBzZXRLZXkoc2VsZiwga2V5KToKCQkiIiJXaWxsIHNldCB0aGUgY3J5cHRpbmcga2V5IGZvciB0aGlzIG9iamVjdC4gRWl0aGVyIDE2IG9yIDI0IGJ5dGVzIGxvbmcuIiIiCgkJc2VsZi5rZXlfc2l6ZSA9IDI0ICAjIFVzZSBERVMtRURFMyBtb2RlCgkJaWYgbGVuKGtleSkgIT0gc2VsZi5rZXlfc2l6ZToKCQkJaWYgbGVuKGtleSkgPT0gMTY6ICMgVXNlIERFUy1FREUyIG1vZGUKCQkJCXNlbGYua2V5X3NpemUgPSAxNgoJCQllbHNlOgoJCQkJcmFpc2UgVmFsdWVFcnJvcigiSW52YWxpZCB0cmlwbGUgREVTIGtleSBzaXplLiBLZXkgbXVzdCBiZSBlaXRoZXIgMTYgb3IgMjQgYnl0ZXMgbG9uZyIpCgkJaWYgc2VsZi5nZXRNb2RlKCkgPT0gQ0JDIGFuZCAobm90IHNlbGYuZ2V0SVYoKSBvciBsZW4oc2VsZi5nZXRJVigpKSAhPSBzZWxmLmJsb2NrX3NpemUpOgoJCQlyYWlzZSBWYWx1ZUVycm9yKCJJbnZhbGlkIElWLCBtdXN0IGJlIDggYnl0ZXMgaW4gbGVuZ3RoIikgIyMgVE9ETzogQ2hlY2sgdGhpcwoJCSMgbW9kZXMgZ2V0IGhhbmRsZWQgbGF0ZXIsIHNpbmNlIENCQyBnb2VzIG9uIHRvcCBvZiB0aGUgdHJpcGxlLWRlcwoJCXNlbGYuX19rZXkxID0gZGVzKGtleVs6OF0pCgkJc2VsZi5fX2tleTIgPSBkZXMoa2V5Wzg6MTZdKQoJCWlmIHNlbGYua2V5X3NpemUgPT0gMTY6CgkJCXNlbGYuX19rZXkzID0gc2VsZi5fX2tleTEKCQllbHNlOgoJCQlzZWxmLl9fa2V5MyA9IGRlcyhrZXlbMTY6XSkKCQlzZWxmLl9fa2V5ID0ga2V5CglkZWYgZ2V0TW9kZShzZWxmKToKCQkiIiJnZXRNb2RlKCkgLT4gcHlEZXMuRUNCIG9yIHB5RGVzLkNCQyIiIgoJCXJldHVybiBzZWxmLl9fbW9kZQoJZGVmIHNldE1vZGUoc2VsZiwgbW9kZSk6CgkJIiIiU2V0cyB0aGUgdHlwZSBvZiBjcnlwdGluZyBtb2RlLCBweURlcy5FQ0Igb3IgcHlEZXMuQ0JDIiIiCgkJc2VsZi5fX21vZGUgPSBtb2RlCglkZWYgZ2V0SVYoc2VsZik6CgkJIiIiZ2V0SVYoKSAtPiBzdHJpbmciIiIKCQlyZXR1cm4gc2VsZi5fX2l2CglkZWYgc2V0SVYoc2VsZiwgSVYpOgoJCSIiIldpbGwgc2V0IHRoZSBJbml0aWFsIFZhbHVlLCB1c2VkIGluIGNvbmp1bmN0aW9uIHdpdGggQ0JDIG1vZGUiIiIKCQlzZWxmLl9faXYgPSBJVgoJZGVmIHhvcnN0ciggc2VsZiwgeCwgeSApOgoJCSIiIlJldHVybnMgdGhlIGJpdHdpc2UgeG9yIG9mIHRoZSBieXRlcyBpbiB0d28gc3RyaW5ncyIiIgoJCWlmIGxlbih4KSAhPSBsZW4oeSk6CgkJCXJhaXNlICJzdHJpbmcgbGVuZ3RocyBkaWZmZXIgJWQgJWQiICUgKGxlbih4KSwgbGVuKHkpKQoJCXJldCA9ICcnCgkJZm9yIGkgaW4gcmFuZ2UobGVuKHgpKToKCQkJcmV0ICs9IGNocihvcmQoeFtpXSkgXiBvcmQoeVtpXSkpCgkJcmV0dXJuIHJldAoJZGVmIGVuY3J5cHQoc2VsZiwgZGF0YSwgcGFkPScnKToKCQkiIiJlbmNyeXB0KGRhdGEsIFtwYWRdKSAtPiBzdHJpbmcKCQlkYXRhIDogU3RyaW5nIHRvIGJlIGVuY3J5cHRlZAoJCXBhZCAgOiBPcHRpb25hbCBhcmd1bWVudCBmb3IgZW5jcnlwdGlvbiBwYWRkaW5nLiBNdXN0IG9ubHkgYmUgb25lIGJ5dGUKCQlUaGUgZGF0YSBtdXN0IGJlIGEgbXVsdGlwbGUgb2YgOCBieXRlcyBhbmQgd2lsbCBiZSBlbmNyeXB0ZWQKCQl3aXRoIHRoZSBhbHJlYWR5IHNwZWNpZmllZCBrZXkuIERhdGEgZG9lcyBub3QgaGF2ZSB0byBiZSBhCgkJbXVsdGlwbGUgb2YgOCBieXRlcyBpZiB0aGUgcGFkZGluZyBjaGFyYWN0ZXIgaXMgc3VwcGxpZWQsIHRoZQoJCWRhdGEgd2lsbCB0aGVuIGJlIHBhZGRlZCB0byBhIG11bHRpcGxlIG9mIDggYnl0ZXMgd2l0aCB0aGlzCgkJcGFkIGNoYXJhY3Rlci4KCQkiIiIKCQlpZiBzZWxmLmdldE1vZGUoKSA9PSBFQ0I6CgkJCSMgc2ltcGxlCgkJCWRhdGEgPSBzZWxmLl9fa2V5MS5lbmNyeXB0KGRhdGEsIHBhZCkKCQkJZGF0YSA9IHNlbGYuX19rZXkyLmRlY3J5cHQoZGF0YSkKCQkJcmV0dXJuIHNlbGYuX19rZXkzLmVuY3J5cHQoZGF0YSkKCQlpZiBzZWxmLmdldE1vZGUoKSA9PSBDQkM6CgkJCXJhaXNlICJUaGlzIGNvZGUgaGFzbid0IGJlZW4gdGVzdGVkIHlldCIKCQkJaWYgbGVuKGRhdGEpICUgc2VsZi5ibG9ja19zaXplICE9IDA6CgkJCQlyYWlzZSAiQ0JDIG1vZGUgbmVlZHMgZGF0YWxlbiB0byBiZSBhIG11bHRpcGxlIG9mIGJsb2Nrc2l6ZSAoaWdub3JpbmcgcGFkZGluZyBmb3Igbm93KSIKCQkJIyBzaW1wbGUKCQkJbGFzdGJsb2NrID0gc2VsZi5nZXRJVigpCgkJCXJldGRhdGEgPSAnJwoJCQlmb3IgaSBpbiByYW5nZSggMCwgbGVuKGRhdGEpLCBzZWxmLmJsb2NrX3NpemUgKToKCQkJCXRoaXNibG9jayA9IGRhdGFbIGk6aStzZWxmLmJsb2NrX3NpemUgXQoJCQkJIyB0aGUgWE9SIGZvciBDQkMKCQkJCXRoaXNibG9jayA9IHNlbGYueG9yc3RyKCBsYXN0YmxvY2ssIHRoaXNibG9jayApCgkJCQl0aGlzYmxvY2sgPSBzZWxmLl9fa2V5MS5lbmNyeXB0KHRoaXNibG9jaykKCQkJCXRoaXNibG9jayA9IHNlbGYuX19rZXkyLmRlY3J5cHQodGhpc2Jsb2NrKQoJCQkJbGFzdGJsb2NrID0gc2VsZi5fX2tleTMuZW5jcnlwdCh0aGlzYmxvY2spCgkJCQlyZXRkYXRhICs9IGxhc3RibG9jawoJCQlyZXR1cm4gcmV0ZGF0YQoJCXJhaXNlICJOb3QgcmVhY2hlZCIKCWRlZiBkZWNyeXB0KHNlbGYsIGRhdGEsIHBhZD0nJyk6CgkJIiIiZGVjcnlwdChkYXRhLCBbcGFkXSkgLT4gc3RyaW5nCgkJZGF0YSA6IFN0cmluZyB0byBiZSBlbmNyeXB0ZWQKCQlwYWQgIDogT3B0aW9uYWwgYXJndW1lbnQgZm9yIGRlY3J5cHRpb24gcGFkZGluZy4gTXVzdCBvbmx5IGJlIG9uZSBieXRlCgkJVGhlIGRhdGEgbXVzdCBiZSBhIG11bHRpcGxlIG9mIDggYnl0ZXMgYW5kIHdpbGwgYmUgZGVjcnlwdGVkCgkJd2l0aCB0aGUgYWxyZWFkeSBzcGVjaWZpZWQga2V5LiBJZiB0aGUgb3B0aW9uYWwgcGFkZGluZyBjaGFyYWN0ZXIKCQlpcyBzdXBwbGllZCwgdGhlbiB0aGUgdW4tZW5jeXB0ZWQgZGF0YSB3aWxsIGhhdmUgdGhlIHBhZGRpbmcgY2hhcmFjdGVycwoJCXJlbW92ZWQgZnJvbSB0aGUgZW5kIG9mIHRoZSBzdHJpbmcuIFRoaXMgcGFkIHJlbW92YWwgb25seSBvY2N1cnMgb24gdGhlCgkJbGFzdCA4IGJ5dGVzIG9mIHRoZSBkYXRhIChsYXN0IGRhdGEgYmxvY2spLgoJCSIiIgoJCWlmIHNlbGYuZ2V0TW9kZSgpID09IEVDQjoKCQkJIyBzaW1wbGUKCQkJZGF0YSA9IHNlbGYuX19rZXkzLmRlY3J5cHQoZGF0YSkKCQkJZGF0YSA9IHNlbGYuX19rZXkyLmVuY3J5cHQoZGF0YSkKCQkJcmV0dXJuIHNlbGYuX19rZXkxLmRlY3J5cHQoZGF0YSwgcGFkKQoJCWlmIHNlbGYuZ2V0TW9kZSgpID09IENCQzoKCQkJaWYgbGVuKGRhdGEpICUgc2VsZi5ibG9ja19zaXplICE9IDA6CgkJCQlyYWlzZSAiQ2FuIG9ubHkgZGVjcnlwdCBtdWx0aXBsZXMgb2YgYmxvY2tzaXplIgoJCQlsYXN0YmxvY2sgPSBzZWxmLmdldElWKCkKCQkJcmV0ZGF0YSA9ICcnCgkJCWZvciBpIGluIHJhbmdlKCAwLCBsZW4oZGF0YSksIHNlbGYuYmxvY2tfc2l6ZSApOgoJCQkJIyBjYW4gSSBhcnJhbmdlIHRoaXMgYmV0dGVyPyBwcm9iYWJseS4uLgoJCQkJY2lwaGVyY2h1bmsgPSBkYXRhWyBpOmkrc2VsZi5ibG9ja19zaXplIF0KCQkJCXRoaXNibG9jayA9IHNlbGYuX19rZXkzLmRlY3J5cHQoY2lwaGVyY2h1bmspCgkJCQl0aGlzYmxvY2sgPSBzZWxmLl9fa2V5Mi5lbmNyeXB0KHRoaXNibG9jaykKCQkJCXRoaXNibG9jayA9IHNlbGYuX19rZXkxLmRlY3J5cHQodGhpc2Jsb2NrKQoJCQkJcmV0ZGF0YSArPSBzZWxmLnhvcnN0ciggbGFzdGJsb2NrLCB0aGlzYmxvY2sgKQoJCQkJbGFzdGJsb2NrID0gY2lwaGVyY2h1bmsKCQkJcmV0dXJuIHJldGRhdGEKCQlyYWlzZSAiTm90IHJlYWNoZWQiCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiMgCQkJCUV4YW1wbGVzCQkJCSAgICAjCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCmRlZiBleGFtcGxlX3RyaXBsZV9kZXMoKToKCWZyb20gdGltZSBpbXBvcnQgdGltZQoJIyBVdGlsaXR5IG1vZHVsZQoJZnJvbSBiaW5hc2NpaSBpbXBvcnQgdW5oZXhsaWZ5IGFzIHVuaGV4CgkjIGV4YW1wbGUgc2hvd3MgdHJpcGxlLWRlcyBlbmNyeXB0aW9uIHVzaW5nIHRoZSBkZXMgY2xhc3MKCXByaW50ICJFeGFtcGxlIG9mIHRyaXBsZSBERVMgZW5jcnlwdGlvbiBpbiBkZWZhdWx0IEVDQiBtb2RlIChERVMtRURFMylcbiIKCXByaW50ICJUcmlwbGUgZGVzIHVzaW5nIHRoZSBkZXMgY2xhc3MgKDMgdGltZXMpIgoJdCA9IHRpbWUoKQoJazEgPSBkZXModW5oZXgoIjEzMzQ1Nzc5OUJCQ0RGRjEiKSkKCWsyID0gZGVzKHVuaGV4KCIxMTIyMzM0NDU1NjY3Nzg4IikpCglrMyA9IGRlcyh1bmhleCgiNzc2NjExMDBERDIyMzMxMSIpKQoJZCA9ICJUcmlwbGUgREVTIHRlc3Qgc3RyaW5nLCB0byBiZSBlbmNyeXB0ZWQgYW5kIGRlY3J5cHRlZC4uLiIKCXByaW50ICJLZXkxOiAgICAgICVzIiAlIGsxLmdldEtleSgpCglwcmludCAiS2V5MjogICAgICAlcyIgJSBrMi5nZXRLZXkoKQoJcHJpbnQgIktleTM6ICAgICAgJXMiICUgazMuZ2V0S2V5KCkKCXByaW50ICJEYXRhOiAgICAgICVzIiAlIGQKCWUxID0gazEuZW5jcnlwdChkKQoJZTIgPSBrMi5kZWNyeXB0KGUxKQoJZTMgPSBrMy5lbmNyeXB0KGUyKQoJcHJpbnQgIkVuY3J5cHRlZDogIiArIGUzCglkMyA9IGszLmRlY3J5cHQoZTMpCglkMiA9IGsyLmVuY3J5cHQoZDMpCglkMSA9IGsxLmRlY3J5cHQoZDIpCglwcmludCAiRGVjcnlwdGVkOiAiICsgZDEKCXByaW50ICJERVMgdGltZSB0YWtlbjogJWYgKCVkIGNyeXB0IG9wZXJhdGlvbnMpIiAlICh0aW1lKCkgLSB0LCA2ICogKGxlbihkKSAvIDgpKQoJcHJpbnQgIiIKCSMgRXhhbXBsZSBiZWxvdyB1c2VzIHRoZSB0cmlwbGUtZGVzIGNsYXNzIHRvIGFjaGlldmUgdGhlIHNhbWUgYXMgYWJvdmUKCXByaW50ICJOb3cgdXNpbmcgdHJpcGxlIGRlcyBjbGFzcyIKCXQgPSB0aW1lKCkKCXQxID0gdHJpcGxlX2Rlcyh1bmhleCgiMTMzNDU3Nzk5QkJDREZGMTExMjIzMzQ0NTU2Njc3ODg3NzY2MTEwMEREMjIzMzExIikpCglwcmludCAiS2V5OiAgICAgICAlcyIgJSB0MS5nZXRLZXkoKQoJcHJpbnQgIkRhdGE6ICAgICAgJXMiICUgZAoJdGQxID0gdDEuZW5jcnlwdChkKQoJcHJpbnQgIkVuY3J5cHRlZDogIiArIHRkMQoJdGQyID0gdDEuZGVjcnlwdCh0ZDEpCglwcmludCAiRGVjcnlwdGVkOiAiICsgdGQyCglwcmludCAiVHJpcGxlIERFUyB0aW1lIHRha2VuOiAlZiAoJWQgY3J5cHQgb3BlcmF0aW9ucykiICUgKHRpbWUoKSAtIHQsIDYgKiAobGVuKGQpIC8gOCkpCmRlZiBleGFtcGxlX2RlcygpOgoJZnJvbSB0aW1lIGltcG9ydCB0aW1lCgkjIGV4YW1wbGUgb2YgREVTIGVuY3J5cHRpbmcgaW4gQ0JDIG1vZGUgd2l0aCB0aGUgSVYgb2YgIlwwXDBcMFwwXDBcMFwwXDAiCglwcmludCAiRXhhbXBsZSBvZiBERVMgZW5jcnlwdGlvbiB1c2luZyBDQkMgbW9kZVxuIgoJdCA9IHRpbWUoKQoJayA9IGRlcygiREVTQ1JZUFQiLCBDQkMsICJcMFwwXDBcMFwwXDBcMFwwIikKCWRhdGEgPSAiREVTIGVuY3J5cHRpb24gYWxnb3JpdGhtIgoJcHJpbnQgIktleSAgICAgIDogIiArIGsuZ2V0S2V5KCkKCXByaW50ICJEYXRhICAgICA6ICIgKyBkYXRhCglkID0gay5lbmNyeXB0KGRhdGEpCglwcmludCAiRW5jcnlwdGVkOiAiICsgZAoJZCA9IGsuZGVjcnlwdChkKQoJcHJpbnQgIkRlY3J5cHRlZDogIiArIGQKCXByaW50ICJERVMgdGltZSB0YWtlbjogJWYgKDYgY3J5cHQgb3BlcmF0aW9ucykiICUgKHRpbWUoKSAtIHQpCglwcmludCAiIgpkZWYgX190ZXN0X18oKToKCWV4YW1wbGVfZGVzKCkKCWV4YW1wbGVfdHJpcGxlX2RlcygpCmRlZiBfX2Z1bGx0ZXN0X18oKToKCSMgVGhpcyBzaG91bGQgbm90IHByb2R1Y2UgYW55IHVuZXhwZWN0ZWQgZXJyb3JzIG9yIGV4Y2VwdGlvbnMKCWZyb20gYmluYXNjaWkgaW1wb3J0IHVuaGV4bGlmeSBhcyB1bmhleAoJZnJvbSBiaW5hc2NpaSBpbXBvcnQgaGV4bGlmeSBhcyBkb2hleAoJX190ZXN0X18oKQoJcHJpbnQgIiIKCWsgPSBkZXMoIlwwXDBcMFwwXDBcMFwwXDAiLCBDQkMsICJcMFwwXDBcMFwwXDBcMFwwIikKCWQgPSBrLmVuY3J5cHQoIkRFUyBlbmNyeXB0aW9uIGFsZ29yaXRobSIpCglpZiBrLmRlY3J5cHQoZCkgIT0gIkRFUyBlbmNyeXB0aW9uIGFsZ29yaXRobSI6CgkJcHJpbnQgIlRlc3QgMSBFcnJvcjogVW5lbmN5cHRlZCBkYXRhIGJsb2NrIGRvZXMgbm90IG1hdGNoIHN0YXJ0IGRhdGEiCglrID0gZGVzKCJcMFwwXDBcMFwwXDBcMFwwIiwgQ0JDLCAiXDBcMFwwXDBcMFwwXDBcMCIpCglkID0gay5lbmNyeXB0KCJEZWZhdWx0IHN0cmluZyBvZiB0ZXh0IiwgJyonKQoJaWYgay5kZWNyeXB0KGQsICIqIikgIT0gIkRlZmF1bHQgc3RyaW5nIG9mIHRleHQiOgoJCXByaW50ICJUZXN0IDIgRXJyb3I6IFVuZW5jeXB0ZWQgZGF0YSBibG9jayBkb2VzIG5vdCBtYXRjaCBzdGFydCBkYXRhIgoJayA9IGRlcygiXHJcblx0QUJDXHJcbiIpCglkID0gay5lbmNyeXB0KCJTdHJpbmcgdG8gUGFkIiwgJyonKQoJaWYgay5kZWNyeXB0KGQpICE9ICJTdHJpbmcgdG8gUGFkKioqIjoKCQlwcmludCAiJyVzJyIgJSBrLmRlY3J5cHQoZCkKCQlwcmludCAiVGVzdCAzIEVycm9yOiBVbmVuY3lwdGVkIGRhdGEgYmxvY2sgZG9lcyBub3QgbWF0Y2ggc3RhcnQgZGF0YSIKCWsgPSBkZXMoIlxyXG5cdEFCQ1xyXG4iKQoJZCA9IGsuZW5jcnlwdCh1bmhleCgiMDAwMTAyMDMwNDA1MDYwNzA4RkY4RkRDQjA0MDgwIiksIHVuaGV4KCI0NCIpKQoJaWYgay5kZWNyeXB0KGQsIHVuaGV4KCI0NCIpKSAhPSB1bmhleCgiMDAwMTAyMDMwNDA1MDYwNzA4RkY4RkRDQjA0MDgwIik6CgkJcHJpbnQgIlRlc3QgNGEgRXJyb3I6IFVuZW5jeXB0ZWQgZGF0YSBibG9jayBkb2VzIG5vdCBtYXRjaCBzdGFydCBkYXRhIgoJaWYgay5kZWNyeXB0KGQpICE9IHVuaGV4KCIwMDAxMDIwMzA0MDUwNjA3MDhGRjhGRENCMDQwODA0NCIpOgoJCXByaW50ICJUZXN0IDRiIEVycm9yOiBVbmVuY3lwdGVkIGRhdGEgYmxvY2sgZG9lcyBub3QgbWF0Y2ggc3RhcnQgZGF0YSIKCWsgPSB0cmlwbGVfZGVzKCJNeURlc0tleVxyXG5cdEFCQ1xyXG4wOTg3KjU0MyIpCglkID0gay5lbmNyeXB0KHVuaGV4KCIwMDAxMDIwMzA0MDUwNjA3MDhGRjhGRENCMDQwODAwMDAxMDIwMzA0MDUwNjA3MDhGRjhGRENCMDQwODAwMDAxMDIwMzA0MDUwNjA3MDhGRjhGRENCMDQwODAwMDAxMDIwMzA0MDUwNjA3MDhGRjhGRENCMDQwODAwMDAxMDIwMzA0MDUwNjA3MDhGRjhGRENCMDQwODAwMDAxMDIwMzA0MDUwNjA3MDhGRjhGRENCMDQwODAwMDAxMDIwMzA0MDUwNjA3MDhGRjhGRENCMDQwODAwMDAxMDIwMzA0MDUwNjA3MDhGRjhGRENCMDQwODAiKSkKCWlmIGsuZGVjcnlwdChkKSAhPSB1bmhleCgiMDAwMTAyMDMwNDA1MDYwNzA4RkY4RkRDQjA0MDgwMDAwMTAyMDMwNDA1MDYwNzA4RkY4RkRDQjA0MDgwMDAwMTAyMDMwNDA1MDYwNzA4RkY4RkRDQjA0MDgwMDAwMTAyMDMwNDA1MDYwNzA4RkY4RkRDQjA0MDgwMDAwMTAyMDMwNDA1MDYwNzA4RkY4RkRDQjA0MDgwMDAwMTAyMDMwNDA1MDYwNzA4RkY4RkRDQjA0MDgwMDAwMTAyMDMwNDA1MDYwNzA4RkY4RkRDQjA0MDgwMDAwMTAyMDMwNDA1MDYwNzA4RkY4RkRDQjA0MDgwIik6CgkJcHJpbnQgIlRlc3QgNSBFcnJvcjogVW5lbmN5cHRlZCBkYXRhIGJsb2NrIGRvZXMgbm90IG1hdGNoIHN0YXJ0IGRhdGEiCglrID0gdHJpcGxlX2RlcygiXHJcblx0QUJDXHJcbjA5ODcqNTQzIikKCWQgPSBrLmVuY3J5cHQodW5oZXgoIjAwMDEwMjAzMDQwNTA2MDcwOEZGOEZEQ0IwNDA4MDAwMDEwMjAzMDQwNTA2MDcwOEZGOEZEQ0IwNDA4MDAwMDEwMjAzMDQwNTA2MDcwOEZGOEZEQ0IwNDA4MDAwMDEwMjAzMDQwNTA2MDcwOEZGOEZEQ0IwNDA4MDAwMDEwMjAzMDQwNTA2MDcwOEZGOEZEQ0IwNDA4MDAwMDEwMjAzMDQwNTA2MDcwOEZGOEZEQ0IwNDA4MDAwMDEwMjAzMDQwNTA2MDcwOEZGOEZEQ0IwNDA4MDAwMDEwMjAzMDQwNTA2MDcwOEZGOEZEQ0IwNDA4MCIpKQoJaWYgay5kZWNyeXB0KGQpICE9IHVuaGV4KCIwMDAxMDIwMzA0MDUwNjA3MDhGRjhGRENCMDQwODAwMDAxMDIwMzA0MDUwNjA3MDhGRjhGRENCMDQwODAwMDAxMDIwMzA0MDUwNjA3MDhGRjhGRENCMDQwODAwMDAxMDIwMzA0MDUwNjA3MDhGRjhGRENCMDQwODAwMDAxMDIwMzA0MDUwNjA3MDhGRjhGRENCMDQwODAwMDAxMDIwMzA0MDUwNjA3MDhGRjhGRENCMDQwODAwMDAxMDIwMzA0MDUwNjA3MDhGRjhGRENCMDQwODAwMDAxMDIwMzA0MDUwNjA3MDhGRjhGRENCMDQwODAiKToKCQlwcmludCAiVGVzdCA2IEVycm9yOiBVbmVuY3lwdGVkIGRhdGEgYmxvY2sgZG9lcyBub3QgbWF0Y2ggc3RhcnQgZGF0YSIKZGVmIF9fZmlsZXRlc3RfXygpOgoJZnJvbSB0aW1lIGltcG9ydCB0aW1lCglmID0gb3BlbigicHlEZXMucHkiLCAicmIrIikKCWQgPSBmLnJlYWQoKQoJZi5jbG9zZSgpCgl0ID0gdGltZSgpCglrID0gZGVzKCJNeURFU0tleSIpCglkID0gay5lbmNyeXB0KGQsICIgIikKCWYgPSBvcGVuKCJweURlcy5weS5lbmMiLCAid2IrIikKCWYud3JpdGUoZCkKCWYuY2xvc2UoKQoJZCA9IGsuZGVjcnlwdChkLCAiICIpCglmID0gb3BlbigicHlEZXMucHkuZGVjIiwgIndiKyIpCglmLndyaXRlKGQpCglmLmNsb3NlKCkKCXByaW50ICJERVMgZmlsZSB0ZXN0IHRpbWU6ICVmIiAlICh0aW1lKCkgLSB0KQpkZWYgX19wcm9maWxlX18oKToKCWltcG9ydCBwcm9maWxlCglwcm9maWxlLnJ1bignX19mdWxsdGVzdF9fKCknKQoJI3Byb2ZpbGUucnVuKCdfX2ZpbGV0ZXN0X18oKScpCiNpZiBfX25hbWVfXyA9PSAnX19tYWluX18nOgoJX190ZXN0X18oKQoJI19fZnVsbHRlc3RfXygpCgkjX19maWxldGVzdF9fKCkKCSNfX3Byb2ZpbGVfXygpCg==