Skip to content

Entschlüsseln von Daten


1. Codebeispiel C#

csharp
using System.Collections.Generic;
using System.Text;
using System;
using System.Security.Cryptography;
using System.IO;

namespace CuraGo.Internal
{
    public static class Crypt
    {
        static readonly Encoding Ansi;

        static Crypt() => Ansi = Encoding.GetEncoding("Windows-1252");

        public static string Decrypt(string key, string data)
        {
            switch (GetCryptVersionFromString(data))
            {
                case 1:
                    return DecryptAnsi(key, data);
                case 2:
                    return DecryptUtf8Aes256(key, data);
            }
            Console.WriteLine($"Fehler bei Entschlüsselung. Ungültige Eingabe: {data}");
            return "";
        }

        static bool InputTextToEncryptIsValid(int expectedVersion, string encryptedData, out byte[] initVector, out byte[] cipherText, out string errorText)
        {
            initVector = null;
            cipherText = null;

            var cryptChunks = encryptedData.Split(new char[]{'$'},StringSplitOptions.RemoveEmptyEntries);

            if (cryptChunks.Length == 3)
            {
                if (int.TryParse(cryptChunks[0], out var actualVersion))
                {
                    if (actualVersion == expectedVersion)
                    {
                        var base64InitVector = cryptChunks[1];
                        if (base64InitVector.Length > 0)
                        {
                            var base64CipherText = cryptChunks[2];
                            initVector = Convert.FromBase64String(base64InitVector);
                            cipherText = Convert.FromBase64String(base64CipherText);
                            errorText = "";
                            return true;
                        }
                        else
                        {
                            errorText = $"Fehler bei Entschlüsselung. Kein Initialisierungsvektor angegeben.";
                            return false;
                        }
                    }
                    else
                    {
                        errorText = $"Fehler bei Entschlüsselung. Erwartete Version: '{expectedVersion}' Erhaltene Version: '{actualVersion}'";
                        return false;
                    }
                }
                else
                {
                    errorText = $"Fehler bei Entschlüsselung. Ungültige Version: '{cryptChunks[0]}'";
                    return false;
                }
            }
            else
            {
                errorText = $"Fehler bei Entschlüsselung. Ungültige Eingabe: '{encryptedData}'";
                return false;
            }
        }

        static string DecryptUtf8Aes256(string key, string encryptedData)
        {
            const int expectedVersion = 2;

            if (InputTextToEncryptIsValid(expectedVersion,encryptedData,out var initVector,out var cipherText, out var errorText))
            {
                try
                {
                    var sha256Key = new SHA256Managed().ComputeHash(Encoding.UTF8.GetBytes(key));

                    using (var aesManaged = new AesManaged())
                    {
                        aesManaged.Key = sha256Key;
                        aesManaged.IV = initVector;
                        aesManaged.Padding = PaddingMode.PKCS7;
                        aesManaged.Mode = CipherMode.CBC;

                        // Create a decrytor to perform the stream transform.
                        var decryptor = aesManaged.CreateDecryptor(aesManaged.Key, aesManaged.IV);

                        // Create the streams used for decryption.
                        using (var memoryStreamDecrypt = new MemoryStream(cipherText))
                        {
                            using (var cryptoStreamDecrypt = new System.Security.Cryptography.CryptoStream(memoryStreamDecrypt, decryptor, System.Security.Cryptography.CryptoStreamMode.Read))
                            {
                                using (var streamReaderDecrypt = new StreamReader(cryptoStreamDecrypt,Encoding.UTF8))
                                {
                                    var decryptedData = streamReaderDecrypt.ReadToEnd();
                                    return decryptedData;
                                }
                            }
                        }
                    }
                }
                catch (Exception e)
                {
                    Console.WriteLine($"Fehler bei Entschlüsselung. {e.Message}");
                    return "";
                }
            }

            Console.WriteLine($"Fehler bei Entschlüsselung. {errorText}");
            return "";
        }

        static int GetCryptVersionFromString(string inputString)
        {
            if (inputString.Length >= 3)
            {
                var versionString = inputString.Substring(0, 3);
                if (versionString[0] == '$')
                {
                    char[] versionChars = { versionString[1], versionString[2] };
                    var strVersion = new string(versionChars);
                    if (int.TryParse(strVersion, out var cryptVersion))
                        return cryptVersion;
                }
            }
            return 1;
        }

        static byte[] ReadAllBytes(Stream stream)
        {
            using (var ms = new MemoryStream())
            {
                stream.CopyTo(ms);
                return ms.ToArray();
            }
        }

        static string DecryptAnsi(string key, string data)
        {
            if (string.IsNullOrEmpty(data))
                return "";
            try
            {
                byte[] sha256Key = new SHA256Managed().ComputeHash(Ansi.GetBytes(key));

                byte[] initVector = new MD5CryptoServiceProvider().ComputeHash(Ansi.GetBytes(key));

                byte[] encryptedData = Convert.FromBase64String(data);

                List<byte> toDecryptData = new List<byte>();
                toDecryptData.AddRange(encryptedData);

                using (var aesManaged = new AesManaged())
                {
                    aesManaged.Key = sha256Key;
                    aesManaged.IV = initVector;
                    aesManaged.Padding = PaddingMode.None;
                    aesManaged.Mode = CipherMode.CBC;

                    // Create a decrytor to perform the stream transform.
                    var decryptor = aesManaged.CreateDecryptor(aesManaged.Key, aesManaged.IV);

                    // Create the streams used for decryption.
                    using (var memoryStreamDecrypt = new MemoryStream(toDecryptData.ToArray()))
                    {
                        using (var cryptoStreamDecrypt = new CryptoStream(memoryStreamDecrypt, decryptor, CryptoStreamMode.Read))
                        {
                            var decryptedData = ReadAllBytes(cryptoStreamDecrypt);
                            int padSize = decryptedData[0];
                            byte[] result = new byte[decryptedData.Length - padSize - 1];
                            Array.ConstrainedCopy(decryptedData, 1, result, 0, result.Length);
                            return Ansi.GetString(result, 0, result.Length);
                        }
                    }
                }
            }
            catch (Exception e)
            {
                Console.WriteLine($"Fehler bei Entschlüsselung. {e.Message}");
                return "Fehler bei Entschlüsselung";
            }
        }
    }
}

2. Codebeispiel Go

go
package curasoft

import (
	"bytes"
	"crypto/aes"
	"crypto/cipher"
	"crypto/md5"
	"crypto/sha256"
	"encoding/base64"
	"errors"
	"log"
	"strings"
)

func Decrypt(key, cyphertext string) (string, error) {
	version := getCryptVersion(cyphertext)
	switch version {
	case 1:
		return decryptVersionOne(cyphertext, key)

	case 2:
		return decryptVersionTwo(cyphertext, key)
	}
	return "", nil
}

func getCryptVersion(cypherText string) int {
	stringSlice := strings.Split(cypherText, "$")
	if len(stringSlice) >= 4 {
		versionString := stringSlice[1]
		if versionString == "02" {
			return 2
		}
	}
	return 1
}

// version 1
func decryptVersionOne(data string, passphrase string) (string, error) {
	if data == "" {
		return "", nil
	}

	rawData, err := base64.StdEncoding.DecodeString(data)
	if err != nil {
		log.Print(err)
		return "", err
	}

	key := createSHA256Hash(passphrase)
	iv := createMD5Hash(passphrase)

	block, err := aes.NewCipher(key)
	if err != nil {
		log.Printf("cipher err %s", err)
		return "", err
	}

	decrypted := make([]byte, len(rawData))
	cipher.NewCBCDecrypter(block, iv).CryptBlocks(decrypted, rawData)
	padSize := decrypted[0]
	text := decrypted[1:(len(decrypted) - int(padSize))]

	return string(text), nil
}

// version 2
func decryptVersionTwo(data, passphrase string) (string, error) {
	key := createSHA256Hash(passphrase)
	stringSlice := strings.Split(data, "$")

	iv, err := base64.StdEncoding.DecodeString(stringSlice[2])
	if err != nil {
		return "", err
	}

	rawData, err := base64.StdEncoding.DecodeString(stringSlice[3])
	if err != nil {
		return "", err
	}

	block, err := aes.NewCipher(key)
	if err != nil {
		log.Printf("cipher err %s", err)
	}

	decrypted := make([]byte, len(rawData))
	cipher.NewCBCDecrypter(block, iv).CryptBlocks(decrypted, rawData)

	unPadded, err := pkcs7strip(decrypted, block.BlockSize())
	if err != nil {
		return "", err
	}

	return string(unPadded), nil
}

func pkcs7strip(data []byte, blockSize int) ([]byte, error) {
	length := len(data)
	if length == 0 {
		return nil, errors.New("pkcs7: Data is empty")
	}
	if length%blockSize != 0 {
		return nil, errors.New("pkcs7: Data is not block-aligned")
	}
	padLen := int(data[length-1])
	ref := bytes.Repeat([]byte{byte(padLen)}, padLen)
	if padLen > blockSize || padLen == 0 || !bytes.HasSuffix(data, ref) {
		return nil, errors.New("pkcs7: Invalid padding")
	}
	return data[:length-padLen], nil
}

func createSHA256Hash(key string) []byte {
	hasher := sha256.New()
	hasher.Write([]byte(key))
	return hasher.Sum(nil)
}

func createMD5Hash(key string) []byte {
	hasher := md5.New()
	hasher.Write([]byte(key))
	return hasher.Sum(nil)
}

3. Codebeispiel PHP

php
<?php

namespace Curasoft;

class Crypt
{
    /**
     * @param string $key
     * @param string $data
     * @return string
     */
    public static function Decrypt(string $key, string $data): string
    {
        switch (static::GetCryptVersionFromString($data))
        {
            case 1:
                return static::DecryptInternalOld($key, $data);
            case 2:
                return static::DecryptUtf8Aes256($key, $data);
        }
        return "";
    }

    /**
     * @param string $key
     * @param string $data
     * @return string
     */
    static function DecryptUtf8Aes256(string $key, string $data): string
    {
        if (strlen($data) > 3)
        {
            $version = '02';
            // Trennt nach $ auf und entfernt leere Elemente
            $splittedData = array_values(array_filter(explode("$", $data), 'strlen'));
            if (count($splittedData) == 3 && $splittedData[0] == $version)
            {
                $sha256key = hash('sha256', $key, true);
                $cryptMethod = "AES-256-CBC";
                $initVector = base64_decode($splittedData[1]);
                $cipherData = base64_decode($splittedData[2]);
                // Wenn kein Padding angegeben, wird automatisch PKCS#7 genommen
                return openssl_decrypt($cipherData, $cryptMethod, $sha256key, OPENSSL_RAW_DATA, $initVector);
            }
        }
        return "";
    }

    /**
     * @param string $data
     * @return int
     */
    static function GetCryptVersionFromString(string $data): int
    {
        if (strlen($data) >= 3)
        {
            $versionString = substr($data, 0, 3);
            if ($versionString[0] == '$') {
                $versionString = $versionString[1] . $versionString[2];
                if (is_numeric($versionString))
                {
                    return intval($versionString);
                }
            }
        }
        return 1;
    }

    /**
     * @param string $key
     * @param string $data
     * @return string
     *
     * Alte-Version:
     * Mitarbeiter-Namen von CuraSoft-Seite aus könnten Ansi-Bytes enthalten, deswegen wird am Ende ein utf8_encode durchgeführt,
     * um diese auf der Seite sauber darzustellen.
     * Alles andere (Passwörter, DataKeys) enthalten nur ASCII-Zeichen. Deswegen ist auch an dieser Stelle ein utf8_encode ungefährlich.
     */
    static function DecryptInternalOld(string $key, string $data): string
    {
        // Schlüssel und Initialisierungsvektor vorbereiten
        $hashed_key = hash('sha256', $key, true);
        $init_vector = md5($key, true);
        // Base64 Input
        $decoded_data = base64_decode($data);
        // Entschlüsseln
        $decrypted = openssl_decrypt(
            $decoded_data,
            'aes-256-cbc',
            $hashed_key,
            OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING,
            $init_vector
        );
        // Das erste Byte auslassen und den Inhalt ohne ZeroBytes rausholen
        $data = substr($decrypted, 1, strlen($decrypted) - ord(substr($decrypted, 0, 1)) - 1);
        return utf8_encode($data);
    }
}