Padding tidak valid dan tidak dapat dilepas?

126

Saya telah mencari secara online apa arti pengecualian ini sehubungan dengan program saya tetapi tidak dapat menemukan solusi atau alasan mengapa hal itu terjadi pada program khusus saya. Saya telah menggunakan contoh yang disediakan msdn saya untuk mengenkripsi dan mendekripsi XmlDocument menggunakan algoritma Rijndael. Enkripsi berfungsi dengan baik tetapi ketika saya mencoba mendekripsi, saya mendapatkan pengecualian berikut:

Padding tidak valid dan tidak dapat dilepas

Adakah yang bisa memberi tahu saya apa yang dapat saya lakukan untuk mengatasi masalah ini? Kode saya di bawah ini adalah tempat saya mendapatkan kunci dan data lainnya. Jika cryptoMode salah, itu akan memanggil metode dekripsi, di mana pengecualian terjadi:

public void Cryptography(XmlDocument doc, bool cryptographyMode)
{
    RijndaelManaged key = null;
    try
    {
    // Create a new Rijndael key.
    key = new RijndaelManaged();
    const string passwordBytes = "Password1234"; //password here 

    byte[] saltBytes = Encoding.UTF8.GetBytes("SaltBytes");
    Rfc2898DeriveBytes p = new Rfc2898DeriveBytes(passwordBytes, saltBytes);
    // sizes are devided by 8 because [ 1 byte = 8 bits ] 
    key.IV = p.GetBytes(key.BlockSize/8);
    key.Key = p.GetBytes(key.KeySize/8);

    if (cryptographyMode)
    {
        Ecrypt(doc, "Content", key);
    }
    else
    {
        Decrypt(doc, key);
    }

    }
    catch (Exception ex)
    {
    MessageBox.Show(ex.Message);
    }
    finally
    {
    // Clear the key.
    if (key != null)
    {
        key.Clear();
    }
    }

}

private void Decrypt(XmlDocument doc, SymmetricAlgorithm alg)
{
    // Check the arguments.  
    if (doc == null)
    throw new ArgumentNullException("Doc");
    if (alg == null)
    throw new ArgumentNullException("alg");

    // Find the EncryptedData element in the XmlDocument.
    XmlElement encryptedElement = doc.GetElementsByTagName("EncryptedData")[0] as XmlElement;

    // If the EncryptedData element was not found, throw an exception.
    if (encryptedElement == null)
    {
    throw new XmlException("The EncryptedData element was not found.");
    }


    // Create an EncryptedData object and populate it.
    EncryptedData edElement = new EncryptedData();
    edElement.LoadXml(encryptedElement);

    // Create a new EncryptedXml object.
    EncryptedXml exml = new EncryptedXml();


    // Decrypt the element using the symmetric key.
    byte[] rgbOutput = exml.DecryptData(edElement, alg); <----  I GET THE EXCEPTION HERE
    // Replace the encryptedData element with the plaintext XML element.
    exml.ReplaceData(encryptedElement, rgbOutput);

}
Brown Love
sumber
12
Bisakah Anda mencobanya dengan secara eksplisit mengatur mode padding agar identik pada enkripsi dan dekripsi menjadi indentikal. Misalnya: alg.Padding = PaddingMode.NONE;
NetSquirrel
Seperti apa metode Encrypt () itu?
csharptest.net
1
Terima kasih teman-teman yang berhasil.
Brown Love
2
@NetSquirrel: terima kasih atas pengingatnya untuk PaddingMode.NONE. Ini membuat saya keluar dari kesalahan ini (ke kesalahan lain) ... Melakukan AES di Java dan C #, dan sekarang tidak tahu mengapa C # mengeluh tentang padding Java, meskipun keduanya menggunakan PKCS # 7
Hoàng Long

Jawaban:

81

Rijndael / AES adalah block cypher. Ini mengenkripsi data dalam blok 128 bit (16 karakter). Padding kriptografi digunakan untuk memastikan bahwa blok pesan terakhir selalu berukuran benar.

Metode dekripsi Anda mengharapkan apa pun pengisi defaultnya, dan tidak menemukannya. Seperti yang dikatakan @NetSquirrel, Anda perlu secara eksplisit menyetel padding untuk enkripsi dan dekripsi. Kecuali jika Anda memiliki alasan untuk melakukan sebaliknya, gunakan padding PKCS # 7.

rossum
sumber
7
bagaimana cara mengatur padding secara eksplisit ??
Ahmad Hajjar
7
Terima kasih saya menemukannya rj.Padding = PaddingMode.none; :)
Ahmad Hajjar
7
@AhmadHajjar Tidak ada padding yang memiliki implikasi keamanan, jangan gunakan.
deviantfan
1
Hai, saya menyetel padding secara eksplisit, tetapi tidak berfungsi. Saya tidak tahu langkah apa yang saya lakukan salah. Tolong bantu. alg.Padding = PaddingMode.PKCS7;
Johnny
21
Saya menyadari ini adalah utas lama. Namun, bagi mereka yang berkunjung, pastikan Anda menghapus blok terakhir saat mengenkripsi data.
Markus
53

Pastikan bahwa kunci Anda gunakan untuk mengenkripsi dan mendekripsi yang sama . Metode padding bahkan jika tidak secara eksplisit disetel harus tetap memungkinkan dekripsi / enkripsi yang tepat (jika tidak disetel, keduanya akan sama). Namun jika Anda karena alasan tertentu menggunakan sekumpulan kunci yang berbeda untuk dekripsi daripada yang digunakan untuk enkripsi, Anda akan mendapatkan kesalahan ini:

Padding tidak valid dan tidak dapat dilepas

Jika Anda menggunakan beberapa algoritme untuk secara dinamis menghasilkan kunci yang tidak akan berfungsi. Keduanya harus sama untuk enkripsi dan dekripsi. Salah satu cara yang umum adalah meminta pemanggil menyediakan kunci dalam konstruktor kelas metode enkripsi, untuk mencegah proses enkripsi / dekripsi terlibat dalam pembuatan item ini. Ini berfokus pada tugas yang ada (mengenkripsi dan mendekripsi data) dan memerlukan ivdan keyharus disediakan oleh pemanggil.

atconway
sumber
Tip ini sangat berguna, karena, terkadang kunci disimpan di app.config dan kita harus selalu yakin bahwa kunci yang digunakan untuk mengenkripsi sama dengan yang digunakan untuk mendekripsi.
Mário Meyrelles
@atconway Maukah Anda melihat pertanyaan saya? Saya memiliki masalah serupa tetapi di C ++ / CLI: stackoverflow.com/questions/57139447/…
Sederhana
1
Saya menyarankan bahwa dalam penggunaan sehari-hari, ini mungkin alasan yang paling mungkin mengapa orang akan mengalami kesalahan ini. Apalagi jika Anda tidak mengotak-atik pengaturan padding.
Dan
28

Untuk kepentingan orang-orang yang mencari, mungkin ada baiknya memeriksa input yang sedang didekripsi. Dalam kasus saya, info yang dikirim untuk dekripsi (salah) masuk sebagai string kosong. Ini mengakibatkan kesalahan padding.

Ini mungkin terkait dengan jawaban rossum, tetapi menurut saya itu layak untuk disebutkan.

HokiJ
sumber
Saya setuju, kebetulan saya sama, memeriksa input yang didekripsi SEBELUM melakukan pemeriksaan lainnya. Saya mendapatkan 1 byte lebih banyak dari yang saya encypted ...
Andrea Antonangeli
Tali kosong juga menjadi penyebabnya bagi saya.
dotNET
Kasus saya adalah frasa sandi tidak disetel (ya saya tahu), tetapi jawaban ini membawa saya ke arah yang benar.
Jim
2
Masalah saya adalah string yang akan didekripsi diubah menjadi huruf kecil sebelum saya mencoba mendekripsinya. Saya terobsesi dengan padding dan cipher dan semua itu, tapi ternyata itu hanya masukan yang buruk. Terkadang Anda hanya perlu mundur selangkah!
Tom Gerken
15

Jika kunci dan vektor inisialisasi yang sama digunakan untuk encoding dan decoding, masalah ini tidak berasal dari decoding data tetapi dari encoding data.

Setelah Anda memanggil metode Write pada objek CryptoStream, Anda harus SELALU memanggil metode FlushFinalBlock sebelum metode Tutup.

Dokumentasi MSDN pada metode CryptoStream.FlushFinalBlock mengatakan:
" Memanggil metode Tutup akan memanggil FlushFinalBlock ... "
https://msdn.microsoft.com/en-US/library/system.security.cryptography.cryptostream.flushfinalblock(v=vs .110) .aspx
Ini salah. Memanggil metode Tutup hanya menutup CryptoStream dan Aliran keluaran.
Jika Anda tidak memanggil FlushFinalBlock sebelum Tutup setelah Anda menulis data untuk dienkripsi, saat mendekripsi data, panggilan ke metode Read atau CopyTo pada objek CryptoStream Anda akan memunculkan pengecualian CryptographicException (pesan: "Padding tidak valid dan tidak dapat dihapus").

Ini mungkin benar untuk semua algoritma enkripsi yang diturunkan dari SymmetricAlgorithm (Aes, DES, RC2, Rijndael, TripleDES), meskipun saya baru saja memverifikasi itu untuk AesManaged dan MemoryStream sebagai Output Stream.

Jadi, jika Anda menerima pengecualian CryptographicException ini pada dekripsi, baca nilai properti Stream Length Anda setelah Anda menulis data untuk dienkripsi, lalu panggil FlushFinalBlock dan baca nilainya lagi. Jika sudah berubah, Anda tahu bahwa memanggil FlushFinalBlock TIDAK opsional.

Dan Anda tidak perlu melakukan padding secara terprogram, atau memilih nilai properti Padding lainnya. Padding adalah tugas metode FlushFinalBlock.

.........

Komentar tambahan untuk Kevin:

Ya, CryptoStream memanggil FlushFinalBlock sebelum memanggil Tutup, tetapi sudah terlambat: ketika metode Tutup CryptoStream dipanggil, aliran keluaran juga ditutup.

Jika aliran keluaran Anda adalah MemoryStream, Anda tidak dapat membaca datanya setelah ditutup. Jadi, Anda perlu memanggil FlushFinalBlock di CryptoStream sebelum menggunakan data terenkripsi yang tertulis di MemoryStream.

Jika aliran keluaran Anda adalah FileStream, segalanya menjadi lebih buruk karena penulisan di-buffer. Konsekuensinya adalah byte tertulis terakhir mungkin tidak ditulis ke file jika Anda menutup aliran keluaran sebelum memanggil Flush di FileStream. Jadi sebelum memanggil Tutup di CryptoStream, Anda harus terlebih dahulu memanggil FlushFinalBlock di CryptoStream, lalu memanggil Flush di FileStream Anda.

figolu
sumber
1
Mengapa Anda mengatakan itu salah? Kode untuk Stream.Close()panggilan this.Dispose(true). Kode untuk CryptoStream.Dispose(bool):if (disposing) { if (!this._finalBlockTransformed) { this.FlushFinalBlock(); } this._stream.Close(); }
Kevin Doyon
1
Ini menyelesaikan masalah saya. Saya telah membuang cryptoStream dengan benar, tetapi panggilan buang terjadi "terlambat", seperti yang Anda katakan. Ini mengakibatkan kesalahan "pengisi tidak valid", seperti yang dijelaskan. Dengan menambahkan cryptoStream.FlushFinalBlock (), kesalahan padding yang tidak valid telah diatasi. Terima kasih!
Daniel Lambert
14

Saat pertempuran serval, saya akhirnya memecahkan masalah.
(Catatan: Saya menggunakan AES standar sebagai algoritme simetris. Jawaban ini mungkin tidak cocok untuk semua orang.)

  1. Ubah kelas algoritme. Ganti RijndaelManagedkelas menjadi AESManagedsatu.
  2. Jangan secara eksplisit mengatur KeySizekelas algoritma, biarkan default.
    (Ini adalah langkah yang sangat penting. Saya rasa ada bug di properti KeySize.)

Berikut adalah daftar yang ingin Anda periksa argumen mana yang mungkin Anda lewatkan:

  • Kunci
    (array byte, panjang harus tepat salah satu dari 16, 24, 32 byte untuk ukuran kunci yang berbeda.)
  • IV
    (array byte, 16 byte)
  • CipherMode
    (Salah satu CBC, CFB, CTS, ECB, OFB)
  • PaddingMode
    (Salah satu ANSIX923, ISO10126, Tidak Ada, PKCS7, Nol)
Johnny
sumber
3
Tidak secara eksplisit mengaturnya KeySizelangsung untuk saya. Oh, keunikan .NET :-(
Yohanes
Perhatikan bahwa ini tampaknya regresi dalam .NET Framework itu sendiri. Saya memiliki kode yang digunakan untuk bekerja dengan RijndaelManaged, tetapi berhenti bekerja, dan hanya dengan mengubahnya ke AesManaged / AesCryptoServiceProvider, itu berfungsi lagi. Saya bahkan tidak memiliki kode apa pun yang secara eksplisit mengatur KeySize. Jadi jika Anda digigit oleh ini, merasa lebih baik - kesalahan mungkin bukan terletak pada Anda, tetapi dengan .NET Framework itu sendiri.
Usas
6

Masalah saya adalah bahwa passPhrase enkripsi tidak cocok dengan passPhrase dekripsi ... jadi kesalahan ini muncul .. sedikit menyesatkan.

ecklerpa
sumber
Sebenarnya memang benar kami menggunakan PaddingMode.PKCS7 untuk Encrypt dan Decrypt tapi saya mendapat pesan error yang sama. Kami juga memiliki lingkungan Stage dan Dev dengan nilai kunci yang berbeda. Ketika saya menggunakan tombol -lingkungan yang tepat - kunci pengecualian ini diselesaikan ...
Mayor
Meskipun semua jawaban di atas bagus dan Anda harus menggunakan padding yang sama untuk Encrypt dan Decrypt (tidak ada yang TIDAK disarankan!) Sebenarnya jawaban ini juga bisa benar. Ketika saya menggunakan kunci -environment specific - pengecualian "System.Security.Cryptography.CryptographicException: Padding tidak valid dan tidak dapat dihapus." terpecahkan. Jadi ya itu bisa menyesatkan.
Mayor
Jika dengan "passPhrase" Anda berbicara tentang nilai pasti untuk mengenkripsi / mendekripsi (bukan masalah dengan menggunakan kunci yang salah), maka ya, ini adalah masalah saya. Kasus saya adalah nilai terenkripsi asli lebih panjang dari yang diizinkan bidang tabel database saya sehingga dipotong agar sesuai tanpa saya sadari. Kemudian ketika mendekripsi nilai terpotong itu, pengecualian ini dilemparkan.
David Gunderson
2

Solusi yang memperbaiki milik saya adalah bahwa saya secara tidak sengaja telah menerapkan kunci yang berbeda ke metode Enkripsi dan Dekripsi.

Rondakay
sumber
1

Saya menemukan kesalahan ini ketika mencoba melewati jalur file yang tidak dienkripsi ke metode Decrypt. Solusinya adalah memeriksa apakah file yang dilewati dienkripsi terlebih dahulu sebelum mencoba mendekripsi

if (Sec.IsFileEncrypted(e.File.FullName))
{
    var stream = Sec.Decrypt(e.File.FullName);
} 
else
{
    // non-encrypted scenario  
}
berguna
sumber
1
Saya menantang setiap Pengecut Hit and Run tentang validitas solusi ini.
bergunaBee
+1 karena pengecualian ini dimunculkan saat Anda mendekripsi dua kali atau Anda mendekripsi sesuatu yang tidak dienkripsi. Jadi saya membaca jawaban ini sebagai "apakah Anda yakin bahwa datanya benar-benar dienkripsi?".
Gerardo Grignoli
0

Skenario lain, sekali lagi untuk kepentingan orang yang mencari.

Bagi saya kesalahan ini terjadi selama metode Dispose () yang menutupi kesalahan sebelumnya yang tidak terkait dengan enkripsi.

Setelah komponen lain diperbaiki, pengecualian ini hilang.

Clay Lenhart
sumber
3
Apa kesalahan sebelumnya yang tidak terkait dengan enkripsi?
NStuke
0

Saya mengalami kesalahan padding ini ketika saya mengedit string terenkripsi secara manual dalam file (menggunakan notepad) karena saya ingin menguji bagaimana fungsi dekripsi akan berperilaku jika konten terenkripsi saya diubah secara manual.

Solusi bagi saya adalah menempatkan file

        try
            decryption stuff....
        catch
             inform decryption will not be carried out.
        end try

Seperti yang saya katakan, kesalahan padding saya adalah karena saya mengetik secara manual di atas teks yang didekripsi menggunakan notepad. Semoga jawaban saya dapat memandu Anda untuk solusi Anda.

webzy
sumber
0

Saya mengalami kesalahan yang sama. Dalam kasus saya itu karena saya telah menyimpan data terenkripsi dalam Database SQL. Tabel tempat penyimpanan data, memiliki tipe data biner (1000). Saat mengambil data dari database, itu akan mendekripsi 1000 byte ini, sementara sebenarnya ada 400 byte. Jadi menghapus nol trailing (600) dari hasil itu memperbaiki masalah.

Martijn
sumber
0

Saya mengalami kesalahan ini dan secara eksplisit mengatur blocksize: aesManaged.BlockSize = 128;

Setelah saya menghapusnya, itu berhasil.

Barry Franklin
sumber
0

Saya mengalami masalah yang sama saat mencoba memindahkan program Go ke C #. Ini berarti banyak data telah dienkripsi dengan program Go. Data ini sekarang harus didekripsi dengan C #.

Solusi terakhir adalah PaddingMode.Noneatau lebih tepatnya PaddingMode.Zeros.

Metode kriptografi di Go:

import (
    "crypto/aes"
    "crypto/cipher"
    "crypto/sha1"
    "encoding/base64"
    "io/ioutil"
    "log"

    "golang.org/x/crypto/pbkdf2"
)

func decryptFile(filename string, saltBytes []byte, masterPassword []byte) (artifact string) {

    const (
        keyLength         int = 256
        rfc2898Iterations int = 6
    )

    var (
        encryptedBytesBase64 []byte // The encrypted bytes as base64 chars
        encryptedBytes       []byte // The encrypted bytes
    )

    // Load an encrypted file:
    if bytes, bytesErr := ioutil.ReadFile(filename); bytesErr != nil {
        log.Printf("[%s] There was an error while reading the encrypted file: %s\n", filename, bytesErr.Error())
        return
    } else {
        encryptedBytesBase64 = bytes
    }

    // Decode base64:
    decodedBytes := make([]byte, len(encryptedBytesBase64))
    if countDecoded, decodedErr := base64.StdEncoding.Decode(decodedBytes, encryptedBytesBase64); decodedErr != nil {
        log.Printf("[%s] An error occur while decoding base64 data: %s\n", filename, decodedErr.Error())
        return
    } else {
        encryptedBytes = decodedBytes[:countDecoded]
    }

    // Derive key and vector out of the master password and the salt cf. RFC 2898:
    keyVectorData := pbkdf2.Key(masterPassword, saltBytes, rfc2898Iterations, (keyLength/8)+aes.BlockSize, sha1.New)
    keyBytes := keyVectorData[:keyLength/8]
    vectorBytes := keyVectorData[keyLength/8:]

    // Create an AES cipher:
    if aesBlockDecrypter, aesErr := aes.NewCipher(keyBytes); aesErr != nil {
        log.Printf("[%s] Was not possible to create new AES cipher: %s\n", filename, aesErr.Error())
        return
    } else {

        // CBC mode always works in whole blocks.
        if len(encryptedBytes)%aes.BlockSize != 0 {
            log.Printf("[%s] The encrypted data's length is not a multiple of the block size.\n", filename)
            return
        }

        // Reserve memory for decrypted data. By definition (cf. AES-CBC), it must be the same lenght as the encrypted data:
        decryptedData := make([]byte, len(encryptedBytes))

        // Create the decrypter:
        aesDecrypter := cipher.NewCBCDecrypter(aesBlockDecrypter, vectorBytes)

        // Decrypt the data:
        aesDecrypter.CryptBlocks(decryptedData, encryptedBytes)

        // Cast the decrypted data to string:
        artifact = string(decryptedData)
    }

    return
}

... dan ...

import (
    "crypto/aes"
    "crypto/cipher"
    "crypto/sha1"
    "encoding/base64"
    "github.com/twinj/uuid"
    "golang.org/x/crypto/pbkdf2"
    "io/ioutil"
    "log"
    "math"
    "os"
)

func encryptFile(filename, artifact string, masterPassword []byte) (status bool) {

    const (
        keyLength         int = 256
        rfc2898Iterations int = 6
    )

    status = false
    secretBytesDecrypted := []byte(artifact)

    // Create new salt:
    saltBytes := uuid.NewV4().Bytes()

    // Derive key and vector out of the master password and the salt cf. RFC 2898:
    keyVectorData := pbkdf2.Key(masterPassword, saltBytes, rfc2898Iterations, (keyLength/8)+aes.BlockSize, sha1.New)
    keyBytes := keyVectorData[:keyLength/8]
    vectorBytes := keyVectorData[keyLength/8:]

    // Create an AES cipher:
    if aesBlockEncrypter, aesErr := aes.NewCipher(keyBytes); aesErr != nil {
        log.Printf("[%s] Was not possible to create new AES cipher: %s\n", filename, aesErr.Error())
        return
    } else {

        // CBC mode always works in whole blocks.
        if len(secretBytesDecrypted)%aes.BlockSize != 0 {
            numberNecessaryBlocks := int(math.Ceil(float64(len(secretBytesDecrypted)) / float64(aes.BlockSize)))
            enhanced := make([]byte, numberNecessaryBlocks*aes.BlockSize)
            copy(enhanced, secretBytesDecrypted)
            secretBytesDecrypted = enhanced
        }

        // Reserve memory for encrypted data. By definition (cf. AES-CBC), it must be the same lenght as the plaintext data:
        encryptedData := make([]byte, len(secretBytesDecrypted))

        // Create the encrypter:
        aesEncrypter := cipher.NewCBCEncrypter(aesBlockEncrypter, vectorBytes)

        // Encrypt the data:
        aesEncrypter.CryptBlocks(encryptedData, secretBytesDecrypted)

        // Encode base64:
        encodedBytes := make([]byte, base64.StdEncoding.EncodedLen(len(encryptedData)))
        base64.StdEncoding.Encode(encodedBytes, encryptedData)

        // Allocate memory for the final file's content:
        fileContent := make([]byte, len(saltBytes))
        copy(fileContent, saltBytes)
        fileContent = append(fileContent, 10)
        fileContent = append(fileContent, encodedBytes...)

        // Write the data into a new file. This ensures, that at least the old version is healthy in case that the
        // computer hangs while writing out the file. After a successfully write operation, the old file could be
        // deleted and the new one could be renamed.
        if writeErr := ioutil.WriteFile(filename+"-update.txt", fileContent, 0644); writeErr != nil {
            log.Printf("[%s] Was not able to write out the updated file: %s\n", filename, writeErr.Error())
            return
        } else {
            if renameErr := os.Rename(filename+"-update.txt", filename); renameErr != nil {
                log.Printf("[%s] Was not able to rename the updated file: %s\n", fileContent, renameErr.Error())
            } else {
                status = true
                return
            }
        }

        return
    }
}

Sekarang, dekripsi di C #:

public static string FromFile(string filename, byte[] saltBytes, string masterPassword)
{
    var iterations = 6;
    var keyLength = 256;
    var blockSize = 128;
    var result = string.Empty;
    var encryptedBytesBase64 = File.ReadAllBytes(filename);

    // bytes -> string:
    var encryptedBytesBase64String = System.Text.Encoding.UTF8.GetString(encryptedBytesBase64);

    // Decode base64:
    var encryptedBytes = Convert.FromBase64String(encryptedBytesBase64String);
    var keyVectorObj = new Rfc2898DeriveBytes(masterPassword, saltBytes.Length, iterations);
    keyVectorObj.Salt = saltBytes;
    Span<byte> keyVectorData = keyVectorObj.GetBytes(keyLength / 8 + blockSize / 8);
    var key = keyVectorData.Slice(0, keyLength / 8);
    var iv = keyVectorData.Slice(keyLength / 8);

    var aes = Aes.Create();
    aes.Padding = PaddingMode.Zeros;
    // or ... aes.Padding = PaddingMode.None;
    var decryptor = aes.CreateDecryptor(key.ToArray(), iv.ToArray());
    var decryptedString = string.Empty;

    using (var memoryStream = new MemoryStream(encryptedBytes))
    {
        using (var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read))
        {
            using (var reader = new StreamReader(cryptoStream))
            {
                decryptedString = reader.ReadToEnd();
            }
        }
    }

    return result;
}

Bagaimana masalah padding bisa dijelaskan? Tepat sebelum enkripsi, program Go memeriksa padding:

// CBC mode always works in whole blocks.
if len(secretBytesDecrypted)%aes.BlockSize != 0 {
    numberNecessaryBlocks := int(math.Ceil(float64(len(secretBytesDecrypted)) / float64(aes.BlockSize)))
    enhanced := make([]byte, numberNecessaryBlocks*aes.BlockSize)
    copy(enhanced, secretBytesDecrypted)
    secretBytesDecrypted = enhanced
}

Bagian pentingnya adalah ini:

enhanced := make([]byte, numberNecessaryBlocks*aes.BlockSize)
copy(enhanced, secretBytesDecrypted)

Sebuah array baru dibuat dengan panjang yang sesuai, sehingga panjangnya adalah kelipatan dari ukuran blok. Array baru ini diisi dengan angka nol. Metode salin kemudian menyalin data yang ada ke dalamnya. Dipastikan bahwa larik baru lebih besar dari data yang ada. Karenanya, ada nol di akhir larik.

Dengan demikian, kode C # dapat digunakan PaddingMode.Zeros. Alternatifnya PaddingMode.Nonehanya mengabaikan padding apa pun, yang juga berfungsi. Saya harap jawaban ini bermanfaat bagi siapa saja yang harus mem-port kode dari Go to C #, dll.

SommerEngineering
sumber
0

Saya melaporkan kesalahan yang sama oleh klien. Saya pribadi tidak bisa menegurnya. Melihat kode metode Enkripsi dan Dekripsi , keduanya memiliki Padding yang disetel ke PaddingMode.PKCS7 . Dekripsi terlihat seperti ini dan saya tidak dapat melihat masalah terkait dengan ' FlushFinalBlock '. Bisakah seseorang menjelaskannya?

public string Decrypt(string cipherText)
{
  if (string.IsNullOrEmpty(cipherText))
    return "";
  string result;
  Encoding byteEncoder = Encoding.Default;

  byte[] rijnKey = byteEncoder.GetBytes(Password);
  byte[] rijnIv = byteEncoder.GetBytes(InitialVector);
  RijndaelManaged rijn = new RijndaelManaged { Mode = CipherMode.ECB, Padding = PaddingMode.PKCS7 };

  using (MemoryStream msDecrypt = new MemoryStream(Convert.FromBase64String(cipherText)))
  {
    using (ICryptoTransform decryptor = rijn.CreateDecryptor(rijnKey, rijnIv))
    {
      using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
      {
                    using (StreamReader swDecrypt = new StreamReader(csDecrypt))
                    {
                        result = swDecrypt.ReadToEnd();
                    }
                }
    }
  }
  rijn.Clear();      
  return result.Replace("\0", "");
}
Alexander
sumber
0

Saya mengalami kesalahan yang sama. Dalam kasus saya kata sandi yang diberikan lebih besar dari 16 berarti dienkripsi tetapi saat dekripsi saya mendapatkan kesalahan ini. Enkripsi:

string keyString = "CDFUYP@ssw0rd123";
            var key = Encoding.UTF8.GetBytes(keyString);            
            using (var aesAlg = Aes.Create())
            {
                using (var encryptor = aesAlg.CreateEncryptor(key, aesAlg.IV))
                {
                    using (var msEncrypt = new MemoryStream())
                    {
                        using (var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
                        using (var swEncrypt = new StreamWriter(csEncrypt))
                        {
                            swEncrypt.Write(text);
                        }                          
                        var iv = aesAlg.IV;

                        var decryptedContent = msEncrypt.ToArray();

                        var result = new byte[iv.Length + decryptedContent.Length];

                        Buffer.BlockCopy(iv, 0, result, 0, iv.Length);
                        Buffer.BlockCopy(decryptedContent, 0, result, iv.Length, decryptedContent.Length);

                        var encryptedString = Convert.ToBase64String(result);
                        var decryptedString = Decrypt(encryptedString);
                        if (decryptedString == null)
                        {
                            return null;
                        }
                        return encryptedString;

                    }
                }

Dekripsi:

 string keyString = "CDFUYP@ssw0rd123";
            var fullCipher = Convert.FromBase64String(cipherText);
            var iv = new byte[16];
            var cipher = new byte[16];
            Buffer.BlockCopy(fullCipher, 0, iv, 0, iv.Length);
            Buffer.BlockCopy(fullCipher, iv.Length, cipher, 0, iv.Length);
            var key = Encoding.UTF8.GetBytes(keyString);

            using (var aesAlg = Aes.Create())
            {
                using (var decryptor = aesAlg.CreateDecryptor(key, iv))
                {
                    string result;
                    using (var msDecrypt = new MemoryStream(cipher))
                    {
                        using (var csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
                        {
                            using (var srDecrypt = new StreamReader(csDecrypt))
                            {
                                result = srDecrypt.ReadToEnd();
                            }
                        }
                    }

                    return result;
                }
            }
sundarraj.dll
sumber
Hai @sundarraj, apakah ini pertanyaan?
Tiago Martins Peres 李大仁