forked from cyanogilvie/crypto
-
Notifications
You must be signed in to change notification settings - Fork 0
/
rsa.tcl
2127 lines (1844 loc) · 67.7 KB
/
rsa.tcl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
# vim: ft=tcl foldmethod=marker foldmarker=<<<,>>> ts=4 shiftwidth=4
# Copyright 2009-2015 Cyan Ogilvie. See license.terms for license.
# Most of the in-line comments are taken directly from the standards documents:
# https://www.inf.pucrs.br/~calazans/graduate/TPVLSI_I/RSA-oaep_spec.pdf and
# rfc3447.
# Those comments are copyright their original authors. The purpuse of
# including them in this source code is to facilitate auditing the code
# against the specification.
# While I have been careful to adhere to the implementation guidelines as
# closely as possible, no cryptographic audit has been performed on this code
# and I make no warrenties as to its correctness or security. You are
# encouraged to examine the code yourself or get a qualified cryptographer to
# audit this code before using it in an application with specific security
# requirements.
#
# In particular it should be noted that key privacy is poor - the limitations
# of working in a scripting language means that the keys could be leaked
# through freed memory, so this code should not be used in any situation where
# an attacker could have access to system memory. Certain timing attacks
# are also probably made more feasible because the script runs more slowly
# than native code, magnifying the effects of taking different branches in
# the code.
# public key asn structure:
#
# ASN1_SEQUENCE_cb(RSAPublicKey, rsa_cb) = {
# ASN1_SIMPLE(RSA, n, BIGNUM),
# ASN1_SIMPLE(RSA, e, BIGNUM),
# }
# private key asn structure:
#
# ASN1_SEQUENCE_cb(RSAPrivateKey, rsa_cb) = {
# ASN1_SIMPLE(RSA, version, LONG),
# ASN1_SIMPLE(RSA, n, BIGNUM),
# ASN1_SIMPLE(RSA, e, BIGNUM),
# ASN1_SIMPLE(RSA, d, BIGNUM),
# ASN1_SIMPLE(RSA, p, BIGNUM),
# ASN1_SIMPLE(RSA, q, BIGNUM),
# ASN1_SIMPLE(RSA, dmp1, BIGNUM),
# ASN1_SIMPLE(RSA, dmq1, BIGNUM),
# ASN1_SIMPLE(RSA, iqmp, BIGNUM)
# }
# Based on http://www.comms.scitech.susx.ac.uk/fft/crypto/rsa-oaep_spec.pdf
namespace eval crypto::rsa {
variable debug 0
# The first 2000 primes <<<
variable smallprimes {
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97
101 103 107 109 113 127 131 137 139 149 151 157 163 167 173 179 181 191
193 197 199 211 223 227 229 233 239 241 251 257 263 269 271 277 281 283
293 307 311 313 317 331 337 347 349 353 359 367 373 379 383 389 397 401
409 419 421 431 433 439 443 449 457 461 463 467 479 487 491 499 503 509
521 523 541 547 557 563 569 571 577 587 593 599 601 607 613 617 619 631
641 643 647 653 659 661 673 677 683 691 701 709 719 727 733 739 743 751
757 761 769 773 787 797 809 811 821 823 827 829 839 853 857 859 863 877
881 883 887 907 911 919 929 937 941 947 953 967 971 977 983 991 997
1009 1013 1019 1021 1031 1033 1039 1049 1051 1061 1063 1069 1087 1091
1093 1097 1103 1109 1117 1123 1129 1151 1153 1163 1171 1181 1187 1193
1201 1213 1217 1223 1229 1231 1237 1249 1259 1277 1279 1283 1289 1291
1297 1301 1303 1307 1319 1321 1327 1361 1367 1373 1381 1399 1409 1423
1427 1429 1433 1439 1447 1451 1453 1459 1471 1481 1483 1487 1489 1493
1499 1511 1523 1531 1543 1549 1553 1559 1567 1571 1579 1583 1597 1601
1607 1609 1613 1619 1621 1627 1637 1657 1663 1667 1669 1693 1697 1699
1709 1721 1723 1733 1741 1747 1753 1759 1777 1783 1787 1789 1801 1811
1823 1831 1847 1861 1867 1871 1873 1877 1879 1889 1901 1907 1913 1931
1933 1949 1951 1973 1979 1987 1993 1997 1999 2003 2011 2017 2027 2029
2039 2053 2063 2069 2081 2083 2087 2089 2099 2111 2113 2129 2131 2137
2141 2143 2153 2161 2179 2203 2207 2213 2221 2237 2239 2243 2251 2267
2269 2273 2281 2287 2293 2297 2309 2311 2333 2339 2341 2347 2351 2357
2371 2377 2381 2383 2389 2393 2399 2411 2417 2423 2437 2441 2447 2459
2467 2473 2477 2503 2521 2531 2539 2543 2549 2551 2557 2579 2591 2593
2609 2617 2621 2633 2647 2657 2659 2663 2671 2677 2683 2687 2689 2693
2699 2707 2711 2713 2719 2729 2731 2741 2749 2753 2767 2777 2789 2791
2797 2801 2803 2819 2833 2837 2843 2851 2857 2861 2879 2887 2897 2903
2909 2917 2927 2939 2953 2957 2963 2969 2971 2999 3001 3011 3019 3023
3037 3041 3049 3061 3067 3079 3083 3089 3109 3119 3121 3137 3163 3167
3169 3181 3187 3191 3203 3209 3217 3221 3229 3251 3253 3257 3259 3271
3299 3301 3307 3313 3319 3323 3329 3331 3343 3347 3359 3361 3371 3373
3389 3391 3407 3413 3433 3449 3457 3461 3463 3467 3469 3491 3499 3511
3517 3527 3529 3533 3539 3541 3547 3557 3559 3571 3581 3583 3593 3607
3613 3617 3623 3631 3637 3643 3659 3671 3673 3677 3691 3697 3701 3709
3719 3727 3733 3739 3761 3767 3769 3779 3793 3797 3803 3821 3823 3833
3847 3851 3853 3863 3877 3881 3889 3907 3911 3917 3919 3923 3929 3931
3943 3947 3967 3989 4001 4003 4007 4013 4019 4021 4027 4049 4051 4057
4073 4079 4091 4093 4099 4111 4127 4129 4133 4139 4153 4157 4159 4177
4201 4211 4217 4219 4229 4231 4241 4243 4253 4259 4261 4271 4273 4283
4289 4297 4327 4337 4339 4349 4357 4363 4373 4391 4397 4409 4421 4423
4441 4447 4451 4457 4463 4481 4483 4493 4507 4513 4517 4519 4523 4547
4549 4561 4567 4583 4591 4597 4603 4621 4637 4639 4643 4649 4651 4657
4663 4673 4679 4691 4703 4721 4723 4729 4733 4751 4759 4783 4787 4789
4793 4799 4801 4813 4817 4831 4861 4871 4877 4889 4903 4909 4919 4931
4933 4937 4943 4951 4957 4967 4969 4973 4987 4993 4999 5003 5009 5011
5021 5023 5039 5051 5059 5077 5081 5087 5099 5101 5107 5113 5119 5147
5153 5167 5171 5179 5189 5197 5209 5227 5231 5233 5237 5261 5273 5279
5281 5297 5303 5309 5323 5333 5347 5351 5381 5387 5393 5399 5407 5413
5417 5419 5431 5437 5441 5443 5449 5471 5477 5479 5483 5501 5503 5507
5519 5521 5527 5531 5557 5563 5569 5573 5581 5591 5623 5639 5641 5647
5651 5653 5657 5659 5669 5683 5689 5693 5701 5711 5717 5737 5741 5743
5749 5779 5783 5791 5801 5807 5813 5821 5827 5839 5843 5849 5851 5857
5861 5867 5869 5879 5881 5897 5903 5923 5927 5939 5953 5981 5987 6007
6011 6029 6037 6043 6047 6053 6067 6073 6079 6089 6091 6101 6113 6121
6131 6133 6143 6151 6163 6173 6197 6199 6203 6211 6217 6221 6229 6247
6257 6263 6269 6271 6277 6287 6299 6301 6311 6317 6323 6329 6337 6343
6353 6359 6361 6367 6373 6379 6389 6397 6421 6427 6449 6451 6469 6473
6481 6491 6521 6529 6547 6551 6553 6563 6569 6571 6577 6581 6599 6607
6619 6637 6653 6659 6661 6673 6679 6689 6691 6701 6703 6709 6719 6733
6737 6761 6763 6779 6781 6791 6793 6803 6823 6827 6829 6833 6841 6857
6863 6869 6871 6883 6899 6907 6911 6917 6947 6949 6959 6961 6967 6971
6977 6983 6991 6997 7001 7013 7019 7027 7039 7043 7057 7069 7079 7103
7109 7121 7127 7129 7151 7159 7177 7187 7193 7207 7211 7213 7219 7229
7237 7243 7247 7253 7283 7297 7307 7309 7321 7331 7333 7349 7351 7369
7393 7411 7417 7433 7451 7457 7459 7477 7481 7487 7489 7499 7507 7517
7523 7529 7537 7541 7547 7549 7559 7561 7573 7577 7583 7589 7591 7603
7607 7621 7639 7643 7649 7669 7673 7681 7687 7691 7699 7703 7717 7723
7727 7741 7753 7757 7759 7789 7793 7817 7823 7829 7841 7853 7867 7873
7877 7879 7883 7901 7907 7919 7927 7933 7937 7949 7951 7963 7993 8009
8011 8017 8039 8053 8059 8069 8081 8087 8089 8093 8101 8111 8117 8123
8147 8161 8167 8171 8179 8191 8209 8219 8221 8231 8233 8237 8243 8263
8269 8273 8287 8291 8293 8297 8311 8317 8329 8353 8363 8369 8377 8387
8389 8419 8423 8429 8431 8443 8447 8461 8467 8501 8513 8521 8527 8537
8539 8543 8563 8573 8581 8597 8599 8609 8623 8627 8629 8641 8647 8663
8669 8677 8681 8689 8693 8699 8707 8713 8719 8731 8737 8741 8747 8753
8761 8779 8783 8803 8807 8819 8821 8831 8837 8839 8849 8861 8863 8867
8887 8893 8923 8929 8933 8941 8951 8963 8969 8971 8999 9001 9007 9011
9013 9029 9041 9043 9049 9059 9067 9091 9103 9109 9127 9133 9137 9151
9157 9161 9173 9181 9187 9199 9203 9209 9221 9227 9239 9241 9257 9277
9281 9283 9293 9311 9319 9323 9337 9341 9343 9349 9371 9377 9391 9397
9403 9413 9419 9421 9431 9433 9437 9439 9461 9463 9467 9473 9479 9491
9497 9511 9521 9533 9539 9547 9551 9587 9601 9613 9619 9623 9629 9631
9643 9649 9661 9677 9679 9689 9697 9719 9721 9733 9739 9743 9749 9767
9769 9781 9787 9791 9803 9811 9817 9829 9833 9839 9851 9857 9859 9871
9883 9887 9901 9907 9923 9929 9931 9941 9949 9967 9973 10007 10009
10037 10039 10061 10067 10069 10079 10091 10093 10099 10103 10111 10133
10139 10141 10151 10159 10163 10169 10177 10181 10193 10211 10223 10243
10247 10253 10259 10267 10271 10273 10289 10301 10303 10313 10321 10331
10333 10337 10343 10357 10369 10391 10399 10427 10429 10433 10453 10457
10459 10463 10477 10487 10499 10501 10513 10529 10531 10559 10567 10589
10597 10601 10607 10613 10627 10631 10639 10651 10657 10663 10667 10687
10691 10709 10711 10723 10729 10733 10739 10753 10771 10781 10789 10799
10831 10837 10847 10853 10859 10861 10867 10883 10889 10891 10903 10909
10937 10939 10949 10957 10973 10979 10987 10993 11003 11027 11047 11057
11059 11069 11071 11083 11087 11093 11113 11117 11119 11131 11149 11159
11161 11171 11173 11177 11197 11213 11239 11243 11251 11257 11261 11273
11279 11287 11299 11311 11317 11321 11329 11351 11353 11369 11383 11393
11399 11411 11423 11437 11443 11447 11467 11471 11483 11489 11491 11497
11503 11519 11527 11549 11551 11579 11587 11593 11597 11617 11621 11633
11657 11677 11681 11689 11699 11701 11717 11719 11731 11743 11777 11779
11783 11789 11801 11807 11813 11821 11827 11831 11833 11839 11863 11867
11887 11897 11903 11909 11923 11927 11933 11939 11941 11953 11959 11969
11971 11981 11987 12007 12011 12037 12041 12043 12049 12071 12073 12097
12101 12107 12109 12113 12119 12143 12149 12157 12161 12163 12197 12203
12211 12227 12239 12241 12251 12253 12263 12269 12277 12281 12289 12301
12323 12329 12343 12347 12373 12377 12379 12391 12401 12409 12413 12421
12433 12437 12451 12457 12473 12479 12487 12491 12497 12503 12511 12517
12527 12539 12541 12547 12553 12569 12577 12583 12589 12601 12611 12613
12619 12637 12641 12647 12653 12659 12671 12689 12697 12703 12713 12721
12739 12743 12757 12763 12781 12791 12799 12809 12821 12823 12829 12841
12853 12889 12893 12899 12907 12911 12917 12919 12923 12941 12953 12959
12967 12973 12979 12983 13001 13003 13007 13009 13033 13037 13043 13049
13063 13093 13099 13103 13109 13121 13127 13147 13151 13159 13163 13171
13177 13183 13187 13217 13219 13229 13241 13249 13259 13267 13291 13297
13309 13313 13327 13331 13337 13339 13367 13381 13397 13399 13411 13417
13421 13441 13451 13457 13463 13469 13477 13487 13499 13513 13523 13537
13553 13567 13577 13591 13597 13613 13619 13627 13633 13649 13669 13679
13681 13687 13691 13693 13697 13709 13711 13721 13723 13729 13751 13757
13759 13763 13781 13789 13799 13807 13829 13831 13841 13859 13873 13877
13879 13883 13901 13903 13907 13913 13921 13931 13933 13963 13967 13997
13999 14009 14011 14029 14033 14051 14057 14071 14081 14083 14087 14107
14143 14149 14153 14159 14173 14177 14197 14207 14221 14243 14249 14251
14281 14293 14303 14321 14323 14327 14341 14347 14369 14387 14389 14401
14407 14411 14419 14423 14431 14437 14447 14449 14461 14479 14489 14503
14519 14533 14537 14543 14549 14551 14557 14561 14563 14591 14593 14621
14627 14629 14633 14639 14653 14657 14669 14683 14699 14713 14717 14723
14731 14737 14741 14747 14753 14759 14767 14771 14779 14783 14797 14813
14821 14827 14831 14843 14851 14867 14869 14879 14887 14891 14897 14923
14929 14939 14947 14951 14957 14969 14983 15013 15017 15031 15053 15061
15073 15077 15083 15091 15101 15107 15121 15131 15137 15139 15149 15161
15173 15187 15193 15199 15217 15227 15233 15241 15259 15263 15269 15271
15277 15287 15289 15299 15307 15313 15319 15329 15331 15349 15359 15361
15373 15377 15383 15391 15401 15413 15427 15439 15443 15451 15461 15467
15473 15493 15497 15511 15527 15541 15551 15559 15569 15581 15583 15601
15607 15619 15629 15641 15643 15647 15649 15661 15667 15671 15679 15683
15727 15731 15733 15737 15739 15749 15761 15767 15773 15787 15791 15797
15803 15809 15817 15823 15859 15877 15881 15887 15889 15901 15907 15913
15919 15923 15937 15959 15971 15973 15991 16001 16007 16033 16057 16061
16063 16067 16069 16073 16087 16091 16097 16103 16111 16127 16139 16141
16183 16187 16189 16193 16217 16223 16229 16231 16249 16253 16267 16273
16301 16319 16333 16339 16349 16361 16363 16369 16381 16411 16417 16421
16427 16433 16447 16451 16453 16477 16481 16487 16493 16519 16529 16547
16553 16561 16567 16573 16603 16607 16619 16631 16633 16649 16651 16657
16661 16673 16691 16693 16699 16703 16729 16741 16747 16759 16763 16787
16811 16823 16829 16831 16843 16871 16879 16883 16889 16901 16903 16921
16927 16931 16937 16943 16963 16979 16981 16987 16993 17011 17021 17027
17029 17033 17041 17047 17053 17077 17093 17099 17107 17117 17123 17137
17159 17167 17183 17189 17191 17203 17207 17209 17231 17239 17257 17291
17293 17299 17317 17321 17327 17333 17341 17351 17359 17377 17383 17387
17389 17393
}
# The first 2000 primes >>>
proc I2OSP {x l} { #<<<
# Integer to Octet String Primative
# Input: x - nonnegative integer to be converted
# l - intended length of the resulting octet string
# Output: X - corresponding octet string of length l
# Throws: integer_too_large
# Looks like the zero-extended big endian representation
if {$x >= 256**$l} {
throw {integer_too_large} "Integer too large"
}
set X ""
for {set i 1} {$i <= $l} {incr i} {
set s [expr {$l - $i}]
set o [binary format c [expr {($x >> ($s<<3)) & 0xff}]]
append X $o
}
return $X
}
#>>>
proc OS2IP {X} { #<<<
# Octet String to Integer Primative
# Input: X - octet string to be converted
# Output: x - corresponding nonnegative integer
set x 0
set s [string length $X]
foreach o [split $X {}] {
incr s -1
binary scan $o cu v
incr x [expr {$v << ($s<<3)}]
}
return $x
}
#>>>
proc EME-OAEP-Encode {M P emLen Hash MGF} { #<<<
# OAEP encode
# Options: Hash - Hash function (hLen denotes the length in
# octets of the hash function output)
# MGF - Mask Generation Function
# Input: M - Message to be encoded, an octet string of
# length at most emLen - 1 - 2blen (mLen
# denotes the length in octets of the message)
# P - encoding parameters, an octet string
# emLen - intended length in octets of the encoded
# message, at least 2hLen + 1)
# Output: EM - Encoded Message, an octet string of length
# emLen
# Throws: message_too_long, parameter_string_too_long
variable debug
# If the length of P is greater than the input limitation for the hash
# function (2⁶¹ − 1 octets for SHA-1) then output "parameter string
# too long" and stop
if {[string length $P] > [apply $Hash input_limit]} {
throw {parameter_string_too_long} "Parameter string to long for hash"
}
# SHA-1 outputs 160 bits or 20 bytes
set hLen [apply $Hash output_len]
# If mLen > emLen − 2hLen − 1, output "message too long" and stop
set mLen [string length $M]
if {$mLen > $emLen - 2*$hLen - 1} {
throw {message_too_long} "Message too long"
}
# Generate an octet string PS consisting of emLen − mLen − 2hLen − 1
# zero octets. The length of PS may be 0
set PS [string repeat \0 [expr {$emLen - $mLen - 2*$hLen - 1}]]
# Let pHash = Hash(P), an octet string of length hLen
set pHash [apply $Hash hash $P]
if {$debug} {
if {$pHash ne [testvec2os pHash]} {
puts stderr "pHash:\n[binary encode hex $pHash]\n[binary encode [testvec2os pHash]]"
}
}
# Concatenate pHash, PS, the message M, and other padding to form a
# data block DB as DB = pHash || PS || 01 || M
set DB ""
append DB $pHash $PS \1 $M
if {$debug} {
if {$DB ne [testvec2os DB]} {
puts stderr "DB mismatch:\n[binary encode hex $DB]\n[binary encode hex $DB]"
}
}
# Generate a random octet string seed of length hLen.
if {$debug} {
set seed [testvec2os seed]
} else {
#set seed [random_bytes $hLen]
set seed [crypto::blowfish::csprng $hLen]
}
#set seed "12345678901234567890"
# Let dbMask = MGF(seed, emLen − hLen)
set dbMask [apply $MGF $seed [expr {$emLen - $hLen}] $Hash]
if {$debug} {
if {$dbMask ne [testvec2os dbMask]} {
puts "dbMask mismatch:\n[binary encode hex $dbMask]\n[binary encode hex [testvec2os dbMask]]"
}
}
# Let maskedDB = DB ⊕ dbMask
#set maskedDB [expr {$DB ^ $dbMask}]
set maskedDB [xor $DB $dbMask]
# Let seedMask = MGF(maskedDB, hLen)
set seedMask [apply $MGF $maskedDB $hLen $Hash]
# Let maskedSeed = seed ⊕ seedMask
#set maskedSeed [expr {$seed ^ $seedMask}]
set maskedSeed [xor $seed $seedMask]
# Let EM = maskedSeed || maskedDB
set EM ""
append EM $maskedSeed $maskedDB
# Output EM
return $EM
}
#>>>
proc EME-OAEP-Decode {EM P Hash MGF} { #<<<
# OAEP Decode
# Options: Hash - Hash function (hLen denotes the length in
# octets of the hash function output)
# MGF - Mask Generation Function
# Input: EM - Encoded Message, an octet string of length
# at least 2hLen + 1 (emLen denotes the length
# in octets of EM)
# P - encoding parameters, an octet string
# Output: m - recovered message, an octet string of length
# at most emLen - 1 - 2*hLen
# Throws: decoding_error
set hLen [apply $Hash output_len]
set emLen [string length $EM]
# If the length of P is greater than the input limitation for the hash
# function (2⁶¹ − 1 octets for SHA-1) then output "decoding error"
# and stop.
if {[string length $P] > [apply $Hash input_limit]} {
throw {decoding_error} "P is longer than the hash limit"
}
# If emLen < 2hLen + 1, output "decoding error" and stop.
if {$emLen < 2*$hLen + 1} {
throw {decoding_error} "EM is shorter than 2*$hLen + 1"
}
# Let maskedSeed be the first hLen octets of EM and let maskedDB be the
# remaining emLen−hLen octets.
set maskedSeed [string range $EM 0 $hLen-1]
set maskedDB [string range $EM $hLen end]
# Let seedMask = MGF(maskedDB, hLen).
#lset MGF 2 [namespace current]
set seedMask [apply $MGF $maskedDB $hLen $Hash]
# Let seed = maskedSeed ⊕ seedMask.
#set seed [expr {$maskedSeed ^ $seedMask}]
set seed [xor $maskedSeed $seedMask]
# Let dbMask = MGF(seed, emLen − hLen).
set dbMask [apply $MGF $seed [expr {$emLen - $hLen}] $Hash]
# Let DB = maskedDB ⊕ dbMask.
#set DB [expr {$maskedDB ^ $dbMask}]
set DB [xor $maskedDB $dbMask]
# Let pHash = Hash(P), an octet string of length hLen.
set pHash [apply $Hash hash $P]
# Separate DB into an octet string pHash’ consisting of the first hLen
# octets of DB , a (possibly empty) octet string P S consisting of
# consecutive zero octets following pHash’, and a message M as
# DB = pHash’ || PS || 01 || M
# If there is no 01 octet to separate PS from M, output "decoding
# error" and stop.
set pHash' [string range $DB 0 $hLen-1]
set marker [string first \1 $DB $hLen]
if {$marker == -1} {
throw {decoding_error} "No 0x01 marker between PS and M"
}
set PS [string range $DB $hLen $marker-1]
set M [string range $DB $marker+1 end]
# If pHash’ does not equal pHash, output "decoding error" and stop.
if {$pHash ne ${pHash'}} {
throw {decoding_error} "Hash mismatch"
}
# Output M.
return $M
}
#>>>
proc EMSA-PKCS1-V1_5-ENCODE {M emLen Hash} { #<<<
# Implementation of section 9.2 of rfc3447
#
# Options: Hash - Hash function (hLen denotes the length in
# octets of the hash function output)
# Input: M - Message to be encoded
# emLen - Intended length in octets of the encoded
# message, at least tLen + 11, where tLen is
# the octet length of the DER encoding T of a
# certain value computed during the encoding
# operation
# Output: EM - Encoded message, an octet string of length
# emLen
# Throws: message_too_long, emLen_too_short, padding_too_short
set hLen [apply $Hash output_len]
# Apply the hash function to the message M to produce a hash value H:
# H = Hash(M).
#
# If the hash function outputs "message too long," output "message
# too long" and stop.
set H [apply $Hash hash $M]
# Encode the algorithm ID for the hash function and the hash value
# into an ASN.1 value of type DigestInfo (see Appendix A.2.4) with
# the Distinguished Encoding Rules (DER), where the type DigestInfo
# has the syntax
#
# DigestInfo ::= SEQUENCE {
# digestAlgorithm AlgorithmIdentifier,
# digest OCTET STRING
# }
#
# The first field identifies the hash function and the second
# contains the hash value. Let T be the DER encoding of the
# DigestInfo value (see the notes below) and let tLen be the length
# in octets of T.
set T [asn::asnSequence \
[apply $Hash AlgorithmIdentifier] \
[::asn::asnOctetString $H] \
]
#set T [apply $Hash DigestInfoPrefix]$H
set tLen [string length $T]
# If emLen < tLen + 11, output "intended encoded message length too
# short" and stop.
if {$emLen < $tLen + 11} {
throw emLen_too_short "intended encoded message length too short"
}
# Generate an octet string PS consisting of emLen - tLen - 3 octets
# with hexadecimal value 0xff. The length of PS will be at least 8
# octets.
set PS [string repeat \xff [expr {$emLen - $tLen - 3}]]
if {[string length $PS] < 8} {
# This check is reduntant given the emLen_too_short check
throw padding_too_short "padding must be at least 8 octents, is: [string length $PS]"
}
# Concatenate PS, the DER encoding T, and other padding to form the
# encoded message EM as
#
# EM = 0x00 || 0x01 || PS || 0x00 || T.
set EM ""
append EM \0 \1 $PS \0 $T
# Output EM.
set EM
}
#>>>
proc xor {a b} { #<<<
binary scan $a cu* abytes
binary scan $b cu* bbytes
if {[string length $a] != [string length $b]} {
error "xor a and b are different lengths: a([string length $a]) b([string length $b])"
}
set res {}
foreach abyte $abytes bbyte $bbytes {
if {$abyte eq ""} {set abyte 0}
if {$bbyte eq ""} {set bbyte 0}
lappend res [expr {$abyte ^ $bbyte}]
}
binary format c* $res
}
#>>>
variable MGF [list {Z l Hash} { #<<<
# Mask Generation Function
# Options: Hash - hash function (hLen denotes the length in
# octets of the hash function output)
# Input: Z - seed from which mask is generated, an
# octet string
# l - intended length in octets of the mask, at
# most 2³² * hLen
# Output: mask - mask, an octet string of length l
# Throws: mask_too_long
set hLen [apply $Hash output_len]
# If l > 2³² * hLen, output "mask too long" and stop
if {$l > 2**32 * $hLen} {
throw {mask_too_long} "Mask longer than 2**32 * hLen"
}
# Let T be the empty octet string
set T ""
set Z $Z
# For i = 0 to l/hLen − 1, do
for {set i 0} {$i < int(ceil($l / double($hLen)))} {incr i} {
# Convert i to an octet string C of length 4 with the primitive
# I2OSP:
# C = I2OSP(i, 4)
set C [I2OSP $i 4]
#set C [binary format I $i]
# Concatenate the hash of the seed Z and C to the octet string T:
# T = T || Hash(Z || C)
append T [apply $Hash hash $Z$C]
#set h [apply $Hash hash $Z$C]
#append T $h
}
# Output the leading l octets of T as the octet string mask
return [string range $T 0 $l-1]
} [namespace current]]
#>>>
proc modexp {b e n} { #<<<
set r 1
while {1} {
if {$e & 1} {
set r [expr {($r * $b) % $n}]
}
set e [expr {$e >> 1}]
if {$e == 0} break
set b [expr {($b ** 2) % $n}]
}
return $r
}
#>>>
proc RSAEP {n e m} { #<<<
# RSA public key encryption
# Input: n - RSA public key (modulus)
# e - RSA public key (public exponent)
# m - message representative, an integer between 0 and n-1
# Output: c - ciphertext representative, an integer between
# 0 and n-1
# Throws: message_representative_out_of_range
# Assumptions:
# - public key (n, e) is valid
# If the message representative m is not between 0 and n − 1, output
# "message representative out of range" and stop
if {$m < 0 || $m > $n-1} {
throw {message_representative_out_of_range} \
"Message representative out of range"
}
# Let c = m**e % n
#set c [expr {$m**$e % $n}]
set c [modexp $m $e $n]
# Output c
return $c
}
#>>>
proc RSADP {K c} { #<<<
# RSA private key decryption
# Input: K - RSA private key, in one of the following forms:
# a list of (n, d)
# a list of (p, q, dP, dQ, qInv)
# where:
# n - modulus
# d - private exponent
# p - first prime factor of n
# q - second prime factor of n
# dP - p's exponent
# dQ - q's exponent
# qInv - Chinese Remainder Theorem coefficient
# c - ciphertext representative, an integer between
# 0 and n-1
# Output: m - message representative, an integer between 0 and n-1
# Throws: ciphertext_representative_out_of_range
# Assumptions:
# - private key K is valid
# If the first form (n, d) of K is used:
if {[llength $K] == 2} {
lassign $K n d
# If the ciphertext representative c is not between 0 and n − 1,
# output "ciphertext representative out of range" and stop
if {$c < 0 || $c > $n+1} {
throw {ciphertext_representative_out_of_range} \
"Ciphertext representative out of range"
}
# Let m = c**d % n
#set m [expr {$c**$d % $n}]
set m [modexp $c $d $n]
} else {
# Else, if the second form (p, q, dP, dQ, qInv) of K is used:
lassign $K p q dP dQ qInv
set n [expr {$p * $q}]
# If the ciphertext representative c is not between 0 and n − 1,
# output "ciphertext representative out of range" and stop
if {$c < 0 || $c > $n-1} {
throw {ciphertext_representative_out_of_range} \
"Ciphertext representative out of range"
}
# Let m1 = c**dP % p
#set m1 [expr {$c**$dP % $p}]
set m1 [modexp $c $dP $p]
# Let m2 = c**dQ % q
#set m2 [expr {$c**$dQ % $q}]
set m2 [modexp $c $dQ $q]
# Let h = (m1 - m2) * qInv % p
set h [expr {($m1 - $m2) * $qInv % $p}]
# Let m = m2 + q * h
set m [expr {$m2 + $q * $h}]
}
# Output m
return $m
}
#>>>
proc RSASP {n d m} { #<<<
# RSA private key decryption
# Input: n - modulus
# d - private exponent
# m - message representative, an integer between
# 0 and n-1
# Output: s - ciphertext representative, an integer between
# 0 and n-1
# Throws: message_representative_out_of_range
# Assumptions:
# - private key (d, n) is valid
# If the message representative c is not between 0 and n − 1,
# output "message representative out of range" and stop
if {$m < 0 || $m > $n-1} {
throw {message_representative_out_of_range} \
"Message representative out of range"
}
# Let s = c**d % n
modexp $m $d $n
}
#>>>
proc RSAVP {n e s} { #<<<
# RSA public key encryption
# Input: n - RSA public key (modulus)
# e - RSA public key (public exponent)
# s - ciphertext representative, an integer between
# 0 and n-1
# Output: m - message representative, an integer between
# 0 and n-1
# Throws: ciphertext_representative_out_of_range
# Assumptions:
# - public key (n, e) is valid
# If the ciphertext representative m is not between 0 and n − 1, output
# "ciphertext representative out of range" and stop
if {$s < 0 || $s > $n-1} {
throw {ciphertext_representative_out_of_range} \
"Ciphertext representative out of range"
}
# Let m = s**e % n
modexp $s $e $n
}
#>>>
proc RSAES-OAEP-Encrypt {n e M P Hash MGF} { #<<<
# RSA Encrypt
# Options: Hash - Hash function
# MGF - Mask Generation Function
# Input: n - recipient's RSA public key (modulus)
# e - recipient's RSA public key (public exponent)
# M - message to be encrypted, an octet string of length
# at most k - 2 - 2hLen, where k is the length in
# octets of the modulus n and hLen is the length in
# octets of the hash function output for EME-OAEP
# P - encoding parameters, an octet string that may be
# empty
# Output: C - ciphertext, an octet string of length k
# Throws: message_too_long
# Assumptions:
# - public key (n, e) is valid
variable debug
set k [expr {int(ceil([bitlength $n] / 8.0))}]
if {$debug} {
if {$M ne [testvec2os M]} {
puts stderr "M doesn't match:\n[binary encode hex $M]\n[binary encode hex [testvec2os M]]"
}
}
# 1. Apply the EME-OAEP encoding operation to the message M and the
# encoding parameters P to produce an encoded message EM of length
# k − 1 octets:
# EM = EME-OAEP-Encode(M, P, k − 1)
# If the encoding operation outputs "message too long", then output
# "message too long" and stop
set EM [EME-OAEP-Encode $M $P [expr {$k - 1}] $Hash $MGF]
if {$debug} {
if {$EM ne [testvec2os EM]} {
puts stderr "EM doesn't match:\n[binary encode hex $EM]\n[binary encode hex [testvec2os EM]]"
}
}
# 2. Convert the encoded message EM to an integer message
# representative m:
# m = OS2IP(EM)
set m [OS2IP $EM]
# 3. Apply the RSAEP encryption primitive to the public key (n, e) and
# the message representative m to produce an integer ciphertext
# representative c:
# c = RSAEP((n, e), m)
set c [RSAEP $n $e $m]
# 4. Convert the ciphertext representative c to a ciphertext C of
# length k octets:
# C = I2OSP(c, k)
set C [I2OSP $c $k]
# 5. Output the ciphertext C
return $C
}
#>>>
proc RSAES-OAEP-Decrypt {K C P Hash MGF} { #<<<
# RSA Decrypt
# Options: Hash - Hash function used for EME-OAEP
# MGF - Mask Generation Function used for EME-OAEP
# Input: K - recipient's RSA private key, in one of the
# forms described for RSADP
# C - ciphertext to be decrypted, an octet string
# of length k, where k is the length in octets
# of the modulus n
# P - encoding parameters, an octet string that may
# be empty
# Output: M - message, an octet string of length at most
# k - 2 - 2*hLen, where hLen is the length in
# octets of the hash function output for
# EME-OAEP
# Throws: decryption_error
# Assumptions:
# - private key K is valid
if {[llength $K] == 2} {
lassign $K n d
} else {
lassign $K p q dP dQ qInv
set n [expr {$p * $q}]
}
set k [expr {int(ceil([bitlength $n]/8.0))}]
# 1. If the length of the ciphertext C is not k octets, output
# "decryption error" and stop
if {[string length $C] != $k} {
throw {decryption_error} "Ciphertext length is invalid"
}
# 2. Convert the ciphertext C to an integer ciphertext representative c
# c = OS2IP(C)
set c [OS2IP $C]
# 3. Apply the RSADP decryption primitive to the private key K and the
# ciphertext representative c to produce an integer message
# representative m:
# m = RSADP(K, c)
# If RSADP outputs "ciphertext representative out of range", then
# output "decryption error" and stop
try {
set m [RSADP $K $c]
} trap {ciphertext_representative_out_of_range} {} {
throw {decryption_error} "Ciphertext is out of range"
}
# Remark:
# It is important that the errors in steps 4 and 5 are
# indistinguishable, otherwise an adversary may be able to extract
# useful information from the type of error occurred. In particular,
# the error messages in steps 4 and 5 must be identical. Moreover, the
# execution time of the decryption operation must not reveal whether an
# error has occurred. One way of achieving this is as follows: In case
# of error in step 4, proceed to step 5 with EM set to a string of zero
# octets.
# 4. Convert the message representative m to an encoded message EM of
# length k − 1 octets
# EM = I2OSP(m, k − 1)
# If I2OSP outputs "integer too large", then output "decryption error"
# and stop
try {
set EM [I2OSP $m [expr {$k - 1}]]
} trap {integer_too_large} {} {
set EM [string repeat \0 [expr {$k - 1}]]
}
# 5. Apply the EME-OAEP decoding operation to the encoded message EM
# and the encoding parameters P to recover a message M:
# M = EME-OAEP-Decode(EM, P)
# If the decoding operation outputs "decoding error", then output
# "decryption error" and stop
try {
set M [EME-OAEP-Decode $EM $P $Hash $MGF]
} trap {decoding_error} {} {
throw {decryption_error} "Decryption error"
}
# Output the message M
return $M
}
#>>>
proc RSAES-OAEP-Sign {n d M P Hash MGF} { #<<<
# RSA Encrypt
# Options: Hash - Hash function
# MGF - Mask Generation Function
# Input: n - our RSA private key (modulus)
# d - our RSA private key (private exponent)
# M - message to be encrypted, an octet string of length
# at most k - 2 - 2hLen, where k is the length in
# octets of the modulus n and hLen is the length in
# octets of the hash function output for EME-OAEP
# P - encoding parameters, an octet string that may be
# empty
# Output: C - ciphertext, an octet string of length k
# Throws: message_too_long
# Assumptions:
# - public key (n, e) is valid
variable debug
set k [expr {int(ceil([bitlength $n] / 8.0))}]
if {$debug} {
if {$M ne [testvec2os M]} {
puts stderr "M doesn't match:\n[binary encode hex $M]\n[binary encode hex [testvec2os M]]"
}
}
# 1. Apply the EME-OAEP encoding operation to the message M and the
# encoding parameters P to produce an encoded message EM of length
# k − 1 octets:
# EM = EME-OAEP-Encode(M, P, k − 1)
# If the encoding operation outputs "message too long", then output
# "message too long" and stop
set EM [EME-OAEP-Encode $M $P [expr {$k - 1}] $Hash $MGF]
if {$debug} {
if {$EM ne [testvec2os EM]} {
puts stderr "EM doesn't match:\n[binary encode hex $EM]\n[binary encode hex [testvec2os EM]]"
}
}
# 2. Convert the encoded message EM to an integer message
# representative m:
# m = OS2IP(EM)
set m [OS2IP $EM]
# 3. Apply the RSAEP encryption primitive to the public key (n, e) and
# the message representative m to produce an integer ciphertext
# representative c:
# c = RSASP((n, d), m)
set c [RSASP $n $d $m]
# 4. Convert the ciphertext representative c to a ciphertext C of
# length k octets:
# C = I2OSP(c, k)
set C [I2OSP $c $k]
# 5. Output the ciphertext C
return $C
}
#>>>
proc RSAES-OAEP-Verify {n e C P Hash MGF} { #<<<
# RSA Decrypt
# Options: Hash - Hash function used for EME-OAEP
# MGF - Mask Generation Function used for EME-OAEP
# Input: e - sender's RSA public key, public exponent
# n - sender's RSA public key, modulus
# C - ciphertext to be decrypted, an octet string
# of length k, where k is the length in octets
# of the modulus n
# P - encoding parameters, an octet string that may
# be empty
# Output: M - message, an octet string of length at most
# k - 2 - 2*hLen, where hLen is the length in
# octets of the hash function output for
# EME-OAEP
# Throws: decryption_error
# Assumptions:
# - private key K is valid
set k [expr {int(ceil([bitlength $n]/8.0))}]
# 1. If the length of the ciphertext C is not k octets, output
# "decryption error" and stop
if {[string length $C] != $k} {
throw {decryption_error} "Ciphertext length is invalid"
}
# 2. Convert the ciphertext C to an integer ciphertext representative c
# c = OS2IP(C)
set c [OS2IP $C]
# 3. Apply the RSADP decryption primitive to the private key K and the
# ciphertext representative c to produce an integer message
# representative m:
# m = RSAVP(n, e, c)
# If RSADP outputs "ciphertext representative out of range", then
# output "decryption error" and stop
try {
set m [RSAVP $n $e $c]
} trap {ciphertext_representative_out_of_range} {} {
throw {decryption_error} "Ciphertext is out of range"
}
# Remark:
# It is important that the errors in steps 4 and 5 are
# indistinguishable, otherwise an adversary may be able to extract
# useful information from the type of error occurred. In particular,
# the error messages in steps 4 and 5 must be identical. Moreover, the
# execution time of the decryption operation must not reveal whether an
# error has occurred. One way of achieving this is as follows: In case
# of error in step 4, proceed to step 5 with EM set to a string of zero
# octets.
# 4. Convert the message representative m to an encoded message EM of
# length k − 1 octets
# EM = I2OSP(m, k − 1)
# If I2OSP outputs "integer too large", then output "decryption error"
# and stop
try {
set EM [I2OSP $m [expr {$k - 1}]]
} trap {integer_too_large} {} {
set EM [string repeat \0 [expr {$k - 1}]]
}
# 5. Apply the EME-OAEP decoding operation to the encoded message EM
# and the encoding parameters P to recover a message M:
# M = EME-OAEP-Decode(EM, P)
# If the decoding operation outputs "decoding error", then output
# "decryption error" and stop
try {
set M [EME-OAEP-Decode $EM $P $Hash $MGF]
} trap {decoding_error} {} {
throw {decryption_error} "Decryption error"
}
# Output the message M
return $M
}
#>>>
proc RSASSA-PKCS1-V1_5-SIGN {K M Hash} { #<<<
# Implementation of section 8.2.1 of rfc3447
#
# Input: K - Signer's RSA private key
# M - Message to be signed, an octet string
# Output: S - Signature, an octet string of length k, where k
# is the length in octets of the RSA modulus n
# Throws: message_too_long, RSA_modulus_too_short
# Assumptions: