| |
| /pliant/util/crypto/rsa.pli |
| |
| 1 |
abstract | |
| 2 |
[This is Pliant (Rivest-Shamir-Adelman) RSA implementation.] ; eol | |
| 3 |
| |
| 4 |
doc | |
| 5 |
para | |
| 6 |
[The RSA key is encoded in a string, using the three 'rsa' letters followed by a space, then the 'n' base64 encoded number followed by another space, and finally the 'e' or 'd' base64 encoded number. ] | |
| 7 |
[When we say base64 encoded number, we mean the bits representing it, in low indan order, encoded through the well known ] ; link "base64" "/pliant/util/encoding/base64.pli" ; [ encoding standard.] ; eol | |
| 8 |
para | |
| 9 |
[The RSA algorithm was patended in the US, but the patent is now expired.] | |
| 10 |
| |
| 11 |
| |
| 12 |
module "/pliant/language/unsafe.pli" | |
| 13 |
module "/pliant/language/context.pli" | |
| 14 |
module "/pliant/util/encoding/base64.pli" | |
| 15 |
module "/pliant/language/type/text/str8.pli" | |
| 16 |
module "/pliant/language/type/misc/blob.pli" | |
| 17 |
module "/pliant/admin/md5.pli" | |
| 18 |
module "intn.pli" | |
| 19 |
module "random.pli" | |
| 20 |
module "/pliant/fullpliant/user.pli" | |
| 21 |
module "/pliant/protocol/dns/name.pli" | |
| 22 |
module "/pliant/protocol/http/site.pli" | |
| 23 |
module "cipher.pli" | |
| 24 |
| |
| 25 |
constant mp processor_count>1 | |
| 26 |
constant trace false | |
| 27 |
constant verbose false | |
| 28 |
constant wait true | |
| 29 |
| |
| 30 |
doc | |
| 31 |
listing | |
| 32 |
function rsa_nbbits key -> bits | |
| 33 |
arg Str key ; arg Int bits | |
| 34 |
[What is the size of the RSA key.] ; eol | |
| 35 |
| |
| 36 |
function rsa_nbbits key -> bits | |
| 37 |
arg Str key ; arg Int bits | |
| 38 |
if (key parse word:"rsa" _ any:(var Str encoded_n) _ any:(var Str encoded_e_or_d)) | |
| 39 |
(var Intn n) binary_decode base64_decode:encoded_n true | |
| 40 |
bits := n:nbbits | |
| 41 |
else | |
| 42 |
bits := undefined | |
| 43 |
| |
| 44 |
doc | |
| 45 |
listing | |
| 46 |
function rsa_cipher input key -> output | |
| 47 |
arg Str input key output | |
| 48 |
[Applys the RSA key.] | |
| 49 |
[The 'input' and 'output' string are binary encoded numbers.] ; eol | |
| 50 |
| |
| 51 |
function rsa_cipher input key -> output | |
| 52 |
arg Str input key output | |
| 53 |
if not (key parse word:"rsa" _ any:(var Str encoded_n) _ any:(var Str encoded_e_or_d)) | |
| 54 |
return "" | |
| 55 |
(var Intn n) binary_decode base64_decode:encoded_n true | |
| 56 |
if verbose | |
| 57 |
console "(message " input:len*8 " bis ; rsa key " rsa_nbbits:key " bits " | |
| 58 |
var DateTime start := datetime | |
| 59 |
if trace | |
| 60 |
console "n=" n eol | |
| 61 |
(var Intn e_or_d) binary_decode base64_decode:encoded_e_or_d true | |
| 62 |
if trace | |
| 63 |
console "e_or_d=" e_or_d eol | |
| 64 |
(var Intn in) binary_decode input true | |
| 65 |
if trace | |
| 66 |
console "in=" in eol | |
| 67 |
var Intn out := 0 | |
| 68 |
var Intn f := 1 | |
| 69 |
if mp | |
| 70 |
parallel | |
| 71 |
while in<>0 | |
| 72 |
var Intn out_i | |
| 73 |
task | |
| 74 |
share n e_or_d | |
| 75 |
var Intn in_i := in%n | |
| 76 |
out_i := ( in_i^e_or_d%n )*f | |
| 77 |
post | |
| 78 |
share out | |
| 79 |
out := out+out_i | |
| 80 |
f := f*n | |
| 81 |
in := in\n | |
| 82 |
else | |
| 83 |
while in<>0 | |
| 84 |
var Intn in_i := in%n | |
| 85 |
var Intn out_i := in_i^e_or_d%n | |
| 86 |
out := out+out_i*f | |
| 87 |
f := f*n | |
| 88 |
in := in\n | |
| 89 |
if trace | |
| 90 |
console "out=" out eol | |
| 91 |
output := out binary_encode | |
| 92 |
if verbose | |
| 93 |
console "-> time " datetime:seconds-start:seconds "s)" eol | |
| 94 |
if wait | |
| 95 |
sleep 0.25*(datetime:seconds-start:seconds)*(cast random:1000000n Int)/1000000 | |
| 96 |
| |
| 97 |
function rsa_cipher input key -> output | |
| 98 |
arg Blob input ; arg Str key ; arg Blob output | |
| 99 |
addressof:output map Str := rsa_cipher (addressof:input map Str) key | |
| 100 |
| |
| 101 |
doc | |
| 102 |
listing | |
| 103 |
function rsa_generate nbits error_probability public private | |
| 104 |
arg Int nbits ; arg Float error_probability ; arg_w Str public private | |
| 105 |
[Generates a new RSA keys pair.] ; eol | |
| 106 |
['nbits' specify how many bits we want in the two prime numbers that will be used to generate the RSA keys pair.] | |
| 107 |
[The 'error_probability' should be a very small number such as 1e-100. The smaller it is, the slower the algorithm will be.] ; eol | |
| 108 |
| |
| 109 |
function rsa_generate nbits error_probability public private -> status | |
| 110 |
arg Int nbits ; arg Float error_probability ; arg_w Str public private ; arg Status status | |
| 111 |
part generate | |
| 112 |
var Intn p q | |
| 113 |
if mp | |
| 114 |
parallel | |
| 115 |
task | |
| 116 |
share p := prime 2n^(nbits\2) error_probability | |
| 117 |
task | |
| 118 |
share q := prime 2n^(nbits\2) error_probability | |
| 119 |
else | |
| 120 |
p := prime 2n^(nbits\2) error_probability | |
| 121 |
q := prime 2n^(nbits\2) error_probability | |
| 122 |
if trace | |
| 123 |
console "p=" p eol | |
| 124 |
console "q=" q eol | |
| 125 |
var Intn n := p*q | |
| 126 |
if trace | |
| 127 |
console "n=" n " (" n:nbbits ")" eol | |
| 128 |
if n:nbbits<nbits-2 | |
| 129 |
restart generate # the key is too small | |
| 130 |
part pick_e | |
| 131 |
var Intn e := random (p-1)*(q-1) | |
| 132 |
if (pgcd e (p-1)*(q-1))<>1 | |
| 133 |
restart pick_e | |
| 134 |
var Intn d := inverse e (p-1)*(q-1) | |
| 135 |
if trace | |
| 136 |
console "e=" e " (" e:nbbits ")" eol | |
| 137 |
console "d=" d " (" d:nbbits ")" eol | |
| 138 |
public := "rsa "+(base64_encode n:binary_encode)+" "+(base64_encode e:binary_encode) | |
| 139 |
private := "rsa "+(base64_encode n:binary_encode)+" "+(base64_encode d:binary_encode) | |
| 140 |
if trace | |
| 141 |
console "public key is " public " (" rsa_nbbits:public " bits)" eol | |
| 142 |
console "private key is " private " (" rsa_nbbits:private " bits)" eol | |
| 143 |
return success | |
| 144 |
| |
| 145 |
| |
| 146 |
doc | |
| 147 |
listing | |
| 148 |
function rsa_check public private test_message_bits -> status | |
| 149 |
arg Str public private ; arg Int test_message_bits ; arg Status status | |
| 150 |
[Test the RSA pair on a random message.] | |
| 151 |
| |
| 152 |
function rsa_check public private test_message_bits -> status | |
| 153 |
arg Str public private ; arg Int test_message_bits ; arg Status status | |
| 154 |
var Str m := (random_string test_message_bits\8)+"." | |
| 155 |
var Str c := rsa_cipher m public | |
| 156 |
var Str m2 := rsa_cipher c private | |
| 157 |
var Str c := rsa_cipher m private | |
| 158 |
var Str m3 := rsa_cipher c public | |
| 159 |
status := shunt m2=m and m3=m success failure | |
| 160 |
| |
| 161 |
| |
| 162 |
doc | |
| 163 |
listing | |
| 164 |
function rsa_generate username nbits error_probability -> status | |
| 165 |
arg Str username ; arg Int nbits ; arg Float error_probability ; arg Status status | |
| 166 |
[Also generates a new RSA keys pair, but the result is stored in Pliant sites and users database.] ; eol | |
| 167 |
[The Pliant sites and users database are the security:/site.pdb file (usualy /etc/pliant/site.pdb or /pliant_security/site.pdb), security:/site_secret.pdb, security:/user.pdb and security:/user_secret.pdb and they contains the definition of all users Pliant is awared of on this system, including the RSA public and private keys.] ; eol | |
| 168 |
color hsl 0 75 50 | |
| 169 |
[You must keep the security:/site_secret.pdb file very secret because anybody that can read it will also read the RSA private keys it contains, so can get administrator access to all your sites, and you should keep the security:/user_secret.pdb also secret because somebody that can read it will only need to grab users passwords to get their secret keys.] | |
| 170 |
| |
| 171 |
function rsa_generate name nbits password -> status | |
| 172 |
arg Str name ; arg Int nbits ; arg Str password ; arg Status status | |
| 173 |
if verbose | |
| 174 |
console "Now " | |
| 175 |
random 2n^nbits | |
| 176 |
console "generating a " nbits " bits RSA key." eol | |
| 177 |
var DateTime dt := datetime | |
| 178 |
status := rsa_generate nbits 1e-90 (var Str public) (var Str private) | |
| 179 |
if verbose | |
| 180 |
var Float s := datetime:seconds-dt:seconds | |
| 181 |
if status=success | |
| 182 |
status := rsa_check public private 1024 | |
| 183 |
if status=success | |
| 184 |
if (name eparse "user:" any:(var Str username)) | |
| 185 |
user:username public_key := public | |
| 186 |
user_secret_database:data:user create username | |
| 187 |
user_secret_database:data:user:username private_key := straight_to_Str8 (cipher private password) | |
| 188 |
user_secret_database:data:user:username key_md5 := string_md5_hexa_signature private | |
| 189 |
data_reset user_secret_database:data:user:username:session | |
| 190 |
user_database store | |
| 191 |
user_secret_database store | |
| 192 |
eif (name eparse "host:" any:(var Str hostname)) | |
| 193 |
name_database:data:host create hostname | |
| 194 |
name_database:data:host:hostname public_key := public | |
| 195 |
name_secret_database:data:host create hostname | |
| 196 |
name_secret_database:data:host:hostname private_key := private | |
| 197 |
data_reset name_secret_database:data:host:hostname:session | |
| 198 |
name_database store | |
| 199 |
name_secret_database store | |
| 200 |
eif (name eparse "site:" any:(var Str sitename)) | |
| 201 |
site_database:data:site create sitename | |
| 202 |
site:sitename public_key := public | |
| 203 |
site_secret_database:data:site create sitename | |
| 204 |
site_secret_database:data:site:sitename private_key := private | |
| 205 |
data_reset site_secret_database:data:site:sitename:session | |
| 206 |
site_database store | |
| 207 |
site_secret_database store | |
| 208 |
eif (name eparse "target:" any:(var Str hostname)) | |
| 209 |
name_database:data:host create hostname | |
| 210 |
name_database:data:host:hostname public_key := public | |
| 211 |
name_database store | |
| 212 |
var (Link Database:NameDatabase) name_db :> new Database:NameDatabase | |
| 213 |
name_db load "target:/pliant_security/name.pdb" | |
| 214 |
var (Data Set:NameHost) name_tbl :> name_db:data:host | |
| 215 |
name_tbl create hostname | |
| 216 |
name_tbl:hostname public_key := public | |
| 217 |
name_db store | |
| 218 |
var (Link Database:NameSecretDatabase) secret_db :> new Database:NameSecretDatabase | |
| 219 |
secret_db load "target:/pliant_security/name_secret.pdb" | |
| 220 |
var (Data Set:NameSecret) secret_tbl :> secret_db:data:host | |
| 221 |
secret_tbl create hostname | |
| 222 |
secret_tbl:hostname private_key := private | |
| 223 |
data_reset secret_tbl:hostname:session | |
| 224 |
secret_db store | |
| 225 |
if verbose | |
| 226 |
console "Succeded to generate a valid " rsa_nbbits:public " bits RSA key in " s " seconds" eol | |
| 227 |
else | |
| 228 |
console "Failed to generate a valid RSA key." eol | |
| 229 |
| |
| 230 |
| |
| 231 |
export rsa_cipher rsa_nbbits | |
| 232 |
export rsa_generate | |
| |