Dolgu geçersiz ve kaldırılamaz mı?


126

Programımla ilgili olarak bu istisnanın ne anlama geldiğini çevrimiçi olarak araştırdım, ancak bir çözüm bulamadım veya özel programıma neden olmasının nedenini bulamadım. Rijndael algoritmasını kullanarak bir XmlDocument'i şifrelemek ve şifresini çözmek için msdn'mi sağlayan örneği kullanıyorum. Şifreleme iyi çalışıyor ancak şifresini çözmeye çalıştığımda aşağıdaki istisnayı alıyorum:

Dolgu geçersiz ve kaldırılamaz

Bu sorunu çözmek için ne yapabileceğimi bana söyleyen var mı? Aşağıdaki kodum, anahtarı ve diğer verileri aldığım yerdir. CryptoMode yanlışsa, istisnanın meydana geldiği şifre çözme yöntemini çağıracaktır:

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

}

12
Doldurma modunu hem şifreleme hem de şifre çözmede aynı olacak şekilde girintili olacak şekilde açıkça ayarlayarak deneyebilir misiniz? Örneğin: alg.Padding = PaddingMode.NONE;
NetSquirrel

Encrypt () yöntemi neye benziyor?
csharptest.net

1
Teşekkürler işe yarayan çocuklar.
Brown Love

2
@NetSquirrel: PaddingMode.NONE için hatırlatıcı için teşekkür ederim. Beni bu hatadan kurtarıyor (bir başkasına) ... Hem Java'da hem de C #'de AES yapmak ve şimdi her ikisi de PKCS # 7
Hoàng Long

Yanıtlar:


81

Rijndael / AES bir blok şifredir. Verileri 128 bit (16 karakter) bloklar halinde şifreler. İletinin son bloğunun her zaman doğru boyutta olduğundan emin olmak için şifreleme doldurma kullanılır.

Şifre çözme yönteminiz, varsayılan dolgusu ne olursa olsun bekliyor ve bulamıyor. @NetSquirrel'ın dediği gibi, hem şifreleme hem de şifre çözme için dolguyu açıkça ayarlamanız gerekir. Aksini yapmak için bir nedeniniz olmadıkça, PKCS # 7 dolgu kullanın.


7
dolgu açıkça nasıl ayarlanır?
Ahmad Hajjar

7
Teşekkür ederim buldum rj.Padding = PaddingMode.none; :)
Ahmad Hajjar

7
@AhmadHajjar Hiçbir dolgu uygulamasının güvenlik açısından etkileri yoktur, kullanmayın.
deviantfan

1
Merhaba, dolguyu açıkça belirledim ama çalışmıyor. Hangi adımları yanlış yaptığımı bilmiyorum. Lütfen yardım et. alg.Padding = PaddingMode.PKCS7;
Johnny

21
Bunun eski bir konu olduğunun farkındayım. Ancak, ziyaret edenler için, verileri şifrelerken son bloğu temizlediğinizden emin olun.
Markus

53

Şifreleme ve şifre çözme için kullandığınız anahtarların aynı olduğundan emin olun . Dolgu yöntemi, açıkça ayarlanmasa bile, uygun şifre çözme / şifrelemeye izin vermelidir (ayarlanmazsa, aynı olacaktır). Herhangi bir nedenle şifreleme için kullanılan daha şifre çözme için farklı bir anahtar kümesini kullanıyor Ancak eğer olacak bu hatayı alıyorum:

Dolgu geçersiz ve kaldırılamaz

Çalışmayan anahtarları dinamik olarak oluşturmak için bir algoritma kullanıyorsanız. Hem şifreleme hem de şifre çözme için aynı olmaları gerekir. Yaygın bir yol, şifreleme / şifre çözme işleminin bu öğelerin yaratılmasında herhangi bir etkiye sahip olmasını önlemek için, arayanın şifreleme yöntemleri sınıfının yapıcısındaki anahtarları sağlamasıdır. Bu eldeki göreve (şifreleme ve veri şifresini) odaklanır ve gerektirir ivve keyarayan tarafından temin edilecek.


Bu ipucu çok kullanışlıdır, çünkü bazen anahtarlar app.config'de saklanır ve şifrelemek için kullanılan anahtarların şifresini çözmek için kullanılanlarla aynı olduğundan her zaman emin olmalıyız.
Mário Meyrelles

@atconway Soruma bir göz atabilir misiniz? Benzer bir sorunum var ama C ++ / CLI'de: stackoverflow.com/questions/57139447/…
Basit

1
Günlük kullanımda, muhtemelen insanların bu hatayla karşılaşmalarının en olası nedeni budur. Özellikle de dolgu ayarlarıyla uğraşmıyorsanız.
Dan

28

Arama yapan kişilerin yararına, şifresi çözülen girdiyi kontrol etmeye değer olabilir. Benim durumumda, şifre çözme için gönderilen bilgi (yanlış bir şekilde) boş bir dize olarak giriyordu. Dolgu hatasıyla sonuçlandı.

Bu Rossum'un cevabıyla ilgili olabilir, ancak bahsetmeye değer olduğunu düşündü.


Kabul ediyorum, başka kontroller yapmadan ÖNCE girişin şifresi çözülen girişi kontrol ederek benim de aynı şey oldu. Kodladığımdan 1 bayt daha fazlasını alıyordum ...
Andrea Antonangeli

Boş bir ip benim için de suçluydu.
dotNET

Durumum parola belirlenmemişti (evet biliyorum), ancak bu cevap beni doğru yöne götürdü.
Jim

2
Sorunum, şifresi çözülecek dizenin şifresini çözmeye çalışmadan önce küçük harfe dönüştürülmesiydi. Dolguya, şifrelere ve tüm o şeylere takıntılıydım, ama sadece kötü girdi olduğu ortaya çıktı. Bazen sadece bir adım geri atmanız gerekir!
Tom Gerken

15

Kodlama ve kod çözme için aynı anahtar ve başlatma vektörü kullanılırsa, bu sorun veri kod çözme değil, veri kodlamadan kaynaklanır.

Bir CryptoStream nesnesinde Write yöntemini çağırdıktan sonra, Close yönteminden önce DAİMA FlushFinalBlock yöntemini çağırmalısınız.

CryptoStream.FlushFinalBlock yöntemiyle ilgili MSDN dokümantasyonu şunu söylüyor:
" Close yönteminin çağrılması FlushFinalBlock'u çağıracaktır ... "
https://msdn.microsoft.com/en-US/library/system.security.cryptography.cryptostream.flushfinalblock(v=vs .110) .aspx
Bu yanlış. Close yönteminin çağrılması yalnızca CryptoStream'i ve çıkış Akışını kapatır.
Şifrelenecek verileri yazdıktan sonra Kapatmadan önce FlushFinalBlock'u çağırmazsanız, verilerin şifresini çözerken, CryptoStream nesnenizdeki Read veya CopyTo yöntemine yapılan bir çağrı bir CryptographicException istisnası (mesaj: "Dolgu geçersizdir ve kaldırılamaz") oluşturur.

Bu muhtemelen SymmetricAlgorithm'den (Aes, DES, RC2, Rijndael, TripleDES) türetilen tüm şifreleme algoritmaları için doğrudur, ancak bunu AesManaged ve çıkış Akışı olarak bir MemoryStream için doğruladım.

Bu nedenle, şifre çözmede bu CryptographicException istisnasını alırsanız, şifrelenecek verilerinizi yazdıktan sonra çıktı Akış Uzunluğu özellik değerinizi okuyun, ardından FlushFinalBlock'u çağırın ve değerini yeniden okuyun. Değiştiyse, FlushFinalBlock'u çağırmanın isteğe bağlı OLMADIĞINI bilirsiniz.

Ve programlı olarak herhangi bir dolgu gerçekleştirmenize veya başka bir Dolgu özelliği değeri seçmenize gerek yoktur. Dolgu, FlushFinalBlock yöntemi işidir.

.........

Kevin için ek açıklama:

Evet, CryptoStream, Close'u çağırmadan önce FlushFinalBlock'u çağırır, ancak artık çok geç: CryptoStream Close yöntemi çağrıldığında, çıktı akışı da kapatılır.

Çıkış akışınız bir MemoryStream ise, kapatıldıktan sonra verilerini okuyamazsınız. Bu nedenle, MemoryStream'de yazılan şifrelenmiş verileri kullanmadan önce CryptoStream'inizde FlushFinalBlock'u çağırmanız gerekir.

Çıktı akışınız bir FileStream ise, işler daha kötüdür çünkü yazma arabelleğe alınmıştır. Sonuç olarak, son yazılan baytlar, FileStream üzerinde Flush çağırmadan önce çıktı akışını kapatırsanız dosyaya yazılmayabilir. Bu nedenle, CryptoStream'de Close'u çağırmadan önce, CryptoStream'inizde FlushFinalBlock'u ve ardından FileStream'inizde Flush'ı çağırmanız gerekir.


1
Neden yanlış olduğunu söylüyorsun? Stream.Close()Aramalar için kod this.Dispose(true). Kod CryptoStream.Dispose(bool)şu if (disposing) { if (!this._finalBlockTransformed) { this.FlushFinalBlock(); } this._stream.Close(); }
şekildedir

1
Bu benim sorunumu çözdü. CryptoStream'i doğru bir şekilde dağıtıyordum, ancak dispose çağrısı tam da sizin de söylediğiniz gibi "çok geç" oluyordu. Bu, açıklandığı gibi "geçersiz dolgu" hatasıyla sonuçlandı. CryptoStream.FlushFinalBlock () eklenerek geçersiz doldurma hatası çözüldü. Teşekkürler!
Daniel Lambert

14

Serval savaş zamanları, sonunda sorunu çözdüm.
(Not: Simetrik algoritma olarak standart AES kullanıyorum. Bu cevap herkes için uygun olmayabilir.)

  1. Algoritma sınıfını değiştirin. RijndaelManagedSınıfı şununla değiştirin:AESManaged .
  2. KeySizeAlgoritma sınıfını açık bir şekilde ayarlamayın, onları varsayılan olarak bırakın.
    (Bu çok önemli bir adımdır. KeySize özelliğinde bir hata olduğunu düşünüyorum.)

İşte hangi argümanı kaçırmış olabileceğinizi kontrol etmek istediğiniz bir liste:

  • Anahtar
    (bayt dizisi, uzunluk, farklı anahtar boyutu için tam olarak 16, 24, 32 bayttan biri olmalıdır.)
  • IV
    (bayt dizisi, 16 bayt)
  • CipherMode
    (CBC, CFB, CTS, ECB, OFB'den biri)
  • PaddingMode
    (ANSIX923, ISO10126, Yok, PKCS7, Sıfırlardan biri)

3
Açıkça ayarlamamak, KeySizehemen benim için düzeltildi. Oh .NET'in tuhaflıkları :-(
John

Bunun .NET Framework içinde bir gerileme gibi göründüğünü unutmayın. Eskiden RijndaelManaged ile çalışan, ancak çalışmayı durduran kodum var ve onu AesManaged / AesCryptoServiceProvider olarak değiştirerek tekrar çalışıyor. Açıkça KeySize ayarlayan herhangi bir kodum bile yoktu. Bu yüzden ısırılırsanız, kendinizi daha iyi hissedin - hata sizinle değil, .NET Framework'ün kendisinde olabilir.
Usas

6

Benim sorunum, şifrelemenin passPhrase'ının şifre çözmenin passPhrase'iyle eşleşmemesiydi ... bu yüzden bu hatayı attı .. biraz yanıltıcı.


Aslında, Şifreleme ve Şifre Çözme için PaddingMode.PKCS7 kullandığımız doğru, ancak aynı hata mesajını aldım. Ayrıca farklı anahtar değerlere sahip Stage ve Dev ortamımız var. - Çevreye özel - anahtarı kullandığımda bu istisna çözüldü ...
Binbaşı

Yukarıdaki yanıtların tümü iyi olmasına ve Şifreleme ve Şifre Çözme için aynı dolguyu kullanmanız gerekse de (hiçbiri önerilmez!) Aslında bu cevap da doğru olabilir. Uygun-çevreye özel - anahtarını kullandığımda "System.Security.Cryptography.CryptographicException: Dolgu geçersiz ve kaldırılamaz." çözüldü. Yani evet yanıltıcı olabilir.
Major

"PassPhrase" ile şifreleme / şifre çözme için tam değerden bahsediyorsanız (yanlış anahtar kullanımıyla ilgili bir sorun değil), o zaman evet, bu benim sorunumdu. Benim durumum, orijinal şifrelenmiş değerin veritabanı tablo alanımın izin verdiğinden daha uzun olmasıydı, bu yüzden ben fark etmeden sığması için kesiliyordu. Sonra bu kesilmiş değerin şifresini çözerken bu istisna atıldı.
David Gunderson

2

Benimkini düzelten çözüm, Şifreleme ve Şifre Çözme yöntemlerine yanlışlıkla farklı anahtarlar uygulamamdı.


1

Şifre çözme yöntemine şifrelenmemiş bir dosya yolunu geçmeye çalışırken bu hatayla karşılaştım.Çözüm, şifresini çözmeye çalışmadan önce aktarılan dosyanın şifrelenip şifrelenmediğini kontrol etmekti.

if (Sec.IsFileEncrypted(e.File.FullName))
{
    var stream = Sec.Decrypt(e.File.FullName);
} 
else
{
    // non-encrypted scenario  
}

1
Herhangi bir Hit and Run Coward'a bu çözümün geçerliliği konusunda meydan okuyorum.
usefulBee

+1 çünkü bu istisna, şifresini iki kez çözdüğünüzde veya şifrelenmemiş bir şeyin şifresini çözdüğünüzde ortaya çıkar. Bu yüzden bu cevabı "verilerin gerçekten şifreli olduğundan emin misiniz?" Şeklinde okudum.
Gerardo Grignoli

0

Yine arama yapan insanların yararına olan başka bir senaryo.

Benim için bu hata, şifrelemeyle ilgili olmayan önceki bir hatayı maskeleyen Dispose () yöntemi sırasında meydana geldi.

Diğer bileşen düzeltildikten sonra bu istisna ortadan kalktı.


3
Şifrelemeyle ilgili olmayan önceki hata neydi?
NStuke

0

Dosyadaki şifrelenmiş dizeleri manuel olarak düzenlerken (not defteri kullanarak) bu doldurma hatasıyla karşılaştım çünkü şifrelenmiş içeriğim manuel olarak değiştirilirse şifre çözme işlevinin nasıl davranacağını test etmek istedim.

Benim için çözüm, bir

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

Dediğim gibi doldurma hatam, not defteri kullanarak şifresi çözülen metni manuel olarak yazmamdı. Cevabım, çözümünüz için size rehberlik edebilir.


0

Ben de aynı hatayı aldım. Benim durumumda bunun nedeni şifrelenmiş verileri bir SQL Veritabanında saklamış olmamdı. Verilerin saklandığı tablo ikili (1000) veri tipine sahiptir. Verileri veritabanından alırken, bu 1000 baytın şifresini çözerken, gerçekte 400 bayt oradaydı. Sonuçtan sondaki sıfırları (600) kaldırmak sorunu çözdü.


0

Bu hatayı aldım ve açıkça engelleme boyutunu ayarlıyordum: aesManaged.BlockSize = 128;

Bunu kaldırdıktan sonra işe yaradı.


0

Bir Go programını C # 'a taşımaya çalışırken aynı sorunu yaşadım. Bu, birçok verinin zaten Go programıyla şifrelenmiş olduğu anlamına gelir. Bu verilerin şimdi C # ile şifresi çözülmelidir.

Nihai çözüm daha PaddingMode.Nonedoğrusu idi PaddingMode.Zeros.

Go'daki kriptografik yöntemler:

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
}

... ve ...

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
    }
}

Şimdi, C # ile şifre çözme:

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;
}

Dolgu ile ilgili sorun nasıl açıklanabilir? Go programı şifrelemeden hemen önce dolguyu kontrol eder:

// 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
}

Önemli olan kısım şudur:

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

Uygun uzunlukta yeni bir dizi oluşturulur, böylece uzunluk blok boyutunun bir katıdır. Bu yeni dizi sıfırlarla dolu. Kopyalama yöntemi daha sonra mevcut verileri içine kopyalar. Yeni dizinin mevcut verilerden daha büyük olması sağlanır. Buna göre dizinin sonunda sıfırlar var.

Böylece C # kodu kullanabilir PaddingMode.Zeros. Alternatif PaddingMode.None, aynı zamanda çalışan herhangi bir dolguyu yok sayar. Umarım bu yanıt, kodu Go'dan C #'a vb. Taşımak zorunda olan herkes için yararlıdır.


0

Müşteri tarafından aynı hatayı bildirdim. Şahsen onu suçlayamam. Encrypt ve Decrypt yöntemlerinin koduna bakıldığında , her ikisinin de Padding ayarı PaddingMode.PKCS7 olarak ayarlanmıştır . Şifre çözme şuna benziyor ve ' FlushFinalBlock ' ile ilgili sorunu göremiyorum . Biri lütfen biraz ışık tutabilir mi?

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", "");
}

0

Ben de aynı hatayı aldım. Benim durumumda verilen parolanın 16'dan büyük olması şifreli olduğu anlamına gelir ancak şifre çözme sırasında bu hatayı alıyorum. Şifreleme:

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;

                    }
                }

Şifre çözme:

 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;
                }
            }

Merhaba @sundarraj, bu bir soru mu?
Tiago Martins Peres 李大仁
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.