X-Git-Url: https://git.cryptolib.org/?a=blobdiff_plain;f=host%2Frsaes_pkcs1v15_check.rb;fp=host%2Frsaes_pkcs1v15_check.rb;h=04b995c8c5ab8f97ffb91c61c0324c29a9837322;hb=1cdc772d04bae747c339badaa99f6132eedbcd2f;hp=0000000000000000000000000000000000000000;hpb=e5296441c98c35140f909ca1dbdb8d6852f996d3;p=arm-crypto-lib.git diff --git a/host/rsaes_pkcs1v15_check.rb b/host/rsaes_pkcs1v15_check.rb new file mode 100644 index 0000000..04b995c --- /dev/null +++ b/host/rsaes_pkcs1v15_check.rb @@ -0,0 +1,443 @@ +#!/usr/bin/ruby +# rsaes_pkcs1v15_check.rb +=begin + This file is part of the AVR-Crypto-Lib. + Copyright (C) 2008 Daniel Otte (daniel.otte@rub.de) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +=end + +require 'rubygems' +require 'serialport' +require 'getopt/std' +require 'fileutils' + +$buffer_size = 0 # set automatically in init_system +$conffile_check = Hash.new +$conffile_check.default = 0 +$progress_dots = false +$debug = false +$logfile = nil + +################################################################################ +# readconfigfile # +################################################################################ + +def read_line_from_device() + repeat_counter = 10000 + l = nil + s = '' + begin + l = $sp.gets() + repeat_counter -= 1 + end while !l && repeat_counter > 0 + t = Time.new + $logfile.printf("DBG: (%02d:%02d:%02d)<< %s\n", t.hour, t.min, t.sec, l.inspect) if $debug + if l && l.include?("AVR-Crypto-Lib") + $logfile.printf("DBG: system crashed !!!\n") + exit(false) + end + return l +end + +def readconfigfile(fname, conf) + return conf if $conffile_check[fname]==1 + $conffile_check[fname]=1 + section = "default" + if not File.exists?(fname) + return conf + end + file = File.open(fname, "r") + until file.eof + line = file.gets() + next if /[\s]*#/.match(line) + if m=/\[[\s]*([^\s]*)[\s]*\]/.match(line) + section=m[1] + conf[m[1]] = Hash.new + next + end + next if ! /=/.match(line) + m=/[\s]*([^\s]*)[\s]*=[\s]*([^\s]*)/.match(line) + if m[1]=="include" + Dir.glob(m[2]){ |fn| conf = readconfigfile(fn, conf) } + else + conf[section][m[1]] = m[2] + end + end + file.close() + return conf +end + +################################################################################ +# reset_system # +################################################################################ + +def reset_system + $sp.print("\r") + sleep 0.1 + $sp.print("\r") + sleep 0.1 + $sp.print("echo off\r") + sleep 0.1 +end + + +def read_block(f) + d = Array.new + begin + v = false + l = f.gets + # x = l.split.collect { |e| e.to_i(16) } + t = l.split + t.each { |e| v = true if e.length != 2 } + x = [] + x = t.collect { |e| e.to_i(16) } if ! v + d += x + end while x.length == 16 && ! v + return d +end + +=begin +# Modulus: +# Exponent: +# Modulus: +# Public exponent: +# Exponent: +# Prime 1: +# Prime 2: +# Prime exponent 1: +# Prime exponent 2: +# Coefficient: +# Message: +# Seed: +# Encryption: + +=end + +def get_next_block(f) + ret = Hash.new + data = Array.new + begin + l = f.gets + end while l && ! m= l.match(/^#[\s](.*):[\s]*$/) + return nil if ! l + ret['tag'] = m[1] + ret['line'] = f.lineno + data = read_block(f) + ret['data'] = data + return ret +end + +$key_sequence = [ + 'Modulus', # 0 + 'Exponent', # 1 + 'Modulus', # 2 + 'Public exponent', # 3 + 'Exponent', # 4 + 'Prime 1', # 5 + 'Prime 2', # 6 + 'Prime exponent 1', # 7 + 'Prime exponent 2', # 8 + 'Coefficient', # 9 +] + +def key_consitency_check(k) + return true +end + +def process_file(f, skip_key=1, skip_vec=1) + a = get_next_block(f) + key_no = 0 + ok_counter = 0 + fail_counter = 0 + begin + if !a || ! a['tag'] == 'Modulus' + printf("ERROR: a = %s %d\n", a.inspect, __LINE__) + return + end + k_seq = Array.new + k_seq[0] = a + (1..($key_sequence.length-1)).each do |i| + a = get_next_block(f) + if ! a || a['tag'] != $key_sequence[i] + printf("ERROR: (expecting: %s) a = %s %d\n", $key_sequence[i], a.inspect, __LINE__) + end + k_seq[i] = a + end + key = convert_key(k_seq) + printf("ERROR: %d\n", __LINE__) if ! key + key_no += 1 + vec_no = 0 + printf("\n run %3d: ", key_no) + skip_key_flag = (key_no < skip_key) + load_key(key) if ! skip_key_flag + test_seq = Array.new + a = get_next_block(f) + printf("ERROR: %d\n", __LINE__) if ! a + begin + vec_no += 1 + b = get_next_block(f) + c = get_next_block(f) + tv = Hash.new + tv['msg'] = a['data'] + tv['seed'] = b['data'] + tv['enc'] = c['data'] + skip_vec_flag = (skip_key_flag || (key_no == skip_key && vec_no < skip_vec)) + if skip_vec_flag + printf('o') + else + v = check_tv(tv) + if(v == true) + printf('*') + $logfile.printf("[[Test %2d.%02d = OK]]\n", key_no, vec_no) + ok_counter += 1 + else + printf('%c', v ? '*' : '!') + $logfile.printf("[[Test %2d.%02d = FAIL]]\n", key_no, vec_no) + fail_counter += 1 + end + end + a = get_next_block(f) + end while a && a['tag'] == 'Message' + end while a && a['tag'] = 'Modulus' +# printf("\nResult: %d OK / %d FAIL ==> %s \nFinished\n", ok_counter, fail_counter, fail_counter==0 ? ':-)' : ':-(') + return ok_counter,fail_counter +end + +def convert_key(k_seq) + l = ['n', 'e', 'd', 'p', 'q', 'dP', 'dQ', 'qInv'] + r = Hash.new + return nil if k_seq[0]['data'] != k_seq[2]['data'] + return nil if k_seq[1]['data'] != k_seq[3]['data'] + 8.times do |i| + r[l[i]] = k_seq[2 + i]['data'] + end + return r +end + +def wait_for_dot + begin + s = $sp.gets() + end while !s || !s.include?('.') +end + +def load_bigint(d) + $sp.printf("%d\r", d.length) + while l = read_line_from_device() + break if /data:/.match(l) + end + printf "ERROR: got no answer from system!" if !l + i = 0 + d.each do |e| + $sp.printf("%02x", e) + i += 1 + if i % 60 == 0 +# we should now wait for incomming dot + wait_for_dot() + print('.') if $progress_dots + end + end +end + +def hexdump(a) + i = 0 + a.each do |e| + printf("\n\t") if i % 16 == 0 + printf('%02x ', e) + i += 1 + end + puts('') if i % 16 != 1 +end + +def str_hexdump(a) + i = 0 + s = '' + a.each do |e| + s += "\n\t" if i % 16 == 0 + s += sprintf('%02x ', e) + i += 1 + end + s += "\n" if i % 16 != 1 + return s +end + +def load_key(k) + $sp.print("load-key\r") + sleep 0.1 + v = ['n', 'e', 'p', 'q', 'dP', 'dQ', 'qInv'] + v.each do |e| + load_bigint(k[e]) + $logfile.printf("DBG: loaded %s\n", e) if $debug + end + while l = read_line_from_device() + break if />/.match(l) + end +end + +def strip_leading_zeros(a) + loop do + return [] if a.length == 0 + return a if a[0] != 0 + a.delete_at(0) + end +end + +def check_tv(tv) + sleep 0.1 + $sp.print("seed-test\r") + sleep 0.1 + load_bigint(tv['msg']) + $logfile.printf("DBG: loaded %s\n", 'msg') if $debug + sleep 0.1 + tv['seed'].each { |e| $sp.printf(" %02x", e) } + while l = read_line_from_device() + break if /ciphertext:/.match(l) + end + test_enc = '' + loop do + l = read_line_from_device() + t = l.split + v = false + t.each { |e| v = true if e.length != 2 } + x = t.collect { |e| e.to_i(16) } + break if v + test_enc += l if l + end + test_enc_a = Array.new + test_enc = test_enc.split(/[\W\r\n]+/) + test_enc.each do |e| + v = e.sub(/[^0-9A-Fa-f]/, '') + test_enc_a << v if v.length == 2 + end + test_enc_a.collect!{ |e| e.to_i(16) } + strip_leading_zeros(test_enc_a) + strip_leading_zeros(tv['enc']) + enc_ok = (test_enc_a == tv['enc']) + if !enc_ok + $logfile.printf("DBG: ref = %s test = %s\n", str_hexdump(tv['enc']) , str_hexdump(test_enc_a)) + end + m = nil + loop do + l = read_line_from_device() + m = /(>>OK<<|ERROR)/.match(l) + break if m + end + return true if enc_ok && (m[1] == '>>OK<<') + return false +end + +######################################## +# MAIN +######################################## +help_text = <ruby rsaes_pkcs1v15_check -f [-c ] [-s .] [-n | -l ] + -d enable debugging (logging all received text, not only responses) + -c use as configuration file + -f read testvectors from + -s . start with testvector . + -n log to a file which name is based on + +EOF + +opts = Getopt::Std.getopts('dc:f:l:s:n:') + +if !opts['f'] + print help_text + exit 0 +end + +conf = Hash.new +conf = readconfigfile("/etc/testport.conf", conf) +conf = readconfigfile("~/.testport.conf", conf) +conf = readconfigfile("testport.conf", conf) +conf = readconfigfile(opts["c"], conf) if opts["c"] + +#puts conf.inspect + +puts("serial port interface version: " + SerialPort::VERSION); +$linewidth = 64 +params = { "baud" => conf["PORT"]["baud"].to_i, + "data_bits" => conf["PORT"]["databits"].to_i, + "stop_bits" => conf["PORT"]["stopbits"].to_i, + "parity" => SerialPort::NONE } +params["paraty"] = SerialPort::ODD if conf["PORT"]["paraty"].downcase == "odd" +params["paraty"] = SerialPort::EVEN if conf["PORT"]["paraty"].downcase == "even" +params["paraty"] = SerialPort::MARK if conf["PORT"]["paraty"].downcase == "mark" +params["paraty"] = SerialPort::SPACE if conf["PORT"]["paraty"].downcase == "space" + +puts("\nPort: "+conf["PORT"]["port"]+"@" + + params["baud"].to_s + + " " + + params["data_bits"].to_s + + conf["PORT"]["paraty"][0,1].upcase + + params["stop_bits"].to_s + + "\n") + +$sp = SerialPort.new(conf["PORT"]["port"], params) + +$sp.read_timeout=1000; # 5 minutes +$sp.flow_control = SerialPort::SOFT + +$debug = true if opts['d'] + +if opts['l'] && ! opts['n'] + $logfile = File.open(opts['l'], 'w') +end + +base_name = 'rsaes_pkcs1v15' + +if opts['n'] + logfilename = conf['PORT']['testlogbase'] + base_name + '_' + opts['n'] + '.txt' + if File.exists?(logfilename) + i=1 + begin + logfilename = sprintf('%s%04d%s', conf['PORT']['testlogbase'] + base_name + '_' + opts['n'] + '_',i,'.txt') + i+=1 + end while(File.exists?(logfilename)) + while(i>2) do + n1 = sprintf('%s%04d%s', conf['PORT']['testlogbase'] + base_name + '_' + opts['n'] + '_', i-2, '.txt') + n2 = sprintf('%s%04d%s', conf['PORT']['testlogbase'] + base_name + '_' + opts['n'] + '_', i-1, '.txt') + File.rename(n1, n2) + printf("%s -> %s\n", n1, n2) + i-=1 + end + n1 = sprintf('%s%s', conf['PORT']['testlogbase'], base_name + '_' + opts['n'] + '.txt') + n2 = sprintf('%s%04d%s', conf['PORT']['testlogbase'] + base_name + '_' + opts['n'] + '_', 1, '.txt') + File.rename(n1, n2) + printf("%s -> %s\n", n1, n2) + logfilename = conf['PORT']['testlogbase'] + base_name + '_' + opts['n'] + '.txt' + end + printf("logging to %s", logfilename) + $logfile = File.open(logfilename, 'w') +end + +$logfile = STDOUT if ! $logfile +$logfile.sync = true +reset_system() + +if opts['s'] && ( m = opts['s'].match(/([\d]+)\.([\d]+)/) ) + sk = m[1].to_i + sv = m[2].to_i +else + sk = 1 + sv = 1 +end + +f = File.open(opts['f'], "r") +exit if !f +ok,fail = process_file(f,sk,sv) +printf("\nOK: %d FAIL: %d :-%s\n",ok,fail, fail==0 ? ')':'(') + +