2010-01-11 12 views
3

J'utilise Rinjael pour encoder en VB.NET et j'ai besoin de décoder en Ruby. Ma classe de cryptage VB.NET ressemble à ceci:Comment décoder Rijndael en ruby ​​(codé en VB.net)

Private Class Encryptor 
     Private symmetricKey As System.Security.Cryptography.RijndaelManaged 
     Private iVector As Byte() 
     Private Key As Byte() 
     Public Function encrypt(ByVal data As String) As String 
      Try 
       Dim plainTextBytes As Byte() = System.Text.Encoding.ASCII.GetBytes(data) 
       Dim encryptor As System.Security.Cryptography.ICryptoTransform = symmetricKey.CreateEncryptor(Key, iVector) 
       Dim memoryStream As New System.IO.MemoryStream 
       Dim cryptoStream As System.Security.Cryptography.CryptoStream = New System.Security.Cryptography.CryptoStream(memoryStream, encryptor, System.Security.Cryptography.CryptoStreamMode.Write) 
       cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length) 
       cryptoStream.FlushFinalBlock() 
       Dim cipherTextBytes As Byte() = memoryStream.ToArray() 
       memoryStream.Close() 
       cryptoStream.Close() 
       Return Convert.ToBase64String(cipherTextBytes) 
      Catch 
       Return "" 
      End Try 
     End Function 
     Public Function decrypt(ByVal data As String) As String 
      Try 
       Dim crypted As Byte() = Convert.FromBase64String(data) 
       Dim decryptor As System.Security.Cryptography.ICryptoTransform = symmetricKey.CreateDecryptor(Key, iVector) 
       Dim memoryStream As New System.IO.MemoryStream(crypted) 
       Dim cryptoStream As System.Security.Cryptography.CryptoStream = New System.Security.Cryptography.CryptoStream(memoryStream, decryptor, System.Security.Cryptography.CryptoStreamMode.Read) 
       Dim plain(crypted.Length) As Byte 
       Dim count As Integer = cryptoStream.Read(plain, 0, plain.Length) 
       memoryStream.Close() 
       cryptoStream.Close() 
       Return System.Text.Encoding.UTF8.GetString(plain, 0, count) 
      Catch 
       Return "" 
      End Try 
     End Function 

     Public Sub New(ByVal clientkey As String) 
      iVector = System.Text.Encoding.ASCII.GetBytes("123456789") 
      Key = System.Text.Encoding.ASCII.GetBytes(clientkey) 
      symmetricKey = New System.Security.Cryptography.RijndaelManaged 
      symmetricKey.Mode = System.Security.Cryptography.CipherMode.CBC 
     End Sub 
    End Class 

cela fonctionne bien et je suis capable de décrypter en Java en utilisant AES/CBC/PKCS5Padding. Maintenant, mon mot de passe et iv sont de 16 caractères (16 * 16 bits = 256). Quand j'essaye de décrypter dans Ruby, il se plaint que mon mot de passe est trop court ... Je suppose qu'il utilise des caractères de 8 bits. J'utilise cette classe pour le décryptage en ruby:

require 'openssl' 

module Crypt 
    # Decrypts a block of data (encrypted_data) given an encryption key 
    # and an initialization vector (iv). Keys, iv's, and the data 
    # returned are all binary strings. Cipher_type should be 
    # "AES-256-CBC", "AES-256-ECB", or any of the cipher types 
    # supported by OpenSSL. Pass nil for the iv if the encryption type 
    # doesn't use iv's (like ECB). 
    #:return: => String 
    #:arg: encrypted_data => String 
    #:arg: key => String 
    #:arg: iv => String 
    #:arg: cipher_type => String 
    def Crypt.decrypt(encrypted_data, key, iv, cipher_type) 
    aes = OpenSSL::Cipher::Cipher.new(cipher_type) 
    aes.decrypt 
    aes.key = key 
    aes.iv = iv if iv != nil 
    aes.update(encrypted_data) + aes.final 
    end 

    # Encrypts a block of data given an encryption key and an 
    # initialization vector (iv). Keys, iv's, and the data returned 
    # are all binary strings. Cipher_type should be "AES-256-CBC", 
    # "AES-256-ECB", or any of the cipher types supported by OpenSSL. 
    # Pass nil for the iv if the encryption type doesn't use iv's (like 
    # ECB). 
    #:return: => String 
    #:arg: data => String 
    #:arg: key => String 
    #:arg: iv => String 
    #:arg: cipher_type => String 
    def Crypt.encrypt(data, key, iv, cipher_type) 
    aes = OpenSSL::Cipher::Cipher.new(cipher_type) 
    aes.encrypt 
    aes.key = key 
    aes.iv = iv if iv != nil 
    aes.update(data) + aes.final  
    end 
end 

Maintenant. En essayant de décrypter en utilisant Crypt.decrypt (data, key, iv, "AES-CBC-256") je suis certain que les transformations chaîne/octet préliminaires doivent être faites sur mes données, clé, iv pour fonctionner correctement.

Comment appeler Crypt.decrypt en utilisant key = "passwordpassword" et iv = "123456789"? Ai-je besoin de base64 pour décoder mes données?

Voici mon appel de déchiffrement, ce qui ne semble pas fonctionner (essayer rembourrage avec des zéros):

text = Base64.decode64(text) 
    pass = Digest::SHA1.hexdigest("#{@pass}0000000000000000").unpack('a2'*32).map{|x| x.hex}.pack('c'*32) 
    iv = Digest::SHA1.hexdigest("123456789").unpack('a2'*32).map{|x| x.hex}.pack('c'*32) 
    return Crypt.decrypt(text,pass,iv,"AES-256-CBC") 
+0

Une raison particulière d'appeler l'algorithme Rijndael? Pourquoi ne pas s'en tenir à l'appeler AES seulement? –

Répondre

1

Parce que l'application VB code le résultat en base64, il n'a pas l'air comme le script Ruby devra utilisez le module Base64 pour le décoder en premier.

Je crois que la clé donnée à la clé Ruby AES doit être de 256 bits. Donc, votre mot de passe devrait être de 32 octets exactement dans ce cas. Il serait préférable d'utiliser un schéma tel que this.

+0

Le chiffrement VB.NET est déjà implémenté et ne peut pas être modifié. Le problème est: pourquoi VB.NET crypte-t-il avec un mot de passe de 16 caractères/iv, mais ruby ​​ne décrypte pas en utilisant le même mot de passe/iv? Je pense que le problème réside dans le nombre d'octets/caractères que les deux systèmes utilisent: 16bit dans VB.NET et 8bit dans ruby ​​... Par conséquent, le mot de passe 16character fonctionne dans VB.net (16 * 16 = 256). Mais comment puis-je le décoder dans ruby, s'il est déjà codé en utilisant le code VB.NET ci-dessus? – Sparky

+0

Je ne pense pas que ce soit un problème de 16 bits par rapport à 8 bits. L'application VB utilise un codage ASCII (il devrait donc s'agir de caractères de 8 bits). Étant donné que la taille de clé par défaut est de 256 bits et ne semble pas être spécifiée, il semble que la conclusion est que .NET rembourse la clé donnée à 256 bits. Vous devriez pouvoir tester cela assez facilement dans .NET. La valeur de remplissage évidente serait zéros. –

+0

Merci d'avoir signalé cela. Logique. J'ai juste essayé de tamponner mon iv/pass avec des zéros (voir le dernier code ci-dessus). Et il semble retourner une réponse (au moins, ça ne plante pas). Cependant, la réponse est cryptée et! = Original: - / – Sparky

3

Solution. C'était un cryptage 128 bits (pensant à tort que le .NET géré par défaut était de 256). Par conséquent, ce code fonctionne (remarque "AES-128-CBC"):

text = Base64.decode64(text) 
    pass = "passwordpassword" 
    iv = "123456789" 
    return Crypt.decrypt(text,pass,iv,"AES-128-CBC")