मैं वर्तमान में अपने सी # एईएस-जीसीएम क्रिप्टोग्राफी कोड को PHP में बदलने पर काम कर रहा हूं। हालांकि, कुछ शोध के बाद, मेरे PHP सिस्टम द्वारा एन्क्रिप्ट किए गए पाठ को सी # एक द्वारा डिक्रिप्ट नहीं किया जा सकता है। मैं जानना चाहता हूं कि दोनों कोड से कोई अंतर है या नहीं:

सी # बाउंसीकैसल के साथ:

using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Crypto.Modes;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Security;
using System;
using System.IO;
using System.Text;

//the helper for all AES methods
public class AESHelper {

    private const int KEY_BIT_SIZE = 256;
    private const int MAC_BIT_SIZE = 128;
    private const int NONCE_BIT_SIZE = 128;

    private readonly SecureRandom random;

    private static AESHelper instance;
    public static AESHelper Instance //property of this class. Create an instance if it is not created yet
    {
        get
        {
            if (instance == null)
                instance = new AESHelper();
            return instance;
        }
    }

    public AESHelper()
    {
        random = new SecureRandom();
    }

    //decrypt with strings
    public string Decrypt(string message, string key, int nonSecretPayloadLength = 0)
    {
        if (string.IsNullOrEmpty(message))
            throw new ArgumentException("Message required!", "message");
        var decodedKey = Convert.FromBase64String(key);
        var cipherText = Convert.FromBase64String(message);
        var plainText = DecryptWithKey(cipherText, decodedKey, nonSecretPayloadLength);
        return Encoding.UTF8.GetString(plainText);
    }

    //encrypt with strings
    public string Encrypt(string text, string key, byte[] nonSecretPayload = null)
    {
        if (string.IsNullOrEmpty(text))
            throw new ArgumentException("Text required!", "text");
        var decodedKey = Convert.FromBase64String(key);
        var plainText = Encoding.UTF8.GetBytes(text);
        var cipherText = EncryptWithKey(plainText, decodedKey, nonSecretPayload);
        return Convert.ToBase64String(cipherText);
    }

    //create new key
    public string NewKey()
    {
        var key = new byte[KEY_BIT_SIZE / 8];
        random.NextBytes(key);
        return Convert.ToBase64String(key);
    }

    //decrypt with byte array
    private byte[] DecryptWithKey(byte[] message, byte[] key, int nonSecretPayloadLength = 0)
    {
        if (key == null || key.Length != KEY_BIT_SIZE / 8)
            throw new ArgumentException(String.Format("Key needs to be {0} bit!", KEY_BIT_SIZE), "key");
        if (message == null || message.Length == 0)
            throw new ArgumentException("Message required!", "message");

        using (var cipherStream = new MemoryStream(message))
            using (var cipherReader = new BinaryReader(cipherStream))
        {
            var nonSecretPayload = cipherReader.ReadBytes(nonSecretPayloadLength);
            var nonce = cipherReader.ReadBytes(NONCE_BIT_SIZE / 8);
            var cipher = new GcmBlockCipher(new AesEngine());
            var parameters = new AeadParameters(new KeyParameter(key), MAC_BIT_SIZE, nonce, nonSecretPayload);
            cipher.Init(false, parameters);
            var cipherText = cipherReader.ReadBytes(message.Length - nonSecretPayloadLength - nonce.Length);
            var plainText = new byte[cipher.GetOutputSize(cipherText.Length)];
            try
            {
                var len = cipher.ProcessBytes(cipherText, 0, cipherText.Length, plainText, 0);
                cipher.DoFinal(plainText, len);
            }
            catch (InvalidCipherTextException)
            {
                return null;
            }
            return plainText;
        }
    }

    //encrypt with byte array
    private byte[] EncryptWithKey(byte[] text, byte[] key, byte[] nonSecretPayload = null)
    {
        if (key == null || key.Length != KEY_BIT_SIZE / 8)
            throw new ArgumentException(String.Format("Key needs to be {0} bit!", KEY_BIT_SIZE), "key");

        nonSecretPayload = nonSecretPayload ?? new byte[] { };
        var nonce = new byte[NONCE_BIT_SIZE / 8];
        random.NextBytes(nonce, 0, nonce.Length);
        var cipher = new GcmBlockCipher(new AesEngine());
        var parameters = new AeadParameters(new KeyParameter(key), MAC_BIT_SIZE, nonce, nonSecretPayload);
        cipher.Init(true, parameters);
        var cipherText = new byte[cipher.GetOutputSize(text.Length)];
        var len = cipher.ProcessBytes(text, 0, text.Length, cipherText, 0);
        cipher.DoFinal(cipherText, len);
        using (var combinedStream = new MemoryStream())
        {
            using (var binaryWriter = new BinaryWriter(combinedStream))
            {
                binaryWriter.Write(nonSecretPayload);
                binaryWriter.Write(nonce);
                binaryWriter.Write(cipherText);
            }
            return combinedStream.ToArray();
        }
    }
}

यहाँ पीएचपी प्रणाली है:

<?php
    echo '<pre>';

    $hash_string = 'qIANSOwtdfF4y5Yk33ZLE5s6KwKBAeu6qzJRG84Sjjo=';
    echo "password : ";
    var_dump($hash_string);
    echo '<hr>';
    $decode_string = base64_decode($hash_string);
    $app_cc_aes_key = substr($decode_string, 0, 32);
    $cipher = 'aes-256-gcm';
    $iv_len = openssl_cipher_iv_length($cipher);
    echo "app_cc_aes_key : ";
    var_dump($app_cc_aes_key);
    echo '<br>';
    echo "cipher :";
    var_dump($cipher);
    echo '<hr>';

    $data = '7bc9d6ae-982f-11e9-bc42-526af7764f64';
    echo "data : {$data}";
    echo '<hr>';

    $tag_length = 16;
    $iv = openssl_random_pseudo_bytes($iv_len);
    $tag = "";
    $encrypt = openssl_encrypt($data, $cipher, $app_cc_aes_key, OPENSSL_RAW_DATA, $iv, $tag, "", $tag_length);
    $encrypt_text = base64_encode($iv.$tag.$encrypt);
    echo "encrypt :";
    var_dump($encrypt);
    echo '<br>';
    echo "encrypt_text :";
    var_dump($encrypt_text);
    echo '<hr>';

    $decoded_text = base64_decode($encrypt_text);
    $iv = substr($decoded_text, 0, $iv_len);
    $tag = substr($decoded_text, $iv_len, $tag_length);
    $ciphertext = substr($decoded_text, $iv_len + $tag_length);
    $decrypt_text = openssl_decrypt($ciphertext, $cipher, $app_cc_aes_key, OPENSSL_RAW_DATA, $iv, $tag);
    echo "decrypt_text : {$decrypt_text}";
    echo '<hr>';
?>

क्या कोई मुझे बता सकता है कि PHP कोड में कुछ गुम या अलग है जो उन्हें अलग तरीके से करता है? या अगर PHP फ़ंक्शंस और BouncyCastle फ़ंक्शंस के बीच कुछ आंतरिक अंतर है जो उन्हें अलग बनाता है?

0
Sunny Leung 4 जुलाई 2019, 11:57

1 उत्तर

सबसे बढ़िया उत्तर
  • C#-कोड में, एन्क्रिप्शन के दौरान डेटा को निम्न क्रम में संयोजित किया जाता है:

    nonSecretPyload nonce cipherText

    यहां cipherText में दो भाग होते हैं, एन्क्रिप्टेड संदेश और प्रमाणीकरण टैग। एन्क्रिप्टेड संदेश में टैग संलग्न करना GcmBlockCipher#DoFinal.

    PHP-कोड में, एन्क्रिप्शन के दौरान डेटा को निम्न क्रम में संयोजित किया जाता है:

    $iv $tag $encrypt

    यहाँ $iv, nonce का प्रतिरूप है। GcmBlockCipher#DoFinal के विपरीत, PHP-विधि openssl_encrypt केवल एन्क्रिप्ट किया गया संदेश ($encrypt) देता है। प्रमाणीकरण टैग एक अलग चर (6वें openssl_encrypt-पैरामीटर $tag) में लौटाया जाता है। इसलिए, $tag और $encrypt विपरीत क्रम में cipherText के अनुरूप हैं। PHP-कोड में अतिरिक्त प्रमाणित डेटा, यानी nonSecretPyload के समकक्ष पर विचार नहीं किया जाता है।

    यह तुरंत स्पष्ट है कि दो कोडों में अलग-अलग घटकों के क्रम अलग-अलग हैं। इसका अर्थ यह है कि C#-कोड में एन्क्रिप्ट किए गए संदेश को PHP-कोड (और इसके विपरीत) में डिक्रिप्ट नहीं किया जा सकता है। इसके लिए संभव होने के लिए, PHP-कोड में क्रम को निम्नानुसार बदला जाना चाहिए:

    $aad $iv $encrypt $tag

    यहाँ $aad, nonSecretPyload का प्रतिरूप है। आदेश (साथ ही अतिरिक्त प्रमाणित डेटा पर विचार) को एन्क्रिप्शन भाग और डिक्रिप्शन भाग दोनों में अनुकूलित किया जाना चाहिए।

  • इसके अलावा, विभिन्न IV लंबाई का उपयोग किया जाता है: C#-कोड 16 बाइट्स में, PHP-कोड 12 बाइट्स में (बाद वाला क्योंकि openssl_cipher_iv_length('aes-256-gcm') रिटर्न 12), जहां 12 बाइट्स वास्तव में अनुशंसित लंबाई। संगतता के लिए, दोनों कोडों में एक समान IV लंबाई का उपयोग किया जाना चाहिए!

4
Topaco 4 जुलाई 2019, 18:17