private static void VerifyIntegrity(FileData fileData)
{
BlobBuilder builder = new BlobBuilder();
if (fileData.ppkFileVersion != Version.V1) {
builder.AddStringBlob(fileData.publicKeyAlgorithm.GetIdentifierString());
builder.AddStringBlob(fileData.privateKeyAlgorithm.GetIdentifierString());
builder.AddBlob(Encoding.GetEncoding(1252).GetBytes(fileData.comment));
builder.AddBlob(fileData.publicKeyBlob);
builder.AddInt(fileData.privateKeyBlob.Data.Length);
}
builder.AddBytes(fileData.privateKeyBlob.Data);
byte[] computedHash;
SHA1 sha = SHA1.Create();
if (fileData.isHMAC) {
HMAC hmac = HMACSHA1.Create();
if (fileData.passphrase != null) {
using (PinnedArray<byte> hashData =
new PinnedArray<byte>(cMACKeySalt.Length +
fileData.passphrase.Length)) {
Array.Copy(Encoding.UTF8.GetBytes(cMACKeySalt),
hashData.Data, cMACKeySalt.Length);
IntPtr passphrasePtr =
Marshal.SecureStringToGlobalAllocUnicode(fileData.passphrase);
for (int i = 0; i < fileData.passphrase.Length; i++) {
int unicodeChar = Marshal.ReadInt16(passphrasePtr + i * 2);
byte ansiChar = Util.UnicodeToAnsi(unicodeChar);
hashData.Data[cMACKeySalt.Length + i] = ansiChar;
Marshal.WriteByte(passphrasePtr, i * 2, 0);
}
Marshal.ZeroFreeGlobalAllocUnicode(passphrasePtr);
hmac.Key = sha.ComputeHash(hashData.Data);
}
} else {
hmac.Key = sha.ComputeHash(Encoding.UTF8.GetBytes(cMACKeySalt));
}
computedHash = hmac.ComputeHash(builder.GetBlob());
hmac.Clear();
} else {
computedHash = sha.ComputeHash(builder.GetBlob());
}
sha.Clear();
builder.Clear();
try {
int macLength = computedHash.Length;
bool failed = false;
if (fileData.privateMAC.Length == macLength) {
for (int i = 0; i < macLength; i++) {
if (fileData.privateMAC[i] != computedHash[i]) {
failed = true;
break;
}
}
} else {
failed = true;
}
if (failed) {
// private key data should start with 3 bytes with value 0 if it was
// properly decrypted or does not require decryption
if ((fileData.privateKeyBlob.Data[0] == 0) &&
(fileData.privateKeyBlob.Data[1] == 0) &&
(fileData.privateKeyBlob.Data[2] == 0)) {
// so if they bytes are there, passphrase decrypted properly and
// something else is wrong with the file contents
throw new PpkFormatterException(PpkFormatterException.PpkErrorType.FileCorrupt);
} else {
// if the bytes are not zeros, we assume that the data was not
// properly decrypted because the passphrase was incorrect.
throw new PpkFormatterException(PpkFormatterException.PpkErrorType.BadPassphrase);
}
}
} catch {
throw;
} finally {
Array.Clear(computedHash, 0, computedHash.Length);
}
}