2016-06-07 6 views
2

Ich versuche, einen AES-Schlüssel zu generieren, zu verschlüsseln und mit RSA zu entschlüsseln. Es Art von funktioniert, außer dass nach dem Entschlüsseln der Daten und Codierung mit Base64 bekomme ich einen Stapel von "A" Buchstaben vor meiner eigentlichen Zeichenfolge (der Base64-codierte AES-Schlüssel). Ich denke, das waren Nullen in Byte.Entschlüsseln einer Zeichenfolge mit RSA gibt am Anfang zusätzliche Nullen zurück

Die Parameter "RSA/ECB/NoPadding" sind obligatorisch. Was mache ich falsch ? Ich brauche es, um die ursprüngliche Zeichenfolge/Bytes zurückzugeben. Hier

package szyfrator; 

import java.io.BufferedInputStream; 
import java.io.File; 
import java.io.FileInputStream; 
import java.io.FileOutputStream; 
import java.io.IOException; 
import java.security.KeyFactory; 
import java.security.NoSuchAlgorithmException; 
import java.security.PrivateKey; 
import java.security.PublicKey; 
import java.security.spec.PKCS8EncodedKeySpec; 
import java.security.spec.X509EncodedKeySpec; 

import javax.crypto.Cipher; 
import javax.crypto.KeyGenerator; 
import javax.crypto.SecretKey; 

import org.apache.commons.compress.compressors.bzip2.BZip2CompressorInputStream; 
import org.apache.commons.compress.utils.IOUtils; 
import org.apache.tools.bzip2.CBZip2OutputStream; 

import com.google.common.hash.HashCode; 
import com.google.common.hash.Hashing; 
import com.google.common.io.Files; 
import com.sun.org.apache.xml.internal.security.utils.Base64; 

public class Cryptography { 

    private static byte[] aesKey; 
    private static String base64AESKey; 
    private static byte[] encryptedAESKey; 
    private static String base64AESEncryptedKey; 
    private static byte[] aesKeyTransformed; 

    public static void main(String args[]){ 

     Cryptography.generateAESkey(); 
     Cryptography.encryptAESKey(new File("G:\\HASHBABYHASH\\public.txt")); 
     Cryptography.decryptAESKey(new File("G:\\HASHBABYHASH\\private.txt")); 

     System.out.println("String: " + Base64.encode(Cryptography.getAesKey()) + "\r\n"); 
     System.out.println("Encrypted string: " + Cryptography.getBase64EncryptedKey() + "\r\n"); 
     System.out.println("Decrypted String: " + Base64.encode(Cryptography.getAesKeyTransformed()) + "\r\n"); 

    } 

    public static void generateAESkey(){ 

     try { 
      KeyGenerator keyGen = KeyGenerator.getInstance("AES"); 

      keyGen.init(256); 
      SecretKey secretKey = keyGen.generateKey(); 

      byte[] keyBytes = secretKey.getEncoded(); 
      base64AESKey = Base64.encode(keyBytes); 

      aesKey = keyBytes; 
     } catch (NoSuchAlgorithmException e) { 
      e.printStackTrace(); 
     } 
    } 

    public static void encryptAESKey(File publicKeyFile){ 

     try {  
      FileInputStream input = new FileInputStream(publicKeyFile); 

      byte[] decoded = Base64.decode(IOUtils.toByteArray(input));  

      X509EncodedKeySpec publicSpec = new X509EncodedKeySpec(decoded); 
      KeyFactory keyFactory = KeyFactory.getInstance("RSA"); 
      PublicKey publicKey = keyFactory.generatePublic(publicSpec); 

      Cipher cipher = Cipher.getInstance("RSA/ECB/NoPadding"); 
      cipher.init(Cipher.ENCRYPT_MODE, publicKey); 

      encryptedAESKey = cipher.doFinal(aesKey); 
      base64AESEncryptedKey = Base64.encode(encryptedAESKey); 

      input.close(); 
     }catch (Exception e) { 
      e.printStackTrace(); 
     } 
    } 

    public static void decryptAESKey(File privateKeyFile){ 

     try { 
      FileInputStream input = new FileInputStream(privateKeyFile); 

      byte[] decoded = Base64.decode(IOUtils.toByteArray(input)); 

      PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(decoded); 
      KeyFactory keyFactory = KeyFactory.getInstance("RSA"); 
      PrivateKey privateKey = keyFactory.generatePrivate(keySpec); 

      Cipher cipher = Cipher.getInstance("RSA/ECB/NoPadding"); 
      cipher.init(Cipher.DECRYPT_MODE, privateKey); 

      aesKeyTransformed = cipher.doFinal(encryptedAESKey); 
      input.close(); 
     }catch (Exception e) { 
      e.printStackTrace(); 
     } 
    } 
} 

ist das Ergebnis:

String: xVwH7Nbz84emVoH0J31sRHC+B669T9wCUVlTDhYgXiI= 

Encrypted string: INTA8rx46hX6bZbDIl4iiWsUGO4ywCW0Aee1reqQ3wR5X7He5ztLHvyZoa0WZmUGYbYwprNGffRI 
OVJFxczMHkxUfHU1WWCTzcfNylD+sWObIYrbyc13aZi9OL/r1GXuaGtkIgTJyqv0QPHfIri7iaH3 
Lr/F4EIcyphJM3E2reQ= 

Decrypted String: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAxVwH7Nbz84emVoH0J31sRHC+ 
B669T9wCUVlTDhYgXiI= 
+0

Ist die 'PKCS8EncodedKeySpec' die gewünschte Schlüsselspezifikation für die Entschlüsselung? Sollte X509 sein, oder? – venture

Antwort

1

In RSA einige Daten in eine große Zahl codiert und berechnet auf. NoPadding (nicht gepolsterte oder Lehrbuch RSA) bedeutet, dass Sie für die ordnungsgemäße Codierung der Nachricht vollständig verantwortlich sind. Alle Berechnungen werden gegen einen großen Modul durchgeführt (sollte heutzutage mindestens 2048 Bit sein). Da Java Big-Endian-Zahlen annimmt, wird Ihre Nachricht automatisch in die niedrigstwertigen Bytes codiert, aber die Entschlüsselung gibt die decodierte Nachricht in der gleichen Größe des Moduls zurück, weil sie nicht wissen kann, ob die führenden Null-Bytes beabsichtigt waren oder nicht.

Um diese Berechnung zu korrigieren und sicher ist es notwendig, Padding anzuwenden. Das alte PKCS # 1 v1.5 Padding wird heutzutage nicht als sicher angesehen, aber es hat nur 11 Byte Overhead (nur 2048/8-11 = 245 Bytes können mit einem Schlüssel von 2048 Bit verschlüsselt werden). Das neuere PKCS # 1 v2.1 Padding (OAEP) gilt als sicher und sollte hier verwendet werden. Es hat einen Overhead von 42 Bytes, wenn SHA-1 verwendet wird.

Die Parameter "RSA/ECB/NoPadding" sind obligatorisch.

Das ist wirklich schlecht, weil es sehr unsicher ist: Which attacks are possible against raw/textbook RSA?

Wenn Sie nicht bereit sind, einfach die Chiffre Zeichenfolge Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding"); zu ändern, werden Sie die führenden Nullen selbst zu entfernen. Das Problem ist natürlich, dass dieser "Zero-Padding" -Modus mehrdeutig ist und wenn der Klartext mit einem 0x00 Byte beginnt, können Sie ihn nicht von einem Füllbyte unterscheiden und müssen ihn entfernen, wodurch Ihr Klartext aufgebrochen wird. Wenn der Klartext wie in Ihrem Fall ein AES-Schlüssel ist, besteht eine Wahrscheinlichkeit von 0,3%, dass er mit einem 0x00-Byte beginnt und somit den Schlüssel bricht. Sie müssen sicherstellen, dass der Schlüssel tatsächlich korrekt ist und füllen Sie mit Null Bytes, wenn es nicht die richtige Länge hat.

Hier ist, wie Sie können führende Null-Bytes entfernen:

byte[] unpadZeros(byte[] in) { 
    int i = 0; 
    while(in[i] == 0) i++; 
    return Arrays.copyOfRange(in, i, in.length); 
} 

Wenn Sie wissen, dass Sie einen AES-Schlüssel sind zu entschlüsseln, dann ist es möglich, die unpadding keine Produkte falsche Daten zu machen:

byte[] unpadZerosToGetAesKey(byte[] in) { 
    int i = 0; 
    while(in[i] == 0) i++; 
    int len = in.length - i; 
    if (len <= 16) len = 16; 
    else if (len <= 24) len = 24; 
    else len = 32; 
    return Arrays.copyOfRange(in, in.length - len, in.length); 
} 
+0

Lustig (oder traurig) über diese Parameter ist, dass sie vom Finanzamt in meinem Land verhängt wurden =). Die zweite Methode ist genau das, was ich brauche, danke. – c00ckiez

Verwandte Themen