/// <summary> /// Low level RSA Process function for use with private key. /// Should never be used; Because without padding RSA is vulnerable to attacks. Use with caution. /// </summary> /// <param name="plainText">Data to encrypt. Length must be less than Modulus size in octets.</param> /// <param name="usePrivate">True to use Private key, else Public.</param> /// <returns>Encrypted Data</returns> private byte[] RSAProcess(byte[] plainText, bool usePrivate) { if (usePrivate && !rsaParams.HasPrivateInfo) { throw new CryptographicException("RSA Process: Incomplete Private Key Info"); } if (usePrivate == false && !rsaParams.HasPublicInfo) { throw new CryptographicException("RSA Process: Incomplete Public Key Info"); } BigInteger e = usePrivate ? rsaParams.D : rsaParams.E; BigInteger pt = RSAxUtils.OS2IP(plainText, false); BigInteger m = BigInteger.ModPow(pt, e, rsaParams.N); if (m.Sign == -1) { return(RSAxUtils.I2OSP(m + rsaParams.N, rsaParams.OctetsInModulus, false)); } else { return(RSAxUtils.I2OSP(m, rsaParams.OctetsInModulus, false)); } }
/// <summary> /// Low level RSA Decryption function for use with private key. Uses CRT and is Much faster. /// Should never be used; Because without padding RSA is vulnerable to attacks. Use with caution. /// </summary> /// <param name="data">Data to encrypt. Length must be less than Modulus size in octets.</param> /// <returns>Encrypted Data</returns> private byte[] RSADecryptPrivateCRT(byte[] data) { if (rsaParams.HasPrivateInfo && rsaParams.HasCRTInfo) { BigInteger c = RSAxUtils.OS2IP(data, false); BigInteger m1 = BigInteger.ModPow(c, rsaParams.DP, rsaParams.P); BigInteger m2 = BigInteger.ModPow(c, rsaParams.DQ, rsaParams.Q); BigInteger h = (m1 - m2) * rsaParams.InverseQ % rsaParams.P; BigInteger m = m2 + rsaParams.Q * h; if (m.Sign == -1) { return(RSAxUtils.I2OSP(m + rsaParams.N, rsaParams.OctetsInModulus, false)); } else { return(RSAxUtils.I2OSP(m, rsaParams.OctetsInModulus, false)); } } else { throw new CryptographicException("RSA Decrypt CRT: Incomplete Key Info"); } }
/// <summary> /// Initialize the RSA class. Only the public parameters. /// </summary> /// <param name="modulus">Modulus of the RSA key.</param> /// <param name="exponent">Exponent of the RSA key</param> /// <param name="modulusSize">Modulus size in number of bits. Ex: 512, 1024, 2048, 4096 etc.</param> public RSAxParameters(byte[] modulus, byte[] exponent, int modulusSize) { // rsaParams; OctetsInModulus = modulusSize / 8; E = RSAxUtils.OS2IP(exponent, false); N = RSAxUtils.OS2IP(modulus, false); HasPublicInfo = true; }
/// <summary> /// Initialize the RSA class from a PEM string. /// </summary> /// <param name="keyInfo">PEM string</param> /// <param name="pw">password</param> public static RSAx CreateFromPEM(string keyInfo, string pw = "") { var key = OpenSSLKey.OpenSSLKey.PEMKeyToXKMSKey(keyInfo, pw); if (key.KeyPrivate != null) { return(new RSAx(RSAxUtils.GetRSAxParameters(key.KeyPrivate, key.KeySize), true)); } else { return(new RSAx(RSAxUtils.GetRSAxParameters(key.KeyPublic, key.KeySize), true)); } }
/// <summary> /// Initialize the RSA class. For CRT. /// </summary> /// <param name="modulus">Modulus of the RSA key.</param> /// <param name="exponent">Exponent of the RSA key</param> /// /// <param name="d">Exponent of the RSA key</param> /// <param name="p">P paramater of RSA Algorithm.</param> /// <param name="q">Q paramater of RSA Algorithm.</param> /// <param name="dp">DP paramater of RSA Algorithm.</param> /// <param name="dq">DQ paramater of RSA Algorithm.</param> /// <param name="inverseQ">InverseQ paramater of RSA Algorithm.</param> /// <param name="modulusSize">Modulus size in number of bits. Ex: 512, 1024, 2048, 4096 etc.</param> public RSAxParameters(byte[] modulus, byte[] exponent, byte[] d, byte[] p, byte [] q, byte [] dp, byte [] dq, byte [] inverseQ, int modulusSize) { // rsaParams; OctetsInModulus = modulusSize / 8; E = RSAxUtils.OS2IP(exponent, false); N = RSAxUtils.OS2IP(modulus, false); D = RSAxUtils.OS2IP(d, false); P = RSAxUtils.OS2IP(p, false); Q = RSAxUtils.OS2IP(q, false); DP = RSAxUtils.OS2IP(dp, false); DQ = RSAxUtils.OS2IP(dq, false); InverseQ = RSAxUtils.OS2IP(inverseQ, false); HasCRTInfo = true; HasPublicInfo = true; HasPrivateInfo = true; }
/// <summary> /// Initialize the RSA class. It's assumed that both the Public and Extended Private info are there. /// </summary> /// <param name="rsaParams">Preallocated RSAParameters containing the required keys.</param> /// <param name="modulusSize">Modulus size in bits</param> public RSAxParameters(RSAParameters rsaParams, int modulusSize) { // rsaParams; OctetsInModulus = modulusSize / 8; E = RSAxUtils.OS2IP(rsaParams.Exponent, false); D = RSAxUtils.OS2IP(rsaParams.D, false); N = RSAxUtils.OS2IP(rsaParams.Modulus, false); P = RSAxUtils.OS2IP(rsaParams.P, false); Q = RSAxUtils.OS2IP(rsaParams.Q, false); DP = RSAxUtils.OS2IP(rsaParams.DP, false); DQ = RSAxUtils.OS2IP(rsaParams.DQ, false); InverseQ = RSAxUtils.OS2IP(rsaParams.InverseQ, false); HasCRTInfo = true; HasPublicInfo = true; HasPrivateInfo = true; }
/// <summary> /// Mask Generation Function /// </summary> /// <param name="z">Initial pseudorandom Seed.</param> /// <param name="l">Length of output required.</param> /// <returns></returns> private byte[] MGF(byte[] z, int l) { if (l > Math.Pow(2, 32)) { throw new ArgumentException("Mask too long."); } List <byte> result = new List <byte>(); for (int i = 0; i <= l / rsaParams.HLen; i++) { List <byte> data = new List <byte>(); data.AddRange(z); data.AddRange(RSAxUtils.I2OSP(i, 4, false)); result.AddRange(rsaParams.ComputeHash(data.ToArray())); } if (l > result.Count) { throw new ArgumentException("Invalid Mask Length."); } return(result.GetRange(0, l).ToArray()); }
/// <summary> /// Initialize the RSA class from a XML KeyInfo string. /// </summary> /// <param name="keyInfo">XML Containing Key Information</param> /// <param name="modulusSize">Length of RSA Modulus in bits.</param> public static RSAx CreateFromXML(string keyInfo, int modulusSize) { return(new RSAx(RSAxUtils.GetRSAxParameters(keyInfo, modulusSize), true)); }
private byte[] Decrypt(byte[] message, byte [] parameters, bool usePrivate, bool fOAEP) { byte[] em; if (usePrivate && UseCRTForPublicDecryption && rsaParams.HasCRTInfo) { em = RSADecryptPrivateCRT(message); } else { em = RSAProcess(message, usePrivate); } if (fOAEP) //DECODE OAEP { if (em.Length == rsaParams.OctetsInModulus && em.Length > 2 * rsaParams.HLen + 1) { byte[] pHash = rsaParams.ComputeHash(parameters); if (em[0] == 0) // RFC3447 Format : http://tools.ietf.org/html/rfc3447 { var maskedSeed = em.ToList().GetRange(1, rsaParams.HLen).ToArray(); var maskedDB = em.ToList().GetRange(1 + rsaParams.HLen, em.Length - rsaParams.HLen - 1).ToArray(); var seedMask = MGF(maskedDB, rsaParams.HLen); var seed = RSAxUtils.XOR(maskedSeed, seedMask); var dbMask = MGF(seed, rsaParams.OctetsInModulus - rsaParams.HLen - 1); var db = RSAxUtils.XOR(maskedDB, dbMask); if (db.Length >= rsaParams.HLen + 1) { byte[] pHashInner = db.ToList().GetRange(0, rsaParams.HLen).ToArray(); List <byte> psM = db.ToList().GetRange(rsaParams.HLen, db.Length - rsaParams.HLen); int pos = psM.IndexOf(0x01); if (pos >= 0 && pos < psM.Count) { List <byte> list01M = psM.GetRange(pos, psM.Count - pos); byte[] m; if (list01M.Count > 1) { m = list01M.GetRange(1, list01M.Count - 1).ToArray(); } else { m = new byte[0]; } bool success = true; for (int i = 0; i < rsaParams.HLen; i++) { if (pHashInner[i] != pHash[i]) { success = false; break; } } if (success) { return(m); } throw new CryptographicException("OAEP Decode Error"); } // #3: Invalid Encoded Message Length. throw new CryptographicException("OAEP Decode Error"); } // #2: Invalid Encoded Message Length. throw new CryptographicException("OAEP Decode Error"); } // Standard : ftp://ftp.rsasecurity.com/pub/rsalabs/rsa_algorithm/rsa-oaep_spec.pdf //OAEP : THIS STADNARD IS NOT IMPLEMENTED throw new CryptographicException("OAEP Decode Error"); } // #1: Invalid Encoded Message Length. throw new CryptographicException("OAEP Decode Error"); } // DECODE PKCS v1.5 if (em.Length >= 11) { if (em[0] == 0x00 && em[1] == 0x02) { int startIndex = 2; List <byte> ps = new List <byte>(); for (int i = startIndex; i < em.Length; i++) { if (em[i] != 0) { ps.Add(em[i]); } else { break; } } if (ps.Count >= 8) { int decodedDataIndex = startIndex + ps.Count + 1; if (decodedDataIndex < em.Length - 1) { List <byte> data = new List <byte>(); for (int i = decodedDataIndex; i < em.Length; i++) { data.Add(em[i]); } return(data.ToArray()); } return(new byte[0]); //throw new CryptographicException("PKCS v1.5 Decode Error #4: No Data"); } // #3: Invalid Key / Invalid Random Data Length throw new CryptographicException("PKCS v1.5 Decode Error"); } // #2: Invalid Key / Invalid Identifiers throw new CryptographicException("PKCS v1.5 Decode Error"); } // #1: Invalid Key / PKCS Encoding throw new CryptographicException("PKCS v1.5 Decode Error"); }
private byte[] RSAProcessEncodeOAEP(byte[] m, byte[] p, bool usePrivate) { // +----------+---------+-------+ // DB = | lHash | PS | M | // +----------+---------+-------+ // | // +----------+ V // | seed |--> MGF ---> XOR // +----------+ | // | | // +--+ V | // |00| XOR <----- MGF <-----| // +--+ | | // | | | // V V V // +--+----------+----------------------------+ // EM = |00|maskedSeed| maskedDB | // +--+----------+----------------------------+ int mLen = m.Length; if (mLen > rsaParams.OctetsInModulus - 2 * rsaParams.HLen - 2) { throw new ArgumentException("Message too long."); } else { byte[] ps = new byte[rsaParams.OctetsInModulus - mLen - 2 * rsaParams.HLen - 2]; //4. pHash = Hash(P), byte[] pHash = rsaParams.ComputeHash(p); //5. DB = pHash||PS||01||M. List <byte> dblist = new List <byte>(); dblist.AddRange(pHash); dblist.AddRange(ps); dblist.Add(0x01); dblist.AddRange(m); byte[] db = dblist.ToArray(); //6. Generate a random octet string seed of length hLen. byte[] seed = new byte[rsaParams.HLen]; rng.GetBytes(seed); //7. dbMask = MGF(seed, k - hLen -1). byte[] dbMask = MGF(seed, rsaParams.OctetsInModulus - rsaParams.HLen - 1); //8. maskedDB = DB XOR dbMask byte[] maskedDB = RSAxUtils.XOR(db, dbMask); //9. seedMask = MGF(maskedDB, hLen) byte[] seedMask = MGF(maskedDB, rsaParams.HLen); //10. maskedSeed = seed XOR seedMask. byte[] maskedSeed = RSAxUtils.XOR(seed, seedMask); //11. EM = 0x00 || maskedSeed || maskedDB. var result = new byte[] { 0x00 }.Concat(maskedSeed).Concat(maskedDB).ToArray(); return(RSAProcess(result, usePrivate)); } }