So verschlüsseln Sie String in Java

149

Ich muss eine Zeichenfolge verschlüsseln, die im 2D-Barcode (PDF-417) angezeigt wird. Wenn also jemand eine Idee zum Scannen hat, ist sie nicht lesbar.

Andere Vorraussetzungen:

  • sollte nicht kompliziert sein
  • Es sollte nicht aus RSA, PKI-Infrastruktur, Schlüsselpaaren usw. bestehen.

Es muss einfach genug sein, um die herumschnüffelnden Leute loszuwerden, und für andere Unternehmen, die daran interessiert sind, diese Daten zu erhalten, leicht zu entschlüsseln. Sie rufen uns an, wir teilen ihnen den Standard mit oder geben ihnen einen einfachen Schlüssel, der dann zur Entschlüsselung verwendet werden kann.

Wahrscheinlich könnten diese Unternehmen unterschiedliche Technologien verwenden, daher wäre es gut, sich an einen Standard zu halten, der nicht an eine spezielle Plattform oder Technologie gebunden ist.

Was schlagen Sie vor? Gibt es eine Java - Klasse zu tun encrypt()und decrypt()ohne viel Komplikation bei der Erreichung hoher Sicherheitsstandards?

ante.sabo
quelle
Warnung . Viele der folgenden Antworten zeigen die eine oder andere Methode, um eine Kryptografie unter Java durchzuführen . Die Antworten spiegeln möglicherweise nicht die guten kryptografischen Praktiken wider und werden möglicherweise nicht gut überprüft. Es gibt keine Sicherheit zum Kopieren / Einfügen . Antworten sollten zumindest die Zeichenfolgenkonvertierung berücksichtigen. Die eigentliche Frage mit dem enthaltenen 2D-Barcode ist viel zu weit gefasst und sollte eine kundenspezifische Lösung erfordern.
Maarten Bodewes

Antworten:

155

Dies ist die erste Seite, die über Google angezeigt wird, und die Sicherheitslücken in allen Implementierungen lassen mich zusammenzucken. Ich poste diese Seite, um Informationen zur Verschlüsselung für andere hinzuzufügen, da dies 7 Jahre nach dem ursprünglichen Beitrag der Fall war. Ich habe einen Master-Abschluss in Computertechnik und viel Zeit damit verbracht, Kryptographie zu studieren und zu lernen. Deshalb werfe ich meine zwei Cent, um das Internet sicherer zu machen.

Beachten Sie auch, dass viele Implementierungen für eine bestimmte Situation sicher sein können. Warum sollten Sie diese jedoch verwenden und möglicherweise versehentlich einen Fehler machen? Verwenden Sie die stärksten verfügbaren Tools, es sei denn, Sie haben einen bestimmten Grund, dies nicht zu tun. Insgesamt empfehle ich dringend, eine Bibliothek zu benutzen und sich von den Details fernzuhalten, wenn Sie können.

UPDATE 05.04.18: Ich habe einige Teile umgeschrieben, um das Verständnis zu vereinfachen, und die empfohlene Bibliothek von Jasypt in Googles neue Bibliothek Tink geändert. Ich würde empfehlen, Jasypt vollständig aus einem vorhandenen Setup zu entfernen .

Vorwort

Ich werde im Folgenden die Grundlagen der sicheren symmetrischen Kryptographie skizzieren und auf häufige Fehler hinweisen, die ich online sehe, wenn Leute Krypto selbst mit der Standard-Java-Bibliothek implementieren. Wenn Sie nur alle Details überspringen möchten, die in die neue Google-Bibliothek Tink übertragen wurden, importieren Sie diese in Ihr Projekt und verwenden Sie den AES-GCM-Modus für alle Ihre Verschlüsselungen. So sind Sie sicher.

Wenn Sie nun die wichtigsten Details zum Verschlüsseln in Java erfahren möchten, lesen Sie weiter :)

Blockchiffren

Als erstes müssen Sie einen Blockchiffre mit symmetrischem Schlüssel auswählen. Eine Blockverschlüsselung ist eine Computerfunktion / ein Computerprogramm, mit dem Pseudozufälligkeit erzeugt wird. Pseudozufälligkeit ist eine gefälschte Zufälligkeit, die kein anderer Computer als ein Quantencomputer in der Lage wäre, den Unterschied zwischen ihm und der realen Zufälligkeit zu erkennen. Die Blockverschlüsselung ist wie der Baustein für die Kryptografie, und wenn sie mit verschiedenen Modi oder Schemata verwendet wird, können wir Verschlüsselungen erstellen.

Nun in Bezug auf Block - Cipher Algorithmen heute verfügbar, Achten Sie darauf, nie , ich wiederhole NIE verwenden DIE , ich würde sogar sagen nie verwenden 3DES . Die einzige Blockverschlüsselung, mit der sogar die NSA-Version von Snowden nachweisen konnte, dass sie Pseudo-Random so nahe wie möglich kommt, ist AES 256 . Es gibt auch AES 128; Der Unterschied besteht darin, dass AES 256 in 256-Bit-Blöcken arbeitet, während AES 128 in 128 Blöcken arbeitet. Alles in allem gilt AES 128 als sicher, obwohl einige Schwachstellen entdeckt wurden, aber 256 ist so solide wie es nur geht.

Unterhaltsame Tatsache DES wurde von der NSA bei ihrer Gründung gebrochen und tatsächlich einige Jahre lang geheim gehalten. Obwohl einige Leute immer noch behaupten, 3DES sei sicher, gibt es einige Forschungsarbeiten, die Schwachstellen in 3DES gefunden und analysiert haben .

Verschlüsselungsmodi

Die Verschlüsselung wird erstellt, wenn Sie eine Blockverschlüsselung verwenden und ein bestimmtes Schema verwenden, sodass die Zufälligkeit mit einem Schlüssel kombiniert wird, um etwas zu erstellen, das reversibel ist, solange Sie den Schlüssel kennen. Dies wird als Verschlüsselungsmodus bezeichnet.

Hier ist ein Beispiel für einen Verschlüsselungsmodus und den einfachsten Modus, der als EZB bezeichnet wird, damit Sie visuell verstehen können, was passiert:

EZB-Modus

Die Verschlüsselungsmodi, die Sie am häufigsten online sehen, sind die folgenden:

EZB CTR, CBC, GCM

Es gibt andere als die aufgeführten Modi, und die Forscher arbeiten ständig an neuen Modi, um bestehende Probleme zu verbessern.

Kommen wir nun zu den Implementierungen und dem, was sicher ist. Verwenden Sie die EZB NIEMALS. Dies ist schlecht, wenn Sie sich wiederholende Daten verbergen, wie der berühmte Linux-Pinguin zeigt .Linux Penguin Beispiel

Beachten Sie bei der Implementierung in Java, dass der EZB-Modus standardmäßig festgelegt ist, wenn Sie den folgenden Code verwenden:

Cipher cipher = Cipher.getInstance("AES");

... GEFAHR DAS IST EINE VULNERABILITÄT! und leider ist dies überall in StackOverflow und online in Tutorials und Beispielen zu sehen.

Nonces und IVs

Als Reaktion auf das Problem im EZB-Modus wurden Substantive, auch IVs genannt, erstellt. Die Idee ist, dass wir eine neue Zufallsvariable generieren und sie an jede Verschlüsselung anhängen, damit beim Verschlüsseln von zwei gleichen Nachrichten unterschiedliche Nachrichten ausgegeben werden. Das Schöne daran ist, dass eine IV oder Nonce öffentlich bekannt ist. Das bedeutet, dass ein Angreifer Zugriff darauf haben kann, aber solange er nicht über Ihren Schlüssel verfügt, kann er mit diesem Wissen nichts anfangen.

Häufige Probleme, die ich sehen werde, sind, dass Benutzer die IV als statischen Wert festlegen, wie in demselben festen Wert in ihrem Code. und hier ist die Gefahr für IVs, sobald Sie eine wiederholen, gefährden Sie tatsächlich die gesamte Sicherheit Ihrer Verschlüsselung.

Zufällige IV generieren

SecureRandom randomSecureRandom = SecureRandom.getInstance("SHA1PRNG");
byte[] iv = new byte[cipher.getBlockSize()];
randomSecureRandom.nextBytes(iv);
IvParameterSpec ivParams = new IvParameterSpec(iv);

Hinweis: SHA1 ist defekt, aber ich konnte nicht finden, wie SHA256 in diesem Anwendungsfall richtig implementiert werden kann. Wenn also jemand eine Pause einlegen und es aktualisieren möchte, wäre es fantastisch! Auch SHA1-Angriffe sind immer noch unkonventionell, da es einige Jahre dauern kann, bis ein riesiger Cluster geknackt ist. Details finden Sie hier.

CTR-Implementierung

Für den CTR-Modus ist keine Auffüllung erforderlich.

 Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding");

CBC-Implementierung

Wenn Sie den CBC-Modus implementieren möchten, gehen Sie wie folgt mit PKCS7Padding vor:

 Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");

CBC- und CTR-Sicherheitsanfälligkeit und warum Sie GCM verwenden sollten

Obwohl einige andere Modi wie CBC und CTR sicher sind, tritt das Problem auf, dass ein Angreifer die verschlüsselten Daten umdrehen und ihren Wert beim Entschlüsseln ändern kann. Nehmen wir also an, Sie verschlüsseln eine imaginäre Banknachricht "Sell 100". Ihre verschlüsselte Nachricht sieht wie folgt aus: "eu23ng". Der Angreifer ändert ein Bit in "eu53ng". Wenn Ihre Nachricht entschlüsselt wird, lautet sie plötzlich "Sell 900".

Um dies zu vermeiden, verwendet der Großteil des Internets GCM, und jedes Mal, wenn Sie HTTPS sehen, verwenden sie wahrscheinlich GCM. GCM signiert die verschlüsselte Nachricht mit einem Hash und überprüft, ob die Nachricht mit dieser Signatur nicht geändert wurde.

Ich würde die Implementierung von GCM aufgrund seiner Komplexität vermeiden. Sie sind besser dran, wenn Sie Googles neue Bibliothek Tink verwenden, denn auch hier gefährden Sie, wenn Sie versehentlich eine IV wiederholen, den Schlüssel im Fall von GCM, was die ultimative Sicherheitslücke darstellt. Neue Forscher arbeiten an IV-Wiederholungs-resistenten Verschlüsselungsmodi, bei denen der Schlüssel selbst dann nicht gefährdet ist, wenn Sie die IV wiederholen, aber dies ist noch kein Mainstream.

Wenn Sie nun GCM implementieren möchten, finden Sie hier einen Link zu einer netten GCM-Implementierung . Ich kann jedoch die Sicherheit nicht gewährleisten oder wenn sie ordnungsgemäß implementiert ist, aber die Basis ist schlecht. Beachten Sie auch, dass bei GCM keine Polsterung vorhanden ist.

Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");

Schlüssel gegen Passwörter

Ein weiterer sehr wichtiger Hinweis ist, dass bei der Kryptografie ein Schlüssel und ein Passwort nicht dasselbe sind. Ein Schlüssel in der Kryptographie muss ein gewisses Maß an Entropie und Zufälligkeit aufweisen, um als sicher zu gelten. Aus diesem Grund müssen Sie sicherstellen, dass Sie die richtigen kryptografischen Bibliotheken verwenden, um den Schlüssel für Sie zu generieren.

Sie haben also wirklich zwei Implementierungen, die Sie hier ausführen können. Die erste besteht darin, den Code in diesem StackOverflow-Thread für die Zufallsschlüsselgenerierung zu verwenden . Diese Lösung verwendet einen sicheren Zufallszahlengenerator, um einen Schlüssel von Grund auf neu zu erstellen, den Sie verwenden können.

Die andere weniger sichere Option ist die Verwendung von Benutzereingaben wie einem Kennwort. Das Problem, das wir besprochen haben, ist, dass das Passwort nicht genug Entropie hat, daher müssten wir PBKDF2 verwenden , einen Algorithmus, der das Passwort nimmt und es verstärkt. Hier ist eine StackOverflow-Implementierung, die mir gefallen hat . In der Google Tink-Bibliothek ist all dies integriert, und Sie sollten es nutzen.

Android-Entwickler

Ein wichtiger Punkt, auf den Sie hier hinweisen sollten, ist zu wissen, dass Ihr Android-Code rückentwickelbar ist und in den meisten Fällen auch der meiste Java-Code. Das heißt, wenn Sie das Passwort im Klartext in Ihrem Code speichern. Ein Hacker kann es leicht abrufen. Normalerweise möchten Sie für diese Art der Verschlüsselung die asymmetrische Kryptographie usw. verwenden. Dies liegt außerhalb des Rahmens dieses Beitrags, daher werde ich vermeiden, darauf einzugehen.

Eine interessante Lektüre aus dem Jahr 2013 : Weist darauf hin, dass 88% der Crypto-Implementierungen in Android nicht ordnungsgemäß durchgeführt wurden.

Abschließende Gedanken

Noch einmal, ich würde vorschlagen, die Java-Bibliothek für Krypto nicht direkt zu implementieren und Google Tink zu verwenden. Dies erspart Ihnen Kopfschmerzen, da sie wirklich gute Arbeit geleistet haben, um alle Algorithmen richtig zu implementieren. Und selbst dann sollten Sie sich über Probleme informieren, die auf dem Tink-Github aufgetreten sind. Hier und da tauchen Schwachstellen auf.

Wenn Sie Fragen oder Feedback haben, können Sie diese gerne kommentieren! Die Sicherheit ändert sich ständig und Sie müssen Ihr Bestes geben, um Schritt zu halten :)

Konstantino Sparakis
quelle
15
Dies ist das sauberste, was ich je gesehen habe.
Seraf
1
@ SabirKhan Es könnte Anlass zur Sorge geben, aber die Kernalgorithmen sind immer noch nicht defekt, sodass ich mir darüber keine Sorgen machen würde. Wenn Sie dem nicht vertrauen , besuchen Sie auch github.com/google/keyczar . Es wurde vom Sicherheitsteam von googles entwickelt.
Konstantino Sparakis
1
@KonstantinoSparakis: Wenn ich die Dokumentation für Jasypt's BasicTextEncryptor und StrongTextEncryptor nicht falsch interpretiert habe, verwenden diese Klassen DES und 3DES zum Verschlüsseln. Genau das raten Sie den Lesern, nicht zu verwenden. IMO sollten Sie die angegebenen Codebeispiele durch eines ersetzen, das den StandardPBEStringEncryptor von Jasypt verwendet und manuell einen zu verwendenden AES-Algorithmus definiert.
xpages-noob
1
@ xpages-noob Ich habe den Beitrag aktualisiert. Ich habe tatsächlich Google Tink gefunden, die neueste unterstützte Bibliothek für Krypto, also sollten Sie es sich ansehen!
Konstantino Sparakis
2
Die AES-Blockgröße beträgt 128 Bit. In AES 256 beträgt die Schlüsselgröße 256 Bit. Ebenso AES 192 und AES 128. Seit Java 8 ist die getInstanceStrong()Methode von CipherSHA1PRNG
Saptarshi Basu
110

Ich würde empfehlen, eine standardmäßige symmetrische Chiffre wie DES , 3DES oder AES zu verwenden . Dies ist zwar nicht der sicherste Algorithmus, es gibt jedoch zahlreiche Implementierungen, und Sie müssen den Schlüssel nur jedem geben, der die Informationen im Barcode entschlüsseln soll. Mit javax.crypto.Cipher möchten Sie hier arbeiten.

Nehmen wir an, die zu verschlüsselnden Bytes befinden sich in

byte[] input;

Als Nächstes werden Sie die Schlüssel und benötigen Initialisierungsvektor Bytes

byte[] keyBytes;
byte[] ivBytes;

Jetzt können Sie die Verschlüsselung für den von Ihnen ausgewählten Algorithmus initialisieren:

// wrap key data in Key/IV specs to pass to cipher
SecretKeySpec key = new SecretKeySpec(keyBytes, "DES");
IvParameterSpec ivSpec = new IvParameterSpec(ivBytes);
// create the cipher with the algorithm you choose
// see javadoc for Cipher class for more info, e.g.
Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");

Die Verschlüsselung würde so aussehen:

cipher.init(Cipher.ENCRYPT_MODE, key, ivSpec);
byte[] encrypted= new byte[cipher.getOutputSize(input.length)];
int enc_len = cipher.update(input, 0, input.length, encrypted, 0);
enc_len += cipher.doFinal(encrypted, enc_len);

Und Entschlüsselung wie folgt:

cipher.init(Cipher.DECRYPT_MODE, key, ivSpec);
byte[] decrypted = new byte[cipher.getOutputSize(enc_len)];
int dec_len = cipher.update(encrypted, 0, enc_len, decrypted, 0);
dec_len += cipher.doFinal(decrypted, dec_len);
VoidPointer
quelle
9
Kann ich vorschlagen, dass Sie dieses Beispiel aktualisieren, um auf den DESedeAlgorithmus zu verweisen ? Da dies eine beliebte Frage (und Antwort) ist, wäre es eine Schande, die Menschen zur Verwendung von DES zu ermutigen, da die Chiffre nach heutigen Maßstäben so schwach ist.
Duncan Jones
etwas stimmt nicht mit javax.crypto.BadPaddingException: Angesichts des letzten Blocks, der beim Beschreiben nicht richtig aufgefüllt wurde
Neugier
2
@ Duncan In der Tat ist DES schwach, aber ich nehme an, AES wäre DESede (auch bekannt als TipleDES) vorzuziehen: http://security.stackexchange.com/a/26181/69785
Piovezan
2
Dies sollte aktualisiert werden, um AES / GCM / NoPadding zu haben, DES ist anfällig für Bruteforce-Angriffe, TripleDes wird ebenfalls nicht empfohlen
Konstantino Sparakis
1
Die Antwort von Konstantino Sparakis unten ist so viel besser als diese.
Steve
22

Warnung

Verwenden Sie dies nicht als Sicherheitsmaßnahme.

Der Verschlüsselungsmechanismus in diesem Beitrag ist ein einmaliger Block. Dies bedeutet, dass der geheime Schlüssel von einem Angreifer mithilfe von 2 verschlüsselten Nachrichten leicht wiederhergestellt werden kann. XOR 2-verschlüsselte Nachrichten und Sie erhalten den Schlüssel. So einfach!

Von Moussa darauf hingewiesen


Ich verwende Suns Base64Encoder / Decoder, der in Suns JRE zu finden ist, um ein weiteres JAR in lib zu vermeiden. Das ist gefährlich, wenn man OpenJDK oder die JRE eines anderen verwendet. Gibt es außerdem einen weiteren Grund, warum ich die Verwendung von Apache Commons Lib mit Encoder / Decoder in Betracht ziehen sollte?

public class EncryptUtils {
    public static final String DEFAULT_ENCODING = "UTF-8"; 
    static BASE64Encoder enc = new BASE64Encoder();
    static BASE64Decoder dec = new BASE64Decoder();

    public static String base64encode(String text) {
        try {
            return enc.encode(text.getBytes(DEFAULT_ENCODING));
        } catch (UnsupportedEncodingException e) {
            return null;
        }
    }//base64encode

    public static String base64decode(String text) {
        try {
            return new String(dec.decodeBuffer(text), DEFAULT_ENCODING);
        } catch (IOException e) {
            return null;
        }
    }//base64decode

    public static void main(String[] args) {
        String txt = "some text to be encrypted";
        String key = "key phrase used for XOR-ing";
        System.out.println(txt + " XOR-ed to: " + (txt = xorMessage(txt, key)));

        String encoded = base64encode(txt);       
        System.out.println(" is encoded to: " + encoded + " and that is decoding to: " + (txt = base64decode(encoded)));
        System.out.print("XOR-ing back to original: " + xorMessage(txt, key));
    }

    public static String xorMessage(String message, String key) {
        try {
            if (message == null || key == null) return null;

            char[] keys = key.toCharArray();
            char[] mesg = message.toCharArray();

            int ml = mesg.length;
            int kl = keys.length;
            char[] newmsg = new char[ml];

            for (int i = 0; i < ml; i++) {
                newmsg[i] = (char)(mesg[i] ^ keys[i % kl]);
            }//for i

            return new String(newmsg);
        } catch (Exception e) {
            return null;
        }
    }//xorMessage
}//class
ante.sabo
quelle
1
Ich habe diesen Lösungsvorschlag auch über sun.misc.BASE64Encoder verwendet, aber wenn zum Codieren ziemlich große Zeichenfolgen verwendet wurden, gab der Codierer Chunk-Zeichenfolgen (jeweils 76 Zeichen) zurück. Ich bin dann zu Apache Commons Codec Base64 gewechselt, der Codierungsmethoden ohne Chunking bietet!
BasZero
78
Der von Ihnen beschriebene Verschlüsselungsmechanismus ist SEHR GEFÄHRLICH, wenn er mehrmals verwendet wird. Das ist der Grund, warum es als One-Time-Pad bezeichnet wird. Der geheime Schlüssel kann von einem Angreifer mithilfe von 2 verschlüsselten Nachrichten leicht wiederhergestellt werden. xoder 2 verschlüsselte Nachrichten und Sie erhalten den Schlüssel. So einfach!
Xtrem
3
Die Idee ist nicht, schwer zu sein, sondern nur die Leute davon abzuhalten, zu lesen, was in PDF-417 2D-Barcodes geschrieben ist. Und überhaupt, es gibt nur einige Indizes, die für niemanden von entscheidender Bedeutung sind ...
ante.sabo
2
OK. Nur besorgt, dass jemand dies als Verschlüsselungsmechanismus verwendet.
Xtrem
Bei der Verschlüsselung kann vermieden werden, dass ein Encoder (z. B. BASE64Encoder) Brute-Force-Angriffe ausführt.
Jagrut Dalwadi
13

danke, dass ich diese Klasse mit Ihrem Code erstellt habe, vielleicht findet es jemand benutzerfreundlich

Objekt Crypter

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.ShortBufferException;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;


public class ObjectCrypter {

private Cipher deCipher;
private Cipher enCipher;
private SecretKeySpec key;
private IvParameterSpec ivSpec;


public ObjectCrypter(byte[] keyBytes,   byte[] ivBytes) {
    // wrap key data in Key/IV specs to pass to cipher


     ivSpec = new IvParameterSpec(ivBytes);
    // create the cipher with the algorithm you choose
    // see javadoc for Cipher class for more info, e.g.
    try {
         DESKeySpec dkey = new  DESKeySpec(keyBytes);
          key = new SecretKeySpec(dkey.getKey(), "DES");
         deCipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
         enCipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
    } catch (NoSuchAlgorithmException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (NoSuchPaddingException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (InvalidKeyException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}
public byte[] encrypt(Object obj) throws InvalidKeyException, InvalidAlgorithmParameterException, IOException, IllegalBlockSizeException, ShortBufferException, BadPaddingException {
    byte[] input = convertToByteArray(obj);
    enCipher.init(Cipher.ENCRYPT_MODE, key, ivSpec);

    return enCipher.doFinal(input);




//  cipher.init(Cipher.ENCRYPT_MODE, key, ivSpec);
//  byte[] encypted = new byte[cipher.getOutputSize(input.length)];
//  int enc_len = cipher.update(input, 0, input.length, encypted, 0);
//  enc_len += cipher.doFinal(encypted, enc_len);
//  return encypted;


}
public Object decrypt( byte[]  encrypted) throws InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException, IOException, ClassNotFoundException {
    deCipher.init(Cipher.DECRYPT_MODE, key, ivSpec);

    return convertFromByteArray(deCipher.doFinal(encrypted));

}



private Object convertFromByteArray(byte[] byteObject) throws IOException,
        ClassNotFoundException {
    ByteArrayInputStream bais;

    ObjectInputStream in;
    bais = new ByteArrayInputStream(byteObject);
    in = new ObjectInputStream(bais);
    Object o = in.readObject();
    in.close();
    return o;

}



private byte[] convertToByteArray(Object complexObject) throws IOException {
    ByteArrayOutputStream baos;

    ObjectOutputStream out;

    baos = new ByteArrayOutputStream();

    out = new ObjectOutputStream(baos);

    out.writeObject(complexObject);

    out.close();

    return baos.toByteArray();

}


}
Sherif
quelle
eine ähnliche Frage gestellt hier !
user2023507
Sollte es nicht so sein, dass das Übergeben verschiedener Schlüssel während des Ver- und Entschlüsselns den Text nicht zurückgeben sollte? Das scheint hier nicht zu passieren. PS: Ich verwende verschiedene Objekte dieser Klasse, um diesen Test durchzuführen.
instanceOfObject
6

Update am 12-DEZ-2019

Im Gegensatz zu einigen anderen Modi wie CBC muss der IV im GCM-Modus nicht unvorhersehbar sein. Die einzige Voraussetzung ist, dass die IV für jeden Aufruf mit einem bestimmten Schlüssel eindeutig ist. Wenn es für einen bestimmten Schlüssel einmal wiederholt wird, kann die Sicherheit beeinträchtigt werden. Ein einfacher Weg, dies zu erreichen, besteht darin, eine zufällige IV von einem starken Pseudozufallszahlengenerator zu verwenden, wie unten gezeigt.

Die Verwendung einer Sequenz oder eines Zeitstempels als IV ist ebenfalls möglich, jedoch möglicherweise nicht so trivial, wie es sich anhört. Wenn das System beispielsweise die Sequenzen, die bereits als IV in einem persistenten Speicher verwendet wurden, nicht korrekt verfolgt, kann ein Aufruf eine IV nach einem Systemneustart wiederholen. Ebenso gibt es keine perfekte Uhr. Computeruhr stellt sich neu ein usw.

Außerdem sollte der Schlüssel nach jeweils 2 ^ 32 Aufrufen gedreht werden. Weitere Einzelheiten zur IV-Anforderung finden Sie in dieser Antwort und in den NIST-Empfehlungen .


Dies ist der Verschlüsselungs- und Entschlüsselungscode, den ich gerade in Java 8 geschrieben habe, unter Berücksichtigung der folgenden Punkte. Hoffe, jemand würde dies nützlich finden:

  1. Verschlüsselungsalgorithmus : Blockverschlüsselung AES mit 256-Bit-Schlüssel wird als sicher genug angesehen. Um eine vollständige Nachricht zu verschlüsseln, muss ein Modus ausgewählt werden. Eine authentifizierte Verschlüsselung (die sowohl Vertraulichkeit als auch Integrität bietet) wird empfohlen. GCM, CCM und EAX sind die am häufigsten verwendeten authentifizierten Verschlüsselungsmodi. GCM wird normalerweise bevorzugt und funktioniert gut in Intel-Architekturen, die spezielle Anweisungen für GCM bereitstellen. Alle diese drei Modi sind CTR-basierte (zählerbasierte) Modi und müssen daher nicht aufgefüllt werden. Infolgedessen sind sie nicht anfällig für Polsterangriffe

  2. Für das GCM ist ein Initialisierungsvektor (IV) erforderlich. Die IV ist kein Geheimnis. Die einzige Voraussetzung ist, dass es zufällig oder unvorhersehbar ist. In Java soll die SecuredRandomKlasse kryptografisch starke Pseudozufallszahlen erzeugen. Der Algorithmus zur Erzeugung von Pseudozufallszahlen kann in der getInstance()Methode angegeben werden. Seit Java 8 wird jedoch empfohlen, eine getInstanceStrong()Methode zu verwenden , die den stärksten Algorithmus verwendet, der von der konfiguriert und bereitgestellt wirdProvider

  3. NIST empfiehlt 96-Bit-IV für GCM, um Interoperabilität, Effizienz und Einfachheit des Designs zu fördern

  4. Um zusätzliche Sicherheit zu gewährleisten, wird in der folgenden Implementierung SecureRandomnach dem Erzeugen alle 2 ^ 16 Bytes der Pseudozufallsbytegenerierung erneut geimpft

  5. Der Empfänger muss die IV kennen, um den Chiffretext entschlüsseln zu können. Daher muss die IV zusammen mit dem Chiffretext übertragen werden. Einige Implementierungen senden die IV als AD (Associated Data), was bedeutet, dass das Authentifizierungs-Tag sowohl für den Chiffretext als auch für die IV berechnet wird. Dies ist jedoch nicht erforderlich. Der IV kann einfach der Chiffretext vorangestellt werden, da die Validierung des Authentifizierungs-Tags ohnehin fehlschlägt, wenn die IV während der Übertragung aufgrund eines absichtlichen Angriffs oder eines Netzwerk- / Dateisystemfehlers geändert wird

  6. Strings sollten nicht verwendet werden, um die Klartextnachricht oder den Schlüssel zu speichern, da Strings unveränderlich sind und wir sie daher nach der Verwendung nicht löschen können. Diese ungeklärten Strings bleiben dann im Speicher und können in einem Heap-Dump angezeigt werden. Aus dem gleichen Grund sollte der Client, der diese Verschlüsselungs- oder Entschlüsselungsmethoden aufruft, alle Variablen oder Arrays löschen, die die Nachricht oder den Schlüssel enthalten, nachdem sie nicht mehr benötigt werden.

  7. Kein Anbieter ist im Code gemäß den allgemeinen Empfehlungen fest codiert

  8. Schließlich sollte für die Übertragung über ein Netzwerk oder einen Speicher der Schlüssel oder der Chiffretext unter Verwendung der Base64-Codierung codiert werden. Die Details zu Base64 finden Sie hier . Der Java 8-Ansatz sollte befolgt werden

Byte-Arrays können gelöscht werden mit:

Arrays.fill(clearTextMessageByteArray, Byte.MIN_VALUE);

Ab Java 8 gibt es jedoch keine einfache Möglichkeit zum Löschen, SecretKeyspecund SecretKeyda die Implementierungen dieser beiden Schnittstellen die Methode destroy()der Schnittstelle nicht implementiert zu haben scheinen Destroyable. Im folgenden Code wird eine separate Methode geschrieben, um die Reflexion zu löschen SecretKeySpecund zu SecretKeyverwenden.

Der Schlüssel sollte mit einem der beiden unten genannten Ansätze generiert werden.

Beachten Sie, dass Schlüssel Geheimnisse wie Passwörter sind, aber im Gegensatz zu Passwörtern, die für den menschlichen Gebrauch bestimmt sind, sollen Schlüssel von kryptografischen Algorithmen verwendet werden und sollten daher nur auf die oben beschriebene Weise generiert werden.

package com.sapbasu.javastudy;

import java.lang.reflect.Field;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

import javax.crypto.Cipher;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;

public class Crypto {

  private static final int AUTH_TAG_SIZE = 128; // bits

  // NIST recommendation: "For IVs, it is recommended that implementations
  // restrict support to the length of 96 bits, to
  // promote interoperability, efficiency, and simplicity of design."
  private static final int IV_LEN = 12; // bytes

  // number of random number bytes generated before re-seeding
  private static final double PRNG_RESEED_INTERVAL = Math.pow(2, 16);

  private static final String ENCRYPT_ALGO = "AES/GCM/NoPadding";

  private static final List<Integer> ALLOWED_KEY_SIZES = Arrays
      .asList(new Integer[] {128, 192, 256}); // bits

  private static SecureRandom prng;

  // Used to keep track of random number bytes generated by PRNG
  // (for the purpose of re-seeding)
  private static int bytesGenerated = 0;

  public byte[] encrypt(byte[] input, SecretKeySpec key) throws Exception {

    Objects.requireNonNull(input, "Input message cannot be null");
    Objects.requireNonNull(key, "key cannot be null");

    if (input.length == 0) {
      throw new IllegalArgumentException("Length of message cannot be 0");
    }

    if (!ALLOWED_KEY_SIZES.contains(key.getEncoded().length * 8)) {
      throw new IllegalArgumentException("Size of key must be 128, 192 or 256");
    }

    Cipher cipher = Cipher.getInstance(ENCRYPT_ALGO);

    byte[] iv = getIV(IV_LEN);

    GCMParameterSpec gcmParamSpec = new GCMParameterSpec(AUTH_TAG_SIZE, iv);

    cipher.init(Cipher.ENCRYPT_MODE, key, gcmParamSpec);
    byte[] messageCipher = cipher.doFinal(input);

    // Prepend the IV with the message cipher
    byte[] cipherText = new byte[messageCipher.length + IV_LEN];
    System.arraycopy(iv, 0, cipherText, 0, IV_LEN);
    System.arraycopy(messageCipher, 0, cipherText, IV_LEN,
        messageCipher.length);
    return cipherText;
  }

  public byte[] decrypt(byte[] input, SecretKeySpec key) throws Exception {
    Objects.requireNonNull(input, "Input message cannot be null");
    Objects.requireNonNull(key, "key cannot be null");

    if (input.length == 0) {
      throw new IllegalArgumentException("Input array cannot be empty");
    }

    byte[] iv = new byte[IV_LEN];
    System.arraycopy(input, 0, iv, 0, IV_LEN);

    byte[] messageCipher = new byte[input.length - IV_LEN];
    System.arraycopy(input, IV_LEN, messageCipher, 0, input.length - IV_LEN);

    GCMParameterSpec gcmParamSpec = new GCMParameterSpec(AUTH_TAG_SIZE, iv);

    Cipher cipher = Cipher.getInstance(ENCRYPT_ALGO);
    cipher.init(Cipher.DECRYPT_MODE, key, gcmParamSpec);

    return cipher.doFinal(messageCipher);
  }

  public byte[] getIV(int bytesNum) {

    if (bytesNum < 1) throw new IllegalArgumentException(
        "Number of bytes must be greater than 0");

    byte[] iv = new byte[bytesNum];

    prng = Optional.ofNullable(prng).orElseGet(() -> {
      try {
        prng = SecureRandom.getInstanceStrong();
      } catch (NoSuchAlgorithmException e) {
        throw new RuntimeException("Wrong algorithm name", e);
      }
      return prng;
    });

    if (bytesGenerated > PRNG_RESEED_INTERVAL || bytesGenerated == 0) {
      prng.setSeed(prng.generateSeed(bytesNum));
      bytesGenerated = 0;
    }

    prng.nextBytes(iv);
    bytesGenerated = bytesGenerated + bytesNum;

    return iv;
  }

  private static void clearSecret(Destroyable key)
      throws IllegalArgumentException, IllegalAccessException,
      NoSuchFieldException, SecurityException {
    Field keyField = key.getClass().getDeclaredField("key");
    keyField.setAccessible(true);
    byte[] encodedKey = (byte[]) keyField.get(key);
    Arrays.fill(encodedKey, Byte.MIN_VALUE);
  }
}

Der Verschlüsselungsschlüssel kann hauptsächlich auf zwei Arten generiert werden:

  • Ohne Passwort

    KeyGenerator keyGen = KeyGenerator.getInstance("AES");
    keyGen.init(KEY_LEN, SecureRandom.getInstanceStrong());
    SecretKey secretKey = keyGen.generateKey();
    SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey.getEncoded(),
        "AES");
    Crypto.clearSecret(secretKey);
    // After encryption or decryption with key
    Crypto.clearSecret(secretKeySpec);
  • Mit Passwort

    SecureRandom random = SecureRandom.getInstanceStrong();
    byte[] salt = new byte[32];
    random.nextBytes(salt);
    PBEKeySpec keySpec = new PBEKeySpec(password, salt, iterations, 
       keyLength);
    SecretKeyFactory keyFactory = 
        SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
    SecretKey secretKey = keyFactory.generateSecret(keySpec);
    SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey.getEncoded(),
        "AES");
    Crypto.clearSecret(secretKey);
    // After encryption or decryption with key
    Crypto.clearSecret(secretKeySpec);

Update basierend auf Kommentaren

Wie von @MaartenBodewes hervorgehoben, hat meine Antwort keine Stringder in der Frage geforderten beantwortet. Daher werde ich versuchen, diese Lücke zu schließen, falls jemand auf diese Antwort stößt und sich über die Handhabung wundert String.

Wie bereits in der Antwort erwähnt, ist der Umgang mit vertraulichen Informationen in a Stringim Allgemeinen keine gute Idee, da sie Stringunveränderlich sind und daher nach der Verwendung nicht gelöscht werden können. Und wie wir wissen, beeilt sich Stringder Garbage Collector nicht sofort, um einen vom Haufen zu entfernen , selbst wenn a keine starke Referenz hat. Somit Stringbleibt das für ein unbekanntes Zeitfenster im Speicher, obwohl es für das Programm nicht zugänglich ist. Das Problem dabei ist, dass ein Heap-Dump während dieses Zeitraums die vertraulichen Informationen enthüllt. Daher ist es immer besser, alle vertraulichen Informationen in einem Byte-Array oder Char-Array zu verarbeiten und das Array dann mit Nullen zu füllen, sobald ihr Zweck erfüllt ist.

Wenn wir jedoch mit all diesem Wissen immer noch in einer Situation enden, in der sich die zu verschlüsselnden vertraulichen Informationen in a befinden String, müssen wir sie zuerst in ein Byte-Array konvertieren encryptund decryptdie oben eingeführten Funktionen und aufrufen . (Der andere Eingabeschlüssel kann mit dem oben angegebenen Codeausschnitt generiert werden.)

A Stringkann folgendermaßen in Bytes konvertiert werden:

byte[] inputBytes = inputString.getBytes(StandardCharsets.UTF_8);

Ab Java 8 Stringwird intern im Heap mit UTF-16Codierung gespeichert . Wir haben UTF-8hier jedoch verwendet , da es normalerweise weniger Platz benötigt als UTF-16insbesondere für ASCII-Zeichen.

Ebenso kann das verschlüsselte Byte-Array wie folgt in einen String konvertiert werden:

String encryptedString = new String(encryptedBytes, StandardCharsets.UTF_8);
Saptarshi Basu
quelle
1
So sehr ich diese Antwort positiv bewerten möchte, da sie anscheinend den aktuellen Kryptopraktiken entspricht, sehe ich überhaupt keine Zeichenfolgenbehandlung, sodass sie eher nur eine Beschreibung der Verwendung des GCM-Modus darstellt. Als solches kann es die Frage nicht beantworten .
Maarten Bodewes
1
@ MaartenBodewes Vielen Dank, dass Sie sich die Zeit genommen haben, Feedback zu überprüfen und auszutauschen. Ich habe dies mit dem Verständnis geschrieben, dass das Verschlüsseln Stringmit den oben erstellten Funktionen trivial wäre. Bei einem zweiten Blick nach dem Lesen Ihres Kommentars verstehe ich jedoch, dass dies möglicherweise nicht offensichtlich ist. Ich werde sicherlich bearbeiten, um diese Details hinzuzufügen.
Saptarshi Basu
5

Wie wäre es damit:

private static byte[] xor(final byte[] input, final byte[] secret) {
    final byte[] output = new byte[input.length];
    if (secret.length == 0) {
        throw new IllegalArgumentException("empty security key");
    }
    int spos = 0;
    for (int pos = 0; pos < input.length; ++pos) {
        output[pos] = (byte) (input[pos] ^ secret[spos]);
        ++spos;
        if (spos >= secret.length) {
            spos = 0;
        }
    }
    return output;
}

Funktioniert gut für mich und ist ziemlich kompakt.

yegor256
quelle
Was passiert, wenn der Eingabeparameter secret == null oder input == null ist? Die Arbeit mit Bytes statt mit Strings ist in Ordnung, war aber in meinem Fall irrelevant. Entscheidend ist nur, dass dies mit jedem Gerät lesbar und dekodierbar sein muss, in jeder möglichen Zeichenkodierung ...
ante.sabo
@ ante.sabo anscheinend wird es eine NPE werfen. Dies ist das einzige, was mit NULL zu tun hat.
Miha_x64
Solange input.length <= secret.lengthHolds und No secretjemals wiederverwendet werden, ist dies sicher und wird als a bezeichnet one-time-pad. In diesen Fällen input.length > secret.lengthhandelt es sich um eine Variante der Vigenère-Chiffre, die als sehr schwach angesehen wird.
Trichner
5

Sie können Jasypt verwenden

Mit Jasypt kann das Verschlüsseln und Überprüfen eines Passworts so einfach sein wie ...

StrongTextEncryptor textEncryptor = new StrongTextEncryptor();
textEncryptor.setPassword(myEncryptionPassword);

Verschlüsselung:

String myEncryptedText = textEncryptor.encrypt(myText);

Entschlüsselung:

String plainText = textEncryptor.decrypt(myEncryptedText);

Gradle:

compile group: 'org.jasypt', name: 'jasypt', version: '1.9.2'

Eigenschaften:

Jasypt bietet Ihnen einfache unidirektionale (Digest) und bidirektionale Verschlüsselungstechniken.

Öffnen Sie die API zur Verwendung mit jedem JCE-Anbieter und nicht nur mit der Standard-Java-VM. Jasypt kann problemlos mit bekannten Anbietern wie Bouncy Castle verwendet werden. Mehr erfahren.

Höhere Sicherheit für die Passwörter Ihrer Benutzer. Mehr erfahren.

Unterstützung für binäre Verschlüsselung. Jasypt ermöglicht den Digest und die Verschlüsselung von Binärdateien (Byte-Arrays). Verschlüsseln Sie Ihre Objekte oder Dateien bei Bedarf (z. B. zum Senden über das Internet).

Unterstützung für Nummernverschlüsselung. Neben Texten und Binärdateien können numerische Werte verdaut und verschlüsselt werden (BigInteger und BigDecimal, andere numerische Typen werden beim Verschlüsseln für die Persistenz im Ruhezustand unterstützt). Mehr erfahren.

Völlig threadsicher.

Unterstützung für Encryptor / Digester-Pooling, um eine hohe Leistung in Multiprozessor- / Multi-Core-Systemen zu erzielen.

Enthält eine leichtgewichtige ("Lite") Version der Bibliothek für eine bessere Verwaltbarkeit in größenbeschränkenden Umgebungen wie mobilen Plattformen.

Bietet sowohl einfache Verschlüsselungstools ohne Konfiguration für Benutzer, die noch nicht mit Verschlüsselung vertraut sind, als auch hoch konfigurierbare Standardverschlüsselungstools für Hauptbenutzer.

Optionale Integration von Ruhezustand 3 und 4 für die verschlüsselte Beibehaltung von Feldern Ihrer zugeordneten Entitäten. Die Verschlüsselung von Feldern wird in den Zuordnungsdateien für den Ruhezustand definiert und bleibt für den Rest der Anwendung transparent (nützlich für vertrauliche personenbezogene Daten, Datenbanken mit vielen lesbaren Benutzern ...). Verschlüsseln Sie Texte, Binärdateien, Zahlen, Boolesche Werte, Datumsangaben ... Weitere Informationen.

Nahtlos in eine Spring-Anwendung integrierbar, mit spezifischen Integrationsfunktionen für Spring 2, Spring 3.0 und Spring 3.1. Alle Digester und Verschlüsseler in Jasypt sind so konzipiert, dass sie ab Spring problemlos verwendet werden können (instanziiert, abhängig injiziert ...). Und da sie threadsicher sind, können sie in einer Singleton-orientierten Umgebung wie Spring ohne Synchronisationsprobleme verwendet werden. Weitere Informationen: Frühling 2, Frühling 3.0, Frühling 3.1.

Optionale Integration von Spring Security (ehemals Acegi Security) zur Durchführung der Kennwortverschlüsselung und zum Abgleichen von Aufgaben für das Sicherheitsframework, Verbesserung der Sicherheit der Kennwörter Ihrer Benutzer durch Verwendung sicherer Kennwortverschlüsselungsmechanismen und Bereitstellung eines höheren Maßes an Konfiguration und Kontrolle. Mehr erfahren.

Bietet erweiterte Funktionen zum Verschlüsseln aller oder eines Teils der Konfigurationsdateien einer Anwendung, einschließlich vertraulicher Informationen wie Datenbankkennwörter. Integrieren Sie die verschlüsselte Konfiguration nahtlos in einfache, Spring-basierte und / oder Hibernate-fähige Anwendungen. Mehr erfahren.

Bietet benutzerfreundliche CLI-Tools (Command Line Interface), mit denen Entwickler ihre verschlüsselten Daten initialisieren und Verschlüsselungs- / Entschlüsselungs- / Digest-Vorgänge in Wartungsaufgaben oder Skripts einbeziehen können. Mehr erfahren.

Integriert in Apache Wicket für eine robustere Verschlüsselung von URLs in Ihren sicheren Anwendungen.

Umfassende Anleitungen und Javadoc-Dokumentation, damit Entwickler besser verstehen können, was sie wirklich mit ihren Daten tun.

Robuste Zeichensatzunterstützung, mit der Texte unabhängig vom ursprünglichen Zeichensatz angemessen verschlüsselt und verarbeitet werden können. Umfassende Unterstützung für Sprachen wie Japanisch, Koreanisch, Arabisch ... ohne Codierungs- oder Plattformprobleme.

Sehr hohe Konfigurationsmöglichkeiten: Der Entwickler kann Tricks implementieren, z. B. einen "Verschlüsseler" anweisen, beispielsweise einen Remote-HTTPS-Server nach dem Kennwort zu fragen, das für die Verschlüsselung verwendet werden soll. Damit können Sie Ihre Sicherheitsanforderungen erfüllen.

Kamil Nekanowicz
quelle
1
Aber welche Sicherheit bietet Jasypt? Ich kann es nicht von ihrer Website herausfinden. Ist es bei ausgewählten Klartextangriffen nicht zu unterscheiden? Integrität? Vertraulichkeit?
Trichner
4

Hier ist meine Implementierung von meta64.com als Spring Singleton. Wenn Sie für jeden Aufruf eine Ciper-Instanz erstellen möchten, die auch funktioniert, können Sie die synchronisierten Aufrufe entfernen. Beachten Sie jedoch, dass die Verschlüsselung nicht threadsicher ist.

import java.security.Key;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

@Component
@Scope("singleton")
public class Encryptor {

    @Value("${aeskey}")
    private String keyStr;

    private Key aesKey = null;
    private Cipher cipher = null;

    synchronized private void init() throws Exception {
        if (keyStr == null || keyStr.length() != 16) {
            throw new Exception("bad aes key configured");
        }
        if (aesKey == null) {
            aesKey = new SecretKeySpec(keyStr.getBytes(), "AES");
            cipher = Cipher.getInstance("AES");
        }
    }

    synchronized public String encrypt(String text) throws Exception {
        init();
        cipher.init(Cipher.ENCRYPT_MODE, aesKey);
        return toHexString(cipher.doFinal(text.getBytes()));
    }

    synchronized public String decrypt(String text) throws Exception {
        init();
        cipher.init(Cipher.DECRYPT_MODE, aesKey);
        return new String(cipher.doFinal(toByteArray(text)));
    }

    public static String toHexString(byte[] array) {
        return DatatypeConverter.printHexBinary(array);
    }

    public static byte[] toByteArray(String s) {
        return DatatypeConverter.parseHexBinary(s);
    }

    /*
     * DO NOT DELETE
     * 
     * Use this commented code if you don't like using DatatypeConverter dependency
     */
    // public static String toHexStringOld(byte[] bytes) {
    // StringBuilder sb = new StringBuilder();
    // for (byte b : bytes) {
    // sb.append(String.format("%02X", b));
    // }
    // return sb.toString();
    // }
    //
    // public static byte[] toByteArrayOld(String s) {
    // int len = s.length();
    // byte[] data = new byte[len / 2];
    // for (int i = 0; i < len; i += 2) {
    // data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) + Character.digit(s.charAt(i +
    // 1), 16));
    // }
    // return data;
    // }
}
mkobit
quelle
3
Dies wird mit dem EZB-Modus verschlüsselt, was schrecklich ist. Sie sollten mindestens den CBC-Modus oder den GCM-Modus
einstellen
Vielen Dank für den Vorschlag Konstantinto, ich habe das gegoogelt und einen Code gefunden, der "AES / CBC / PKCS5Padding" als Init-Zeichenfolge für Cipher verwendet, anstatt nur "AES", aber ich werde mich näher damit befassen. Oder wenn Sie möchten, können Sie das eigentliche Update bereitstellen, damit andere den besseren Weg sehen können. Abgesehen von den CBC-Details glaube ich jedoch, dass meine Lösung die einfachste und sicherste ist und es verdient, vor allem der anderen positiv bewertet zu werden.
Ja, keine Sorge, Crypto ist ein kompliziertes Thema. Leider ist jede Implementierung auf dieser Seite fehlerhaft und leider ist es die erste Seite, die angezeigt wird, wenn Sie mit Google nach "Java-Verschlüsselung" suchen. Wenn ich die Gelegenheit dazu bekomme, werde ich versuchen, alle zu reparieren.
Konstantino Sparakis
Mein Beispiel ist das gleiche wie folgt : docs.oracle.com/javase/8/docs/technotes/guides/security/crypto/… Außer ich brauchte Cipher.getInstance ("AES / ECB / PKCS5Padding"); Mein Code geht davon aus, dass es eine Eigenschaftendatei mit einem perfekt 16 Byte langen Verschlüsselungsschlüssel gibt, aber zum Verschlüsseln einer Zeichenfolge aus einem vom Benutzer angegebenen Kennwort zeigt die Oracle-Seite (oben verlinkt) auch, wie dies möglich ist.
1
Das Problem mit der EZB ist also, dass sie extrem anfällig für Frequenzanalysen ist. Es gibt das berühmte Beispiel des Linux-Pinguins, blog.filippo.io/the-ecb-penguin. Sehen Sie, wie Sie, obwohl das Bild verschlüsselt ist, immer noch erkennen können, dass es sich um einen Pinguin handelt. Ich ging voran und schrieb meine Gedanken zu diesem Thema unten :) stackoverflow.com/a/43779197/2607972
Konstantino Sparakis
4

Hier eine einfache Lösung mit nur java.*und javax.crypto.*Abhängigkeiten für die Verschlüsselung von Bytes, die Vertraulichkeit und Integrität bieten . Es ist bei einem ausgewählten Klartextangriff für Kurznachrichten in der Größenordnung von Kilobyte nicht zu unterscheiden.

Es wird AESim GCMModus ohne Auffüllen verwendet, ein 128-Bit-Schlüssel wird PBKDF2mit vielen Iterationen und einem statischen Salt aus dem angegebenen Passwort abgeleitet. Dies stellt sicher, dass das brutale Erzwingen von Passwörtern schwierig ist, und verteilt die Entropie auf den gesamten Schlüssel.

Ein zufälliger Initialisierungsvektor (IV) wird erzeugt und dem Chiffretext vorangestellt. Darüber hinaus wird dem statischen Byte 0x01das erste Byte als 'Version' vorangestellt.

Die gesamte Nachricht wird in den Nachrichtenauthentifizierungscode (MAC) eingegeben, der von generiert wird AES/GCM.

Hier geht es los, keine Verschlüsselungsklasse für externe Abhängigkeiten, die Vertraulichkeit und Integrität bietet :

package ch.n1b.tcrypt.utils;

import java.nio.charset.StandardCharsets;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;

import javax.crypto.*;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;

/**
 * This class implements AES-GCM symmetric key encryption with a PBKDF2 derived password.
 * It provides confidentiality and integrity of the plaintext.
 *
 * @author Thomas Richner
 * @created 2018-12-07
 */
public class AesGcmCryptor {

    // /crypto/26783/ciphertext-and-tag-size-and-iv-transmission-with-aes-in-gcm-mode
    private static final byte VERSION_BYTE = 0x01;
    private static final int VERSION_BYTE_LENGTH = 1;
    private static final int AES_KEY_BITS_LENGTH = 128;


    // fixed AES-GCM constants
    private static final String GCM_CRYPTO_NAME = "AES/GCM/NoPadding";
    private static final int GCM_IV_BYTES_LENGTH = 12;
    private static final int GCM_TAG_BYTES_LENGTH = 16;

    // can be tweaked, more iterations = more compute intensive to brute-force password
    private static final int PBKDF2_ITERATIONS = 1024;

    // protects against rainbow tables
    private static final byte[] PBKDF2_SALT = hexStringToByteArray("4d3fe0d71d2abd2828e7a3196ea450d4");

    public String encryptString(char[] password, String plaintext) throws CryptoException {

        byte[] encrypted = null;
        try {
            encrypted = encrypt(password, plaintext.getBytes(StandardCharsets.UTF_8));
        } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException //
                | InvalidAlgorithmParameterException | IllegalBlockSizeException | BadPaddingException //
                | InvalidKeySpecException e) {
            throw new CryptoException(e);
        }
        return byteArrayToHexString(encrypted);
    }

    public String decryptString(char[] password, String ciphertext)
            throws CryptoException {

        byte[] ct = hexStringToByteArray(ciphertext);
        byte[] plaintext = null;
        try {
            plaintext = decrypt(password, ct);
        } catch (AEADBadTagException e) {
            throw new CryptoException(e);
        } catch ( //
                NoSuchPaddingException | NoSuchAlgorithmException | InvalidKeySpecException //
                        | InvalidKeyException | InvalidAlgorithmParameterException | IllegalBlockSizeException //
                        | BadPaddingException e) {
            throw new CryptoException(e);
        }
        return new String(plaintext, StandardCharsets.UTF_8);
    }

    /**
     * Decrypts an AES-GCM encrypted ciphertext and is
     * the reverse operation of {@link AesGcmCryptor#encrypt(char[], byte[])}
     *
     * @param password   passphrase for decryption
     * @param ciphertext encrypted bytes
     * @return plaintext bytes
     * @throws NoSuchPaddingException
     * @throws NoSuchAlgorithmException
     * @throws NoSuchProviderException
     * @throws InvalidKeySpecException
     * @throws InvalidAlgorithmParameterException
     * @throws InvalidKeyException
     * @throws BadPaddingException
     * @throws IllegalBlockSizeException
     * @throws IllegalArgumentException           if the length or format of the ciphertext is bad
     * @throws CryptoException
     */
    public byte[] decrypt(char[] password, byte[] ciphertext)
            throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeySpecException,
            InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {

        // input validation
        if (ciphertext == null) {
            throw new IllegalArgumentException("ciphertext cannot be null");
        }

        if (ciphertext.length <= VERSION_BYTE_LENGTH + GCM_IV_BYTES_LENGTH + GCM_TAG_BYTES_LENGTH) {
            throw new IllegalArgumentException("ciphertext too short");
        }

        // the version must match, we don't decrypt other versions
        if (ciphertext[0] != VERSION_BYTE) {
            throw new IllegalArgumentException("wrong version: " + ciphertext[0]);
        }

        // input seems legit, lets decrypt and check integrity

        // derive key from password
        SecretKey key = deriveAesKey(password, PBKDF2_SALT, AES_KEY_BITS_LENGTH);

        // init cipher
        Cipher cipher = Cipher.getInstance(GCM_CRYPTO_NAME);
        GCMParameterSpec params = new GCMParameterSpec(GCM_TAG_BYTES_LENGTH * 8,
                ciphertext,
                VERSION_BYTE_LENGTH,
                GCM_IV_BYTES_LENGTH
        );
        cipher.init(Cipher.DECRYPT_MODE, key, params);

        final int ciphertextOffset = VERSION_BYTE_LENGTH + GCM_IV_BYTES_LENGTH;

        // add version and IV to MAC
        cipher.updateAAD(ciphertext, 0, ciphertextOffset);

        // decipher and check MAC
        return cipher.doFinal(ciphertext, ciphertextOffset, ciphertext.length - ciphertextOffset);
    }

    /**
     * Encrypts a plaintext with a password.
     * <p>
     * The encryption provides the following security properties:
     * Confidentiality + Integrity
     * <p>
     * This is achieved my using the AES-GCM AEAD blockmode with a randomized IV.
     * <p>
     * The tag is calculated over the version byte, the IV as well as the ciphertext.
     * <p>
     * Finally the encrypted bytes have the following structure:
     * <pre>
     *          +-------------------------------------------------------------------+
     *          |         |               |                             |           |
     *          | version | IV bytes      | ciphertext bytes            |    tag    |
     *          |         |               |                             |           |
     *          +-------------------------------------------------------------------+
     * Length:     1B        12B            len(plaintext) bytes            16B
     * </pre>
     * Note: There is no padding required for AES-GCM, but this also implies that
     * the exact plaintext length is revealed.
     *
     * @param password  password to use for encryption
     * @param plaintext plaintext to encrypt
     * @throws NoSuchAlgorithmException
     * @throws NoSuchProviderException
     * @throws NoSuchPaddingException
     * @throws InvalidAlgorithmParameterException
     * @throws InvalidKeyException
     * @throws BadPaddingException
     * @throws IllegalBlockSizeException
     * @throws InvalidKeySpecException
     */
    public byte[] encrypt(char[] password, byte[] plaintext)
            throws NoSuchAlgorithmException, NoSuchPaddingException,
            InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException,
            InvalidKeySpecException {

        // initialise random and generate IV (initialisation vector)
        SecretKey key = deriveAesKey(password, PBKDF2_SALT, AES_KEY_BITS_LENGTH);
        final byte[] iv = new byte[GCM_IV_BYTES_LENGTH];
        SecureRandom random = SecureRandom.getInstanceStrong();
        random.nextBytes(iv);

        // encrypt
        Cipher cipher = Cipher.getInstance(GCM_CRYPTO_NAME);
        GCMParameterSpec spec = new GCMParameterSpec(GCM_TAG_BYTES_LENGTH * 8, iv);
        cipher.init(Cipher.ENCRYPT_MODE, key, spec);

        // add IV to MAC
        final byte[] versionBytes = new byte[]{VERSION_BYTE};
        cipher.updateAAD(versionBytes);
        cipher.updateAAD(iv);

        // encrypt and MAC plaintext
        byte[] ciphertext = cipher.doFinal(plaintext);

        // prepend VERSION and IV to ciphertext
        byte[] encrypted = new byte[1 + GCM_IV_BYTES_LENGTH + ciphertext.length];
        int pos = 0;
        System.arraycopy(versionBytes, 0, encrypted, 0, VERSION_BYTE_LENGTH);
        pos += VERSION_BYTE_LENGTH;
        System.arraycopy(iv, 0, encrypted, pos, iv.length);
        pos += iv.length;
        System.arraycopy(ciphertext, 0, encrypted, pos, ciphertext.length);

        return encrypted;
    }

    /**
     * We derive a fixed length AES key with uniform entropy from a provided
     * passphrase. This is done with PBKDF2/HMAC256 with a fixed count
     * of iterations and a provided salt.
     *
     * @param password passphrase to derive key from
     * @param salt     salt for PBKDF2 if possible use a per-key salt, alternatively
     *                 a random constant salt is better than no salt.
     * @param keyLen   number of key bits to output
     * @return a SecretKey for AES derived from a passphrase
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeySpecException
     */
    private SecretKey deriveAesKey(char[] password, byte[] salt, int keyLen)
            throws NoSuchAlgorithmException, InvalidKeySpecException {

        if (password == null || salt == null || keyLen <= 0) {
            throw new IllegalArgumentException();
        }
        SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
        KeySpec spec = new PBEKeySpec(password, salt, PBKDF2_ITERATIONS, keyLen);
        SecretKey pbeKey = factory.generateSecret(spec);

        return new SecretKeySpec(pbeKey.getEncoded(), "AES");
    }

    /**
     * Helper to convert hex strings to bytes.
     * <p>
     * May be used to read bytes from constants.
     */
    private static byte[] hexStringToByteArray(String s) {

        if (s == null) {
            throw new IllegalArgumentException("Provided `null` string.");
        }

        int len = s.length();
        if (len % 2 != 0) {
            throw new IllegalArgumentException("Invalid length: " + len);
        }

        byte[] data = new byte[len / 2];
        for (int i = 0; i < len - 1; i += 2) {
            byte b = (byte) toHexDigit(s, i);
            b <<= 4;
            b |= toHexDigit(s, i + 1);
            data[i / 2] = b;
        }
        return data;
    }

    private static int toHexDigit(String s, int pos) {
        int d = Character.digit(s.charAt(pos), 16);
        if (d < 0) {
            throw new IllegalArgumentException("Cannot parse hex digit: " + s + " at " + pos);
        }
        return d;
    }

    private static String byteArrayToHexString(byte[] bytes) {
        StringBuilder sb = new StringBuilder();
        for (byte b : bytes) {
            sb.append(String.format("%02X", b));
        }
        return sb.toString();
    }

    public class CryptoException extends Exception {

        public CryptoException(Throwable cause) {
            super(cause);
        }
    }
}

Hier das gesamte Projekt mit einer schönen CLI: https://github.com/trichner/tcrypt

Edit: jetzt mit entsprechenden encryptStringunddecryptString

Trichner
quelle
Das ist unglaublich. Danke dir! Ich habe viel aus Ihrem Code gelernt und nach dem Erstellen der BadVersionException Exception-Klasse hat Ihr Code beim ersten Mal perfekt funktioniert. Ausgezeichnet!!
Morkus
Ich mag diesen Versuch. Das heißt ... Salz sollte zufällig sein, nicht statisch. Iterationen sollten wahrscheinlich auch nicht statisch sein. GCM bezieht die IV bereits in die Berechnung des Tags ein. Es enthält jedoch nicht die Versionsnummer. Sie sollten den Anbieter für die Portabilität nicht angeben. Der "SunJCE" -Anbieter ist der Standard auf den Plattformen, die ihn unterstützen. Dieser Code enthält keine Behandlung von Nachrichtenzeichenfolgen, die für diese spezielle Frage erforderlich ist .
Maarten Bodewes
Okay, ich habe es ein bisschen mehr aufgeräumt und das angeforderte encryptStringund decryptString:) hinzugefügt
Trichner
Das hat sehr gut funktioniert; ty für den Code. Es ist zu beachten, dass für diesen Code API 19 (Kit Kat) oder höher erforderlich ist, um ordnungsgemäß zu funktionieren.
PGMacDesign
3

Ich würde in Betracht ziehen, etwas wie https://www.bouncycastle.org/ zu verwenden. Es ist eine vorgefertigte Bibliothek, mit der Sie alles, was Sie möchten, mit einer Reihe verschiedener Chiffren verschlüsseln können. Ich verstehe, dass Sie nur vor Schnüffeln schützen möchten, aber wenn Sie es wirklich tun Wenn Sie die Informationen schützen möchten, werden Sie mit Base64 nicht wirklich geschützt.

hdost
quelle
1
Nur eine zufällige Kryptobibliothek mit Chiffren zu empfehlen, ist keine Antwort auf die Frage. Verwenden Sie außerdem die eingebauten Chiffren.
Maarten Bodewes
2

Hier sind einige Links, die Sie lesen können, was Java unterstützt

Verschlüsseln / Entschlüsseln eines Datenstroms.

Dieses Beispiel zeigt, wie eine große Datenmenge verschlüsselt wird (mithilfe eines symmetrischen Verschlüsselungsalgorithmus wie AES, Blowfish, RC2, 3DES usw.). Die Daten werden in Blöcken an eine der Verschlüsselungsmethoden übergeben: EncryptBytes, EncryptString, EncryptBytesENC oder EncryptStringENC. (Der Methodenname gibt den Typ der Eingabe (Zeichenfolge oder Byte-Array) und den Rückgabetyp (codierte Zeichenfolge oder Byte-Array) an. Die Eigenschaften FirstChunk und LastChunk geben an, ob ein Block der erste, mittlere oder letzte in einem Stream ist Standardmäßig sind sowohl FirstChunk als auch LastChunk gleich true - was bedeutet, dass die übergebenen Daten die gesamte Menge sind.

JCERefGuide

Beispiele für Java-Verschlüsselung

Markus Lausberg
quelle
Ja, es gibt Kryptografie, die von Java unterstützt wird. Die Verschlüsselung eines Streams ist auch nicht das, wonach gefragt wurde.
Maarten Bodewes
2

Wie viele der Jungs bereits gesagt haben, sollten Sie eine Standard-Chiffre verwenden, die häufig wie DES oder AES verwendet wird.

Ein einfaches Beispiel dafür, wie Sie eine Zeichenfolge in Java mit AES verschlüsseln und entschlüsseln können .

import org.apache.commons.codec.binary.Base64;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

public class EncryptorDemo {

    public static String encrypt(String key, String randomVector, String value) {
        try {
            IvParameterSpec iv = new IvParameterSpec(randomVector.getBytes("UTF-8"));
            SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
            cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
            byte[] encrypted = cipher.doFinal(value.getBytes());
            System.out.println("encrypted text: "  + Base64.encodeBase64String(encrypted));
            return Base64.encodeBase64String(encrypted);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static String decrypt(String key, String randomVector, String encrypted) {
        try {
            IvParameterSpec iv = new IvParameterSpec(randomVector.getBytes("UTF-8"));
            SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
            cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);
            byte[] originalText = cipher.doFinal(Base64.decodeBase64(encrypted));
            System.out.println("decrypted text: "  + new String(originalText));
            return new String(originalText);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static void main(String[] args) {
        String key = "JavasEncryptDemo"; // 128 bit key
        String randomVector = "RandomJavaVector"; // 16 bytes IV
        decrypt(key, randomVector, encrypt(key, randomVector, "Anything you want to encrypt!"));

    }
}
viveknaskar
quelle
CBC ist kein sicherer Modus mehr. Das Auffüllen ist anfällig für das Auffüllen von Oracle-Angriffen. Außerdem ist die Behandlung des Schlüssels und der Nachrichten in String nicht sicher. Sie werden im String-Pool verweilen und in einem Heap-Dump erscheinen
Saptarshi Basu
2
Schätzen Sie den Kommentar. Dies war ein einfaches Beispiel für die Verschlüsselungs- und Entschlüsselungsmethoden von Java, die der Benutzer fragte. Die Frage wurde vor 9 Jahren gestellt und darauf basierend beantwortet. Vielen Dank.
Viveknaskar
2
Ja, dies scheint eine einfache Möglichkeit zu sein, das Ver- und Entschlüsseln einzuführen. Hat wie ein Zauber für mich funktioniert ... Danke.
Codewrapper
0

Hier ist eine Lösung zum Kopieren / Einfügen. Ich empfehle auch, die Antwort von @ Konstantino zu lesen und dafür zu stimmen , obwohl sie keinen Code enthält. Der Initialisierungsvektor (IV) ist wie ein Salz - er muss nicht geheim gehalten werden. Ich bin neu in GCM und anscheinend ist AAD optional und wird nur unter bestimmten Umständen verwendet. Legen Sie den Schlüssel in der Umgebungsvariablen fest SECRET_KEY_BASE. Verwenden Sie so etwas wie KeePass , um ein 32-stelliges Passwort zu generieren. Diese Lösung ist meiner Ruby-Lösung nachempfunden.

    public static String encrypt(String s) {
        try {
            byte[] input = s.getBytes("UTF-8");
            String keyString = System.getProperty("SECRET_KEY_BASE", System.getenv("SECRET_KEY_BASE"));
            if (keyString == null || keyString.length() == 0) {
                Logger.error(Utils.class, "encrypt()", "$SECRET_KEY_BASE is not set.");
                return null;
            }
            byte[] keyBytes = keyString.getBytes("UTF-8");
            SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");
            // generate IV
            SecureRandom secureRandom = SecureRandom.getInstanceStrong();
            Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
            byte[] ivBytes = new byte[cipher.getBlockSize()];
            secureRandom.nextBytes(ivBytes);
            GCMParameterSpec gcmSpec = new GCMParameterSpec(96, ivBytes); // 96 bit tag length
            cipher.init(Cipher.ENCRYPT_MODE, keySpec, gcmSpec);
            // generate AAD
//          byte[] aadBytes = new byte[cipher.getBlockSize()];
//          secureRandom.nextBytes(aadBytes);
//          cipher.updateAAD(aadBytes);
            // encrypt
            byte[] encrypted = cipher.doFinal(input);
            byte[] returnBytes = new byte[ivBytes.length + encrypted.length];
//          byte[] returnBytes = new byte[ivBytes.length + aadBytes.length + encrypted.length];
            System.arraycopy(ivBytes, 0, returnBytes, 0, ivBytes.length);
//          System.arraycopy(aadBytes, 0, returnBytes, ivBytes.length, aadBytes.length);
            System.arraycopy(encrypted, 0, returnBytes, ivBytes.length, encrypted.length);
//          System.arraycopy(encrypted, 0, returnBytes, ivBytes.length+aadBytes.length, encrypted.length);
            String encryptedString = Base64.getEncoder().encodeToString(returnBytes);
            return encryptedString;
        } catch (UnsupportedEncodingException | NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | 
                InvalidAlgorithmParameterException | IllegalBlockSizeException | BadPaddingException e) {
            Logger.error(Utils.class, "encrypt()", "Could not encrypt string: " + e.getMessage());
            return null;
        }
    }

    public static String decrypt(String s) {
        if (s == null || s.length() == 0) return "";
        try {
            byte[] encrypted = Base64.getDecoder().decode(s);
            String keyString = System.getProperty("SECRET_KEY_BASE", System.getenv("SECRET_KEY_BASE"));
            if (keyString == null || keyString.length() == 0) {
                Logger.error(Utils.class, "encrypt()", "$SECRET_KEY_BASE is not set.");
                return null;
            }
            byte[] keyBytes = keyString.getBytes("UTF-8");
            SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");
            Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
            byte[] ivBytes = new byte[cipher.getBlockSize()];
            System.arraycopy(encrypted, 0, ivBytes, 0, ivBytes.length);
            GCMParameterSpec gcmSpec = new GCMParameterSpec(96, ivBytes);
            cipher.init(Cipher.DECRYPT_MODE, keySpec, gcmSpec);
//          cipher.updateAAD(encrypted, ivBytes.length, cipher.getBlockSize());
            byte[] decrypted = cipher.doFinal(encrypted, cipher.getBlockSize(), encrypted.length - cipher.getBlockSize());
//          byte[] decrypted = cipher.doFinal(encrypted, cipher.getBlockSize()*2, encrypted.length - cipher.getBlockSize()*2);
            String decryptedString = new String(decrypted, "UTF-8");
            return decryptedString;
        } catch (NoSuchAlgorithmException | NoSuchPaddingException | UnsupportedEncodingException | InvalidKeyException | 
                InvalidAlgorithmParameterException | IllegalBlockSizeException | BadPaddingException e) {
            Logger.error(Utils.class, "decrypt()", "Could not decrypt string: " + e.getMessage());
            return null;
        }
    }

Hier ist ein Beispiel:

    String s = "This is a test.";
    String enc = Utils.encrypt(s);
    System.out.println(enc);
    // fQHfYjbD+xAuN5XzH2ojk/EWNeKXUrKRSfx8LU+5dpuKkM/pueCMBjKCZw==
    String dec = Utils.decrypt(enc);
    System.out.println(dec);
    // This is a test.
Chloe
quelle
-4

Möglicherweise möchten Sie ein automatisiertes Tool für die Generierung des Verschlüsselungs- / Entschlüsselungscodes in Betracht ziehen, z. https://www.stringencrypt.com/java-encryption/

Es kann jedes Mal einen anderen Ver- und Entschlüsselungscode für die Zeichenfolgen- oder Dateiverschlüsselung generieren.

Es ist ziemlich praktisch, wenn es um die schnelle Verschlüsselung von Zeichenfolgen ohne Verwendung von RSA, AES usw. geht.

Beispielergebnisse:

// encrypted with https://www.stringencrypt.com (v1.1.0) [Java]
// szTest = "Encryption in Java!"
String szTest = "\u9E3F\uA60F\uAE07\uB61B\uBE1F\uC62B\uCE2D\uD611" +
                "\uDE03\uE5FF\uEEED\uF699\uFE3D\u071C\u0ED2\u1692" +
                "\u1E06\u26AE\u2EDC";

for (int iatwS = 0, qUJQG = 0; iatwS < 19; iatwS++)
{
        qUJQG = szTest.charAt(iatwS);
        qUJQG ++;
        qUJQG = ((qUJQG << 5) | ( (qUJQG & 0xFFFF) >> 11)) & 0xFFFF;
        qUJQG -= iatwS;
        qUJQG = (((qUJQG & 0xFFFF) >> 6) | (qUJQG << 10)) & 0xFFFF;
        qUJQG ^= iatwS;
        qUJQG -= iatwS;
        qUJQG = (((qUJQG & 0xFFFF) >> 3) | (qUJQG << 13)) & 0xFFFF;
        qUJQG ^= 0xFFFF;
        qUJQG ^= 0xB6EC;
        qUJQG = ((qUJQG << 8) | ( (qUJQG & 0xFFFF) >> 8)) & 0xFFFF;
        qUJQG --;
        qUJQG = (((qUJQG & 0xFFFF) >> 5) | (qUJQG << 11)) & 0xFFFF;
        qUJQG ++;
        qUJQG ^= 0xFFFF;
        qUJQG += iatwS;
        szTest = szTest.substring(0, iatwS) + (char)(qUJQG & 0xFFFF) + szTest.substring(iatwS + 1);
}

System.out.println(szTest);

Wir verwenden es ständig in unserem Unternehmen.

Bartosz Wójcik
quelle
Dies ist Sicherheit durch Dunkelheit und nicht wirklich sicher.
Chloe
Bei dieser Frage geht es um eine moderne Verschlüsselung mit kryptografischer Stärke wie AES, nicht nur um eine Verschleierung, um das statische Extrahieren von Zeichenfolgen zu erschweren. Dies scheint nicht einmal einen Zustand zwischen Zeichen beizubehalten, so dass es für Frequenzanalysen anfällig ist. (Einzelalphabet- Ersetzungsverschlüsselung , außer über UTF-16-Codepunkten anstelle des lateinischen Alphabets. Wenn Sie sie jedoch für englischen ASCII-Text verwenden, erhalten Sie nur wenige eindeutige 16-Bit-Zeichenwerte, es sei denn, ich verstehe dies falsch.)
Peter Cordes
-4
String s1="arshad"; 
char[] s2=s1.toCharArray(); 
int s3= s2.length; 

  System.out.println(s3);
 int i=0; 

// for(int j=0;j<s3;j++) 
// System.out.println(s2[j]); 

for(i=0;i<((s3)/2);i++) { 

char z,f=10; 
z=(char) (s2[i] * f); 
s2[i]=s2[(s3-1)-i]; 
s2[(s3-1)-i]=z; 

String b=new String(s2);

 print(b);  }
Arshad Shaik
quelle
Formal verschlüsselt es die Daten in ein unlesbares Format. Verwenden Sie zum Entschlüsseln denselben Code. Und ändere s [i] * f in s [I] / f.
Arshad Shaik
Dies ist Sicherheit durch Dunkelheit und nicht wirklich sicher.
Chloe
-5
public static String encryptParams(String myTextInput) {

        String myKey = "40674244454045cb9a70040a30e1c007";
        String myVector = "@1B2c3D4e5F6g7H8";

        String encData = "";

        try{
            JavaEncryprtionUtil encUtil = new JavaEncryprtionUtil();
            encData = Base64.encodeToString(encUtil.encrypt(myTextInput.getBytes("UTF-8"), myKey.getBytes("UTF-8"), myVector.getBytes("UTF-8")),Base64.DEFAULT);
            System.out.println(encData);
        }catch(NoSuchAlgorithmException ex){
            ex.printStackTrace();
        }catch(NoSuchPaddingException ex){
            ex.printStackTrace();
        }catch(InvalidKeyException ex){
            ex.printStackTrace();
        }catch(InvalidAlgorithmParameterException ex){
            ex.printStackTrace();
        }catch(IllegalBlockSizeException ex){
            ex.printStackTrace();
        }catch(BadPaddingException ex){
            ex.printStackTrace();
        }catch(UnsupportedEncodingException ex){
            ex.printStackTrace();
        }

        return encData;
    }
Rishikesh
quelle
1
Ist JavaEncryprtionUtil Teil der JDK-API? Wenn nicht, sollten Sie den Namen der Bibliothek buchstabieren.
Fermats kleiner Student
4
Kann diese Klasse nicht finden. Fühlt sich an, als wäre die Antwort erfunden.
James.garriss