Dart DocumentationbignumRSAKey

RSAKey class

class RSAKey {
 var n;
 var e;
 var d;
 var p;
 var q;
 var dmp1;
 var dmq1;
 var coeff;

 // "empty" RSA key constructor
 RSAKey() {
   this.n = null;
   this.e = 0;
   this.d = null;
   this.p = null;
   this.q = null;
   this.dmp1 = null;
   this.dmq1 = null;
   this.coeff = null;
 }

 // Set the public key fields N and e from hex strings
 setPublic(N,E) {
   if(N != null && E != null && N.length > 0 && E.length > 0) {
     this.n = parseBigInt(N,16);
     //this.e = parseInt(E,16);
     this.e = Fixnum.int32.parseHex(E).toInt();
     //Mathx.parseInt("A");
   }
   else {
     print("Invalid RSA public key");
   }
 }

 // Perform raw public operation on "x": return x^e (mod n)
 doPublic(x) {
   return x.modPowInt(this.e, this.n);
 }

 // Return the PKCS#1 RSA encryption of "text" as an even-length hex string
 encrypt(text) {
   var m = pkcs1pad2(text,(this.n.bitLength()+7)>>3);
   if(m == null) return null;
   var c = this.doPublic(m);
   if(c == null) return null;
   var h = c.toString(16);
   if((h.length & 1) == 0) {
       return h;
     } else {
       //return "0" + h;
       return "0${h}";
     }
 }

 // Undo PKCS#1 (type 2, random) padding and, if valid, return the plaintext
 pkcs1unpad2(d,n) {
   List<int> b = d.toByteArray();
   var i = 0;
   while(i < b.length && b[i] == 0) ++i;
   if(b.length-i != n-1 || b[i] != 2) {
     return null;
   }
   ++i;
   while(b[i] != 0)
     if(++i >= b.length) return null;
   var ret = "";
   while(++i < b.length) {
     var c = new String.fromCharCodes([b[i]]);
     ret = "$ret${c}";
   }
     //ret += String.fromCharCode(b[i]);
   return ret;
 }

 // Set the private key fields N, e, and d from hex strings
 setPrivate(N,E,D) {
   if(N != null && E != null && N.length > 0 && E.length > 0) {
     this.n = parseBigInt(N,16);
     //this.e = parseInt(E,16);
     this.e = Fixnum.int32.parseHex(E).toInt();
     this.d = parseBigInt(D,16);
   }
   else {
     print("Invalid RSA private key");
   }
 }

 // Set the private key fields N, e, d and CRT params from hex strings
 setPrivateEx(N,E,D,P,Q,DP,DQ,C) {
   if(N != null && E != null && N.length > 0 && E.length > 0) {
     this.n = parseBigInt(N,16);
     //this.e = parseInt(E,16);
     this.e = Fixnum.int32.parseHex(E).toInt();
     this.d = parseBigInt(D,16);
     this.p = parseBigInt(P,16);
     this.q = parseBigInt(Q,16);
     this.dmp1 = parseBigInt(DP,16);
     this.dmq1 = parseBigInt(DQ,16);
     this.coeff = parseBigInt(C,16);
   }
   else {
     print("Invalid RSA private key");
   }
 }

 // Generate a new random private key B bits long, using public expt E
 generate(B,E) {
   var rng = new SecureRandom();
   var qs = B>>1;
   //this.e = parseInt(E,16);
   this.e = Fixnum.int32.parseHex(E).toInt();
   var ee = new BigInteger(E,16);
   for(;;) {
     for(;;) {
       this.p = new BigInteger(B-qs,1,rng);
       if(this.p.subtract(BigInteger.ONE).gcd(ee).compareTo(BigInteger.ONE) == 0 && this.p.isProbablePrime(10)) break;
     }
     for(;;) {
       this.q = new BigInteger(qs,1,rng);
       if(this.q.subtract(BigInteger.ONE).gcd(ee).compareTo(BigInteger.ONE) == 0 && this.q.isProbablePrime(10)) break;
     }
     if(this.p.compareTo(this.q) <= 0) {
       var t = this.p;
       this.p = this.q;
       this.q = t;
     }
     var p1 = this.p.subtract(BigInteger.ONE);
     var q1 = this.q.subtract(BigInteger.ONE);
     var phi = p1.multiply(q1);
     if(phi.gcd(ee).compareTo(BigInteger.ONE) == 0) {
       this.n = this.p.multiply(this.q);
       this.d = ee.modInverse(phi);
       this.dmp1 = this.d.mod(p1);
       this.dmq1 = this.d.mod(q1);
       this.coeff = this.q.modInverse(this.p);
       break;
     }
   }
 }

 // Perform raw private operation on "x": return x^d (mod n)
 doPrivate(x) {
   if(this.p == null || this.q == null) {
     return x.modPow(this.d, this.n);
   }

   // TODO: re-calculate any missing CRT params
   var xp = x.mod(this.p).modPow(this.dmp1, this.p);
   var xq = x.mod(this.q).modPow(this.dmq1, this.q);

   while(xp.compareTo(xq) < 0) {
     xp = xp.add(this.p);
   }
   return xp.subtract(xq).multiply(this.coeff).mod(this.p).multiply(this.q).add(xq);
 }

 // Return the PKCS#1 RSA decryption of "ctext".
 // "ctext" is an even-length hex string and the output is a plain string.
 decrypt(ctext) {
   var c = parseBigInt(ctext, 16);
   var m = this.doPrivate(c);
   if(m == null) return null;
   return pkcs1unpad2(m, (this.n.bitLength()+7)>>3);
 }

}

Constructors

new RSAKey() #

RSAKey() {
 this.n = null;
 this.e = 0;
 this.d = null;
 this.p = null;
 this.q = null;
 this.dmp1 = null;
 this.dmq1 = null;
 this.coeff = null;
}

Properties

var coeff #

coeff

var d #

d

var dmp1 #

dmp1

var dmq1 #

dmq1

var e #

e

var n #

n

var p #

p

var q #

q

Methods

decrypt(ctext) #

decrypt(ctext) {
 var c = parseBigInt(ctext, 16);
 var m = this.doPrivate(c);
 if(m == null) return null;
 return pkcs1unpad2(m, (this.n.bitLength()+7)>>3);
}

doPrivate(x) #

doPrivate(x) {
 if(this.p == null || this.q == null) {
   return x.modPow(this.d, this.n);
 }

 // TODO: re-calculate any missing CRT params
 var xp = x.mod(this.p).modPow(this.dmp1, this.p);
 var xq = x.mod(this.q).modPow(this.dmq1, this.q);

 while(xp.compareTo(xq) < 0) {
   xp = xp.add(this.p);
 }
 return xp.subtract(xq).multiply(this.coeff).mod(this.p).multiply(this.q).add(xq);
}

doPublic(x) #

doPublic(x) {
 return x.modPowInt(this.e, this.n);
}

encrypt(text) #

encrypt(text) {
 var m = pkcs1pad2(text,(this.n.bitLength()+7)>>3);
 if(m == null) return null;
 var c = this.doPublic(m);
 if(c == null) return null;
 var h = c.toString(16);
 if((h.length & 1) == 0) {
     return h;
   } else {
     //return "0" + h;
     return "0${h}";
   }
}

generate(B, E) #

generate(B,E) {
 var rng = new SecureRandom();
 var qs = B>>1;
 //this.e = parseInt(E,16);
 this.e = Fixnum.int32.parseHex(E).toInt();
 var ee = new BigInteger(E,16);
 for(;;) {
   for(;;) {
     this.p = new BigInteger(B-qs,1,rng);
     if(this.p.subtract(BigInteger.ONE).gcd(ee).compareTo(BigInteger.ONE) == 0 && this.p.isProbablePrime(10)) break;
   }
   for(;;) {
     this.q = new BigInteger(qs,1,rng);
     if(this.q.subtract(BigInteger.ONE).gcd(ee).compareTo(BigInteger.ONE) == 0 && this.q.isProbablePrime(10)) break;
   }
   if(this.p.compareTo(this.q) <= 0) {
     var t = this.p;
     this.p = this.q;
     this.q = t;
   }
   var p1 = this.p.subtract(BigInteger.ONE);
   var q1 = this.q.subtract(BigInteger.ONE);
   var phi = p1.multiply(q1);
   if(phi.gcd(ee).compareTo(BigInteger.ONE) == 0) {
     this.n = this.p.multiply(this.q);
     this.d = ee.modInverse(phi);
     this.dmp1 = this.d.mod(p1);
     this.dmq1 = this.d.mod(q1);
     this.coeff = this.q.modInverse(this.p);
     break;
   }
 }
}

pkcs1unpad2(d, n) #

pkcs1unpad2(d,n) {
 List<int> b = d.toByteArray();
 var i = 0;
 while(i < b.length && b[i] == 0) ++i;
 if(b.length-i != n-1 || b[i] != 2) {
   return null;
 }
 ++i;
 while(b[i] != 0)
   if(++i >= b.length) return null;
 var ret = "";
 while(++i < b.length) {
   var c = new String.fromCharCodes([b[i]]);
   ret = "$ret${c}";
 }
   //ret += String.fromCharCode(b[i]);
 return ret;
}

setPrivate(N, E, D) #

setPrivate(N,E,D) {
 if(N != null && E != null && N.length > 0 && E.length > 0) {
   this.n = parseBigInt(N,16);
   //this.e = parseInt(E,16);
   this.e = Fixnum.int32.parseHex(E).toInt();
   this.d = parseBigInt(D,16);
 }
 else {
   print("Invalid RSA private key");
 }
}

setPrivateEx(N, E, D, P, Q, DP, DQ, C) #

setPrivateEx(N,E,D,P,Q,DP,DQ,C) {
 if(N != null && E != null && N.length > 0 && E.length > 0) {
   this.n = parseBigInt(N,16);
   //this.e = parseInt(E,16);
   this.e = Fixnum.int32.parseHex(E).toInt();
   this.d = parseBigInt(D,16);
   this.p = parseBigInt(P,16);
   this.q = parseBigInt(Q,16);
   this.dmp1 = parseBigInt(DP,16);
   this.dmq1 = parseBigInt(DQ,16);
   this.coeff = parseBigInt(C,16);
 }
 else {
   print("Invalid RSA private key");
 }
}

setPublic(N, E) #

setPublic(N,E) {
 if(N != null && E != null && N.length > 0 && E.length > 0) {
   this.n = parseBigInt(N,16);
   //this.e = parseInt(E,16);
   this.e = Fixnum.int32.parseHex(E).toInt();
   //Mathx.parseInt("A");
 }
 else {
   print("Invalid RSA public key");
 }
}