You've already forked linux-packaging-mono
Imported Upstream version 4.0.0~alpha1
Former-commit-id: 806294f5ded97629b74c85c09952f2a74fe182d9
This commit is contained in:
215
external/referencesource/System.Web/Security/MachineKey.cs
vendored
Normal file
215
external/referencesource/System.Web/Security/MachineKey.cs
vendored
Normal file
@ -0,0 +1,215 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <copyright file="MachineKey.cs" company="Microsoft">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/*
|
||||
* MachineKey
|
||||
*
|
||||
* Copyright (c) 2009 Microsoft Corporation
|
||||
*/
|
||||
|
||||
namespace System.Web.Security {
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Web.Configuration;
|
||||
using System.Web.Security.Cryptography;
|
||||
using System.Web.Util;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
public enum MachineKeyProtection {
|
||||
All,
|
||||
Encryption,
|
||||
Validation
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
public static class MachineKey {
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
[Obsolete("This method is obsolete and is only provided for compatibility with existing code. It is recommended that new code use the Protect and Unprotect methods instead.")]
|
||||
public static string Encode(byte[] data, MachineKeyProtection protectionOption) {
|
||||
if (data == null)
|
||||
throw new ArgumentNullException("data");
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Step 1: Get the MAC and add to the blob
|
||||
if (protectionOption == MachineKeyProtection.All || protectionOption == MachineKeyProtection.Validation) {
|
||||
byte[] bHash = MachineKeySection.HashData(data, null, 0, data.Length);
|
||||
byte[] bAll = new byte[bHash.Length + data.Length];
|
||||
Buffer.BlockCopy(data, 0, bAll, 0, data.Length);
|
||||
Buffer.BlockCopy(bHash, 0, bAll, data.Length, bHash.Length);
|
||||
data = bAll;
|
||||
}
|
||||
|
||||
if (protectionOption == MachineKeyProtection.All || protectionOption == MachineKeyProtection.Encryption) {
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Step 2: Encryption
|
||||
data = MachineKeySection.EncryptOrDecryptData(true, data, null, 0, data.Length, false, false, IVType.Random, !AppSettings.UseLegacyMachineKeyEncryption);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Step 3: Covert the buffer to HEX string and return it
|
||||
return CryptoUtil.BinaryToHex(data);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
[Obsolete("This method is obsolete and is only provided for compatibility with existing code. It is recommended that new code use the Protect and Unprotect methods instead.")]
|
||||
public static byte[] Decode(string encodedData, MachineKeyProtection protectionOption) {
|
||||
if (encodedData == null)
|
||||
throw new ArgumentNullException("encodedData");
|
||||
|
||||
if ((encodedData.Length % 2) != 0)
|
||||
throw new ArgumentException(null, "encodedData");
|
||||
|
||||
byte[] data = null;
|
||||
try {
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Step 1: Covert the HEX string to byte array
|
||||
data = CryptoUtil.HexToBinary(encodedData);
|
||||
}
|
||||
catch {
|
||||
throw new ArgumentException(null, "encodedData");
|
||||
}
|
||||
|
||||
if (data == null || data.Length < 1)
|
||||
throw new ArgumentException(null, "encodedData");
|
||||
|
||||
if (protectionOption == MachineKeyProtection.All || protectionOption == MachineKeyProtection.Encryption) {
|
||||
//////////////////////////////////////////////////////////////////
|
||||
// Step 2: Decrypt the data
|
||||
data = MachineKeySection.EncryptOrDecryptData(false, data, null, 0, data.Length, false, false, IVType.Random, !AppSettings.UseLegacyMachineKeyEncryption);
|
||||
if (data == null)
|
||||
return null;
|
||||
}
|
||||
|
||||
if (protectionOption == MachineKeyProtection.All || protectionOption == MachineKeyProtection.Validation) {
|
||||
//////////////////////////////////////////////////////////////////
|
||||
// Step 3a: Remove the hash from the end of the data
|
||||
if (data.Length < MachineKeySection.HashSize)
|
||||
return null;
|
||||
byte[] originalData = data;
|
||||
data = new byte[originalData.Length - MachineKeySection.HashSize];
|
||||
Buffer.BlockCopy(originalData, 0, data, 0, data.Length);
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
// Step 3b: Calculate the hash and make sure it matches
|
||||
byte[] bHash = MachineKeySection.HashData(data, null, 0, data.Length);
|
||||
if (bHash == null || bHash.Length != MachineKeySection.HashSize)
|
||||
return null; // Sizes don't match
|
||||
for (int iter = 0; iter < bHash.Length; iter++) {
|
||||
if (bHash[iter] != originalData[data.Length + iter])
|
||||
return null; // Mis-match found
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cryptographically protects and tamper-proofs the specified data.
|
||||
/// </summary>
|
||||
/// <param name="userData">The plaintext data that needs to be protected.</param>
|
||||
/// <param name="purposes">(optional) A list of purposes that describe what the data is meant for.
|
||||
/// If this value is specified, the same list must be passed to the Unprotect method in order
|
||||
/// to decipher the returned ciphertext.</param>
|
||||
/// <returns>The ciphertext data. To decipher the data, call the Unprotect method, passing this
|
||||
/// value as the 'protectedData' parameter.</returns>
|
||||
/// <remarks>
|
||||
/// This method supercedes the Encode method, which required the caller to know whether he wanted
|
||||
/// the plaintext data to be encrypted, signed, or both. In contrast, the Protect method just
|
||||
/// does the right thing and securely protects the data. Ciphertext data produced by this method
|
||||
/// can only be deciphered by the Unprotect method.
|
||||
///
|
||||
/// The 'purposes' parameter is an optional list of reason strings that can lock the ciphertext
|
||||
/// to a specific purpose. The intent of this parameter is that different subsystems within
|
||||
/// an application may depend on cryptographic operations, and a malicious client should not be
|
||||
/// able to get the result of one subsystem's Protect method and feed it as input to another
|
||||
/// subsystem's Unprotect method, which could have undesirable or insecure behavior. In essence,
|
||||
/// the 'purposes' parameter helps ensure that some protected data can be consumed only by the
|
||||
/// component that originally generated it. Applications should take care to ensure that each
|
||||
/// subsystem uses a unique 'purposes' list.
|
||||
///
|
||||
/// For example, to protect or unprotect an authentication token, the application could call:
|
||||
/// MachineKey.Protect(..., "Authentication token");
|
||||
/// MachineKey.Unprotect(..., "Authentication token");
|
||||
///
|
||||
/// Applications may dynamically generate the 'purposes' parameter if desired. If an application
|
||||
/// does this, user-supplied values like usernames should never directly be passed for the 'purposes'
|
||||
/// parameter. They should instead be prefixed with something (like "Username: " + username) to
|
||||
/// minimize the risk of a malicious client crafting input that collides with a token in use by some
|
||||
/// other part of the system. Any dynamically-generated tokens should come after non-dynamically
|
||||
/// generated tokens.
|
||||
///
|
||||
/// For example, to protect or unprotect a private message that is tied to a specific user, the
|
||||
/// application could call:
|
||||
/// MachineKey.Protect(..., "Private message", "Recipient: " + username);
|
||||
/// MachineKey.Unprotect(..., "Private message", "Recipient: " + username);
|
||||
///
|
||||
/// In both of the above examples, is it important that the caller of the Unprotect method be able to
|
||||
/// resurrect the original 'purposes' list. Otherwise the operation will fail with a CryptographicException.
|
||||
/// </remarks>
|
||||
public static byte[] Protect(byte[] userData, params string[] purposes) {
|
||||
if (userData == null) {
|
||||
throw new ArgumentNullException("userData");
|
||||
}
|
||||
|
||||
// Technically we don't care if the purposes array contains whitespace-only entries,
|
||||
// but the DataProtector class does, so we'll just block them right here.
|
||||
if (purposes != null && purposes.Any(String.IsNullOrWhiteSpace)) {
|
||||
throw new ArgumentException(SR.GetString(SR.MachineKey_InvalidPurpose), "purposes");
|
||||
}
|
||||
|
||||
return Protect(AspNetCryptoServiceProvider.Instance, userData, purposes);
|
||||
}
|
||||
|
||||
// Internal method for unit testing.
|
||||
internal static byte[] Protect(ICryptoServiceProvider cryptoServiceProvider, byte[] userData, string[] purposes) {
|
||||
// If the user is calling this method, we want to use the ICryptoServiceProvider
|
||||
// regardless of whether or not it's the default provider.
|
||||
|
||||
Purpose derivedPurpose = Purpose.User_MachineKey_Protect.AppendSpecificPurposes(purposes);
|
||||
ICryptoService cryptoService = cryptoServiceProvider.GetCryptoService(derivedPurpose);
|
||||
return cryptoService.Protect(userData);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies the integrity of and deciphers the given ciphertext.
|
||||
/// </summary>
|
||||
/// <param name="protectedData">Ciphertext data that was produced by the Protect method.</param>
|
||||
/// <param name="purposes">(optional) A list of purposes that describe what the data is meant for.</param>
|
||||
/// <returns>The plaintext data.</returns>
|
||||
/// <exception>Throws a CryptographicException if decryption fails. This can occur if the 'protectedData' has
|
||||
/// been tampered with, if an incorrect 'purposes' parameter is specified, or if an application is deployed
|
||||
/// to more than one server (as in a farm scenario) but is using auto-generated encryption keys.</exception>
|
||||
/// <remarks>See documentation on the Protect method for more information.</remarks>
|
||||
public static byte[] Unprotect(byte[] protectedData, params string[] purposes) {
|
||||
if (protectedData == null) {
|
||||
throw new ArgumentNullException("protectedData");
|
||||
}
|
||||
|
||||
// Technically we don't care if the purposes array contains whitespace-only entries,
|
||||
// but the DataProtector class does, so we'll just block them right here.
|
||||
if (purposes != null && purposes.Any(String.IsNullOrWhiteSpace)) {
|
||||
throw new ArgumentException(SR.GetString(SR.MachineKey_InvalidPurpose), "purposes");
|
||||
}
|
||||
|
||||
return Unprotect(AspNetCryptoServiceProvider.Instance, protectedData, purposes);
|
||||
}
|
||||
|
||||
// Internal method for unit testing.
|
||||
internal static byte[] Unprotect(ICryptoServiceProvider cryptoServiceProvider, byte[] protectedData, string[] purposes) {
|
||||
// If the user is calling this method, we want to use the ICryptoServiceProvider
|
||||
// regardless of whether or not it's the default provider.
|
||||
|
||||
Purpose derivedPurpose = Purpose.User_MachineKey_Protect.AppendSpecificPurposes(purposes);
|
||||
ICryptoService cryptoService = cryptoServiceProvider.GetCryptoService(derivedPurpose);
|
||||
return cryptoService.Unprotect(protectedData);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user