]> git.cryptolib.org Git - arm-crypto-lib.git/blob - host/rsa_oaep_check.rb
8277c14ac4cee01a7e165ecb8f95445da9fa3dd1
[arm-crypto-lib.git] / host / rsa_oaep_check.rb
1 #!/usr/bin/ruby
2 # nessie_check.rb
3 =begin
4     This file is part of the ARM-Crypto-Lib.
5     Copyright (C) 2008  Daniel Otte (daniel.otte@rub.de)
6
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.
11
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.
16
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/>.
19 =end
20
21 require 'rubygems'
22 require 'serialport'
23 require 'getopt/std'
24
25 $buffer_size = 0 # set automatically in init_system
26 $conffile_check = Hash.new
27 $conffile_check.default = 0
28
29 ################################################################################
30 # readconfigfile                                                               #
31 ################################################################################
32
33 def read_line_from_device()
34   repeat_counter = 10000
35   l = nil
36   s = ''
37   begin
38     l = $sp.gets()
39     repeat_counter -= 1
40   end while !l && repeat_counter > 0
41 #  printf("DBG: << %s\n", l.inspect)
42   return l
43 end
44
45 def readconfigfile(fname, conf)
46   return conf if $conffile_check[fname]==1
47   $conffile_check[fname]=1
48   section = "default"
49   if not File.exists?(fname)
50     return conf
51   end
52   file = File.open(fname, "r")
53   until file.eof
54     line = file.gets()
55           next if /[\s]*#/.match(line)
56         if m=/\[[\s]*([^\s]*)[\s]*\]/.match(line)
57             section=m[1]
58             conf[m[1]] = Hash.new
59             next
60           end
61           next if ! /=/.match(line)
62           m=/[\s]*([^\s]*)[\s]*=[\s]*([^\s]*)/.match(line)
63           if m[1]=="include"
64             Dir.glob(m[2]){ |fn| conf = readconfigfile(fn, conf) }
65           else
66           conf[section][m[1]] = m[2]
67           end
68   end
69   file.close()
70   return conf
71 end
72
73 ################################################################################
74 # reset_system                                                                 #
75 ################################################################################
76
77 def reset_system
78   $sp.print("\r")
79   sleep 0.1
80   $sp.print("\r")
81   sleep 0.1
82   $sp.print("echo off\r")
83   sleep 0.1
84 end
85
86
87 def read_block(f)
88   d = Array.new
89   begin
90     l = f.gets
91     x = l.split.collect { |e| e.to_i(16) }
92     d += x
93   end while x.length == 16
94   return d
95 end
96
97 def goto_next_header(f)
98   while l = f.gets()
99     m = /^#\ (=|-)*[=-]{5}/.match(l)
100     t = :subblock  if m && m[1] == '-'
101     t = :mainblock if m && m[1] == '='
102     if !m && n = /^#\ (.*)$/.match(l)
103       id = n[1]
104       id.sub!(/[\r\n]/,'')
105       return t,id
106     end
107     if !m && !id
108       t = nil
109     end
110   end
111   return nil,nil if !l
112 end
113
114 def skip_file_header(f)
115   while l = f.gets()
116     return if m = /^#\ [=]{40}/.match(l)
117   end
118 end
119
120 def test_parse(f)
121   skip_file_header(f)
122   loop do
123     a,b = goto_next_header(f)
124     if !b
125       puts(">>EOF<<")
126       return
127     end
128     if a
129       printf(">>%sblock: %s\n", a==:mainblock ? "main":"sub", b)
130       next
131     end
132     printf(">item: %s\n", b)
133     d = read_block(f)
134     printf(">length: %d (0x%x)\n>data:", d.length, d.length)
135     i = 0
136     d.each do |e|
137       printf("\n>") if i % 16 == 0
138       printf(" %02x", e)
139       i += 1
140     end
141     puts('')
142   end
143 end
144 =begin
145 >item: RSA modulus n:
146 >item: RSA public exponent e: 
147 >item: RSA private exponent d: 
148 >item: Prime p: 
149 >item: Prime q: 
150 >item: p's CRT exponent dP: 
151 >item: q's CRT exponent dQ: 
152 >item: CRT coefficient qInv: 
153 =end
154
155 def read_key(f)
156   h = Hash.new
157   8.times do
158     q,id = goto_next_header(f)
159     d = read_block(f)    
160     m = /[\ \t]([^\ \t]*):[\ \t]*$/.match(id)
161     if m
162       id = m[1]
163     end
164     h[id] = d
165   end
166   req_items = ['n', 'e', 'd', 'p', 'q', 'dP', 'dQ', 'qInv']
167   req_items.each do |e|
168     printf("ERROR: key component %s is missing!\n", e) if !h[e]
169   end
170   h.each_key do |e|     
171     printf("ERROR: unknown item '%s'!\n", e) if !req_items.index(e)
172   end
173   return h
174 end
175
176 =begin
177 >item: Message to be encrypted:
178 >item: Seed:
179 >item: Encryption:
180 =end
181
182 def read_tv(f)
183   subst_hash = {
184     'Message to be encrypted:' => 'msg',
185     'Seed:' => 'seed',
186     'Encryption:' => 'enc'}
187   h = Hash.new
188   3.times do
189     q,id = goto_next_header(f)
190     d = read_block(f)
191     n = subst_hash[id]
192     printf("ERROR: unknown item '%s'!\n", id) if !n
193     h[n] = d
194   end  
195   req_items = ['msg', 'seed', 'enc']
196   req_items.each do |e|
197     printf("ERROR: testvector component %s is missing!\n", e) if !h[e]
198   end
199   while h['enc'][0] == 0
200     h['enc'].delete_at(0)
201   end 
202   return h
203 end
204
205 def load_bigint(d)
206   $sp.printf("%d\r", d.length)
207   while l = read_line_from_device()
208     break if /data:/.match(l)
209   end
210   printf "ERROR: got no answer from system!" if !l
211   d.each do |e|
212     $sp.printf(" %02x", e)
213   end
214 end
215
216 def load_key(k)
217   $sp.print("load-key\r")
218   sleep 0.1
219   v = ['n', 'e', 'p', 'q', 'dP', 'dQ', 'qInv']  
220   v.each do |e|
221     load_bigint(k[e])
222 #    printf("DBG: loaded %s\n", e)
223   end 
224   while l = read_line_from_device()
225     break if />/.match(l)
226   end
227 end
228
229 def check_tv(tv)
230   sleep 0.1
231   $sp.print("seed-test\r")
232   sleep 0.1
233   load_bigint(tv['msg'])
234 #  printf("DBG: loaded %s\n", 'msg')
235   sleep 0.1
236   tv['seed'].each { |e| $sp.printf(" %02x", e) } 
237   while l = read_line_from_device() 
238     break if /ciphertext:/.match(l)
239   end
240   test_enc = ''
241   loop do 
242     l = read_line_from_device()
243     break if /decrypting/.match(l)
244     test_enc += l if l
245   end
246   test_enc_a = Array.new
247   test_enc = test_enc.split(/[\W\r\n]+/)
248   test_enc.each do |e|
249     v = e.sub(/[^0-9A-Fa-f]/, '') 
250     test_enc_a << v if v.length == 2
251   end
252   test_enc_a.collect!{ |e| e.to_i(16) }
253   enc_ok = (test_enc_a == tv['enc'])
254   if !enc_ok
255     printf("DBG: ref = %s test = %s\n", tv['enc'].inspect , test_enc_a.inspect)
256   end
257   m = nil
258   loop do 
259     l = read_line_from_device() 
260     m = /(>>OK<<|ERROR)/.match(l)
261     break if m
262   end
263   return true if enc_ok && (m[1] == '>>OK<<') 
264   return false
265 end
266
267 def run_test(f)
268   ok = 0
269   fail = 0
270   skip_file_header(f)
271   loop do
272     a,b = goto_next_header(f)
273 #    printf("DBG: a=%s b=%s\n", a.inspect, b.inspect)
274     return ok,fail if !b
275     if a == :mainblock
276 # Example 1: A 1024-bit RSA Key Pair
277       b.sub!(/[\d]+:/) { |s| sprintf("%3d,", s.to_i)} 
278       printf("\n>> %s: ", b)
279     #  (35-b.length).times { putc(' ')}
280     end
281     if a == :subblock
282       if b == 'Components of the RSA Key Pair'
283         k = read_key(f)
284         load_key(k)
285       else
286         tv = read_tv(f)
287         r = check_tv(tv)
288         if r
289           ok += 1
290           putc('*')
291         else
292           fail += 1
293           putc('!')
294         end      
295       end
296     end
297   end
298 end
299
300 ########################################
301 # MAIN
302 ########################################
303
304
305 opts = Getopt::Std.getopts("c:f:")
306
307 conf = Hash.new
308 conf = readconfigfile("/etc/testport.conf", conf)
309 conf = readconfigfile("~/.testport.conf", conf)
310 conf = readconfigfile("testport.conf", conf)
311 conf = readconfigfile(opts["c"], conf) if opts["c"]
312
313 #puts conf.inspect
314
315 puts("serial port interface version: " + SerialPort::VERSION);
316 $linewidth = 64
317 params = { "baud"       => conf["PORT"]["baud"].to_i,
318             "data_bits" => conf["PORT"]["databits"].to_i,
319             "stop_bits" => conf["PORT"]["stopbits"].to_i,
320             "parity"    => SerialPort::NONE }
321 params["paraty"] = SerialPort::ODD   if conf["PORT"]["paraty"].downcase == "odd"
322 params["paraty"] = SerialPort::EVEN  if conf["PORT"]["paraty"].downcase == "even"
323 params["paraty"] = SerialPort::MARK  if conf["PORT"]["paraty"].downcase == "mark"
324 params["paraty"] = SerialPort::SPACE if conf["PORT"]["paraty"].downcase == "space"
325
326 puts("\nPort: "+conf["PORT"]["port"]+"@"    +
327                 params["baud"].to_s      +
328                 " "                      +
329                 params["data_bits"].to_s +
330                 conf["PORT"]["paraty"][0,1].upcase +
331                 params["stop_bits"].to_s +
332                 "\n")
333
334 $sp = SerialPort.new(conf["PORT"]["port"], params)
335
336 $sp.read_timeout=1000; # 5 minutes
337 $sp.flow_control = SerialPort::SOFT
338
339 reset_system()
340
341 f = File.open(opts['f'], "r")
342 exit if !f
343 ok,fail = run_test(f)
344 printf("\nOK: %d FAIL: %d :-%s\n",ok,fail, fail==0 ? ')':'(')
345
346