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: [EMAIL PROTECTED]
        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

-- 
To unsubscribe from this list, please send an email to
[EMAIL PROTECTED] with "unsubscribe" in the 
subject, without the quotes.

Reply via email to