Mailing List Archive: 49091 messages
  • Home
  • Script library
  • AltME Archive
  • Mailing list
  • Articles Index
  • Site search
 

[REBOL] rsa for core

From: tomc::darkwing::uoregon::edu at: 13-Apr-2001 11:53

Hi List, I'm dumping this on the list because I need to get back to working on my school work, and if if someone else is playing with maybe I won't have to. if you make wonderful improvments please forward them on. Carl & RT If you want to include this somewhere talk to me about your plans for educational licences first. -- Attached file included as plaintext by Listar -- -- File: rsa.r -- Desc: rsa.r rebol [ Title: "Core RSA" File: %rsa.r Author: "Tom Conlin" Date: [2001-Feb-08 2001-Apr-13] Email: [tomc--acm--org] Purpose: {mainly to keep me sane while finishing my arts&letters requirements also because I want rebol to be able to handle big numbers. Hopefully this will generate some interest in a multiple-pricision math libary for rebol and I wont have to implement it all myself. } notes: { this started out as a multiple-precision libary the basic math functions all had a /base refinement so that any 0 < base > 2^31 could be used. I decided to hardcode the base to 24 bits for this implementation (hence the b24b- names) negative numbers could be implemented by having the first "digit" in a block be signed. } Example: {
>> do %rsa.r >> bobs-keys: rsa-generate-keys 2
P: 7261841 16111233 Q: [ 13873587 12066569 ] N: [ 6005036 15379644 5820230 5646729 ] N': [ 6005036 15379643 1462016 11023360 ] E: [ 15253178 4110405 ] (N',E) -> 1 4971765 1843430 13129528 10357389 [[encode common][decode commom]] == [["6L66PrhF" "W6Es6qy8WM9GVimJ"]["S9z1HCDmyFc4ngqN W6Es6qy8WM9GVimJ"]]
>> bobs-public-key: bobs-keys/1
== ["6L66PrhF" "W6Es6qy8WM9GVimJ"]
>> bobs-private-key: bobs-keys/2
== ["S9z1HCDmyFc4ngqN W6Es6qy8WM9GVimJ"]
>> alice-says: "my cc number is 1234567890"
== "my cc number is 1234567890"
>> chucky-sees: rsa-encipher-message alice-says bobs-public-key
== "QJtjaTA2gcFFx+SxChiWeuElGpRA8KraGp0zeF79766jCDqx"
>> bob-reads: rsa-decipher-message chucky-sees bobs-private-key
== "my cc number is 1234567890"
>>
} ] b64-b24b: func [ "convert a base64 encoded string into a block of (unsigned) 24bit integers" s [string!] /local a b c d x result ] [ result: copy [] a: none b: none c: none d: none foreach [a b c d] s [ append result to-integer debase rejoin [a b c d] a: none b: none c: none d: none ] result ] a24b-b64: func [ {convert a single unsigned 24bit integer into it's 4-char base64 string-representation intended to be used by b24b-b64} n [integer!] /local a b c d x result base64 ] [ if n < 256 [return enbase to-string to-char n] base64: {ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=} either n < 65536 [b: to-integer ((n and 15) * 4) + 1 c: to-integer ((n and 1008) / 16) + 1 d: to-integer ((n and 64512) / 1024) + 1 a: 65 ] [x: n a: ((x and 63) + 1) x: to-integer (x / 64) b: ((x and 63) + 1) x: to-integer (x / 64) c: ((x and 63) + 1) x: to-integer (x / 64) d: ((x and 63) + 1) ] result: rejoin [base64/:d base64/:c base64/:b base64/:a] ] b24b-b64: func [ {convert a block of 24bit integers into a string of base64 chars, needs a24b-b64} blk [block!] /local b result ] [ result: copy "" foreach b blk [append result a24b-b64 b] result ] {Is one block (of positive integers) greater-than, less-than or equal-to another block head is most significant place value -- tail least significant place value} b24b-compare: func ["return 1|0|-1 for u greater|equal|less than v" u [block!] v [block!] /local x y ] [ while [all [(zero? (pick u 1)) ((length? u) > 1)]] [remove u] while [all [(zero? (pick v 1)) ((length? v) > 1)]] [remove v] ; clean-up either (length? u) < (length? v) [-1] ; u has fewer significant digits than v [either (length? v) < (length? u) [1] ; v has fewer significant digits than u [;u & v have the same number of significant digits x: u y: v while [not tail? x] [either equal? (pick x 1) (pick y 1) [ x: next x y: next y ] [either (pick x 1) > (pick y 1) [return 1] [return -1] ] ] return 0 ; u == v ] ] ] ; I am ordering most significant place at head of block ; least significant place at tail of block b24b-add: func ["place-wise addition of two blocks of 24bit integers" u [block!] v [block!] /local b result w x y carry ] [ b: 16777216 ; == ((2^24)) either (length? u) < (length? v) [x: tail v y: tail u] [x: tail u y: tail v] result: copy make block! (length? head x) + 1 carry: 0 while [not head? y] [ x: back x y: back y w: (pick x 1) + (pick y 1) + carry carry: to-integer (w / b) insert result (w // b) ] while [not head? x] [ x: back x w: (pick x 1) + carry carry: to-integer (w / b) insert result (w // b) ] if carry > 0 [insert result carry] result ] ; specialized add with fewer tests than adding two possibaly different numbers b24b-double: func ["doubling a block of 24bit integers" u [block!] /local b result w x y carry ] [ b: 16777216 ; == ((2^24)) x: tail u result: copy [] carry: 0 while [not head? x] [ x: back x w: (pick x 1) + (pick x 1) + carry carry: to-integer (w / b) insert result (w // b) ] if carry > 0 [insert result carry] :result ] ;returns the absolute difference-- b24b-minus: func ["keep first argument not-less-than second argument." u [block!] v [block!] /local result t w x y z b ] [ b: 16777216 ; == ((2^24)) w: b24b-compare u v if zero? w [return [0]] result: copy [] either negative? w [t: copy/deep v x: tail t y: tail u print "NEGATIVE WARNING!!!" ] [t: copy/deep u x: tail t y: tail v ] while [not head? y] [ x: back x ; y: back y ; z: back x ; carry column w: ((pick x 1) - (pick y 1)) if negative? w [ w: (w + 16777216) if zero? (pick z 1) [ change z b z: back z while [zero? (pick z 1)] [change z (b - 1) z: back z] change z ((pick z 1) - 1) z: back x ] change z ((pick z 1) - 1) ] insert result w ] while [not head? x] [ x: back x insert result (pick x 1) ] while [all [(zero? (pick result 1)) ((length? result) > 1)]] [remove result] result ] b24b-mod: func [ {while first arg greater-than or equal-to the second arg; subtract second from first} u [block!] m [block!] /local result ] [; strip leading zeros while [all [(zero? (pick u 1)) ((length? u) > 1)]] [remove u] while [all [(zero? (pick m 1)) ((length? m) > 1)]] [remove m] result: copy/deep u if equal? m [0] [return result] while [not negative? b24b-compare result m] [result: b24b-minus result m] result ] b24b-add-mod: func ["(u+v) mod m" u [block!] v [block!] m [block!] /local x y result ] [ x: b24b-mod u m y: b24b-mod v m result: b24b-add x y result: b24b-mod result m ] b24b-double-mod: func ["(u+u) mod m" u [block!] m [block!] /local x result ] [ x: b24b-mod u m result: b24b-double x result: b24b-mod result m ] ; I have not seen this anywhere before (i.e. in Knuth) but it works ; reduces a positive integer (base < 2^31) to half its original magnitude ; (rounding down) b24b-half: func ["returns floor(u/2) where u is a block of 24bit integers" u [block!] /local result b h x y z carry ] [ b: 16777216 h: 8388608 ; half of base (I think the base may have to be even) result: copy [] x: back tail u insert result to-integer (pick x 1) / 2 while [not head? x] [ x: back x if odd? (pick x 1) [ change result (pick result 1) + h ] insert result to-integer (pick x 1) / 2 ] while [((length? result) > 1) and zero? (pick result 1)] [remove result] result ] ; multiplication via repeated doubling/halfing (Egypt cicra 4000 B.P.)" ; an easy to implement not too quick way to multiply ; note base depends on base used in b24b-add, b24b-double & b24b-half b24b-mult: func ["(u*v)" u [block!] v [block!] /local result x y ] [ x: copy u y: copy v if any [(equal? x [0]) (equal? y [0])] [return [0]] if equal? x [1] [return y] if equal? y [1] [return x] result: [0] while [positive? b24b-compare y [0]] [ if odd? (last y) [result: b24b-add result x] x: b24b-double x y: b24b-half y ] result ] ; multiplication via repeated doubling (Egypt cicra 2000 B.C.) b24b-mult-mod: func ["(u*v) mod m" u [block!] v [block!] m [block!] /local result x y ] [ x: b24b-mod u m y: b24b-mod v m if any [(equal? x [0]) (equal? y [0])] [return [0]] if equal? x [1] [return y] if equal? y [1] [return x] result: [0] while [positive? b24b-compare y [0]] ;y > 0 [if odd? (last y) [result: b24b-add-mod result x m] x: b24b-double-mod x m y: b24b-half y ] result ] ; Itterative power mod function based on Knuth, Vol 2. sec. 4.6.3 b24b-power-mod: func ["(b^e) mod m" b [block!] e [block!] m [block!] /local n y z ] [ n: copy/deep e while [all [(zero? first n) ((length? n) > 1)]] [remove n] ;cleanup input if equal? n [0] [return [1]] ; x^0 = 1 if equal? b [0] [return [0]] ; 0^x = 0 (x <> 0) if equal? n [1] [return copy/deep b] ; x^1 = x (x not 0) y: [1] ; mult identity z: copy/deep b ; wreck a copy while [not equal? n [0]] [ if odd? (last n) [y: b24b-mult-mod y z m] z: b24b-mult-mod z z m n: b24b-half n ] y ] b24b-probable-prime: func [ "return false if the block is composite,true if block may (likely) be prime" q [block!] ] [ equal? [1] b24b-power-mod [2] b24b-minus q [1] q ] ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; This Algorithm is credited to Professor Eugene Luks, University of Oregon. ; Extended Binary GCD with no divisions or negative numbers ; when a > b and a is even and b is odd (relativy prime to 'a actually) . b24b-exbin-gcd: func [a [block!] b [block!] /local c d x y u v t m n acc ] [ ; a few sanity checks important for this rsa implementation only if any [negative? b24b-compare a b even? (last b) odd? (last a)] [return none] c: copy/deep a x: copy/deep a y: b24b-minus b [1] d: copy/deep b u: [1] v: [0] t: copy [] ; a temp for swapping while [d > [0]] [ either even? last c [c: b24b-half c either (even? last x) and (even? last y) [x: b24b-half x y: b24b-half y ] [x: b24b-half (b24b-add x a) y: b24b-half (b24b-add y b) ] if positive? b24b-compare d c [ t: c c: d d: t t: x x: u u: t t: y y: v v: t ] ] [either even? last d [d: b24b-half d either (even? last u) and (even? last v) [u: b24b-half u v: b24b-half v ] [u: b24b-half (b24b-add u a) v: b24b-half (b24b-add v b) ] ] [c: b24b-minus c d either negative? b24b-compare x u [x: b24b-minus (b24b-add x a) u y: b24b-minus (b24b-add y b) v ] [x: b24b-minus x u y: b24b-minus y v ] if positive? b24b-compare d c [ t: c c: d d: t t: x x: u u: t t: y y: v v: t ] ] ] ] t: copy [] append t copy/deep c append t copy/deep x t ] ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; end math begin rsa ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; RSA-generate-keys: func [ len [integer!] "the number of 48-bit groups in the keys" /local p q n com enc dec cd ] [ random/seed now p: make block! len repeat i len [append p to-block (random 16777215)] if even? pick p len [poke p len ((pick p len) - 1)] while [not b24b-probable-prime p] [ for i 1 len 1 [poke p i (random 16777215)] if even? pick p len [poke p len ((pick p len) - 1)] ] print ["P: " p] q: make block! len repeat i len [append q to-block (random 16777215)] if even? pick q len [poke q len ((pick q len) - 1)] while [not b24b-probable-prime q] [ for i 1 len 1 [poke q i (random 16777215)] if even? pick q len [poke q len ((pick q len) - 1)] ] print ["Q: [" q "]"] com: b24b-mult p q print ["N: [" com "]"] n: b24b-mult (b24b-minus p [1]) (b24b-minus q [1]) print ["N': [" n "]"] enc: copy [] repeat i len [append enc to-block (random 16777215)] if even? last enc [poke enc len ((last enc) - 1)] cd: b24b-exbin-gcd n enc while [not equal? cd/1 1] [ for i 1 len 1 [poke enc i (random 16777215)] if even? last enc [poke enc len ((last enc) - 1)] cd: b24b-exbin-gcd n enc ] print ["E: [" enc "]"] print ["(N',E) -> " cd] print "[[public common][private commom]]" enc: b24b-b64 enc dec: b24b-b64 remove cd com: b24b-b64 com reduce [reduce [enc com] reduce [dec com]] ] ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; RSA-encipher-message: func [ plaintext [string!] public-key [block!] ;ek[string!] ck[string!] /local m n c e mp ciphertext ] [ plaintext: enbase plaintext n: (length? public-key/2) - 4 ;pad plaintext till mod n so we won't loose the last bite deciphering?? while[not zero? ((length? plaintext) // n) ][append plaintext "="] c: b64-b24b public-key/2 ; ck e: b64-b24b public-key/1 ; ek m: plaintext ciphertext: copy [] while [not tail? m] [ mp: b64-b24b copy/part m n append ciphertext b24b-power-mod mp e c m: skip m n ] b24b-b64 ciphertext ] ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; RSA-decipher-message: func [ ciphertext [string!] private-key [block!] ;dk[string!] ck[string!] /local n m d c mp plaintext ] [ n: (length? private-key/2) c: b64-b24b private-key/2 ;ck d: b64-b24b private-key/1 ;dk m: ciphertext plaintext: copy [] while [not tail? m] [ mp: b64-b24b copy/part m n append plaintext b24b-power-mod mp d c m: skip m n ] to-string debase b24b-b64 plaintext ] ;end