/// <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."); } else { 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) { return(result.GetRange(0, l).ToArray()); } else { throw new ArgumentException("Invalid Mask Length."); } } }
/// <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> public byte[] RSADecryptPrivateCRT(byte[] Data) { if (rsaParams.Has_PRIVATE_Info && 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; _ModulusOctets = ModulusSize / 8; _E = RSAxUtils.OS2IP(Exponent, false); _N = RSAxUtils.OS2IP(Modulus, false); _Has_PUBLIC_Info = 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; _ModulusOctets = 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); _Has_CRT_Info = true; _Has_PUBLIC_Info = true; _Has_PRIVATE_Info = 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; _ModulusOctets = 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); _Has_CRT_Info = true; _Has_PUBLIC_Info = true; _Has_PRIVATE_Info = true; }
/// <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> public byte[] RSAProcess(byte[] PlainText, bool usePrivate) { if (usePrivate && (!rsaParams.Has_PRIVATE_Info)) { throw new CryptographicException("RSA Process: Incomplete Private Key Info"); } if ((usePrivate == false) && (!rsaParams.Has_PUBLIC_Info)) { throw new CryptographicException("RSA Process: Incomplete Public Key Info"); } BigInteger _E; if (usePrivate) { _E = rsaParams.D; } else { _E = 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> /// 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 RSAx(String keyInfo, int ModulusSize) { this.rsaParams = RSAxUtils.GetRSAxParameters(keyInfo, ModulusSize); UseCRTForPublicDecryption = true; }
private byte[] Decrypt(byte[] Message, byte [] Parameters, bool usePrivate, bool fOAEP) { byte[] EM = new byte[0]; try { if ((usePrivate == true) && (UseCRTForPublicDecryption) && (rsaParams.HasCRTInfo)) { EM = RSADecryptPrivateCRT(Message); } else { EM = RSAProcess(Message, usePrivate); } } catch (CryptographicException ex) { throw new CryptographicException("Exception while Decryption: " + ex.Message); } catch { throw new Exception("Exception while Decryption: "); } try { if (fOAEP) //DECODE OAEP { if ((EM.Length == rsaParams.OctetsInModulus) && (EM.Length > (2 * rsaParams.hLen + 1))) { byte[] maskedSeed; byte[] maskedDB; byte[] pHash = rsaParams.ComputeHash(Parameters); if (EM[0] == 0) // RFC3447 Format : http://tools.ietf.org/html/rfc3447 { maskedSeed = EM.ToList().GetRange(1, rsaParams.hLen).ToArray(); maskedDB = EM.ToList().GetRange(1 + rsaParams.hLen, EM.Length - rsaParams.hLen - 1).ToArray(); byte[] seedMask = MGF(maskedDB, rsaParams.hLen); byte[] seed = RSAxUtils.XOR(maskedSeed, seedMask); byte[] dbMask = MGF(seed, rsaParams.OctetsInModulus - rsaParams.hLen - 1); byte[] DB = RSAxUtils.XOR(maskedDB, dbMask); if (DB.Length >= (rsaParams.hLen + 1)) { byte[] _pHash = DB.ToList().GetRange(0, rsaParams.hLen).ToArray(); List <byte> PS_M = DB.ToList().GetRange(rsaParams.hLen, DB.Length - rsaParams.hLen); int pos = PS_M.IndexOf(0x01); if (pos >= 0 && (pos < PS_M.Count)) { List <byte> _01_M = PS_M.GetRange(pos, PS_M.Count - pos); byte[] M; if (_01_M.Count > 1) { M = _01_M.GetRange(1, _01_M.Count - 1).ToArray(); } else { M = new byte[0]; } bool success = true; for (int i = 0; i < rsaParams.hLen; i++) { if (_pHash[i] != pHash[i]) { success = false; break; } } if (success) { return(M); } else { M = new byte[rsaParams.OctetsInModulus]; //Hash Match Failure. throw new CryptographicException("OAEP Decode Error"); } } else {// #3: Invalid Encoded Message Length. throw new CryptographicException("OAEP Decode Error"); } } else {// #2: Invalid Encoded Message Length. throw new CryptographicException("OAEP Decode Error"); } } else // 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"); } } else {// #1: Invalid Encoded Message Length. throw new CryptographicException("OAEP Decode Error"); } } else // 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()); } else { return(new byte[0]); //throw new CryptographicException("PKCS v1.5 Decode Error #4: No Data"); } } else {// #3: Invalid Key / Invalid Random Data Length throw new CryptographicException("PKCS v1.5 Decode Error"); } } else {// #2: Invalid Key / Invalid Identifiers throw new CryptographicException("PKCS v1.5 Decode Error"); } } else {// #1: Invalid Key / PKCS Encoding throw new CryptographicException("PKCS v1.5 Decode Error"); } } } catch (CryptographicException ex) { throw new CryptographicException("Exception while decoding: " + ex.Message); } catch { throw new CryptographicException("Exception while decoding"); } }
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> _DB = new List <byte>(); _DB.AddRange(pHash); _DB.AddRange(PS); _DB.Add(0x01); _DB.AddRange(M); byte[] DB = _DB.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. List <byte> result = new List <byte>(); result.Add(0x00); result.AddRange(maskedSeed); result.AddRange(maskedDB); return(RSAProcess(result.ToArray(), usePrivate)); } }