2 # rsassa_pkcs1v15_check.rb
4 This file is part of the AVR-Crypto-Lib.
5 Copyright (C) 2012 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
30 $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)
192 tv['msg'] = a['data']
193 tv['sign'] = b['data']
194 skip_vec_flag = (skip_key_flag || (key_no == skip_key && vec_no < skip_vec))
201 $logfile.printf("[[Test %2d.%02d = OK]]\n", key_no, vec_no)
204 printf('%c', v ? '*' : '!')
205 $logfile.printf("[[Test %2d.%02d = FAIL]]\n", key_no, vec_no)
209 a = get_next_block(f)
210 end while a && a['tag'] == 'Message to be signed'
211 end while a && a['tag'] = 'Modulus'
212 # printf("\nResult: %d OK / %d FAIL ==> %s \nFinished\n", ok_counter, fail_counter, fail_counter==0 ? ':-)' : ':-(')
213 return ok_counter,fail_counter
216 def convert_key(k_seq)
217 l = ['n', 'e', 'd', 'p', 'q', 'dP', 'dQ', 'qInv']
219 return nil if k_seq[0]['data'] != k_seq[2]['data']
220 return nil if k_seq[1]['data'] != k_seq[3]['data']
222 r[l[i]] = k_seq[2 + i]['data']
230 end while !s || !s.include?('.')
234 $sp.printf("%d\r", d.length)
235 while l = read_line_from_device()
236 break if /data:/.match(l)
238 printf "ERROR: got no answer from system!" if !l
241 $sp.printf("%02x", e)
244 # we should now wait for incomming dot
246 print('.') if $progress_dots
254 printf("\n\t") if i % 16 == 0
258 puts('') if i % 16 != 1
265 s += "\n\t" if i % 16 == 0
266 s += sprintf('%02x ', e)
269 s += "\n" if i % 16 != 1
274 $sp.print("load-key\r")
276 v = ['n', 'e', 'p', 'q', 'dP', 'dQ', 'qInv']
279 $logfile.printf("DBG: loaded %s\n", e) if $debug
281 while l = read_line_from_device()
282 break if />/.match(l)
286 def strip_leading_zeros(a)
288 return [] if a.length == 0
289 return a if a[0] != 0
296 $sp.print("sha1-test\r")
298 load_bigint(tv['msg'])
299 $logfile.printf("DBG: loaded %s\n", 'msg') if $debug
301 while l = read_line_from_device()
302 break if /signature:/.match(l)
306 l = read_line_from_device()
309 t.each { |e| v = true if e.length != 2 }
310 x = t.collect { |e| e.to_i(16) }
314 test_sign_a = Array.new
315 test_sign = test_sign.split(/[\W\r\n]+/)
316 test_sign.each do |e|
317 v = e.sub(/[^0-9A-Fa-f]/, '')
318 test_sign_a << v if v.length == 2
320 test_sign_a.collect!{ |e| e.to_i(16) }
321 strip_leading_zeros(test_sign_a)
322 strip_leading_zeros(tv['sign'])
323 sign_ok = (test_sign_a == tv['sign'])
325 $logfile.printf("DBG: ref = %s test = %s\n", str_hexdump(tv['sign']) , str_hexdump(test_sign_a))
329 l = read_line_from_device()
330 m = /(>>OK<<|ERROR)/.match(l)
333 return true if sign_ok && (m[1] == '>>OK<<')
337 ########################################
339 ########################################
341 Usage of 'rsassa_pkcs1v15_check':
342 >ruby rsassa_pkcs1v15_check -f <file> [-c <file>] [-s <a>.<b>] [-n <name> | -l <file>]
343 -d enable debugging (logging all received text, not only responses)
344 -c <file> use <file> as configuration file
345 -f <file> read testvectors from <file>
346 -s <a>.<b> start with testvector <a>.<b>
347 -n <name> log to a file which name is based on <name>
351 opts = Getopt::Std.getopts('dc:f:l:s:n:')
359 conf = readconfigfile("/etc/testport.conf", conf)
360 conf = readconfigfile("~/.testport.conf", conf)
361 conf = readconfigfile("testport.conf", conf)
362 conf = readconfigfile(opts["c"], conf) if opts["c"]
366 puts("serial port interface version: " + SerialPort::VERSION);
368 params = { "baud" => conf["PORT"]["baud"].to_i,
369 "data_bits" => conf["PORT"]["databits"].to_i,
370 "stop_bits" => conf["PORT"]["stopbits"].to_i,
371 "parity" => SerialPort::NONE }
372 params["paraty"] = SerialPort::ODD if conf["PORT"]["paraty"].downcase == "odd"
373 params["paraty"] = SerialPort::EVEN if conf["PORT"]["paraty"].downcase == "even"
374 params["paraty"] = SerialPort::MARK if conf["PORT"]["paraty"].downcase == "mark"
375 params["paraty"] = SerialPort::SPACE if conf["PORT"]["paraty"].downcase == "space"
377 puts("\nPort: "+conf["PORT"]["port"]+"@" +
378 params["baud"].to_s +
380 params["data_bits"].to_s +
381 conf["PORT"]["paraty"][0,1].upcase +
382 params["stop_bits"].to_s +
385 $sp = SerialPort.new(conf["PORT"]["port"], params)
387 $sp.read_timeout=1000; # 5 minutes
388 $sp.flow_control = SerialPort::SOFT
390 $debug = true if opts['d']
392 if opts['l'] && ! opts['n']
393 $logfile = File.open(opts['l'], 'w')
396 base_name = 'rsassa_pkcs1v15'
399 logfilename = conf['PORT']['testlogbase'] + base_name + '_' + opts['n'] + '.txt'
400 if File.exists?(logfilename)
403 logfilename = sprintf('%s%04d%s', conf['PORT']['testlogbase'] + base_name + '_' + opts['n'] + '_', i, '.txt')
405 end while(File.exists?(logfilename))
407 n1 = sprintf('%s%04d%s', conf['PORT']['testlogbase'] + base_name + '_' + opts['n'] + '_', i-2, '.txt')
408 n2 = sprintf('%s%04d%s', conf['PORT']['testlogbase'] + base_name + '_' + opts['n'] + '_', i-1, '.txt')
410 printf("%s -> %s\n", n1, n2)
413 n1 = sprintf('%s%s', conf['PORT']['testlogbase'], base_name + '_' + opts['n'] + '.txt')
414 n2 = sprintf('%s%04d%s', conf['PORT']['testlogbase'] + base_name + '_' + opts['n'] + '_', 1, '.txt')
416 printf("%s -> %s\n", n1, n2)
417 logfilename = conf['PORT']['testlogbase'] + base_name + '_' + opts['n'] + '.txt'
419 printf("logging to %s", logfilename)
420 $logfile = File.open(logfilename, 'w')
423 $logfile = STDOUT if ! $logfile
427 if opts['s'] && ( m = opts['s'].match(/([\d]+)\.([\d]+)/) )
435 f = File.open(opts['f'], "r")
437 ok,fail = process_file(f,sk,sv)
438 printf("\nOK: %d FAIL: %d :-%s\n",ok,fail, fail==0 ? ')':'(')