Cara mengenkripsi String di Java

150

Yang saya butuhkan adalah mengenkripsi string yang akan ditampilkan dalam barcode 2D (PDF-417) sehingga ketika seseorang mendapatkan ide untuk memindai, tidak akan ada yang bisa dibaca.

Persyaratan lainnya:

  • seharusnya tidak rumit
  • tidak boleh terdiri dari RSA, infrastruktur PKI, pasangan kunci, dll.

Itu harus cukup sederhana untuk menyingkirkan orang yang mengintip, dan mudah didekripsi untuk perusahaan lain yang tertarik untuk mendapatkan data itu. Mereka memanggil kami, kami memberi tahu mereka standar atau memberi mereka beberapa kunci sederhana yang kemudian dapat digunakan untuk dekripsi.

Mungkin perusahaan-perusahaan itu dapat menggunakan teknologi yang berbeda sehingga akan baik untuk tetap berpegang pada standar yang tidak terikat pada platform atau teknologi khusus.

Apa yang Anda sarankan? Apakah ada kelas Java yang melakukan encrypt()& decrypt()tanpa banyak kesulitan dalam mencapai standar keamanan yang tinggi?

ante.sabo
sumber
Peringatan . Banyak jawaban di bawah ini menunjukkan satu metode atau yang lain untuk melakukan segala jenis kriptografi di Jawa. Jawaban mungkin tidak mencerminkan praktik kriptografi yang baik dan mungkin tidak ditinjau dengan baik; tidak ada yang namanya keamanan copy / paste . Jawaban setidaknya harus mempertimbangkan konversi string. Pertanyaan aktual dengan barcode 2D termasuk terlalu luas, dan harus memerlukan solusi khusus pelanggan.
Maarten Bodewes

Jawaban:

156

Ini adalah halaman pertama yang muncul melalui Google dan kerentanan keamanan di semua implementasi membuat saya merasa ngeri, jadi saya memposting ini untuk menambahkan informasi mengenai enkripsi untuk orang lain karena sudah 7 tahun dari posting asli. Saya memegang gelar Magister Teknik Komputer dan menghabiskan banyak waktu belajar dan belajar Kriptografi jadi saya melempar dua sen untuk menjadikan internet tempat yang lebih aman.

Juga, perlu dicatat bahwa banyak implementasi mungkin aman untuk situasi tertentu, tetapi mengapa menggunakan itu dan berpotensi membuat kesalahan? Gunakan alat terkuat yang Anda miliki kecuali Anda memiliki alasan khusus untuk tidak melakukannya. Secara keseluruhan saya sangat menyarankan menggunakan perpustakaan dan tinggal jauh dari rincian seluk beluk jika Anda bisa.

UPDATE 4/5/18: Saya menulis ulang beberapa bagian untuk membuatnya lebih mudah dimengerti dan mengubah perpustakaan yang direkomendasikan dari Jasypt ke perpustakaan baru Google Tink , saya akan merekomendasikan sepenuhnya menghapus Jasypt dari pengaturan yang ada.

Kata pengantar

Saya akan menguraikan dasar-dasar kriptografi simetris aman di bawah ini dan menunjukkan kesalahan umum yang saya lihat online ketika orang mengimplementasikan kripto sendiri dengan perpustakaan Java standar. Jika Anda ingin melewatkan semua detail yang berlarian ke perpustakaan baru Google, impor Tink itu ke proyek Anda dan gunakan mode AES-GCM untuk semua enkripsi Anda dan Anda akan aman.

Sekarang jika Anda ingin mempelajari rincian seluk beluk tentang cara mengenkripsi di java baca terus :)

Blokir Cipher

Hal pertama yang pertama Anda perlu memilih kunci simetris Block Cipher. Block Cipher adalah fungsi / program komputer yang digunakan untuk membuat Pseudo-Randomness. Pseudo-Randomness adalah keacakan palsu yang tidak ada komputer selain dari Komputer Quantum yang dapat membedakan antara itu dan keacakan nyata. Block Cipher adalah seperti blok penyusun untuk kriptografi, dan ketika digunakan dengan mode atau skema berbeda kita dapat membuat enkripsi.

Sekarang mengenai Block Cipher Algorithms yang tersedia hari ini, Pastikan untuk TIDAK PERNAH , saya ulangi TIDAK PERNAH menggunakan DES , saya bahkan akan mengatakan TIDAK PERNAH menggunakan 3DES . Satu-satunya Block Cipher yang bahkan rilis NSA Snowden mampu memverifikasi benar-benar sedekat mungkin dengan Pseudo-Random adalah AES 256 . Ada juga AES 128; perbedaannya adalah AES 256 bekerja di blok 256-bit, sedangkan AES 128 bekerja di 128 blok. Secara keseluruhan, AES 128 dianggap aman meskipun beberapa kelemahan telah ditemukan, tetapi 256 sekuat yang didapat.

Fakta asyiknya DES dihancurkan oleh NSA ketika awalnya didirikan dan benar-benar dirahasiakan selama beberapa tahun. Meskipun beberapa orang masih mengklaim 3DES aman, ada beberapa makalah penelitian yang telah menemukan dan menganalisis kelemahan dalam 3DES .

Mode Enkripsi

Enkripsi dibuat ketika Anda mengambil cipher blok dan menggunakan skema tertentu sehingga keacakan dikombinasikan dengan kunci untuk menciptakan sesuatu yang dapat dibalik selama Anda tahu kuncinya. Ini disebut sebagai Mode Enkripsi.

Berikut adalah contoh mode enkripsi dan mode paling sederhana yang dikenal sebagai ECB supaya Anda dapat memahami apa yang sedang terjadi secara visual:

Mode ECB

Mode enkripsi yang paling sering Anda lihat online adalah sebagai berikut:

RKPT ECB, CBC, GCM

Ada mode lain di luar yang terdaftar dan peneliti selalu bekerja menuju mode baru untuk memperbaiki masalah yang ada.

Sekarang mari kita beralih ke implementasi dan apa yang aman. JANGAN PERNAH menggunakan ECB ini buruk menyembunyikan data berulang seperti yang ditunjukkan oleh penguin Linux yang terkenal .Contoh Penguin Linux

Saat menerapkan di Java, perhatikan bahwa jika Anda menggunakan kode berikut, mode ECB diatur secara default:

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

... BAHAYA INI ADALAH KERENTANAN! dan sayangnya, ini terlihat di seluruh StackOverflow dan online dalam tutorial dan contoh.

Nonces dan infus

Menanggapi masalah yang ditemukan dengan mode ECB, kata benda juga dikenal sebagai infus dibuat. Idenya adalah bahwa kita menghasilkan variabel acak baru dan melampirkannya ke setiap enkripsi sehingga ketika Anda mengenkripsi dua pesan yang sama mereka keluar berbeda. Keindahan di balik ini adalah infus atau nonce adalah pengetahuan publik. Itu berarti penyerang dapat memiliki akses ke ini tetapi selama mereka tidak memiliki kunci Anda, mereka tidak dapat melakukan apa pun dengan pengetahuan itu.

Masalah umum yang akan saya lihat adalah bahwa orang akan menetapkan IV sebagai nilai statis seperti dalam nilai tetap yang sama dalam kode mereka. dan di sini adalah jebakan ke infus saat Anda mengulanginya Anda benar-benar kompromi seluruh keamanan enkripsi Anda.

Menghasilkan A Random IV

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

Catatan: SHA1 rusak tetapi saya tidak bisa menemukan cara menerapkan SHA256 ke dalam use case ini dengan benar, jadi jika ada yang ingin mengambil celah ini dan memperbaruinya akan luar biasa! Juga serangan SHA1 masih tidak konvensional karena bisa memakan waktu beberapa tahun pada sekelompok besar untuk memecahkan. Lihat detailnya di sini.

Implementasi RKPT

Padding tidak diperlukan untuk mode CTR.

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

Implementasi KBK

Jika Anda memilih untuk menerapkan Mode CBC melakukannya dengan PKCS7Padding sebagai berikut:

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

Kerentanan CBC dan CTR dan Mengapa Anda Harus Menggunakan GCM

Meskipun beberapa mode lain seperti CBC dan CTR aman, mereka mengalami masalah di mana penyerang dapat membalik data yang dienkripsi, mengubah nilainya ketika didekripsi. Jadi katakanlah Anda mengenkripsi pesan bank imajiner "Jual 100", pesan terenkripsi Anda terlihat seperti ini "eu23ng" penyerang berubah sedikit menjadi "eu53ng" dan tiba-tiba ketika mendekripsi pesan Anda, itu berbunyi "Jual 900".

Untuk menghindari hal ini, sebagian besar internet menggunakan GCM, dan setiap kali Anda melihat HTTPS, mereka mungkin menggunakan GCM. GCM menandatangani pesan terenkripsi dengan hash dan memeriksa untuk memverifikasi bahwa pesan belum diubah menggunakan tanda tangan ini.

Saya akan menghindari penerapan GCM karena kerumitannya. Anda lebih baik menggunakan perpustakaan baru Googles Tink karena di sini lagi jika Anda secara tidak sengaja mengulangi IV Anda kompromi kunci dalam kasus dengan GCM, yang merupakan kelemahan keamanan utama. Peneliti baru sedang bekerja menuju mode enkripsi tahan berulang IV di mana bahkan jika Anda mengulangi IV kuncinya tidak dalam bahaya tetapi ini belum datang arus utama.

Sekarang jika Anda ingin mengimplementasikan GCM, berikut adalah tautan ke implementasi GCM yang bagus . Namun, saya tidak dapat memastikan keamanan atau jika itu diterapkan dengan benar tetapi mendapat dasar. Perhatikan juga dengan GCM tidak ada padding.

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

Kunci vs. Kata Sandi

Catatan lain yang sangat penting, adalah kriptografi Kunci dan Kata Sandi bukanlah hal yang sama. Kunci dalam kriptografi perlu memiliki sejumlah entropi dan keacakan agar dianggap aman. Inilah sebabnya mengapa Anda perlu memastikan untuk menggunakan perpustakaan kriptografi yang tepat untuk menghasilkan kunci untuk Anda.

Jadi Anda benar-benar memiliki dua implementasi yang dapat Anda lakukan di sini, yang pertama adalah menggunakan kode yang ditemukan di utas StackOverflow ini untuk Pembuatan Kunci Acak . Solusi ini menggunakan penghasil angka acak yang aman untuk membuat kunci dari awal yang dapat Anda gunakan.

Opsi lain yang kurang aman adalah menggunakan input pengguna seperti kata sandi. Masalah yang kita bahas adalah bahwa kata sandi tidak memiliki cukup entropi, jadi kita harus menggunakan PBKDF2 , sebuah algoritma yang mengambil kata sandi dan memperkuatnya. Berikut ini adalah implementasi StackOverflow yang saya sukai . Namun pustaka Google Tink memiliki semua ini bawaan dan Anda harus memanfaatkannya.

Pengembang Android

Satu poin penting untuk ditunjukkan di sini adalah tahu bahwa kode android Anda adalah rekayasa balik dan kebanyakan kasus kebanyakan kode java juga. Itu berarti jika Anda menyimpan kata sandi dalam teks biasa dalam kode Anda. Seorang hacker dapat dengan mudah mengambilnya. Biasanya, untuk jenis enkripsi ini, Anda ingin menggunakan Asymmetric Cryptography dan sebagainya. Ini di luar cakupan posting ini jadi saya akan menghindari menyelam ke dalamnya.

Sebuah bacaan yang menarik dari 2013 : hai bahwa 88% dari implementasi Crypto di Android yang dilakukan tidak benar.

Pikiran terakhir

Sekali lagi saya akan menyarankan menghindari menerapkan perpustakaan java untuk crypto secara langsung dan menggunakan Google Tink , ini akan menghemat sakit kepala karena mereka telah benar-benar melakukan pekerjaan yang baik dalam mengimplementasikan semua algoritma dengan benar. Dan bahkan kemudian pastikan Anda memeriksa masalah yang muncul di Tink github, kerentanan muncul di sana-sini.

Jika Anda memiliki pertanyaan atau umpan balik, jangan ragu untuk berkomentar! Keamanan selalu berubah dan Anda harus melakukan yang terbaik untuk mengatasinya :)

Konstantino Sparakis
sumber
15
Ini adalah hal terbersih yang pernah saya lihat.
Seraf
1
@ SabirKhan Ini bisa menjadi penyebab kekhawatiran tetapi algoritma inti masih belum rusak sehingga saya tidak akan terlalu khawatir tentang itu. Jika Anda tidak percaya, lihat juga github.com/google/keyczar , dikembangkan oleh tim keamanan Google.
Konstantino Sparakis
1
@KonstantinoSparakis: Jika saya tidak salah menafsirkan dokumentasi untuk BasicTextEncryptor dan StrongTextEncryptor milik Jasypt, kelas-kelas tersebut menggunakan DES dan 3DES untuk mengenkripsi, yang persis seperti yang Anda katakan kepada pembaca agar tidak digunakan. IMO Anda harus mengganti contoh kode yang diberikan dengan yang menggunakan StandardPBEStringEncryptor Jasypt dan secara manual mendefinisikan algoritma AES untuk digunakan.
xpages-noob
1
@ xpages-noob Saya memperbarui posting Saya sebenarnya menemukan Google Tink, yang merupakan pustaka terbaru yang didukung untuk crypto sehingga Anda harus memeriksanya!
Konstantino Sparakis
2
Ukuran blok AES adalah 128 bit. Dalam AES 256, ukuran kuncinya adalah 256 bit. Demikian juga, AES 192 dan AES 128. Juga, sejak Java 8, getInstanceStrong()metode Cipherlebih disukai daripada SHA1PRNG
Saptarshi Basu
110

Saya akan merekomendasikan untuk menggunakan beberapa cypher simetris standar yang banyak tersedia seperti DES , 3DES atau AES . Meskipun itu bukan algoritma yang paling aman, ada banyak implementasi dan Anda hanya perlu memberikan kunci kepada siapa saja yang seharusnya mendekripsi informasi dalam barcode. javax.crypto.Cipher adalah apa yang ingin Anda kerjakan di sini.

Mari kita asumsikan byte yang akan dienkripsi berada

byte[] input;

Selanjutnya, Anda akan memerlukan byte kunci dan inisialisasi vektor

byte[] keyBytes;
byte[] ivBytes;

Sekarang Anda dapat menginisialisasi Cipher untuk algoritma yang Anda pilih:

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

Enkripsi akan seperti ini:

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

Dan dekripsi seperti ini:

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
sumber
9
Bisakah saya menyarankan Anda memperbarui contoh ini untuk referensi DESedealgoritma? Karena ini adalah pertanyaan populer (dan jawaban), akan memalukan untuk mendorong orang untuk menggunakan DES, karena sandi sangat lemah menurut standar saat ini.
Duncan Jones
ada yang salah dengan javax.crypto.BadPaddingException: Diberikan blok terakhir tidak diisi dengan benar saat diurai
penasaran
2
@Duncan Memang DES lemah tapi saya kira AES akan lebih disukai daripada DESede (alias TipleDES): http://security.stackexchange.com/a/26181/69785
Piovezan
2
Ini harus diperbarui untuk memiliki AES / GCM / NoPadding, DES rentan terhadap serangan bruteforce, TripleDes juga tidak dianjurkan
Konstantino Sparakis
1
Jawaban dari Konstantino Sparakis di bawah ini jauh lebih baik daripada yang ini.
Steve
22

Peringatan

Jangan gunakan ini sebagai semacam pengukuran keamanan.

Mekanisme enkripsi dalam posting ini adalah Pad sekali pakai, yang berarti bahwa kunci rahasia dapat dengan mudah dipulihkan oleh penyerang menggunakan 2 pesan terenkripsi. Pesan terenkripsi XOR 2 dan Anda mendapatkan kuncinya. Sesederhana itu!

Ditunjuk oleh Moussa


Saya menggunakan Sun's Base64Encoder / Decoder yang dapat ditemukan di Sun's JRE, untuk menghindari JAR lain di lib. Itu berbahaya dari titik menggunakan OpenJDK atau JRE orang lain. Selain itu, apakah ada alasan lain saya harus mempertimbangkan untuk menggunakan Apache commons lib dengan 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
ante.sabo
sumber
1
Saya juga menggunakan proposal solusi ini melalui sun.misc.BASE64Encoder tetapi ketika menggunakan string yang agak besar untuk mengkodekan, encoder mengembalikan string yang dipotong (masing-masing 76 karakter). Saya kemudian beralih ke Apache Commons Codec Base64 yang menawarkan metode pengkodean non-chunking!
basZero
78
Mekanisme enkripsi yang Anda gambarkan adalah SANGAT BERBAHAYA jika digunakan lebih dari sekali. itulah alasan mengapa disebut pad sekali pakai. Kunci rahasia dapat dengan mudah dipulihkan oleh penyerang menggunakan 2 pesan terenkripsi. xor 2 pesan terenkripsi dan Anda mendapatkan kuncinya. Sesederhana itu!
xtrem
3
Idenya bukan untuk menjadi berat, hanya untuk memantul orang dari mencoba membaca apa yang tertulis dalam PDF-417 2D barcode.
Lagi
2
BAIK. Hanya khawatir bahwa seseorang menggunakan ini sebagai mekanisme enkripsi.
xtrem
Untuk Enkripsi, enkoder (mis. BASE64Encoder) dapat dihindari untuk mendapatkan serangan brute force.
Jagrut Dalwadi
13

Terima kasih ive membuat kelas ini menggunakan kode Anda, mungkin seseorang menemukannya userfull

objek 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
sumber
memposting pertanyaan terkait di sini !
user2023507
Tidakkah seharusnya menjadi kasus bahwa melewati differentKeys selama mengenkripsi dan mendekripsi seharusnya tidak mengembalikan teks? Sepertinya itu tidak terjadi di sini. PS: Saya menggunakan objek yang berbeda dari kelas ini untuk melakukan tes ini.
instanceOfObject
6

Pembaruan pada 12-DEC-2019

Tidak seperti beberapa mode lain seperti CBC, mode GCM tidak mengharuskan IV tidak dapat diprediksi. Satu-satunya persyaratan adalah bahwa IV harus unik untuk setiap doa dengan kunci yang diberikan. Jika diulangi sekali untuk kunci yang diberikan, keamanan dapat dikompromikan. Cara mudah untuk mencapai ini adalah dengan menggunakan IV acak dari generator nomor acak pseudo yang kuat seperti yang ditunjukkan di bawah ini.

Menggunakan urutan atau stempel waktu sebagai IV juga dimungkinkan, tetapi mungkin tidak sepele kedengarannya. Misalnya, jika sistem tidak melacak dengan benar urutan yang sudah digunakan sebagai IV di toko persisten, doa dapat mengulangi IV setelah sistem reboot. Demikian juga, tidak ada jam yang sempurna. Jam komputer menyesuaikan kembali dll.

Selain itu, kunci harus diputar setelah setiap doa 2 ^ 32. Untuk perincian lebih lanjut tentang persyaratan IV, lihat jawaban ini dan rekomendasi NIST .


Ini adalah kode enkripsi & dekripsi yang baru saja saya tulis di Java 8 dengan mempertimbangkan poin-poin berikut. Semoga seseorang akan menemukan ini berguna:

  1. Algoritma Enkripsi : Blok cipher AES dengan kunci 256 bit dianggap cukup aman. Untuk mengenkripsi pesan lengkap, mode perlu dipilih. Enkripsi yang diautentikasi (yang memberikan kerahasiaan dan integritas) direkomendasikan. GCM, CCM dan EAX adalah mode enkripsi terotentikasi yang paling umum digunakan. GCM biasanya lebih disukai dan berkinerja baik di arsitektur Intel yang memberikan instruksi khusus untuk GCM. Ketiga mode ini adalah mode berbasis CTR (berbasis counter) dan oleh karena itu mereka tidak perlu padding. Akibatnya mereka tidak rentan terhadap serangan terkait padding

  2. Inisialisasi Vektor (IV) diperlukan untuk GCM. IV bukan rahasia. Satu-satunya persyaratan adalah harus acak atau tidak dapat diprediksi. Di Jawa, SecuredRandomkelas ini dimaksudkan untuk menghasilkan angka acak semu yang kuat secara kriptografis. Algoritma bilangan pseudo-acak dapat ditentukan dalam getInstance()metode ini. Namun, sejak Java 8, cara yang disarankan adalah menggunakan getInstanceStrong()metode yang akan menggunakan algoritma terkuat yang dikonfigurasi dan disediakan olehProvider

  3. NIST merekomendasikan 96 bit IV untuk GCM untuk mempromosikan interoperabilitas, efisiensi, dan kesederhanaan desain

  4. Untuk memastikan keamanan tambahan, dalam implementasi berikut SecureRandomdiunggulkan kembali setelah menghasilkan setiap 2 ^ 16 byte generasi byte pseudo acak

  5. Penerima perlu mengetahui IV untuk dapat mendekripsi teks sandi. Oleh karena itu IV harus ditransfer bersama dengan teks sandi. Beberapa implementasi mengirim IV sebagai AD (Data Terkait) yang berarti bahwa tag otentikasi akan dihitung pada teks sandi dan IV. Namun, itu tidak diperlukan. IV dapat dengan mudah ditunda dengan teks sandi karena jika IV diubah selama transmisi karena serangan yang disengaja atau kesalahan sistem jaringan / file, validasi tag otentikasi akan tetap gagal

  6. String tidak boleh digunakan untuk menyimpan pesan teks atau kunci yang jelas karena String tidak dapat diubah dan dengan demikian kita tidak dapat menghapusnya setelah digunakan. String tidak jelas ini kemudian berlama-lama di memori dan dapat muncul di tumpukan sampah. Untuk alasan yang sama, klien yang memanggil metode enkripsi atau dekripsi ini harus menghapus semua variabel atau array yang menyimpan pesan atau kunci setelah mereka tidak lagi diperlukan.

  7. Tidak ada penyedia yang dikodekan dalam kode mengikuti rekomendasi umum

  8. Akhirnya untuk transmisi melalui jaringan atau penyimpanan, kunci atau teks sandi harus dikodekan menggunakan pengkodean Base64. Detail Base64 dapat ditemukan di sini . Pendekatan Java 8 harus diikuti

Array byte dapat dihapus menggunakan:

Arrays.fill(clearTextMessageByteArray, Byte.MIN_VALUE);

Namun, pada Java 8, tidak ada cara mudah untuk menghapus SecretKeyspecdan SecretKeykarena implementasi dari dua antarmuka ini tampaknya tidak menerapkan metode destroy()antarmuka Destroyable. Dalam kode berikut, metode terpisah ditulis untuk menghapus SecretKeySpecdan SecretKeymenggunakan refleksi.

Kunci harus dihasilkan menggunakan salah satu dari dua pendekatan yang disebutkan di bawah ini.

Perhatikan bahwa kunci adalah rahasia seperti kata sandi, tetapi tidak seperti kata sandi yang dimaksudkan untuk penggunaan manusia, kunci dimaksudkan untuk digunakan oleh algoritma kriptografi dan karenanya harus dibuat hanya dengan menggunakan cara di atas.

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

Kunci enkripsi dapat dihasilkan terutama dalam dua cara:

  • Tanpa kata sandi apa pun

    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);
  • Dengan kata sandi

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

Pembaruan Berdasarkan Komentar

Seperti yang ditunjukkan oleh @ MaartenBodewes, jawaban saya tidak menangani apa pun Stringseperti yang diminta oleh pertanyaan. Oleh karena itu, saya akan berusaha mengisi celah itu untuk berjaga-jaga seandainya seseorang menemukan jawaban ini dan bertanya-tanya tentang penanganannya String.

Seperti yang ditunjukkan sebelumnya dalam jawaban, penanganan informasi sensitif di a String, secara umum, bukan ide yang baik karena Stringtidak dapat diubah dan dengan demikian kami tidak dapat menghapusnya setelah digunakan. Dan seperti yang kita tahu, bahkan ketika a Stringtidak memiliki referensi yang kuat, pengumpul sampah tidak segera bergegas untuk mengeluarkannya dari tumpukan. Dengan demikian, Stringterus ada di dalam memori untuk jendela waktu yang tidak diketahui meskipun tidak dapat diakses oleh program. Masalahnya adalah, tumpukan tumpukan selama jangka waktu itu akan mengungkapkan informasi sensitif. Oleh karena itu, selalu lebih baik untuk menangani semua informasi sensitif dalam array byte atau array char dan kemudian mengisi array dengan 0s begitu tujuannya dilayani.

Namun, dengan semua pengetahuan itu, jika kita masih berakhir dalam situasi di mana informasi sensitif yang akan dienkripsi berada dalam a String, pertama-tama kita perlu mengubahnya menjadi array byte dan menjalankan encryptdan decryptfungsi yang diperkenalkan di atas. (Kunci input lainnya dapat dibuat menggunakan potongan kode yang disediakan di atas).

A Stringdapat dikonversi menjadi byte dengan cara berikut:

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

Pada Java 8, Stringdisimpan secara internal di heap dengan UTF-16encoding. Namun, kami telah menggunakan di UTF-8sini karena biasanya memakan waktu lebih sedikit daripada UTF-16, terutama untuk karakter ASCII.

Demikian juga, array byte terenkripsi juga dapat dikonversi menjadi String seperti di bawah ini:

String encryptedString = new String(encryptedBytes, StandardCharsets.UTF_8);
Saptarshi Basu
sumber
1
Sebanyak yang saya ingin upvote jawaban ini karena memang terlihat mematuhi praktik crypto saat ini, saya tidak melihat penanganan string sama sekali, membuatnya lebih seperti hanya deskripsi tentang cara menggunakan mode GCM. Karena itu gagal menjawab pertanyaan .
Maarten Bodewes
1
@MaartenBodewes Terima kasih banyak telah meluangkan waktu untuk meninjau dan berbagi umpan balik. Saya menulis ini dengan pemahaman bahwa mengenkripsi Stringmenggunakan fungsi yang dibuat di atas akan sepele. Namun, pada pandangan kedua setelah membaca komentar Anda, saya mengerti bahwa itu mungkin tidak jelas. Saya pasti akan mengedit untuk menambahkan detail itu.
Saptarshi Basu
5

Bagaimana dengan ini:

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

Bekerja dengan baik untuk saya dan agak kompak.

yegor256
sumber
apa yang akan terjadi jika parameter entry rahasia == null atau input == null? bekerja dengan byte daripada dengan string ok, tetapi tidak relevan dalam kasus saya .. satu-satunya hal yang penting adalah bahwa ini harus dapat dibaca dan didekodekan dengan perangkat apa pun, dalam penyandian karakter apa pun yang mungkin ...
ante.sabo
@ ante.sabo rupanya, ia akan melempar NPE. Ini adalah satu-satunya hal yang harus dilakukan dengan NULLs.
Miha_x64
Selama input.length <= secret.lengthmemegang dan tidak secretpernah digunakan kembali ini aman dan disebut a one-time-pad. Dalam kasus input.length > secret.lengthini adalah varian dari cipher Vigenère dan dianggap sangat lemah.
Trichner
5

Anda bisa menggunakan Jasypt

Dengan Jasypt, mengenkripsi dan memeriksa kata sandi bisa sesederhana ...

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

Enkripsi:

String myEncryptedText = textEncryptor.encrypt(myText);

Dekripsi:

String plainText = textEncryptor.decrypt(myEncryptedText);

Gradle:

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

Fitur:

Jasypt memberi Anda teknik enkripsi searah (intisari) dan bidirectional yang mudah.

Buka API untuk digunakan dengan penyedia JCE apa pun, dan bukan hanya Java VM default. Jasypt dapat dengan mudah digunakan dengan penyedia terkenal seperti Bouncy Castle. Belajarlah lagi.

Keamanan yang lebih tinggi untuk kata sandi pengguna Anda. Belajarlah lagi.

Dukungan enkripsi biner. Jasypt memungkinkan intisari dan enkripsi binari (byte array). Enkripsi objek atau file Anda saat diperlukan (untuk dikirim melalui internet, misalnya).

Dukungan enkripsi nomor. Selain teks dan binari, ini memungkinkan intisari dan enkripsi nilai numerik (BigInteger dan BigDecimal, tipe numerik lainnya didukung ketika mengenkripsi untuk ketekunan Hibernate). Belajarlah lagi.

Sepenuhnya thread-safe.

Dukungan untuk enkripsi / digester pooling, untuk mencapai kinerja tinggi dalam sistem multi-prosesor / multi-core.

Termasuk versi ringan ("lite") perpustakaan untuk pengelolaan yang lebih baik di lingkungan yang membatasi ukuran seperti platform seluler.

Menyediakan alat enkripsi yang mudah dan tanpa konfigurasi untuk pengguna yang baru dalam enkripsi, dan juga alat enkripsi standar yang sangat dapat dikonfigurasi, untuk pengguna yang berdaya guna.

Hibernasi 3 dan 4 integrasi opsional untuk bidang yang ada dari entitas yang dipetakan dengan cara terenkripsi. Enkripsi bidang didefinisikan dalam file pemetaan Hibernate, dan itu tetap transparan untuk sisa aplikasi (berguna untuk data pribadi yang sensitif, basis data dengan banyak pengguna dengan dukungan baca ...). Enkripsi teks, binari, angka, boolean, tanggal ... Pelajari lebih lanjut.

Terintegrasi secara sempurna ke dalam aplikasi Spring, dengan fitur integrasi spesifik untuk Spring 2, Spring 3.0 dan Spring 3.1. Semua digester dan enkripsi di jasypt dirancang agar mudah digunakan (instantiated, dependency-injected ...) dari Spring. Dan, karena thread-safe, mereka dapat digunakan tanpa kekhawatiran sinkronisasi di lingkungan berorientasi tunggal seperti Spring. Pelajari lebih lanjut: Spring 2, Spring 3.0, Spring 3.1.

Spring Security (sebelumnya Acegi Security) integrasi opsional untuk melakukan enkripsi kata sandi dan tugas-tugas yang cocok untuk kerangka kerja keamanan, meningkatkan keamanan kata sandi pengguna Anda dengan menggunakan mekanisme enkripsi kata sandi yang lebih aman dan memberi Anda konfigurasi dan kontrol tingkat tinggi. Belajarlah lagi.

Menyediakan fungsionalitas canggih untuk mengenkripsi semua atau sebagian file konfigurasi aplikasi, termasuk informasi sensitif seperti kata sandi basis data. Integrasikan konfigurasi terenkripsi ke dalam aplikasi polos, berbasis Spring dan / atau Hibernate. Belajarlah lagi.

Menyediakan alat CLI (Command Line Interface) yang mudah digunakan untuk memungkinkan pengembang menginisialisasi data terenkripsi mereka dan menyertakan operasi enkripsi / dekripsi / intisari dalam tugas perawatan atau skrip. Belajarlah lagi.

Terintegrasi dengan Apache Wicket, untuk enkripsi URL yang lebih kuat di aplikasi aman Anda.

Panduan komprehensif dan dokumentasi javadoc, untuk memungkinkan pengembang lebih memahami apa yang sebenarnya mereka lakukan terhadap data mereka.

Dukungan charset yang kuat, dirancang untuk mengenkripsi dan mencerna teks mana pun charset aslinya dengan memadai. Dukungan lengkap untuk bahasa seperti Jepang, Korea, Arab ... tanpa masalah penyandian atau platform.

Tingkat kemampuan konfigurasi yang sangat tinggi: Pengembang dapat menerapkan trik seperti menginstruksikan "enkripsi" untuk meminta, misalnya, server HTTPS jarak jauh untuk kata sandi yang akan digunakan untuk enkripsi. Ini memungkinkan Anda memenuhi kebutuhan keamanan Anda.

Kamil Nekanowicz
sumber
1
Tetapi keamanan apa yang Jasyptdisediakan? Saya tidak bisa mengetahuinya dari situs web mereka. Apakah tidak bisa dibedakan dengan serangan plaintext yang dipilih? Integritas? Kerahasiaan?
trichner
4

Inilah implementasi saya dari meta64.com sebagai Spring Singleton. Jika Anda ingin membuat instance ciper untuk setiap panggilan yang juga berfungsi, dan kemudian Anda bisa menghapus panggilan 'disinkronkan', tetapi waspadalah 'cipher' tidak aman untuk thread.

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
sumber
3
Ini akan mengenkripsi dengan mode ECB yang mengerikan. Anda harus menetapkan setidaknya mode CBC atau Mode GCM
Konstantino Sparakis
Terima kasih atas saran Konstantinto, saya mencari di Google dan menemukan beberapa kode yang menggunakan "AES / CBC / PKCS5Padding" sebagai string Init untuk Cipher, bukan hanya "AES", tetapi saya akan memeriksanya lebih dalam. Atau jika mau, Anda dapat memberikan perbaikan yang sebenarnya, sehingga orang lain dapat melihat cara yang lebih baik. Namun, selain dari detail CBC saya percaya solusi saya adalah yang paling sederhana dan aman, dan layak untuk diunggulkan di atas semua yang lain.
Ya jangan khawatir, Crypto adalah subjek yang rumit. Sayangnya setiap implementasi pada halaman ini rusak dan sayangnya itu adalah halaman pertama yang muncul ketika menggunakan google untuk mencari "bagaimana melakukan enkripsi java." Ketika saya mendapat kesempatan, saya akan mencoba untuk memperbaiki semuanya.
Konstantino Sparakis
Contoh saya sama dengan ini: docs.oracle.com/javase/8/docs/technotes/guides/security/crypto/… Kecuali saya membutuhkan Cipher.getInstance ("AES / ECB / PKCS5Padding"); Kode saya mengasumsikan ada beberapa file properti dengan kunci enkripsi panjang 16 byte yang sempurna, tetapi untuk mengenkripsi string dari kata sandi yang disediakan pengguna, halaman oracle (ditautkan di atas) menunjukkan cara untuk melakukannya juga.
1
Jadi masalah dengan ECB adalah sangat rentan terhadap analisis frekuensi. Ada contoh terkenal dari penguin Linux, blog.filippo.io/the-ecb-penguin lihat bagaimana meskipun gambar dienkripsi Anda masih dapat mengatakan bahwa itu adalah penguin. Saya pergi ke depan dan menulis pemikiran saya tentang subjek di bawah ini :) stackoverflow.com/a/43779197/2607972
Konstantino Sparakis
4

Berikut solusi sederhana dengan hanya java.*dan javax.crypto.*dependensi untuk enkripsi byte menyediakan kerahasiaan dan integritas . Itu harus dibedakan di bawah serangan plaintext yang dipilih untuk pesan pendek dalam urutan kilobyte.

Ini digunakan AESdalam GCMmode tanpa padding, kunci 128bit diturunkan PBKDF2dengan banyak iterasi dan garam statis dari kata sandi yang disediakan. Ini memastikan brute forcing passwords sulit dan mendistribusikan entropi ke seluruh kunci.

Vektor inisialisasi acak (IV) dihasilkan dan akan ditambahkan ke ciphertext. Selanjutnya, byte statis 0x01didahului dengan byte pertama sebagai 'versi'.

Seluruh pesan masuk ke kode otentikasi pesan (MAC) yang dihasilkan oleh AES/GCM.

Ini dia, nol enkripsi kelas dependensi eksternal memberikan kerahasiaan dan integritas :

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

Di sini seluruh proyek dengan CLI yang bagus: https://github.com/trichner/tcrypt

Edit: sekarang dengan yang sesuai encryptStringdandecryptString

trichner
sumber
Ini luar biasa. Terima kasih! Saya belajar banyak dari kode Anda dan setelah membuat kelas Pengecualian BadVersionException, kode Anda bekerja dengan sempurna pertama kali. Luar biasa !!
Morkus
Saya suka upaya ini. Yang mengatakan ... Garam harus acak, bukan statis. Iterasi mungkin tidak boleh statis juga. GCM sudah memasukkan IV dalam perhitungan tag. Itu tidak mengandung nomor versi sekalipun. Anda tidak boleh menentukan penyedia untuk portabilitas, yang "SunJCE" akan menjadi default pada platform yang mendukungnya. Kode ini tidak mengandung penanganan string pesan, yang diperlukan untuk pertanyaan khusus ini .
Maarten Bodewes
Baiklah, saya membersihkannya sedikit lebih banyak dan menambahkan yang diminta encryptStringdan decryptString:)
trichner
Ini bekerja dengan sangat baik; ty untuk kode. Perlu dicatat bahwa kode ini memerlukan API 19 (Kit Kat) atau lebih untuk berfungsi dengan benar.
PGMacDesign
3

Saya akan mempertimbangkan untuk menggunakan sesuatu seperti https://www.bouncycastle.org/ Ini adalah perpustakaan prebuilt yang memungkinkan Anda untuk mengenkripsi apa pun yang Anda suka dengan sejumlah Ciphers yang berbeda. Saya mengerti bahwa Anda hanya ingin melindungi dari pengintaian, tetapi jika Anda benar-benar ingin melindungi informasi, menggunakan Base64 tidak akan benar-benar melindungi Anda.

hdost
sumber
1
Hanya merekomendasikan perpustakaan kripto acak dengan sandi bukan jawaban untuk pertanyaan itu. Selain itu, mengapa tidak menggunakan sandi bawaan?
Maarten Bodewes
2

Berikut adalah beberapa tautan yang dapat Anda baca yang didukung Java

Mengenkripsi / mendekripsi aliran data.

Contoh ini menunjukkan cara mengenkripsi (menggunakan algoritma enkripsi simetris seperti AES, Blowfish, RC2, 3DES, dll) sejumlah besar data. Data dikirimkan dalam potongan ke salah satu metode enkripsi: EncryptBytes, EncryptString, EncryptBytesENC, atau EncryptStringENC. (Nama metode menunjukkan tipe input (string atau byte array) dan tipe kembali (string atau byte array yang dikodekan). Properti FirstChunk dan LastChunk digunakan untuk menunjukkan apakah sebuah chunk adalah yang pertama, tengah, atau terakhir dalam aliran untuk dienkripsi. Secara default, FirstChunk dan LastChunk sama benar - artinya bahwa data yang dikirimkan adalah jumlah keseluruhan.

JCERefGuide

Contoh Enkripsi Java

Markus Lausberg
sumber
Ya, ada kriptografi yang didukung oleh Java. Enkripsi aliran juga tidak diminta.
Maarten Bodewes
2

Seperti yang sudah diceritakan oleh banyak orang, Anda harus menggunakan kode standar yang terlalu banyak digunakan seperti DES atau AES.

Contoh sederhana tentang bagaimana Anda dapat mengenkripsi dan mendekripsi string dalam java menggunakan 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!"));

    }
}
viveknaskar
sumber
CBC bukan lagi mode aman. Padding rentan terhadap padding serangan Oracle. Juga, menangani kunci dan pesan dalam String tidak aman. Mereka akan berlama-lama di kolam String dan muncul di tumpukan sampah
Saptarshi Basu
2
Hargai komentarnya. Ini adalah contoh sederhana dari metode mengenkripsi dan mendekripsi Java seperti yang diminta pengguna. Pertanyaan itu ditanyakan sekitar 9 tahun yang lalu dan dijawab berdasarkan itu. Terima kasih.
viveknaskar
2
Ya ini sepertinya cara sederhana untuk memperkenalkan enkripsi / dekripsi. Bekerja seperti pesona bagiku .... Terima kasih.
Codewrapper
0

Berikut ini adalah solusi salin / tempel. Saya juga merekomendasikan membaca dan memilih jawaban @ Konstantino meskipun tidak menyediakan kode apa pun. Vektor inisialisasi (IV) seperti garam - tidak harus dirahasiakan. Saya baru mengenal GCM dan tampaknya AAD adalah opsional dan hanya digunakan dalam keadaan tertentu. Atur kunci dalam variabel lingkungan SECRET_KEY_BASE. Gunakan sesuatu seperti KeePass untuk menghasilkan kata sandi 32 karakter. Solusi ini dimodelkan setelah solusi Ruby saya.

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

Berikut ini sebuah contoh:

    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
sumber
-4

Anda mungkin ingin mempertimbangkan beberapa alat otomatis untuk melakukan pembuatan kode enkripsi / dekripsi misalnya. https://www.stringencrypt.com/java-encryption/

Ini dapat menghasilkan kode enkripsi dan dekripsi yang berbeda setiap kali untuk string atau enkripsi file.

Ini cukup praktis ketika menyangkut enkripsi string cepat tanpa menggunakan RSA, AES dll.

Hasil sampel:

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

Kami menggunakannya sepanjang waktu di perusahaan kami.

Bartosz Wójcik
sumber
Ini adalah keamanan melalui ketidakjelasan dan tidak benar-benar aman.
Chloe
Pertanyaan ini meminta enkripsi kekuatan kriptografi modern yang sebenarnya seperti AES, bukan hanya kebingungan untuk membuat string lebih sulit untuk diekstraksi secara statis. Ini bahkan tidak muncul untuk menjaga keadaan di antara karakter sehingga rentan terhadap analisis frekuensi. ( Cipher substitusi alfabet tunggal , kecuali lebih dari codepoint UTF-16 alih-alih alfabet Latin. Tetapi jika Anda menggunakannya pada teks ASCII bahasa Inggris, Anda hanya mendapatkan beberapa nilai karakter 16-bit yang unik, kecuali saya salah membaca ini)
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
sumber
Secara resmi mengenkripsi data ke dalam format yang tidak dapat dibaca. Untuk mendekripsi gunakan kode yang sama. Dan ubah s [i] * f ke s [I] / f.
Arshad shaik
Ini adalah keamanan melalui ketidakjelasan dan tidak benar-benar aman.
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;
    }
resi
sumber
1
Apakah JavaEncryprtionUtil bagian dari JDK API? jika tidak, Anda harus menyebutkan nama perpustakaan.
Mahasiswa Kecil Fermat
4
Tidak dapat menemukan kelas itu. Terasa seperti jawabannya.
james.garriss