Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #! /usr/bin/env python2
- import tr_pcc
- import sys
- import argparse
- import des
- import traces
- # The P permutation table, as in the standard. The first entry (16) is the
- # position of the first (leftmost) bit of the result in the input 32 bits word.
- # Used to convert target bit index into SBox index (just for printed summary
- # after attack completion).
- p_table = [16, 7, 20, 21, 29, 12, 28, 17, 1, 15, 23, 26, 5, 18, 31, 10, 2, 8, 24, 14, 32, 27, 3, 9, 19, 13, 30, 6, 22, 11, 4, 25]
- def hamming_weight (v):
- v = v - ((v>>1) & 0x5555555555555555)
- v = (v & 0x3333333333333333) + ((v>>2) & 0x3333333333333333)
- return (((v + (v>>4) & 0xF0F0F0F0F0F0F0F) * 0x101010101010101) >> 56) & 0xFF
- def hamming_distance(n1,n2):
- return hamming_weight(n1^n2)
- def main ():
- # ************************************************************************
- # * Before doing anything else, check the correctness of the DES library *
- # ************************************************************************
- if not des.check ():
- sys.exit ("DES functional test failed")
- # *************************************
- # * Check arguments and read datafile *
- # *************************************
- argparser = argparse.ArgumentParser(description="Apply P. Kocher's DPA algorithm based on decision function")
- argparser.add_argument("datafile", metavar='FILE',
- help='name of the traces file in HWSec format. (e.g. pa.dat)')
- argparser.add_argument("n", metavar='N', type=int,
- help='number of acquisitions to use')
- argparser.add_argument("target_bit", metavar='[B]', type=int, nargs='?', default=1,
- help='index of target bit in L15 (1 to 32, as in DES standard, default: 1)')
- args = argparser.parse_args()
- if args.n < 1: # If invalid number of acquisitions.
- sys.exit ("Invalid number of acquisitions: %d (shall be greater than 1)" % args.n)
- if args.target_bit < 1 or args.target_bit > 32: # If invalid target bit index.
- sys.exit ("Invalid target bit index: %d (shall be between 1 and 32 included)" % args.target_bit)
- # Compute index of corresponding SBox
- target_sbox = (p_table[args.target_bit - 1] - 1) / 4 + 1
- # Read power traces and ciphertexts. n is the number of acquisitions to use.
- ctx = read_datafile (args.datafile, args.n)
- print >> sys.stderr, 'Hey'
- print >> sys.stderr, 'Hope you have had a nice day ! :)'
- # ***************************************************************
- dpa_attack (ctx)
- #print >> sys.stderr, "target bit %d" % args.target_bit
- #dpa_attack(ctx, 1)
- # *******************************************************************************
- # * Print the 64 DPA traces in a data file named dpa.dat. Print corresponding *
- # * gnuplot commands in a command file named dpa.cmd. All DPA traces are *
- # * plotted in blue but the one corresponding to the best guess which is *
- # * plotted in red with the title "Trace X (0xY)" where X and Y are the decimal *
- # * and heaxdecimal forms of the 6 bits best guess. *
- # *******************************************************************************
- # Plot DPA traces in dpa.dat, gnuplot commands in dpa.cmd
- # *****************
- # * Print summary *
- # *****************
- #print >> sys.stderr, "Target bit: %d" % args.target_bit
- #print >> sys.stderr, "Target SBox: %d" % target_sbox
- #print >> sys.stderr, "Best guess: %d (0x%02x)" % (best_guess, best_guess)
- #print >> sys.stderr, "Maximum of DPA trace: %e" % best_max
- #print >> sys.stderr, "Index of maximum in DPA trace: %d" % best_idx
- #print >> sys.stderr, "DPA traces stored in file 'dpa.dat'. In order to plot them, type:"
- #print >> sys.stderr, "$ gnuplot -persist dpa.cmd"
- # ************************
- # * Print last round key *
- # ************************
- # A function to allocate cipher texts and power traces, read the
- # datafile and store its content in allocated context.
- def read_datafile (name, n):
- ctx = traces.trContext (name, n)
- if ctx.n != n:
- sys.exit ("Could not read %d acquisitions from traces file. Traces file contains %d acquisitions." % (n, ctx.n));
- return ctx
- # Apply P. Kocher's DPA algorithm based on decision function. Computes 64 DPA
- # traces dpa[0..63], best_guess (6-bits subkey corresponding to highest DPA
- # peak), best_idx (index of sample with maximum value in best DPA trace) and
- # best_max (value of sample with maximum value in best DPA trace).
- def dpa_attack (ctx):
- pcc = [0]*64
- sbomask = 0xf0000000
- key=[]
- for sbox in range(8):
- print >> sys.stderr, 'Calculating subkey for Sbox number: ' + str(sbox)
- ctx_pcc = tr_pcc.pccContext(ctx.l,64) # pccContext object
- for i in range(ctx.n):
- ct = ctx.c[i]
- r16l16 = des.ip(ct)
- l16 = des.right_half(r16l16)
- r15 = l16
- r16 = des.left_half(r16l16)
- er15 = des.e(l16)
- ctx_pcc.insert_x(ctx.t[i][:])
- rk= 0x0
- for j in range(64):
- l15 = r16^des.p(des.sboxes(er15^rk))
- r14 = l15
- ctx_pcc.insert_y(j, int(hamming_distance(r14 & des.p(sbomask), r15 & des.p(sbomask))))
- rk+= 0x041041041041
- ctx_pcc.consolidate()
- dpa = list([ctx_pcc.get_pcc(g) for g in range(64)])
- maxs = [max(l) for l in dpa]
- idx = [l.index(m) for l,m in zip (dpa, maxs)]
- # Get best maximum
- best_max = max (maxs)
- best_guess = maxs.index (best_max)
- best_idx = idx[best_guess]
- sbomask = sbomask >> 4
- key.append(best_guess)
- print >> sys.stderr, 'Subkey for Sbox nr. ' + str(sbox) +'are ' + str(hex(best_guess))
- #traces.plot('sboxnr' + str(sbox), -1, dpa) # Plot the traces for each sbox
- # Format output
- res = ''
- for i in range(len(key)):
- res += bin(key[i])[2:].zfill(6)
- print hex(int(res,2))
- def shit_i_dont_like (ctx, target_bit):
- t0 = [[0.0] * ctx.l] * 64
- n0 = [0] * 64
- t1 = [[0.0] * ctx.l] * 64
- n1 = [0] * 64
- for ct, t in zip (ctx.c, ctx.t): # For all acquisitions
- d = decision (ct, target_bit) # Compute the 64 decisions
- # For all guesses (64)
- for g in xrange (64):
- if d[g] == 0: # If decision on target bit is zero
- t0[g] = [a+b for a,b in zip (t0[g], t)] # Accumulate power trace in zero-set
- n0[g] += 1 # Increment traces count for zero-set
- else: # If decision on target bit is one
- t1[g] = [a+b for a,b in zip (t1[g], t)] # Accumulate power trace in one-set
- n1[g] += 1 # Increment traces count for one-set
- #DPA=[]
- #for g in range(64):
- #DPA[g] = sum(t1)/float(len(t1))
- # Compute normalized one-set minus zero-set
- dpa = [[t1[g][i]/n1[g] - t0[g][i]/n0[g] for i in xrange (ctx.l)] for g in xrange (64)]
- # Get max and argmax for each guess
- maxs = [max(l) for l in dpa]
- idx = [l.index(m) for l,m in zip (dpa, maxs)]
- # Get best maximum
- best_max = max (maxs)
- best_guess = maxs.index (best_max)
- best_idx = idx[best_guess]
- return dpa, best_guess, best_max, best_idx
- if __name__ == "__main__":
- main ()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement