Hoe tekenreeks in Java te versleutelen

Wat ik nodig heb, is een tekenreeks coderen die in 2D-barcode (PDF-417) wordt weergegeven, zodat wanneer iemand een idee krijgt om te scannen, niets leesbaar is.

Andere vereisten:

  • zou niet ingewikkeld moeten zijn
  • het mag niet bestaan ​​uit RSA, PKI-infrastructuur, sleutelparen, enz.

Het moet eenvoudig genoeg zijn om de rondsnuffelende mensen kwijt te raken, en gemakkelijk te decoderen voor andere bedrijven die geïnteresseerd zijn in het verkrijgen van die gegevens. Ze bellen ons, we vertellen ze de standaard of geven ze een eenvoudige sleutel die vervolgens kan worden gebruikt voor decodering.

Waarschijnlijk zouden die bedrijven verschillende technologieën kunnen gebruiken, dus het zou goed zijn om vast te houden aan een standaard die niet gebonden is aan een speciaal platform of een speciale technologie.

Wat stel je voor? Is er een Java-klasse die encrypt() & decrypt() zonder veel complicaties bij het bereiken van hoge beveiligingsstandaarden?


Antwoord 1, autoriteit 100%

Dit is de eerste pagina die verschijnt via Google en de beveiliging
kwetsbaarheden in alle implementaties doen me ineenkrimpen, dus ik ben
dit posten om informatie over codering voor anderen toe te voegen als het
is 7 jaar verwijderd van het oorspronkelijke bericht. Ik heb een Masters Degree in
Computer Engineering en besteedde veel tijd aan studeren en leren
Cryptografie dus ik gooi mijn twee cent om het internet een te maken
veiligere plek.

Houd er ook rekening mee dat veel implementatie voor een gegeven moment veilig kan zijn
situatie, maar waarom zou u die gebruiken en mogelijk per ongeluk een
fout? Gebruik de sterkste tools die je hebt, tenzij je een
specifieke reden om dat niet te doen. Over het algemeen raad ik het gebruik van een bibliotheek ten zeerste aan en
blijf weg van de nitty gritty details als je kunt.

UPDATE 4/5/18: ik heb sommige delen herschreven om ze eenvoudiger te begrijpen en de aanbevolen bibliotheek gewijzigd van Jasypt naar Google’s nieuwe bibliotheek Tink, ik raad aan om volledig te verwijderen Jasypt van een bestaande installatie.

Voorwoord

Ik zal hieronder de basisprincipes van veilige symmetrische cryptografie schetsen en wijzen op veelvoorkomende fouten die ik online zie wanneer mensen zelf crypto implementeren met de standaard Java-bibliotheek. Als je alle details wilt overslaan, ga dan naar Google’s nieuwe bibliotheek Tink importeer die in je project en gebruik de AES-GCM-modus voor al uw encrypties en u bent veilig.

Als je nu de fijne kneepjes van het versleutelen in Java wilt leren, lees dan verder 🙂

Blokcodes

Als eerste moet je een symmetrische sleutel Block Cipher kiezen. Een Block Cipher is een computerfunctie/-programma dat wordt gebruikt om Pseudo-Randomness te creëren. Pseudo-willekeurigheid is nep-willekeurigheid die geen andere computer dan een kwantumcomputer zou kunnen onderscheiden tussen deze en echte willekeur. De Block Cipher is als de bouwsteen voor cryptografie, en bij gebruik met verschillende modi of schema’s kunnen we versleutelingen maken.

Wat betreft Block Cipher-algoritmen die vandaag beschikbaar zijn, zorg ervoor dat u NOOIT, ik herhaal NOOIT DES, ik zou zelfs zeggen: gebruik NOOIT 3DES. De enige Block Cipher die zelfs de NSA-release van Snowden kon verifiëren dat deze echt zo dicht mogelijk bij Pseudo-Random ligt, is AES 256. Er bestaat ook AES 128; het verschil is dat AES 256 in 256-bits blokken werkt, terwijl AES 128 in 128 blokken werkt. Al met al wordt AES 128 als veilig beschouwd, hoewel er enkele zwakke punten zijn ontdekt, maar 256 is zo solide als maar kan.

Leuk weetje DES werd gebroken door de NSA toen het aanvankelijk werd opgericht en hield feitelijk een een paar jaar geheim. Hoewel sommige mensen nog steeds beweren dat 3DES veilig is, zijn er nogal wat onderzoekspapers die hebben gevonden en geanalyseerd zwakke punten in 3DES.

Versleutelingsmodi

Versleuteling wordt gemaakt wanneer u een blokcijfer gebruikt en een specifiek schema gebruikt, zodat de willekeur wordt gecombineerd met een sleutel om iets te creëren dat omkeerbaar is zolang u de sleutel kent. Dit wordt een versleutelingsmodus genoemd.

Hier is een voorbeeld van een coderingsmodus en de eenvoudigste modus die bekend staat als ECB, zodat u visueel kunt begrijpen wat er gebeurt:

ECB-modus

De coderingsmodi die u het meest online zult zien, zijn de volgende:

ECB CTR, CBC, GCM

Er bestaan ​​andere modi dan de genoemde en onderzoekers werken altijd aan nieuwe modi om bestaande problemen te verbeteren.

Laten we nu verder gaan met implementaties en wat veilig is. NOOIT gebruik ECB, dit is slecht in het verbergen van herhalende gegevens, zoals blijkt uit de beroemde Linux-pinguïn.Linux Penguin-voorbeeld

Houd er bij implementatie in Java rekening mee dat als u de volgende code gebruikt, de ECB-modus standaard is ingesteld:

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

… GEVAAR DIT IS EEN KWETSBAARHEID! en helaas wordt dit overal in StackOverflow en online gezien in tutorials en voorbeelden.

Nonces en IV’s

Als reactie op het gevonden probleem met de ECB-modus zijn er aankondigingen gemaakt, ook wel IV’s genoemd. Het idee is dat we een nieuwe willekeurige variabele genereren en deze aan elke codering koppelen, zodat wanneer je twee berichten codeert die hetzelfde zijn, ze er anders uitkomen. Het mooie hierachter is dat een IV of nonce algemeen bekend is. Dat betekent dat een aanvaller hier toegang toe kan hebben, maar zolang ze jouw sleutel niet hebben, kunnen ze niets met die kennis doen.

Veelvoorkomende problemen die ik zal zien, is dat mensen de IV als een statische waarde instellen als in dezelfde vaste waarde in hun code. en hier is de valkuil voor IV’s, op het moment dat je er een herhaalt, breng je de volledige beveiliging van je codering in gevaar.

Een willekeurige IV genereren

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

Opmerking: SHA1 is kapot, maar ik kon niet vinden hoe ik SHA256 op de juiste manier in deze use-case kan implementeren, dus als iemand hier een poging toe wil doen en een update wil uitvoeren, zou dat geweldig zijn! Ook SHA1-aanvallen zijn nog steeds onconventioneel, omdat het een paar jaar kan duren voordat een enorm cluster is gekraakt. Bekijk hier de details.

CTR-implementatie

Geen opvulling is vereist voor de CTR-modus.

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

CBC-implementatie

Als u ervoor kiest om de CBC-modus te implementeren, doet u dat als volgt met PKCS7Padding:

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

CBC- en CTR-kwetsbaarheid en waarom u GCM zou moeten gebruiken

Hoewel sommige andere modi, zoals CBC en CTR, veilig zijn, stuiten ze op het probleem waarbij een aanvaller de versleutelde gegevens kan omdraaien en de waarde ervan kan veranderen wanneer ze worden ontsleuteld. Dus laten we zeggen dat u een denkbeeldig bankbericht versleutelt “Verkoop 100”, uw versleutelde bericht ziet er zo uit “eu23ng”, de aanvaller verandert één bit in “eu53ng” en plotseling, wanneer uw bericht wordt gedecodeerd, wordt het weergegeven als “Verkoop 900”.

Om dit te voorkomen gebruikt het grootste deel van het internet GCM, en elke keer dat je HTTPS ziet, gebruiken ze waarschijnlijk GCM. GCM ondertekent het versleutelde bericht met een hash en controleert of het bericht niet is gewijzigd met deze handtekening.

Ik zou de implementatie van GCM vermijden vanwege de complexiteit ervan. Je kunt beter Googles nieuwe bibliotheek Tink gebruiken, want ook hier breng je, als je per ongeluk een infuus herhaalt, de sleutel in de behuizing met GCM, wat de ultieme beveiligingsfout is. Nieuwe onderzoekers werken aan IV-resistente coderingsmodi waarbij zelfs als je de IV herhaalt, de sleutel niet in gevaar is, maar dit moet nog mainstream worden.

Als je nu GCM wilt implementeren, is hier een link naar een mooie GCM-implementatie . Ik kan de beveiliging echter niet garanderen of deze correct wordt geïmplementeerd, maar het haalt de basis naar beneden. Merk ook op dat er bij GCM geen opvulling is.

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

Sleutels versus wachtwoorden

Een andere zeer belangrijke opmerking is dat als het om cryptografie gaat, een sleutel en een wachtwoord niet dezelfde dingen zijn. Een sleutel in cryptografie moet een bepaalde hoeveelheid entropie en willekeur hebben om als veilig te worden beschouwd. Daarom moet u ervoor zorgen dat u de juiste cryptografische bibliotheken gebruikt om de sleutel voor u te genereren.

Je hebt dus echt twee implementaties die je hier kunt doen, de eerste is om de code te gebruiken die te vinden is op deze StackOverflow-thread voor het genereren van willekeurige sleutels. Deze oplossing maakt gebruik van een veilige generator voor willekeurige getallen om een ​​geheel nieuwe sleutel te maken die u kunt gebruiken.

De andere, minder veilige optie is om gebruikersinvoer zoals een wachtwoord te gebruiken. Het probleem zoals we hebben besproken, is dat het wachtwoord niet genoeg entropie heeft, dus we zouden PBKDF2, een algoritme dat het wachtwoord neemt en het versterkt. Hier is een StackOverflow-implementatie die ik leuk vond. De Google Tink-bibliotheek heeft dit echter allemaal ingebouwd en u zou er uw voordeel mee moeten doen.

Android-ontwikkelaars

Een belangrijk punt om hier op te wijzen, is dat uw Android-code reverse-engineerbaar is en in de meeste gevallen de meeste Java-code ook. Dat betekent als u het wachtwoord in platte tekst opslaat in uw code. Een hacker kan het gemakkelijk terugvinden. Meestal wilt u voor dit type codering Asymmetrische cryptografie gebruiken, enzovoort. Dit valt buiten het bestek van dit bericht, dus ik zal er niet in duiken.

Een interessante lezing uit 2013: wijst erop dat 88% van de Crypto-implementaties in Android zijn onjuist uitgevoerd.

Laatste gedachten

Nogmaals zou ik willen voorstellen om de Java-bibliotheek voor crypto niet rechtstreeks te implementeren en Google Tink te gebruiken. zal u de hoofdpijn besparen omdat ze echt goed werk hebben geleverd door alle algoritmen correct te implementeren. En zelfs dan zorg je ervoor dat je de problemen controleert die naar voren zijn gebracht op de Tink github, kwetsbaarheden verschijnen hier en daar.

Als je vragen of feedback hebt, reageer dan gerust!
Beveiliging verandert altijd en je moet je best doen om het bij te houden 🙂


Antwoord 2, autoriteit 59%

Ik raad aan om een ​​standaard symmetrische codering te gebruiken die algemeen beschikbaar is, zoals DES, 3DES of AES. Hoewel dat niet het veiligste algoritme is, zijn er heel veel implementaties en je hoeft alleen maar de sleutel te geven aan iedereen die de informatie in de streepjescode zou moeten ontsleutelen. javax.crypto.Cipher is wat je zoekt om hier mee te werken.

Laten we aannemen dat de te versleutelen bytes binnen zijn

byte[] input;

Vervolgens heb je de sleutel en initialisatievector bytes

byte[] keyBytes;
byte[] ivBytes;

Nu kunt u de code initialiseren voor het algoritme dat u selecteert:

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

Encryptie gaat als volgt:

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

En decodering als volgt:

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

Antwoord 3, autoriteit 13%

Waarschuwing

Gebruik dit niet als een soort beveiligingsmeting.

Het coderingsmechanisme in dit bericht is een eenmalige pad, wat betekent dat de geheime sleutel gemakkelijk kan worden hersteld door een aanvaller met behulp van 2 gecodeerde berichten. XOR 2 versleutelde berichten en je krijgt de sleutel. Zo simpel!

Aangewezen door Moussa


Ik gebruik Sun’s Base64Encoder/Decoder die te vinden is in Sun’s JRE, om weer een nieuwe JAR in lib te vermijden. Dat is gevaarlijk als je OpenJDK of de JRE van iemand anders gebruikt. Is er daarnaast nog een reden waarom ik zou moeten overwegen om Apache commons lib te gebruiken met Encoder/Decoder?

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

Antwoord 4, autoriteit 7%

bedankt, ik heb deze les gemaakt met je code, misschien vindt iemand het nuttig

object 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();
}
}

Antwoord 5, autoriteit 5%

Update op 12-DEC-2019

In tegenstelling tot sommige andere modi, zoals CBC, vereist de GCM-modus niet dat de IV onvoorspelbaar is. De enige vereiste is dat de IV uniek moet zijn voor elke aanroep met een bepaalde sleutel. Als het één keer wordt herhaald voor een bepaalde sleutel, kan de beveiliging in gevaar komen. Een gemakkelijke manier om dit te bereiken is door een willekeurige IV te gebruiken van een sterke pseudo-willekeurige nummergenerator, zoals hieronder weergegeven.

Het is ook mogelijk om een ​​reeks of tijdstempel als IV te gebruiken, maar het is misschien niet zo triviaal als het klinkt. Als het systeem bijvoorbeeld de sequenties die al als IV in een persistente winkel zijn gebruikt niet correct bijhoudt, kan een aanroep een IV herhalen nadat het systeem opnieuw is opgestart. Evenzo is er geen perfecte klok. Computerklok stelt opnieuw in enz.

Bovendien moet de sleutel na elke 2^32 aanroepen worden gedraaid. Raadpleeg voor meer informatie over de IV-vereiste dit antwoord en de NIST-aanbevelingen.


Dit is de codering & decoderingscode die ik zojuist in Java 8 heb geschreven, rekening houdend met de volgende punten. Ik hoop dat iemand dit nuttig zou vinden:

  1. Encryptie-algoritme: blokcodering AES met een 256-bits sleutel wordt als voldoende veilig beschouwd. Om een ​​volledig bericht te versleutelen, moet een modus worden geselecteerd. Geauthenticeerde codering (die zowel vertrouwelijkheid als integriteit biedt) wordt aanbevolen. GCM, CCM en EAX zijn de meest gebruikte geauthenticeerde coderingsmodi. GCM heeft meestal de voorkeur en presteert goed in Intel-architecturen die speciale instructies voor GCM bieden. Al deze drie modi zijn op CTR gebaseerde (tellergebaseerde) modi en hebben daarom geen opvulling nodig. Als gevolg hiervan zijn ze niet kwetsbaar voor opvulling gerelateerde aanvallen

  2. Een initialisatievector (IV) is vereist voor GCM. De IV is geen geheim. De enige vereiste is dat het willekeurig of onvoorspelbaar moet zijn. In Java is de klasse SecuredRandom bedoeld om cryptografisch sterke pseudo-willekeurige getallen te produceren. Het pseudo-willekeurige algoritme voor het genereren van getallen kan worden gespecificeerd in de methode getInstance(). Sinds Java 8 is de aanbevolen manier echter om de methode getInstanceStrong() te gebruiken die het sterkste algoritme gebruikt dat is geconfigureerd en geleverd door de Provider

  3. NIST raadt 96-bits IV aan voor GCM om interoperabiliteit, efficiëntie en eenvoud van ontwerp te bevorderen

  4. Om extra veiligheid te garanderen, wordt in de volgende implementatie SecureRandom opnieuw gezaaid na het produceren van elke 2^16 bytes pseudo-willekeurige bytegeneratie

  5. De ontvanger moet het infuus kennen om de versleutelde tekst te kunnen ontcijferen. Daarom moet de IV samen met de cijfertekst worden overgedragen. Sommige implementaties verzenden de IV als AD (Associated Data), wat betekent dat de authenticatietag wordt berekend op zowel de cijfertekst als de IV. Dat is echter niet vereist. De IV kan eenvoudig worden voorafgegaan door de cijfertekst, want als de IV tijdens de verzending wordt gewijzigd vanwege een opzettelijke aanval of een netwerk-/bestandssysteemfout, zal de validatie van de authenticatietag sowieso mislukken.

  6. Strings mogen niet worden gebruikt om het duidelijke tekstbericht of de sleutel vast te houden, aangezien Strings onveranderlijk zijn en we ze dus niet kunnen wissen na gebruik. Deze niet-afgehandelde Strings blijven dan in het geheugen hangen en kunnen in een heapdump verschijnen. Om dezelfde reden moet de client die deze coderings- of decoderingsmethoden aanroept, alle variabelen of arrays wissen die het bericht of de sleutel bevatten nadat ze niet langer nodig zijn.

  7. Geen enkele provider is hard gecodeerd in de code volgens de algemene aanbevelingen

  8. Ten slotte moet voor verzending via netwerk of opslag de sleutel of de cijfertekst worden gecodeerd met Base64-codering. De details van Base64 zijn hier te vinden. De Java 8-aanpak moet worden gevolgd

Byte-arrays kunnen worden gewist met:

Arrays.fill(clearTextMessageByteArray, Byte.MIN_VALUE);

Vanaf Java 8 is er echter geen gemakkelijke manier om SecretKeySpec en SecretKey te wissen, aangezien de implementaties van deze twee interfaces de methode destroy() van de interface Destroyable. In de volgende code is een aparte methode geschreven om de SecretKeySpec en SecretKey te wissen met reflectie.

De sleutel moet worden gegenereerd met een van de twee onderstaande benaderingen.

Houd er rekening mee dat sleutels net als wachtwoorden geheimen zijn, maar in tegenstelling tot wachtwoorden die bedoeld zijn voor menselijk gebruik, zijn sleutels bedoeld om te worden gebruikt door cryptografische algoritmen en mogen ze daarom alleen op de bovenstaande manier worden gegenereerd.

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

De coderingssleutel kan voornamelijk op twee manieren worden gegenereerd:

  • Zonder wachtwoord

    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);
    
  • Met wachtwoord

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

Bijwerken op basis van opmerkingen

Zoals aangegeven door @MaartenBodewes, bevatte mijn antwoord geen enkele String zoals vereist door de vraag. Daarom zal ik een poging doen om die leemte op te vullen voor het geval iemand dit antwoord tegenkomt en zich afvraagt ​​over het omgaan met String.

Zoals eerder in het antwoord aangegeven, is het omgaan met gevoelige informatie in een String over het algemeen geen goed idee, omdat String onveranderlijk is en we deze dus niet kunnen wissen na gebruik. En zoals we weten, zelfs als een String geen sterke referentie heeft, haast de vuilnisman zich niet meteen om hem van de berg af te halen. De String blijft dus gedurende een onbekende tijdsperiode in het geheugen aanwezig, ook al is deze niet toegankelijk voor het programma. Het probleem daarmee is dat een heap dump gedurende die periode de gevoelige informatie zou onthullen. Daarom is het altijd beter om alle gevoelige informatie in een byte-array of char-array te verwerken en de array vervolgens met nullen te vullen zodra hun doel is bereikt.

Als we echter met al die kennis nog steeds in een situatie terechtkomen waarin de gevoelige informatie die moet worden versleuteld zich in een String bevindt, moeten we deze eerst converteren naar een bytearray en de De functies encrypt en decrypt die hierboven zijn geïntroduceerd. (De andere invoersleutel kan worden gegenereerd met behulp van het bovenstaande codefragment).

Een String kan op de volgende manier in bytes worden omgezet:

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

Vanaf Java 8 wordt String intern in heap opgeslagen met UTF-16-codering. We hebben hier echter UTF-8 gebruikt omdat het meestal minder ruimte in beslag neemt dan UTF-16, vooral voor ASCII-tekens.

Evenzo kan de gecodeerde byte-array ook worden omgezet in een String, zoals hieronder:

String encryptedString = new String(encryptedBytes, StandardCharsets.UTF_8);

Antwoord 6, autoriteit 5%

Je kunt Jasypt

gebruiken

Met Jasypt kan het coderen en controleren van een wachtwoord zo simpel zijn als…

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

Encryptie:

String myEncryptedText = textEncryptor.encrypt(myText);

Decodering:

String plainText = textEncryptor.decrypt(myEncryptedText);

Gradel:

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

Kenmerken:

Jasypt biedt u eenvoudige unidirectionele (digest) en bidirectionele versleutelingstechnieken.

Open API voor gebruik met elke JCE-provider, en niet alleen met de standaard Java VM-provider. Jasypt kan eenvoudig worden gebruikt bij bekende providers zoals Springkasteel. Meer informatie.

Hogere beveiliging voor de wachtwoorden van uw gebruikers. Meer informatie.

Ondersteuning voor binaire codering. Jasypt staat de vertering en codering van binaire bestanden (byte-arrays) toe. Versleutel uw objecten of bestanden indien nodig (om bijvoorbeeld over het net te worden verzonden).

Ondersteuning voor nummerversleuteling. Naast teksten en binaire bestanden, maakt het de samenvatting en codering van numerieke waarden mogelijk (BigInteger en BigDecimal, andere numerieke typen worden ondersteund bij codering voor de persistentie van de slaapstand). Meer informatie.

Volledig draadveilig.

Ondersteuning voor encryptor/digester pooling, om hoge prestaties te bereiken in multi-processor/multi-core systemen.

Bevat een lichtgewicht (“lite”) versie van de bibliotheek voor beter beheer in omgevingen met beperkte afmetingen, zoals mobiele platforms.

Biedt zowel eenvoudige, niet-configuratie-encryptietools voor gebruikers die nieuw zijn met encryptie, als ook zeer configureerbare standaardencryptietools voor power-users.

Hibernate 3 en 4 optionele integratie voor persistente velden van uw toegewezen entiteiten op een versleutelde manier. Versleuteling van velden wordt gedefinieerd in de Hibernate-toewijzingsbestanden en blijft transparant voor de rest van de toepassing (handig voor gevoelige persoonlijke gegevens, databases met veel lees-enabled gebruikers…). Versleutel teksten, binaire bestanden, getallen, booleans, datums… Meer informatie.

Naadloos integreerbaar in een Spring-toepassing, met specifieke integratiefuncties voor Spring 2, Spring 3.0 en Spring 3.1. Alle vergisters en versleutelaars in jasypt zijn ontworpen om vanaf Spring gemakkelijk te kunnen worden gebruikt (geïnstantieerd, geïnjecteerd met afhankelijkheid…). En omdat ze thread-safe zijn, kunnen ze worden gebruikt zonder zorgen over synchronisatie in een singleton-georiënteerde omgeving zoals Spring. Meer informatie: lente 2, lente 3.0, lente 3.1.

Spring Security (voorheen Acegi Security) optionele integratie voor het uitvoeren van wachtwoordversleuteling en het afstemmen van taken voor het beveiligingsframework, het verbeteren van de beveiliging van de wachtwoorden van uw gebruikers door veiligere wachtwoordversleutelingsmechanismen te gebruiken en u een hogere mate van configuratie en controle te bieden. Meer informatie.

Biedt geavanceerde functionaliteit voor het versleutelen van alle of een deel van de configuratiebestanden van een toepassing, inclusief gevoelige informatie zoals databasewachtwoorden. Integreer naadloos versleutelde configuratie in gewone, op Spring gebaseerde en/of Hibernate-toepassingen. Meer informatie.

Biedt gebruiksvriendelijke CLI-tools (Command Line Interface) waarmee ontwikkelaars hun versleutelde gegevens kunnen initialiseren en encryptie/decryptie/digest-bewerkingen kunnen opnemen in onderhoudstaken of scripts. Meer informatie.

Integreer in Apache Wicket, voor robuustere versleuteling van URL’s in uw beveiligde applicaties.

Uitgebreide handleidingen en javadoc-documentatie, zodat ontwikkelaars beter begrijpen wat ze werkelijk met hun gegevens doen.

Robuuste tekenset-ondersteuning, ontworpen om teksten adequaat te versleutelen en te verwerken, ongeacht de originele tekenset. Volledige ondersteuning voor talen zoals Japans, Koreaans, Arabisch… zonder codering of platformproblemen.

Zeer hoog niveau van configuratiemogelijkheden: de ontwikkelaar kan trucs implementeren, zoals het instrueren van een “encryptor” om bijvoorbeeld een externe HTTPS-server om het wachtwoord te vragen dat voor de codering moet worden gebruikt. Hiermee kunt u aan uw beveiligingsbehoeften voldoen.


Antwoord 7, autoriteit 3%

Wat dacht je hiervan:

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

Werkt prima voor mij en is vrij compact.


Antwoord 8, autoriteit 3%

Hier een eenvoudige oplossing met alleen java.* en javax.crypto.* afhankelijkheden voor encryptie van bytes die vertrouwelijkheid en bieden integriteit. Het zal niet te onderscheiden zijn onder een gekozen leesbare tekstaanval voor korte berichten in de orde van kilobytes.

Het gebruikt AES in de GCM-modus zonder opvulling, een 128-bits sleutel wordt afgeleid door PBKDF2 met veel iteraties en een statisch zout van het opgegeven wachtwoord. Dit zorgt ervoor dat brute force-wachtwoorden moeilijk zijn en verdeelt de entropie over de hele sleutel.

Er wordt een willekeurige initialisatievector (IV) gegenereerd die aan de cijfertekst wordt toegevoegd. Verder wordt de statische byte 0x01 toegevoegd als de eerste byte als ‘versie’.

Het hele bericht gaat naar de berichtverificatiecode (MAC) die wordt gegenereerd door AES/GCM.

Hier komt het, nul externe afhankelijkheden versleutelingsklasse die vertrouwelijkheid en integriteit biedt:

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 {
    // https://crypto.stackexchange.com/questions/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 het hele project met een mooie CLI: https://github.com/trichner/tcrypt

Bewerken: nu met de juiste encryptString en decryptString


Antwoord 9, autoriteit 2%

Hier is mijn implementatie van meta64.com als Spring Singleton. Als je een cipher-instantie wilt maken voor elke aanroep die ook zou werken, en dan zou je de ‘gesynchroniseerde’ aanroepen kunnen verwijderen, maar pas op dat ‘cipher’ niet thread-safe is.

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

Antwoord 10, autoriteit 2%

Ik zou overwegen iets te gebruiken als https://www.bouncycastle.org/ Het is een vooraf gebouwde bibliotheek waarmee u kunt coderen wat u maar wilt met een aantal verschillende cijfers
Ik begrijp dat je je alleen wilt beschermen tegen snuffelen, maar als je de informatie echt wilt beschermen, zal het gebruik van Base64 je niet echt beschermen.


Antwoord 11, autoriteit 2%

Zoals veel van de jongens al hebben verteld, moet je een standaardcodering gebruiken die overdreven wordt gebruikt, zoals DES of AES.

Een eenvoudig voorbeeld van hoe u een string in Java kunt versleutelen en ontsleutelen met behulp van AES.

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

Antwoord 12

Hier zijn enkele links die u kunt lezen over wat Java ondersteunt

Een gegevensstroom versleutelen/ontsleutelen.

Dit voorbeeld laat zien hoe u:
versleutelen (met behulp van een symmetrische versleuteling)
algoritme zoals AES, Blowfish, RC2,
3DES, enz.) een grote hoeveelheid gegevens. De
gegevens worden in brokken doorgegeven aan een van de
versleutel methoden: EncryptBytes,
EncryptString, EncryptBytesENC, of
EncryptStringENC. (De naam van de methode
geeft het type invoer aan (string of
byte-array) en het retourtype
(gecodeerde string of byte-array). De
Eigenschappen FirstChunk en LastChunk
worden gebruikt om aan te geven of een chunk
is de eerste, middelste of laatste in a
stream te versleutelen. Standaard,
zowel FirstChunk als LastChunk zijn gelijk
waar — wat betekent dat de gegevens zijn doorgegeven
is het volledige bedrag.

JCERefGuide

Voorbeelden van Java-codering


Antwoord 13

Hier is een oplossing voor kopiëren/plakken. Ik raad ook aan om @Konstantino’s antwoord te lezen en te stemmen, ook al bevat het geen code. De initialisatievector (IV) is als een zout – het hoeft niet geheim te worden gehouden. Ik ben nieuw bij GCM en blijkbaar is AAD optioneel en wordt het alleen in bepaalde omstandigheden gebruikt. Stel de sleutel in de omgevingsvariabele SECRET_KEY_BASE in. Gebruik iets als KeePass om een ​​wachtwoord van 32 tekens te genereren. Deze oplossing is gemodelleerd naar mijn Ruby-oplossing.

    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 is een voorbeeld:

    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.

Antwoord 14

Misschien wilt u een geautomatiseerd hulpmiddel overwegen om de codering / decoderingscode te genereren, bijv. https://www.stringencrypt.com/java-encryption/

Het kan elke keer een andere coderings- en decoderingscode genereren voor de tekenreeks of bestandscodering.

Het is best handig als het gaat om snelle string-encryptie zonder gebruik te maken van RSA, AES enz.

Voorbeeldresultaten:

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

We gebruiken het de hele tijd in ons bedrijf.


Antwoord 15

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

Antwoord 16

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

LEAVE A REPLY

Please enter your comment!
Please enter your name here

4 × one =

Other episodes