public static byte[] PssEncode(byte[] m, TpmAlgId hashAlg, int sLen, int emBits) { var emLen = (int)Math.Ceiling(1.0 * emBits / 8); int hLen = CryptoLib.DigestSize(hashAlg); // 1 - Ignore // 2 byte[] mHash = TpmHash.FromData(hashAlg, m); // 3 if (emLen < hLen + sLen + 2) { if (Tpm2._TssBehavior.Passthrough) { return(new byte[0]); } else { throw new Exception("Encoding error"); } } // 4 byte[] salt = Globs.GetRandomBytes(sLen); // 5 byte[] mPrime = Globs.Concatenate(new[] { Globs.ByteArray(8, 0), mHash, salt }); // 6 byte[] h = CryptoLib.HashData(hashAlg, mPrime); // 7 byte[] ps = Globs.GetZeroBytes(emLen - sLen - hLen - 2); // 8 byte[] db = Globs.Concatenate(new[] { ps, new byte[] { 0x01 }, salt }); // 9 byte[] dbMask = CryptoLib.MGF(h, emLen - hLen - 1, hashAlg); // 10 byte[] maskedDb = XorEngine.Xor(db, dbMask); // 11 int numZeroBits = 8 * emLen - emBits; byte mask = GetByteMask(numZeroBits); maskedDb[0] &= mask; // 12 byte[] em = Globs.Concatenate(new[] { maskedDb, h, new byte[] { 0xbc } }); // 13 return(em); }
public static byte[] KdfThenXor(TpmAlgId hashAlg, byte[] key, byte[] contextU, byte[] contextV, byte[] data) { var mask = KDF.KDFa(hashAlg, key, "XOR", contextU, contextV, data.Length * 8); return(XorEngine.Xor(data, mask)); }
public byte[] Decrypt(byte[] data, byte[] iv = null) { byte[] paddedData; int unpadded = data.Length % BlockSize; paddedData = unpadded == 0 ? data : Globs.AddZeroToEnd(data, BlockSize - unpadded); #if TSS_USE_BCRYPT paddedData = Key.Decrypt(paddedData, null, iv ?? IV); return(Globs.CopyData(paddedData, 0, data.Length)); #else bool externalIV = iv != null && iv.Length > 0; if (externalIV) { Alg.IV = iv; } var tempOut = new byte[data.Length]; ICryptoTransform dec = Alg.CreateDecryptor(); using (var outStream = new MemoryStream(paddedData)) { var s = new CryptoStream(outStream, dec, CryptoStreamMode.Read); int numPlaintextBytes = s.Read(tempOut, 0, data.Length); Debug.Assert(numPlaintextBytes == data.Length); } if (externalIV) { var src = data; var res = tempOut; if (res.Length > iv.Length) { src = Globs.CopyData(paddedData, src.Length - iv.Length, iv.Length); res = Globs.CopyData(tempOut, res.Length - iv.Length, iv.Length); } switch (Alg.Mode) { case CipherMode.CBC: case CipherMode.CFB: src.CopyTo(iv, 0); break; case CipherMode.OFB: XorEngine.Xor(res, src).CopyTo(iv, 0); break; case CipherMode.ECB: break; case CipherMode.CTS: Globs.Throw <ArgumentException>("Decrypt: Unsupported symmetric mode"); break; } } return(tempOut); #endif }
/// <summary> /// Performs the TPM-defined CFB encrypt using the associated algorithm. /// This routine assumes that the integrity value has been prepended. /// </summary> /// <param name="data"></param> /// <param name="iv"></param> /// <returns></returns> public byte[] Encrypt(byte[] data, byte[] iv = null) { byte[] paddedData; int unpadded = data.Length % BlockSize; paddedData = unpadded == 0 ? data : Globs.AddZeroToEnd(data, BlockSize - unpadded); #if TSS_USE_BCRYPT paddedData = Key.Encrypt(paddedData, null, iv ?? IV); #else bool externalIV = iv != null && iv.Length > 0; if (externalIV) { Alg.IV = iv; } ICryptoTransform enc = Alg.CreateEncryptor(); using (var outStream = new MemoryStream()) { var s = new CryptoStream(outStream, enc, CryptoStreamMode.Write); s.Write(paddedData, 0, paddedData.Length); s.FlushFinalBlock(); paddedData = outStream.ToArray(); } if (externalIV) { var src = data; var res = paddedData; if (res.Length > iv.Length) { src = Globs.CopyData(data, src.Length - iv.Length, iv.Length); res = Globs.CopyData(paddedData, res.Length - iv.Length, iv.Length); } switch (Alg.Mode) { case CipherMode.CBC: case CipherMode.CFB: res.CopyTo(iv, 0); break; case CipherMode.OFB: XorEngine.Xor(res, src).CopyTo(iv, 0); break; case CipherMode.ECB: break; case CipherMode.CTS: Globs.Throw <ArgumentException>("Encrypt: Unsupported symmetric mode"); break; } } #endif return(unpadded == 0 ? paddedData : Globs.CopyData(paddedData, 0, data.Length)); }
/// <summary> /// PSS verify. Note: we expect the caller to do the hash. /// </summary> /// <param name="m"></param> /// <param name="em"></param> /// <param name="sLen"></param> /// <param name="emBits"></param> /// <param name="hashAlg"></param> /// <returns></returns> public static bool PssVerify(byte[] m, byte[] em, int sLen, int emBits, TpmAlgId hashAlg) { var emLen = (int)Math.Ceiling(1.0 * emBits / 8); int hLen = CryptoLib.DigestSize(hashAlg); // 1 - Skip // 2 byte[] mHash = TpmHash.FromData(hashAlg, m); // 3 if (emLen < hLen + sLen + 2) { return(false); } // 4 if (em[em.Length - 1] != 0xbc) { return(false); } // 5 byte[] maskedDB = Globs.CopyData(em, 0, emLen - hLen - 1); byte[] h = Globs.CopyData(em, emLen - hLen - 1, hLen); // 6 int numZeroBits = 8 * emLen - emBits; // First numZero bits is zero in mask byte mask = GetByteMask(numZeroBits); if ((maskedDB[0] & mask) != maskedDB[0]) { return(false); } // 7 byte[] dbMask = CryptoLib.MGF(h, emLen - hLen - 1, hashAlg); // 8 byte[] db = XorEngine.Xor(maskedDB, dbMask); // 9 int numZeroBits2 = 8 * emLen - emBits; byte mask2 = GetByteMask(numZeroBits2); db[0] &= mask2; // 10 for (int j = 0; j < emLen - hLen - sLen - 2; j++) { if (db[j] != 0) { return(false); } } if (db[emLen - hLen - sLen - 1 - 1] != 1) { return(false); } // 11 byte[] salt = Globs.CopyData(db, db.Length - sLen); // 12 byte[] mPrime = Globs.Concatenate(new[] { Globs.ByteArray(8, 0), mHash, salt }); // 13 byte[] hPrime = TpmHash.FromData(hashAlg, mPrime); // 14 bool match = Globs.ArraysAreEqual(h, hPrime); if (match == false) { return(false); } return(true); }
public static bool OaepDecode(byte[] eMx, byte[] encodingParms, TpmAlgId hashAlg, out byte[] decoded) { decoded = new byte[0]; var em = new byte[eMx.Length + 1]; Array.Copy(eMx, 0, em, 1, eMx.Length); int hLen = CryptoLib.DigestSize(hashAlg); int k = em.Length; // a. byte[] lHash = CryptoLib.HashData(hashAlg, encodingParms); // b. byte y = em[0]; byte[] maskedSeed = Globs.CopyData(em, 1, hLen); byte[] maskedDB = Globs.CopyData(em, 1 + hLen); // c. byte[] seedMask = CryptoLib.MGF(maskedDB, hLen, hashAlg); // d. byte[] seed = XorEngine.Xor(maskedSeed, seedMask); // e. byte[] dbMask = CryptoLib.MGF(seed, k - hLen - 1, hashAlg); // f. byte[] db = XorEngine.Xor(maskedDB, dbMask); // g. byte[] lHashPrime = Globs.CopyData(db, 0, hLen); // Look for the zero.. int j; for (j = hLen; j < db.Length; j++) { if (db[j] == 0) { continue; } if (db[j] == 1) { break; } return(false); } if (j == db.Length - 1) { return(false); } byte[] m = Globs.CopyData(db, j + 1); if (y != 0) { return(false); } if (!Globs.ArraysAreEqual(lHash, lHashPrime)) { return(false); } decoded = m; return(true); }
/// <summary> /// EME-OAEP PKCS1.2, section 9.1.1.1. /// </summary> /// <param name="message"></param> /// <param name="encodingParameters"></param> /// <param name="hashAlg"></param> /// <param name="modulusNumBytes"></param> /// <returns></returns> public static byte[] OaepEncode(byte[] message, byte[] encodingParameters, TpmAlgId hashAlg, int modulusNumBytes) { int encodedMessageLength = modulusNumBytes - 1; int messageLength = message.Length; int hashLength = CryptoLib.DigestSize(hashAlg); // 1 (Step numbers from RSA labs spec.) // Ignore the ParametersLength limitation // 2 if (messageLength > encodedMessageLength - 2 * hashLength - 1) { if (Tpm2._TssBehavior.Passthrough) { return(new byte[0]); } else { throw new ArgumentException("input message too long"); } } int psLen = encodedMessageLength - messageLength - 2 * hashLength - 1; var ps = new byte[psLen]; // 3 (Not needed.) for (int j = 0; j < psLen; j++) { ps[j] = 0; } // 4 byte[] pHash = CryptoLib.HashData(hashAlg, encodingParameters); // 5 var db = new byte[hashLength + psLen + 1 + messageLength]; var one = new byte[1]; one[0] = 1; pHash.CopyTo(db, 0); ps.CopyTo(db, pHash.Length); one.CopyTo(db, pHash.Length + ps.Length); message.CopyTo(db, pHash.Length + ps.Length + 1); // 6 byte[] seed = Globs.GetRandomBytes(hashLength); // 7 byte[] dbMask = CryptoLib.MGF(seed, encodedMessageLength - hashLength, hashAlg); // 8 byte[] maskedDb = XorEngine.Xor(db, dbMask); // 9 byte[] seedMask = CryptoLib.MGF(maskedDb, hashLength, hashAlg); // 10 byte[] maskedSeed = XorEngine.Xor(seed, seedMask); //11 var encodedMessage = new byte[maskedSeed.Length + maskedDb.Length]; maskedSeed.CopyTo(encodedMessage, 0); maskedDb.CopyTo(encodedMessage, maskedSeed.Length); // 12 return(encodedMessage); }