/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 := 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*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 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        := prime 2n^(nbits\2) error_probability 
 121        := prime 2n^(nbits\2) error_probability 
 122      if trace 
 123        console "p=" p eol 
 124        console "q=" q eol 
 125      var Intn := 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 := random (p-1)*(q-1) 
 132        if (pgcd e (p-1)*(q-1))<>1 
 133          restart pick_e 
 134      var Intn := 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 := (random_string test_message_bits\8)+"." 
 155    var Str := rsa_cipher public 
 156    var Str m2 := rsa_cipher private 
 157    var Str := rsa_cipher private 
 158    var Str m3 := rsa_cipher public 
 159    status := shunt m2=and m3=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