2 # rsaes_pkcs1v15_check.rb
4 This file is part of the AVR-Crypto-Lib.
5 Copyright (C) 2008 Daniel Otte (daniel.otte@rub.de)
7 This program is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
26 $buffer_size = 0 # set automatically in init_system
27 $conffile_check = Hash.new
28 $conffile_check.default = 0
29 $progress_dots = false
33 ################################################################################
35 ################################################################################
37 def read_line_from_device()
38 repeat_counter = 10000
44 end while !l && repeat_counter > 0
46 $logfile.printf("DBG: (%02d:%02d:%02d)<< %s\n", t.hour, t.min, t.sec, l.inspect) if $debug
47 if l && l.include?("AVR-Crypto-Lib")
48 $logfile.printf("DBG: system crashed !!!\n")
54 def readconfigfile(fname, conf)
55 return conf if $conffile_check[fname]==1
56 $conffile_check[fname]=1
58 if not File.exists?(fname)
61 file = File.open(fname, "r")
64 next if /[\s]*#/.match(line)
65 if m=/\[[\s]*([^\s]*)[\s]*\]/.match(line)
70 next if ! /=/.match(line)
71 m=/[\s]*([^\s]*)[\s]*=[\s]*([^\s]*)/.match(line)
73 Dir.glob(m[2]){ |fn| conf = readconfigfile(fn, conf) }
75 conf[section][m[1]] = m[2]
82 ################################################################################
84 ################################################################################
91 $sp.print("echo off\r")
101 # x = l.split.collect { |e| e.to_i(16) }
103 t.each { |e| v = true if e.length != 2 }
105 x = t.collect { |e| e.to_i(16) } if ! v
107 end while x.length == 16 && ! v
128 def get_next_block(f)
133 end while l && ! m= l.match(/^#[\s](.*):[\s]*$/)
136 ret['line'] = f.lineno
146 'Public exponent', # 3
150 'Prime exponent 1', # 7
151 'Prime exponent 2', # 8
155 def key_consitency_check(k)
159 def process_file(f, skip_key=1, skip_vec=1)
160 a = get_next_block(f)
165 if !a || ! a['tag'] == 'Modulus'
166 printf("ERROR: a = %s %d\n", a.inspect, __LINE__)
171 (1..($key_sequence.length-1)).each do |i|
172 a = get_next_block(f)
173 if ! a || a['tag'] != $key_sequence[i]
174 printf("ERROR: (expecting: %s) a = %s %d\n", $key_sequence[i], a.inspect, __LINE__)
178 key = convert_key(k_seq)
179 printf("ERROR: %d\n", __LINE__) if ! key
182 printf("\n run %3d: ", key_no)
183 skip_key_flag = (key_no < skip_key)
184 load_key(key) if ! skip_key_flag
186 a = get_next_block(f)
187 printf("ERROR: %d\n", __LINE__) if ! a
190 b = get_next_block(f)
191 c = get_next_block(f)
193 tv['msg'] = a['data']
194 tv['seed'] = b['data']
195 tv['enc'] = c['data']
196 skip_vec_flag = (skip_key_flag || (key_no == skip_key && vec_no < skip_vec))
203 $logfile.printf("[[Test %2d.%02d = OK]]\n", key_no, vec_no)
206 printf('%c', v ? '*' : '!')
207 $logfile.printf("[[Test %2d.%02d = FAIL]]\n", key_no, vec_no)
211 a = get_next_block(f)
212 end while a && a['tag'] == 'Message'
213 end while a && a['tag'] = 'Modulus'
214 # printf("\nResult: %d OK / %d FAIL ==> %s \nFinished\n", ok_counter, fail_counter, fail_counter==0 ? ':-)' : ':-(')
215 return ok_counter,fail_counter
218 def convert_key(k_seq)
219 l = ['n', 'e', 'd', 'p', 'q', 'dP', 'dQ', 'qInv']
221 return nil if k_seq[0]['data'] != k_seq[2]['data']
222 return nil if k_seq[1]['data'] != k_seq[3]['data']
224 r[l[i]] = k_seq[2 + i]['data']
232 end while !s || !s.include?('.')
236 $sp.printf("%d\r", d.length)
237 while l = read_line_from_device()
238 break if /data:/.match(l)
240 printf "ERROR: got no answer from system!" if !l
243 $sp.printf("%02x", e)
246 # we should now wait for incomming dot
248 print('.') if $progress_dots
256 printf("\n\t") if i % 16 == 0
260 puts('') if i % 16 != 1
267 s += "\n\t" if i % 16 == 0
268 s += sprintf('%02x ', e)
271 s += "\n" if i % 16 != 1
276 $sp.print("load-key\r")
278 v = ['n', 'e', 'p', 'q', 'dP', 'dQ', 'qInv']
281 $logfile.printf("DBG: loaded %s\n", e) if $debug
283 while l = read_line_from_device()
284 break if />/.match(l)
288 def strip_leading_zeros(a)
290 return [] if a.length == 0
291 return a if a[0] != 0
298 $sp.print("seed-test\r")
300 load_bigint(tv['msg'])
301 $logfile.printf("DBG: loaded %s\n", 'msg') if $debug
303 tv['seed'].each { |e| $sp.printf(" %02x", e) }
304 while l = read_line_from_device()
305 break if /ciphertext:/.match(l)
309 l = read_line_from_device()
312 t.each { |e| v = true if e.length != 2 }
313 x = t.collect { |e| e.to_i(16) }
317 test_enc_a = Array.new
318 test_enc = test_enc.split(/[\W\r\n]+/)
320 v = e.sub(/[^0-9A-Fa-f]/, '')
321 test_enc_a << v if v.length == 2
323 test_enc_a.collect!{ |e| e.to_i(16) }
324 strip_leading_zeros(test_enc_a)
325 strip_leading_zeros(tv['enc'])
326 enc_ok = (test_enc_a == tv['enc'])
328 $logfile.printf("DBG: ref = %s test = %s\n", str_hexdump(tv['enc']) , str_hexdump(test_enc_a))
332 l = read_line_from_device()
333 m = /(>>OK<<|ERROR)/.match(l)
336 return true if enc_ok && (m[1] == '>>OK<<')
340 ########################################
342 ########################################
344 Usage of 'rsaes_pkcs1v15_check':
345 >ruby rsaes_pkcs1v15_check -f <file> [-c <file>] [-s <a>.<b>] [-n <name> | -l <file>]
346 -d enable debugging (logging all received text, not only responses)
347 -c <file> use <file> as configuration file
348 -f <file> read testvectors from <file>
349 -s <a>.<b> start with testvector <a>.<b>
350 -n <name> log to a file which name is based on <name>
354 opts = Getopt::Std.getopts('dc:f:l:s:n:')
362 conf = readconfigfile("/etc/testport.conf", conf)
363 conf = readconfigfile("~/.testport.conf", conf)
364 conf = readconfigfile("testport.conf", conf)
365 conf = readconfigfile(opts["c"], conf) if opts["c"]
369 puts("serial port interface version: " + SerialPort::VERSION);
371 params = { "baud" => conf["PORT"]["baud"].to_i,
372 "data_bits" => conf["PORT"]["databits"].to_i,
373 "stop_bits" => conf["PORT"]["stopbits"].to_i,
374 "parity" => SerialPort::NONE }
375 params["paraty"] = SerialPort::ODD if conf["PORT"]["paraty"].downcase == "odd"
376 params["paraty"] = SerialPort::EVEN if conf["PORT"]["paraty"].downcase == "even"
377 params["paraty"] = SerialPort::MARK if conf["PORT"]["paraty"].downcase == "mark"
378 params["paraty"] = SerialPort::SPACE if conf["PORT"]["paraty"].downcase == "space"
380 puts("\nPort: "+conf["PORT"]["port"]+"@" +
381 params["baud"].to_s +
383 params["data_bits"].to_s +
384 conf["PORT"]["paraty"][0,1].upcase +
385 params["stop_bits"].to_s +
388 $sp = SerialPort.new(conf["PORT"]["port"], params)
390 $sp.read_timeout=1000; # 5 minutes
391 $sp.flow_control = SerialPort::SOFT
393 $debug = true if opts['d']
395 if opts['l'] && ! opts['n']
396 $logfile = File.open(opts['l'], 'w')
399 base_name = 'rsaes_pkcs1v15'
402 logfilename = conf['PORT']['testlogbase'] + base_name + '_' + opts['n'] + '.txt'
403 if File.exists?(logfilename)
406 logfilename = sprintf('%s%04d%s', conf['PORT']['testlogbase'] + base_name + '_' + opts['n'] + '_',i,'.txt')
408 end while(File.exists?(logfilename))
410 n1 = sprintf('%s%04d%s', conf['PORT']['testlogbase'] + base_name + '_' + opts['n'] + '_', i-2, '.txt')
411 n2 = sprintf('%s%04d%s', conf['PORT']['testlogbase'] + base_name + '_' + opts['n'] + '_', i-1, '.txt')
413 printf("%s -> %s\n", n1, n2)
416 n1 = sprintf('%s%s', conf['PORT']['testlogbase'], base_name + '_' + opts['n'] + '.txt')
417 n2 = sprintf('%s%04d%s', conf['PORT']['testlogbase'] + base_name + '_' + opts['n'] + '_', 1, '.txt')
419 printf("%s -> %s\n", n1, n2)
420 logfilename = conf['PORT']['testlogbase'] + base_name + '_' + opts['n'] + '.txt'
422 printf("logging to %s", logfilename)
423 $logfile = File.open(logfilename, 'w')
426 $logfile = STDOUT if ! $logfile
430 if opts['s'] && ( m = opts['s'].match(/([\d]+)\.([\d]+)/) )
438 f = File.open(opts['f'], "r")
440 ok,fail = process_file(f,sk,sv)
441 printf("\nOK: %d FAIL: %d :-%s\n",ok,fail, fail==0 ? ')':'(')