7

Powershellでこれを行う必要があるとしましょう:

    $SecurePass = Get-Content $CredPath | ConvertTo-SecureString -Key (1..16)
    [String]$CleartextPass = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($CredPass));

$CredPath の内容は、ConvertFrom-SecureString -Key (1..16) の出力を含むファイルです。

ConvertTo-SecureString -key (1..16)C#/.NET でこの部分を実現するにはどうすればよいですか?

の作成方法は知ってSecureStringいますが、暗号化をどのように処理すればよいかわかりません。

AES を使用して各文字を暗号化しますか、それとも文字列を復号化してから文字ごとに安全な文字列を作成しますか?

私は暗号化についてほとんど何も知りませんが、収集した情報から、C# を使用して Powershell コマンドを呼び出したいと思うかもしれません。

参考までに、AES 暗号化/復号化に関する同様の投稿を見つけました: C# での AES 暗号化の使用

アップデート

キースが投稿したリンクを確認しましたが、不明な点が他にもあります。DecryptStringFromBytes_Aes は 3 つの引数を取ります。

static string DecryptStringFromBytes_Aes(byte[] cipherText, byte[] Key, byte[] IV)

最初の引数は、暗号化されたテキストを表すバイト配列です。ここでの問題は、文字列をバイト配列でどのように表現する必要があるかということです。エンコーディングありまたはなしで表現する必要がありますか?

byte[] ciphertext = Encoding.ASCII.GetBytes(encrypted_text);
byte[] ciphertext = Encoding.UTF8.GetBytes(encrypted_text);
byte[] ciphertext = Encoding.Unicode.GetBytes(encrypted_text);    

byte[] ciphertext = new byte[encrypted_password.Length * sizeof(char)];
System.Buffer.BlockCopy(encrypted_password.ToCharArray(), 0, text, 0, text.Length);

2 番目のバイト配列のキーは、単純に整数の配列である必要があります。

byte[] key = { 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16 };

3 番目のバイト配列は「初期化ベクトル」です。Aes.Create() 呼び出しによって IV の byte[] がランダムに生成されるようです。読んでみると、同じ IV を使用する必要があるかもしれないことがわかりました。ConvertFrom-SecureString と ConvertTo-SecureString は単にキーを使用して暗号化/復号化できるため、IV[] がランダムである可能性がある、または静的な定義があるという仮定が残されています。

勝ち組はまだ見つかっていませんが、挑戦し続けます。

4

5 に答える 5

12

私はこれが古い投稿であることを知っています。MSDNまたはstackoverflowで完全な回答が見つからなかったため、完全性と後世のためにこれを投稿しています。これをもう一度行う必要がある場合に備えて、ここにあります。

これは、AES 暗号化を使用した powershell の ConvertTo-SecureString の C# 実装です (-key オプションを使用してオンにします)。ConvertFrom-SecureString の C# 実装をコード化するための演習のために残します。

# 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)

私の仕事は、回答を組み合わせて、user2748365 の回答を読みやすく再配置し、教育的なコメントを追加することです! また、部分文字列を取得する際の問題も修正しました。この投稿の時点では、彼のコードには strArray に 2 つの要素しかありません。

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);
}
于 2015-06-10T13:39:30.913 に答える
3

ConvertFrom-SecureString のドキュメントによると、AES 暗号化アルゴリズムが使用されます。

Key または SecureKey パラメーターを使用して暗号化キーを指定すると、Advanced Encryption Standard (AES) 暗号化アルゴリズムが使用されます。指定されたキーの長さは 128、192、または 256 ビットである必要があります。これは、これらが AES 暗号化アルゴリズムでサポートされているキーの長さであるためです。キーが指定されていない場合、Windows Data Protection API (DPAPI) を使用して標準の文字列表現が暗号化されます。

MSDN docsの DecryptStringFromBytes_Aes の例を見てください。

ところで、簡単なオプションは、C# から PowerShell エンジンを使用してConvertTo-SecureStringコマンドレットを実行し、作業を行うことです。それ以外の場合は、初期化ベクトルが ConvertFrom-SecureString 出力のどこかに埋め込まれているように見え、簡単に抽出できない場合があります。

于 2012-11-29T22:32:04.873 に答える
1

C#/.NET で ConvertTo-SecureString -key (1..16) 部分を実行するにはどうすればよいですか?

次のコードを参照してください。

    private static SecureString ConvertToSecureString(string encrypted, string header, byte[] key)
    {
        string[] strArray = Encoding.Unicode.GetString(Convert.FromBase64String(encrypted.Substring(header.Length, encrypted.Length - header.Length))).Split(new[] {'|'});
        SymmetricAlgorithm algorithm = SymmetricAlgorithm.Create();
        int num2 = strArray[2].Length/2;
        var bytes = new byte[num2];
        for (int i = 0; i < num2; i++)
            bytes[i] = byte.Parse(strArray[2].Substring(2*i, 2), NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture);
        ICryptoTransform transform = algorithm.CreateDecryptor(key, Convert.FromBase64String(strArray[1]));
        using (var stream = new CryptoStream(new MemoryStream(bytes), transform, CryptoStreamMode.Read))
        {
            var buffer = new byte[bytes.Length];
            int num = stream.Read(buffer, 0, buffer.Length);
            var data = new byte[num];
            for (int i = 0; i < num; i++) data[i] = buffer[i];
            var str = new SecureString();
            for (int j = 0; j < data.Length/2; j++) str.AppendChar((char) ((data[(2*j) + 1]*0x100) + data[2*j]));
            return str;
        }
    }

例:

    encrypted = "76492d1116743f0423413b16050a5345MgB8ADcAbgBiAGoAVQBCAFIANABNADgAYwBSAEoAQQA1AGQAZgAvAHYAYwAvAHcAPQA9AHwAZAAzADQAYwBhADYAOQAxAGIAZgA2ADgAZgA0AGMANwBjADQAYwBiADkAZgA1ADgAZgBiAGQAMwA3AGQAZgAzAA==";
    header = "76492d1116743f0423413b16050a5345";

復号化された文字を取得したい場合は、メソッド内のデータを確認してください。

于 2013-09-04T20:43:26.733 に答える
0

最も簡単で簡単な方法は、ConvertTo-SecureStringPowerShell コマンドを C# から直接呼び出すことです。そうすれば、実装に違いはなく、PowerShell から直接呼び出した場合とまったく同じ出力が得られます。

    string encryptedPassword = RunPowerShellCommand("\"" 
            + password 
            + "\" | ConvertTo-SecureString -AsPlainText -Force | ConvertFrom-SecureString", null);

    public static string RunPowerShellCommand(string command, 
        Dictionary<string, object> parameters)
    {
        using (PowerShell powerShellInstance = PowerShell.Create())
        {
            // Set up the running of the script
            powerShellInstance.AddScript(command);

            // Add the parameters
            if (parameters != null)
            {
                foreach (var parameter in parameters)
                {
                    powerShellInstance.AddParameter(parameter.Key, parameter.Value);
                }
            }

            // Run the command
            Collection<PSObject> psOutput = powerShellInstance.Invoke();

            StringBuilder stringBuilder = new StringBuilder();

            if (powerShellInstance.Streams.Error.Count > 0)
            {
                foreach (var errorMessage in powerShellInstance.Streams.Error)
                {
                    if (errorMessage != null)
                    {
                        throw new InvalidOperationException(errorMessage.ToString());
                    }
                }
            }

            foreach (var outputLine in psOutput)
            {
                if (outputLine != null)
                {
                    stringBuilder.Append(outputLine);
                }
            }

            return stringBuilder.ToString();
        }
    }
于 2015-09-07T17:12:45.647 に答える