Saltar al contenido

¿Cómo puedo usar ConvertTo-SecureString?

Solución:

Sé que esta es una publicación antigua. Estoy publicando esto para que esté completo y para la posteridad, porque no pude encontrar una respuesta completa en MSDN o stackoverflow. Estará aquí en caso de que necesite hacer esto de nuevo.

Es una implementación de C # de ConvertTo-SecureString de powershell con cifrado AES (activado mediante la opción -key). Dejaré que el ejercicio codifique una implementación de C # de ConvertFrom-SecureString.

# forward direction
[securestring] $someSecureString = read-host -assecurestring
[string] $psProtectedString = ConvertFrom-SecureString -key (1..16) -SecureString $someSecureString
# reverse direction
$back = ConvertTo-SecureString -string $psProtectedString -key (1..16)

¡Mi trabajo es combinar respuestas y reorganizar la respuesta de user2748365 para que sea más legible y agregar comentarios educativos! También solucioné el problema de tomar una subcadena: en el momento de esta publicación, su código solo tiene dos elementos en strArray.

using System.IO;
using System.Text;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Cryptography;
using System.Globalization;

// psProtectedString - this is the output from
//   powershell> $psProtectedString = ConvertFrom-SecureString -SecureString $aSecureString -key (1..16)
// key - make sure you add size checking 
// notes: this will throw an cryptographic invalid padding exception if it cannot decrypt correctly (wrong key)
public static SecureString ConvertToSecureString(string psProtectedString, byte[] key)
{
    // '|' is indeed the separater
    byte[] asBytes = Convert.FromBase64String( psProtectedString );
    string[] strArray = Encoding.Unicode.GetString(asBytes).Split(new[] { '|' });

    if (strArray.Length != 3) throw new InvalidDataException("input had incorrect format");

    // strArray[0] is a static/magic header or signature (different passwords produce
    //    the same header)  It unused in our case, looks like 16 bytes as hex-string
    // you know strArray[1] is a base64 string by the '=' at the end
    //    the IV is shorter than the body, and you can verify that it is the IV, 
    //    because it is exactly 16bytes=128bits and it decrypts the password correctly
    // you know strArray[2] is a hex-string because it is [0-9a-f]
    byte[] magicHeader = HexStringToByteArray(encrypted.Substring(0, 32));
    byte[] rgbIV = Convert.FromBase64String(strArray[1]);
    byte[] cipherBytes = HexStringToByteArray(strArray[2]);

    // setup the decrypter
    SecureString str = new SecureString();
    SymmetricAlgorithm algorithm = SymmetricAlgorithm.Create();
    ICryptoTransform transform = algorithm.CreateDecryptor(key, rgbIV);
    using (var stream = new CryptoStream(new MemoryStream(cipherBytes), transform, CryptoStreamMode.Read))
    {
        // using this silly loop format to loop one char at a time
        // so we never store the entire password naked in memory
        int numRed = 0;
        byte[] buffer = new byte[2]; // two bytes per unicode char
        while( (numRed = stream.Read(buffer, 0, buffer.Length)) > 0 )
        {
            str.AppendChar(Encoding.Unicode.GetString(buffer).ToCharArray()[0]);
        }
    }

    //
    // non-production code
    // recover the SecureString; just to check
    // from http://stackoverflow.com/questions/818704/how-to-convert-securestring-to-system-string
    //
    IntPtr valuePtr = IntPtr.Zero;
    string secureStringValue = "";
    try
    {
        // get the string back
        valuePtr = Marshal.SecureStringToGlobalAllocUnicode(str);
        secureStringValue = Marshal.PtrToStringUni(valuePtr);
    }
    finally
    {
        Marshal.ZeroFreeGlobalAllocUnicode(valuePtr);
    }

    return str;
}
// from http://stackoverflow.com/questions/311165/how-do-you-convert-byte-array-to-hexadecimal-string-and-vice-versa
public static byte[] HexStringToByteArray(String hex)
{
    int NumberChars = hex.Length;
    byte[] bytes = new byte[NumberChars / 2];
    for (int i = 0; i < NumberChars; i += 2) bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);

    return bytes;
}
public static SecureString DecryptPassword( string psPasswordFile, byte[] key )
{
    if( ! File.Exists(psPasswordFile)) throw new ArgumentException("file does not exist: " + psPasswordFile);

    string formattedCipherText = File.ReadAllText( psPasswordFile );

    return ConvertToSecureString(formattedCipherText, key);
}

De acuerdo con los documentos de ConvertFrom-SecureString, se utiliza el algoritmo de cifrado AES:

Si se especifica una clave de cifrado mediante los parámetros Key o SecureKey, se utiliza el algoritmo de cifrado Advanced Encryption Standard (AES). La clave especificada debe tener una longitud de 128, 192 o 256 bits porque esas son las longitudes de clave admitidas por el algoritmo de cifrado AES. Si no se especifica ninguna clave, se utiliza la API de protección de datos de Windows (DPAPI) para cifrar la representación de cadena estándar.

Mire el ejemplo de DecryptStringFromBytes_Aes en los documentos de MSDN.

Por cierto, una opción fácil sería utilizar el motor PowerShell de C # para ejecutar el ConvertTo-SecureString cmdlet para hacer el trabajo. De lo contrario, parece que el vector de inicialización está incrustado en algún lugar de la salida ConvertFrom-SecureString y puede o no ser fácil de extraer.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *