none
[Cryptography] Bug ??? - AesThenHmac via Powershell RRS feed

  • Frage

  • Hallo Leute, ich bin bei der Fehlersuche gerade am verzweifeln.
    Im Codeblock habe ich das vollständige Script eingefügt um zu verifizieren worin mein Denkfehler liegt... 
    Ich hab nämlich kein blassen Schimmer!?

    Mein System:      

    Windows                              Windows 10 Pro 64-Bit                     
    Kernel                                 10.0.15063   
    .Net                                    4.7.02046                                                                  

    PSVersion                           5.1.15063.608
    PSCompatibleVersions         {1.0, 2.0, 3.0, 4.0...}                                                                               
    BuildVersion                       10.0.15063.608                                                                                        
    CLRVersion                         4.0.30319.42000                                                                                       
    WSManStackVersion            3.0                                                                                                   
    PSRemotingProtocolVersion  2.3                                                                                                   
    SerializationVersion             1.1.0.1

    Codeblock

    using namespace System
    using namespace System.IO
    using namespace System.Text
    using namespace System.Security.Cryptography
    
    cls
    
    $Error.Clear()
    $ErrorActionPreference = "SilentlyContinue"
    
    Add-Type @'
    using System;
    using System.IO;
    using System.Security.Cryptography;
    using System.Text;
    
    namespace EasyEncrypt
    {
        public abstract class AesThenHmac
        {
            public static readonly int BlockBitSize = 128;
            public static readonly int KeyBitSize = 256;
    
            public static readonly int SaltBitSize = 64;
            public static readonly int Iterations = 10000;
    
            public static string SimpleEncryptWithPassword(string secretMessage, string password,
                byte[] nonSecretPayload = null)
            {
                var plainText = Encoding.UTF8.GetBytes(secretMessage);
                var cipherText = SimpleEncryptWithPassword(plainText, password, nonSecretPayload);
                return Convert.ToBase64String(cipherText);
            }
    
            public static byte[] SimpleEncrypt(byte[] secretMessage, byte[] cryptKey, byte[] authKey,
                byte[] nonSecretPayload = null)
            {
                //non-secret payload optional
                nonSecretPayload = nonSecretPayload ?? new byte[] { };
    
                byte[] cipherText;
                byte[] iv;
    
                using (var aes = new AesManaged
                {
                    KeySize = KeyBitSize,
                    BlockSize = BlockBitSize,
                    Mode = CipherMode.CBC,
                    Padding = PaddingMode.PKCS7
                })
                {
                    aes.GenerateIV();
                    iv = aes.IV;
    
                    using (var encrypter = aes.CreateEncryptor(cryptKey, iv))
                    using (var cipherStream = new MemoryStream())
                    {
                        using (var cryptoStream = new CryptoStream(cipherStream, encrypter, CryptoStreamMode.Write))
                        using (var binaryWriter = new BinaryWriter(cryptoStream))
                        {
                            //Encrypt Data
                            binaryWriter.Write(secretMessage);
                        }
    
                        cipherText = cipherStream.ToArray();
                    }
                }
    
                //Assemble encrypted message and add authentication
                using (var hmac = new HMACSHA256(authKey))
                using (var encryptedStream = new MemoryStream())
                {
                    using (var binaryWriter = new BinaryWriter(encryptedStream))
                    {
                        //Prepend non-secret payload if any
                        binaryWriter.Write(nonSecretPayload);
                        //Prepend IV
                        binaryWriter.Write(iv);
                        //Write Ciphertext
                        binaryWriter.Write(cipherText);
                        binaryWriter.Flush();
    
                        //Authenticate all data
                        var tag = hmac.ComputeHash(encryptedStream.ToArray());
                        //Postpend tag
                        binaryWriter.Write(tag);
                    }
                    return encryptedStream.ToArray();
                }
            }
    
            public static byte[] SimpleEncryptWithPassword(byte[] secretMessage, string password,
                byte[] nonSecretPayload = null)
            {
                nonSecretPayload = nonSecretPayload ?? new byte[] { };
    
    
    
                var payload = new byte[((SaltBitSize / 8) * 2) + nonSecretPayload.Length];
    
                Array.Copy(nonSecretPayload, payload, nonSecretPayload.Length);
                int payloadIndex = nonSecretPayload.Length;
    
                byte[] cryptKey;
                byte[] authKey;
                //Use Random Salt to prevent pre-generated weak password attacks.
                using (var generator = new Rfc2898DeriveBytes(password, SaltBitSize / 8, Iterations))
                {
                    var salt = generator.Salt;
    
                    //Generate Keys
                    cryptKey = generator.GetBytes(KeyBitSize / 8);
    
                    //Create Non Secret Payload
                    Array.Copy(salt, 0, payload, payloadIndex, salt.Length);
                    payloadIndex += salt.Length;
                }
                
                using (var generator = new Rfc2898DeriveBytes(password, SaltBitSize / 8, Iterations))
                {
                    var salt = generator.Salt;
    
                    //Generate Keys
                    authKey = generator.GetBytes(KeyBitSize / 8);
    
                    //Create Rest of Non Secret Payload
                    Array.Copy(salt, 0, payload, payloadIndex, salt.Length);
                }
    
                return SimpleEncrypt(secretMessage, cryptKey, authKey, payload);
            }
        }
    }
    '@
    
    [Hashtable] $BitSize = @{ 
        Iterations = 10000
        Key   = 256
        Block = 128    
        Salt  = 64
    }
    
    Function AES
    {
        return New-Object -TypeName AesManaged -Property @{
            BlockSize = 128
            KeySize   = 256  
            Padding   = [PaddingMode]::PKCS7
            Mode      = [CipherMode]::CBC 
        } 
    }
    
    Function Decrypt-String ([string] $Base64String, [string] $password, [int] $nonSecretPayloadLength = 0) {
    
        $encryptedMessage = [Convert]::FromBase64String($Base64String)    
    
        $cryptSalt = New-Object byte[] ($BitSize.Salt / 8)
        $authSalt  = New-Object byte[] ($BitSize.Salt / 8)
    
        [Array]::Copy($encryptedMessage, $nonSecretPayloadLength, $cryptSalt, 0, $cryptSalt.Length);
        [Array]::Copy($encryptedMessage, ($nonSecretPayloadLength + $cryptSalt.Length), $authSalt, 0, $authSalt.Length);
    
        [Rfc2898DeriveBytes] $generator = New-Object Rfc2898DeriveBytes ($password, $cryptSalt, $BitSize.Iterations)
        $cryptKey = $generator.GetBytes(($BitSize.Key / 8))
        $generator.Dispose()
    
        [Rfc2898DeriveBytes] $generator = New-Object Rfc2898DeriveBytes ($password, $authSalt, $BitSize.Iterations)
        $authKey = $generator.GetBytes(($BitSize.Key / 8))
        $generator.Dispose()
    
        $nonSecretPayloadLength = ($cryptSalt.Length + $authSalt.Length + $nonSecretPayloadLength)
    
        [HMACSHA256] $hmac = New-Object HMACSHA256     
        $hmac.Key = $authKey
        $sentTag = New-Object byte[] ($hmac.HashSize / 8)
        $calcTag = $hmac.ComputeHash($encryptedMessage, 0, ($encryptedMessage.Length - $sentTag.Length))
        $ivLength = ($BitSize.Block / 8)    
        if ($encryptedMessage.Length -lt ($sentTag.Length + $nonSecretPayloadLength + $ivLength)) { return $null }
    
        [Array]::Copy($encryptedMessage, ($encryptedMessage.Length - $sentTag.Length), $sentTag, 0, $sentTag.Length)
        
        $compare = 0; for ([int] $i = 0; $i -lt $sentTag.Length; $i++)
        {
            $compare = $compare -or $sentTag[$i] -xor $calcTag[$i]
        }    
        if ($compare -ne 0) { return $null }
    
        try
        {
            [AesManaged] $aes = AES
            $iv = New-Object byte[] $ivLength
            [Array]::Copy($encryptedMessage, $nonSecretPayloadLength, $iv, 0, $iv.Length)
            
            $plainTextStream = New-Object MemoryStream
            $decrypterStream = New-Object CryptoStream @($plainTextStream, $aes.CreateDecryptor($cryptKey, $iv), [CryptoStreamMode]::Write)
            $binaryWriter = New-Object BinaryWriter ($decrypterStream)
            $binaryWriter.Write(
                $encryptedMessage,
                ($nonSecretPayloadLength + $iv.Length),
                ($encryptedMessage.Length - $nonSecretPayloadLength - $iv.Length - $sentTag.Length)
            )
        }
        catch { throw $_ }
        finally
        {            
            if($binaryWriter)    { $binaryWriter.Close() }
            if($decrypterStream) { $decrypterStream.Close() }
            if($plainTextStream) { $plainTextStream.Close() }
            if($aes)             { $aes.Dispose() }
        }
    
        return [Encoding]::UTF8.GetString($plainTextStream.ToArray())
    }
    
    
    Function Encrypt-String ([string] $secretMessage, [string] $password, [byte[]] $nonSecretPayload = $null) {
    
        $plainText = [Encoding]::UTF8.GetBytes($secretMessage)
    
        if ($nonSecretPayload -eq $null) { $nonSecretPayload = New-Object byte[] 0 } else {
            $nonSecretPayload = New-Object byte[] $nonSecretPayload
        }
        
        $payload = New-Object byte[] ((($BitSize.Salt / 8) * 2) + $nonSecretPayload.Length)
        [Array]::Copy($nonSecretPayload, $payload, $nonSecretPayload.Length)
        [int] $payloadIndex = $nonSecretPayload.Length
    
        [Rfc2898DeriveBytes] $generator = New-Object Rfc2898DeriveBytes ($password, ($BitSize.Salt / 8), $BitSize.Iterations)
        $salt = $generator.Salt
        $cryptKey = $generator.GetBytes(($BitSize.Key / 8))
        [Array]::Copy($salt, 0, $payload, $payloadIndex, $salt.Length)
        $payloadIndex = ($payloadIndex + $salt.Length)
        $generator.Dispose()
    
        [Rfc2898DeriveBytes] $generator = New-Object Rfc2898DeriveBytes ($password, ($BitSize.Salt / 8), $BitSize.Iterations)
        $salt = $generator.Salt
        $authKey = $generator.GetBytes(($BitSize.Key / 8))
        [Array]::Copy($salt, 0, $payload, $payloadIndex, $salt.Length)
        $generator.Dispose()
    
        try
        {
            [AesManaged] $aes = AES
            $aes.GenerateIV()    
            $iv = $aes.IV
    
            $cipherStream = New-Object MemoryStream
            [CryptoStream] $cryptoStream = New-Object CryptoStream @($cipherStream, $aes.CreateEncryptor($cryptKey, $iv), [CryptoStreamMode]::Write)
            [BinaryWriter] $binaryWriter = New-Object BinaryWriter ($cryptoStream)
            $binaryWriter.Write($plainText)    
    
        } 
        catch { throw $_ }
        finally
        {
            if ($binaryWriter) { $binaryWriter.Close() }
            if ($cryptoStream) { $cryptoStream.Close() }
            if ($cipherStream) { $cipherStream.Close() }
            if ($aes)          { $aes.Dispose() }
        }
    
        $cipherText = $cipherStream.ToArray()
    
        try
        {
            [HMACSHA256] $hmac = New-Object HMACSHA256
            $hmac.Key = $authKey
            $encryptedStream = New-Object MemoryStream
            [BinaryWriter] $binaryWriter = New-Object BinaryWriter ($encryptedStream)
            $binaryWriter.Write($nonSecretPayload)
            $binaryWriter.Write($iv)
            $binaryWriter.Write($cipherText)
            $binaryWriter.Flush()
            $tag = $hmac.ComputeHash($encryptedStream.ToArray())
            $binaryWriter.Write($tag)
        } 
        catch { throw $_ }
        finally
        {
            if ($binaryWriter)    { $binaryWriter.Close() }
            if ($encryptedStream) { $encryptedStream.Close() }
            if ($hmac)            { $hmac.Dispose() }
        }  
        
        return [Convert]::ToBase64String($encryptedStream.ToArray()) 
    }
    
    $Password = "LLVeDd0dMrYw784TQdRtzpE3Wx@9o75R5OjN/=="
    $Message  = "Ein Geheimer Text!!!"
    
    $AesThenHmac = [EasyEncrypt.AesThenHmac]::SimpleEncryptWithPassword($Message, $Password)
    "Encrypted Message: " + $AesThenHmac
    "Encrypted Length: "  + $AesThenHmac.Length
    "Decrypted Message: " + (Decrypt-String $AesThenHmac $Password) # Return Plain Message
    ""
    
    $EncryptString = Encrypt-String $Message $Password
    "Encrypted Message: " + $EncryptString
    "Encrypted Length: "  + $EncryptString.Length
    "Decrypted Message: " + (Decrypt-String $EncryptString $Password) # Return Null
    
    ""
    "Error:"
    0..$Error.Count | % { $Host.UI.WriteErrorLine($Error[$_]) }

     
    Sonntag, 24. September 2017 09:53

Antworten

  • Ich bedanke mich bei allen die sich die Zeit genommen haben sich hier durchzulesen. Inzwischen habe ich mein Problem selber lösen können

    Ich habe "nonSecretPayload" anstelle von "payload" verwendet, deshalb bekam nur 108 Zeichen.
    Zeile 101: return Encrypt(secretMessage, cryptKey, authKey, payload);
    Zeile 178: $binaryWriter.Write($payload)



    Montag, 25. September 2017 08:28

Alle Antworten

  • Auch auf die Gefahr hin, frech oder abweisend zu erscheinen, aber Du erwartest von uns nicht wirklich, dass wir jetzt Dein Script debuggen, oder? Du hast nicht mal geschrieben, was der Fehler  ist, den Du offenbar bekommst.

    Ich würde Dir empfehlen, bevor Du hier das nächste mal postest, Dir die "Forums-Regeln" mal durchzulesen, die am Anfang der Liste ganz oben festgepinnt sind. Besonders "Wie man am schnellsten die gewünschte Antwort erhält" könnte für Dich meiner Meinung nach sehr hilfreich sein.


    Grüße - Best regards

    PS:> (79,108,97,102|%{[char]$_})-join''

    Sonntag, 24. September 2017 10:45
  • OK, stimmt mein Fehler und Ja, die Regeln habe ich mir jetzt nicht durchgelesen.

    Ist so ziemlich mein erstes mall wo ich nach Hilfe suche, denn normaler weise schaue ich erstmal im Netz auf Antworten oder eventuelle Hinweise auf mein Problem. 

    Der Fehler selbst liegt in der Function "Encrypt-String".

    Es läuft zwar ganz normal durch, aber der String hat nicht die selbe Länge, wie der des Types den ich mit add-type hinzugefügt habe. Ergo gibt es nur eine Fehlermeldung bei der Function "Decrypt-String", weil die Länge nicht übereinstimmt, wie der des hinzugefügten Types. Das Forum brauch ja nicht alles zu Debuggen, ein Hinweis auf einer Zeile würde mir auch schon helfen.

    Und nochmals Entschuldigung.

    Sonntag, 24. September 2017 11:08
  • Ich bedanke mich bei allen die sich die Zeit genommen haben sich hier durchzulesen. Inzwischen habe ich mein Problem selber lösen können

    Ich habe "nonSecretPayload" anstelle von "payload" verwendet, deshalb bekam nur 108 Zeichen.
    Zeile 101: return Encrypt(secretMessage, cryptKey, authKey, payload);
    Zeile 178: $binaryWriter.Write($payload)



    Montag, 25. September 2017 08:28