জাভা 256-বিট এইএস পাসওয়ার্ড-ভিত্তিক এনক্রিপশন


390

আমার 256 বিট AES এনক্রিপশন বাস্তবায়ন করতে হবে, তবে অনলাইনে যে সমস্ত উদাহরণ আমি পেয়েছি সেগুলি 256 বিট কী তৈরি করতে "কীজেনেটর" ব্যবহার করে তবে আমি নিজের পাসকি ব্যবহার করতে চাই। আমি কীভাবে নিজের চাবি তৈরি করতে পারি? আমি এটিকে 256 বিট করে দেওয়ার চেষ্টা করেছি, তবে কীটিটি অনেক দীর্ঘ বলে আমি একটি ত্রুটি পেয়েছি। আমি সীমাহীন এখতিয়ার প্যাচ ইনস্টল করেছি, তাই সমস্যা না :)

অর্থাৎ। কী-জেনারেটর এর মতো দেখাচ্ছে ...

// Get the KeyGenerator
KeyGenerator kgen = KeyGenerator.getInstance("AES");
kgen.init(128); // 192 and 256 bits may not be available

// Generate the secret key specs.
SecretKey skey = kgen.generateKey();
byte[] raw = skey.getEncoded();

কোড এখান থেকে নেওয়া হয়েছে

সম্পাদনা

আমি আসলে পাসওয়ার্ডটি 256 বাইটে বিড করেছিলাম, বিট নয়, যা খুব দীর্ঘ। নিম্নলিখিতটি আমি এখন ব্যবহার করছি এমন কিছু কোড যা এর সাথে আমার আরও কিছু অভিজ্ঞতা রয়েছে।

byte[] key = null; // TODO
byte[] input = null; // TODO
byte[] output = null;
SecretKeySpec keySpec = null;
keySpec = new SecretKeySpec(key, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
cipher.init(Cipher.ENCRYPT_MODE, keySpec);
output = cipher.doFinal(input)

"টুডো" বিটগুলি আপনার নিজের করতে হবে :-)


আপনি কি পরিষ্কার করতে পারেন: কলিং kgen.init (256) কাজ করে?
মিচ গম

2
হ্যাঁ, তবে এটি স্বয়ংক্রিয়ভাবে একটি কী উত্পন্ন করে ... তবে যেহেতু আমি দুটি জায়গার মধ্যে ডেটা এনক্রিপ্ট করতে চাই, তাই আগেই কীটিটি আমার জানা উচিত, সুতরাং "জেনারেট" এর পরিবর্তে আমার একটি নির্দিষ্ট করা দরকার। আমি একটি 16 বিট নির্দিষ্ট করতে পারি যা 128 বিট এনক্রিপশনের জন্য কাজ করে যা কাজ করে। আমি 256 বিট এনক্রিপশনের জন্য একটি 32 বিট এক চেষ্টা করেছি, তবে এটি প্রত্যাশার মতো কার্যকর হয়নি।
নিপ্পিসৌরাস

4
যদি আমি সঠিকভাবে বুঝতে পারি তবে আপনি একটি প্রাক-ব্যবস্থাযুক্ত, 256-বিট কী ব্যবহার করার চেষ্টা করছেন, উদাহরণস্বরূপ, বাইটের অ্যারে হিসাবে। যদি তা হয় তবে সিক্রেটকিস্পিপ ব্যবহার করে ডার্কস্কুইডের পদ্ধতির কাজ করা উচিত। পাসওয়ার্ড থেকে একটি এএস কী অর্জন করাও সম্ভব; আপনি যদি এরপরে থাকেন তবে দয়া করে আমাকে জানান, এবং এটি করার সঠিক উপায়টি আমি আপনাকে দেখাব; কেবল একটি পাসওয়ার্ড হ্যাশ করা সেরা অনুশীলন নয়।
এরিকসন

একটি নম্বর প্যাডিং সম্পর্কে সতর্কতা অবলম্বন করুন, আপনি আপনার AES কম সুরক্ষিত করতে পারেন।
জোশুয়া

1
@ এরিকসন: এটি আমার অত্যন্ত প্রয়োজন (পাসওয়ার্ড থেকে একটি এইএস কী নেওয়া)।
নিপ্পাইসরাস

উত্তর:


475

শেয়ার করুন password(ক char[]) এবং salt(ক byte[]-8 নির্বাচিত দ্বারা বাইট SecureRandomএকটি ভাল নোনা যা গোপন রাখা দরকার নেই তোলে) আউট-অফ-ব্যান্ড প্রাপকের সাথে। তারপরে এই তথ্য থেকে একটি ভাল কী অর্জন করতে:

/* Derive the key, given password and salt. */
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
KeySpec spec = new PBEKeySpec(password, salt, 65536, 256);
SecretKey tmp = factory.generateSecret(spec);
SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");

যাদু সংখ্যা (যা কোথাও ধ্রুবক হিসাবে সংজ্ঞায়িত করা যেতে পারে) 65536 এবং 256 হ'ল যথাক্রমে কী ডেরাইভেশন পুনরাবৃত্তি গণনা এবং কী আকার।

কী ডেরাইভেশন ফাংশনটি উল্লেখযোগ্য গণনা প্রচেষ্টা প্রয়োজন পুনরুক্তি করা হয়, এবং এটি আক্রমণকারীদের দ্রুত বিভিন্ন পাসওয়ার্ড চেষ্টা করে বাধা দেয়। উপলব্ধ কম্পিউটিং সংস্থানগুলির উপর নির্ভর করে পুনরাবৃত্তি গণনা পরিবর্তন করা যেতে পারে।

মূল আকারটি 128 বিটে হ্রাস করা যেতে পারে, যা এখনও "শক্তিশালী" এনক্রিপশন হিসাবে বিবেচিত হয়, তবে আক্রমণগুলি এএসকে দুর্বল করে এমন সন্ধান পেলে এটি কোনও সুরক্ষা মার্জিন দেয় না।

যথাযথ ব্লক-চেইনিং মোডের সাথে ব্যবহার করা, একই উত্পন্ন কীটি অনেক বার্তাকে এনক্রিপ্ট করতে ব্যবহার করা যেতে পারে। ইন সাইফার ব্লক চেইনিং (সিবিসি) , একটি র্যান্ডম আরম্ভের ভেক্টর (চতুর্থ) প্রতিটি বার্তার জন্য উৎপন্ন হয়, বিভিন্ন সাইফার টেক্সট এমনকি যদি প্লেইন টেক্সট অভিন্ন মেনে নেওয়া। সিবিসি আপনার কাছে উপলব্ধ সবচেয়ে সুরক্ষিত মোড নাও হতে পারে (নীচে AEAD দেখুন); বিভিন্ন সুরক্ষা বৈশিষ্ট্য সহ আরও অনেকগুলি মোড রয়েছে তবে তারা সকলেই একটি অনুরূপ এলোমেলো ইনপুট ব্যবহার করে। যাইহোক, প্রতিটি এনক্রিপশন ক্রিয়াকলাপের আউটপুট হ'ল সাইফার পাঠ্য এবং সূচনা ভেক্টর:

/* Encrypt the message. */
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secret);
AlgorithmParameters params = cipher.getParameters();
byte[] iv = params.getParameterSpec(IvParameterSpec.class).getIV();
byte[] ciphertext = cipher.doFinal("Hello, World!".getBytes("UTF-8"));

সঞ্চয় করুন ciphertextএবং iv। ডিক্রিপশন এ, SecretKeyএকই লবণ এবং পুনরাবৃত্তির পরামিতিগুলির সাথে পাসওয়ার্ড ব্যবহার করে ঠিক একইভাবে পুনরায় জেনারেট করা হয়। এই কী এবং সিফারাইজেশন ভেক্টরটি বার্তা সহ সঞ্চিত সিফারটি দিয়ে সূচনা করুন:

/* Decrypt the message, given derived key and initialization vector. */
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(iv));
String plaintext = new String(cipher.doFinal(ciphertext), "UTF-8");
System.out.println(plaintext);

জাভা 7 এআইএডি সাইফার মোডগুলির জন্য এপিআই সমর্থন অন্তর্ভুক্ত করে , এবং ওপেনজেডিকে এবং ওরাকল বিতরণগুলির সাথে অন্তর্ভুক্ত "সানজেসিই" সরবরাহকারী জাভা ৮ দিয়ে এই শুরুটি কার্যকর করে these এটি তথ্যের অখণ্ডতা পাশাপাশি তাদের গোপনীয়তা রক্ষা করবে।


একটি java.security.InvalidKeyExceptionবার্তা "অবৈধ কী আকার বা ডিফল্ট পরামিতি" অর্থ যে ক্রিপ্টোগ্রাফি শক্তিতে হয় সীমাবদ্ধ; সীমাহীন শক্তি এখতিয়ার নীতি ফাইলগুলি সঠিক স্থানে নেই। একটি জেডিকে, তাদের নীচে স্থাপন করা উচিত${jdk}/jre/lib/security

সমস্যার বর্ণনার ভিত্তিতে, শোনা যাচ্ছে যে পলিসি ফাইলগুলি সঠিকভাবে ইনস্টল করা হয়নি। সিস্টেমে সহজেই একাধিক জাভা রানটাইম থাকতে পারে; সঠিক অবস্থানটি ব্যবহার হচ্ছে কিনা তা নিশ্চিত করতে ডাবল-চেক করুন।


29
@ নিক: পিকেসিএস # 5 পড়ুন। পিবিকেডিএফ 2 এর জন্য সল্ট প্রয়োজনীয়, এই কারণেই পাসওয়ার্ড-ভিত্তিক এনক্রিপশনের জন্য এপিআই-তে কী উত্সের জন্য ইনপুট হিসাবে তাদের প্রয়োজন। সল্ট ব্যতীত, একটি অভিধান আক্রমণ ব্যবহার করা যেতে পারে, সম্ভাব্য সংলগ্ন এনক্রিপশন কীগুলির একটি প্রাক-গণিত তালিকা সক্ষম করে। সাইফার চতুর্থ এবং কী-ডেরাইভেশন লবণ বিভিন্ন উদ্দেশ্যে পরিবেশন করে। আইভিগুলি একাধিক বার্তাগুলির জন্য একই কীটি পুনরায় ব্যবহারের অনুমতি দেয়। সল্টগুলি কী-তে অভিধান আক্রমণগুলি রোধ করে।
এরিকসন

2
প্রথমত, এটি DES এনক্রিপশন হবে, AES নয়। বেশিরভাগ সরবরাহকারীদের PBEwith<prf>and<encryption>অ্যালগরিদমের পক্ষে ভাল সমর্থন নেই ; উদাহরণস্বরূপ, সানজেসিই এএসের জন্য সরবরাহ করে না এবং পিবিই করছে। দ্বিতীয়ত, জ্যাসিপ্ট সক্ষম করা একটি অ-লক্ষ্য। অন্তর্নিহিত নীতিগুলি বোঝার প্রয়োজন ছাড়াই সুরক্ষা সরবরাহের পরিকল্পনা করে এমন একটি প্যাকেজ বিপজ্জনক প্রথম বিষয় বলে মনে হচ্ছে।
এরিকসন

6
আমি @ এরিকসনের জবাবকে ক্লাস হিসাবে প্রয়োগ করেছি: github.com/mrclay/jSecureEdit/tree/master/src/org/mrclay/crypto ( পিবিই কাজ করে, পিবিএসটিরেজ আইভি / সিফারেক্সট একসাথে স্টোর করার জন্য একটি মান বস্তু।)
স্টিভ ক্লে

3
@ অ্যান্ডিনিস এই উদাহরণটি বিপরীতমুখী এনক্রিপশনের জন্য, যা সাধারণত পাসওয়ার্ডের জন্য ব্যবহার করা উচিত নয়। আপনি সুরক্ষিতভাবে "হ্যাশ" পাসওয়ার্ডগুলির জন্য PBKDF2 কী ডেরাইভেশন ব্যবহার করতে পারেন। তার মানে যে উপরের উদাহরণে আপনি tmp.getEncoded()হ্যাশ হিসাবে ফলাফল সংরক্ষণ করবেন । saltআপনার পুনরাবৃত্তি এবং পুনরাবৃত্তিগুলিও সংরক্ষণ করা উচিত (এই উদাহরণে 65536) যাতে কেউ যখন প্রমাণীকরণের চেষ্টা করে আপনি হ্যাশটির পুনঃসংযোগ করতে পারেন। এক্ষেত্রে প্রতিবার পাসওয়ার্ড পরিবর্তিত হওয়ার সাথে সাথে কোনও ক্রিপ্টোগ্রাফিক র্যান্ডম নম্বর জেনারেটর দিয়ে লবণ তৈরি করুন।
এরিকসন

6
এই কোডটি চালনার জন্য, আপনার জেআরই
আমির মোগিমি

75

স্প্রিং সিকিউরিটি ক্রিপ্টো মডিউলটি ব্যবহার করার বিষয়টি বিবেচনা করুন

স্প্রিং সিকিউরিটি ক্রিপ্টো মডিউলটি প্রতিসম এনক্রিপশন, কী উত্পন্নকরণ এবং পাসওয়ার্ড এনকোডিংয়ের জন্য সহায়তা সরবরাহ করে। কোডটি মডিউলটির অংশ হিসাবে বিতরণ করা হয়েছে তবে অন্য কোনও স্প্রিং সিকিউরিটি (বা স্প্রিং) কোডের উপর নির্ভরতা নেই has

এটি এনক্রিপশনের জন্য একটি সাধারণ বিমূর্তি সরবরাহ করে এবং এখানে যা প্রয়োজন তা মিলছে বলে মনে হয়,

"মানক" এনক্রিপশন পদ্ধতিটি পিকেসিএস # 5 এর পিবিকেডিএফ 2 (পাসওয়ার্ড ভিত্তিক কী ডেরিভেশন ফাংশন # 2) ব্যবহার করে 256-বিট এএসই হয়। এই পদ্ধতিতে জাভা requires প্রয়োজন the সিক্রেটকি তৈরি করার জন্য ব্যবহৃত পাসওয়ার্ডটি নিরাপদ স্থানে রাখা উচিত এবং ভাগ করা উচিত নয়। আপনার এনক্রিপ্ট করা ডেটা আপোস করা হয় এমন ইভেন্টে কীটির বিরুদ্ধে অভিধান আক্রমণ প্রতিরোধ করতে লবণ ব্যবহার করা হয়। একটি 16-বাইট র্যান্ডম ইনিশিয়েশন ভেক্টর প্রয়োগ করা হয় যাতে প্রতিটি এনক্রিপ্ট করা বার্তা অনন্য।

ইন্টার্নালদের দিকে নজর দেওয়া ইরিকসনের উত্তরের অনুরূপ একটি কাঠামো প্রকাশ করে ।

প্রশ্নে উল্লিখিত হিসাবে, এর জন্য জাভা ক্রিপ্টোগ্রাফি এক্সটেনশন (জেসিই) সীমাহীন শক্তি জুরিডিশন নীতিও প্রয়োজন (অন্যথায় আপনি মুখোমুখি হবেন InvalidKeyException: Illegal Key Size)। এটি জাভা 6 , জাভা 7 এবং জাভা 8 এর জন্য ডাউনলোডযোগ্য ।

ব্যবহারের উদাহরণ

import org.springframework.security.crypto.encrypt.Encryptors;
import org.springframework.security.crypto.encrypt.TextEncryptor;
import org.springframework.security.crypto.keygen.KeyGenerators;

public class CryptoExample {
    public static void main(String[] args) {
        final String password = "I AM SHERLOCKED";  
        final String salt = KeyGenerators.string().generateKey();

        TextEncryptor encryptor = Encryptors.text(password, salt);      
        System.out.println("Salt: \"" + salt + "\"");

        String textToEncrypt = "*royal secrets*";
        System.out.println("Original text: \"" + textToEncrypt + "\"");

        String encryptedText = encryptor.encrypt(textToEncrypt);
        System.out.println("Encrypted text: \"" + encryptedText + "\"");

        // Could reuse encryptor but wanted to show reconstructing TextEncryptor
        TextEncryptor decryptor = Encryptors.text(password, salt);
        String decryptedText = decryptor.decrypt(encryptedText);
        System.out.println("Decrypted text: \"" + decryptedText + "\"");

        if(textToEncrypt.equals(decryptedText)) {
            System.out.println("Success: decrypted text matches");
        } else {
            System.out.println("Failed: decrypted text does not match");
        }       
    }
}

এবং নমুনা আউটপুট,

লবণ: "feacbc02a3a697b0"
মূল পাঠ্য: "* রয়েল সিক্রেটস *"
এনক্রিপ্ট করা পাঠ্য: "7c73c5a83fa580b5d6f8208768adc931ef3123291ac8bc335a1277a39d256d9a" 
ডিক্রিপ্ট করা পাঠ্য: "* রয়েল সিক্রেটস *"
সাফল্য: ডিক্রিপ্ট করা পাঠ্য মিল

আপনি কি সমস্ত বসন্ত লোড না করে মডিউলটি ব্যবহার করতে পারেন? তারা মনে হয় না যে তারা জার ফাইলগুলি ডাউনলোডের জন্য উপলব্ধ করেছে।
theglauber

5
@ থেগ্লাব্বার হ্যাঁ, আপনি স্প্রিং সুরক্ষা বা স্প্রিং ফ্রেমওয়ার্ক ছাড়াই মডিউলটি ব্যবহার করতে পারেন। দিকে তাকিয়ে থেকে পম , শুধুমাত্র রানটাইম নির্ভরতা Apache হয় Commons-লগিং 1.1.1 । আপনি মাভেনের সাথে জারে টানতে পারেন বা সরকারী বাইনারি রেপো থেকে সরাসরি এটি ডাউনলোড করতে পারেন ( স্প্রিং বাইনারিগুলির আরও তথ্যের জন্য স্প্রিং 4 বাইনারি ডাউনলোড করুন)।
জন ম্যাকার্থি

1
কী দৈর্ঘ্য 128-বিট সেট করা সম্ভব? প্রতিটি পিসিতে সুরক্ষা ফোল্ডারটি পরিবর্তন করা আমার পক্ষে কোনও বিকল্প নয়।
ইভানআরএফ

1
@ ইভানআরএফ দুঃখিত, এটির মতো দেখাচ্ছে না। 256 হার্ড কোডেড হয় উৎস
জন ম্যাকার্থি

2
NULL_IV_GENERATORস্প্রিং ইউটিলিটি দ্বারা ব্যবহৃত নিরাপদ নয়। যদি অ্যাপ্লিকেশনটি IV সরবরাহ না করে তবে সরবরাহকারী এটি চয়ন করুন এবং সূচনা করার পরে এটি অনুসন্ধান করুন।
এরিকসন

32

এরিকসনের পরামর্শগুলি পড়ার পরে এবং এখানে আরও কয়েকজন পোস্টিং এবং এই উদাহরণ থেকে আমি কী পারলাম তা সংগ্রহ করার পরে, আমি প্রস্তাবিত পরিবর্তনগুলি সহ ডগের কোড আপডেট করার চেষ্টা করেছি। এটিকে আরও ভাল করে তুলতে নির্দ্বিধায় এডিট করুন।

  • আরম্ভের ভেক্টর আর স্থির হয় না
  • এনক্রিপশন কীটি ইরিকসন থেকে কোড ব্যবহার করে উত্পন্ন
  • সিকিউরআরন্ডম () ব্যবহার করে সেটআপ এনক্রিপ্ট () এ 8 বাইট লবণ তৈরি করা হয়
  • এনক্রিপশন লবণ এবং পাসওয়ার্ড থেকে ডিক্রিপশন কী উত্পন্ন হয়
  • ডিক্রিপশন সাইফারটি ডিক্রিপশন কী এবং আরম্ভকরণ ভেক্টর থেকে উত্পন্ন হয়
  • org.apache.com মনের কোডেক হেক্স রুটিনের পরিবর্তে হেক্স বার্জডিং সরানো হয়েছে

কিছু নোট: এটি 128 বিট এনক্রিপশন কী ব্যবহার করে - জাভা দৃশ্যত-বাক্সের বাইরে 256 বিট এনক্রিপশন করবে না। 256 বাস্তবায়নের জন্য জাভা ইনস্টল ডিরেক্টরিতে কিছু অতিরিক্ত ফাইল ইনস্টল করা প্রয়োজন।

এছাড়াও, আমি কোনও ক্রিপ্টো ব্যক্তি নই। চিন্তা - ভাবনা.

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.AlgorithmParameters;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.InvalidParameterSpecException;
import java.security.spec.KeySpec;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.CipherOutputStream;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;

import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Hex;

public class Crypto
{
    String mPassword = null;
    public final static int SALT_LEN = 8;
    byte [] mInitVec = null;
    byte [] mSalt = null;
    Cipher mEcipher = null;
    Cipher mDecipher = null;
    private final int KEYLEN_BITS = 128; // see notes below where this is used.
    private final int ITERATIONS = 65536;
    private final int MAX_FILE_BUF = 1024;

    /**
     * create an object with just the passphrase from the user. Don't do anything else yet 
     * @param password
     */
    public Crypto (String password)
    {
        mPassword = password;
    }

    /**
     * return the generated salt for this object
     * @return
     */
    public byte [] getSalt ()
    {
        return (mSalt);
    }

    /**
     * return the initialization vector created from setupEncryption
     * @return
     */
    public byte [] getInitVec ()
    {
        return (mInitVec);
    }

    /**
     * debug/print messages
     * @param msg
     */
    private void Db (String msg)
    {
        System.out.println ("** Crypt ** " + msg);
    }

    /**
     * this must be called after creating the initial Crypto object. It creates a salt of SALT_LEN bytes
     * and generates the salt bytes using secureRandom().  The encryption secret key is created 
     * along with the initialization vectory. The member variable mEcipher is created to be used
     * by the class later on when either creating a CipherOutputStream, or encrypting a buffer
     * to be written to disk.
     *  
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeySpecException
     * @throws NoSuchPaddingException
     * @throws InvalidParameterSpecException
     * @throws IllegalBlockSizeException
     * @throws BadPaddingException
     * @throws UnsupportedEncodingException
     * @throws InvalidKeyException
     */
    public void setupEncrypt () throws NoSuchAlgorithmException, 
                                                           InvalidKeySpecException, 
                                                           NoSuchPaddingException, 
                                                           InvalidParameterSpecException, 
                                                           IllegalBlockSizeException, 
                                                           BadPaddingException, 
                                                           UnsupportedEncodingException, 
                                                           InvalidKeyException
    {
        SecretKeyFactory factory = null;
        SecretKey tmp = null;

        // crate secureRandom salt and store  as member var for later use
         mSalt = new byte [SALT_LEN];
        SecureRandom rnd = new SecureRandom ();
        rnd.nextBytes (mSalt);
        Db ("generated salt :" + Hex.encodeHexString (mSalt));

        factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");

        /* Derive the key, given password and salt. 
         * 
         * in order to do 256 bit crypto, you have to muck with the files for Java's "unlimted security"
         * The end user must also install them (not compiled in) so beware. 
         * see here:  http://www.javamex.com/tutorials/cryptography/unrestricted_policy_files.shtml
         */
        KeySpec spec = new PBEKeySpec (mPassword.toCharArray (), mSalt, ITERATIONS, KEYLEN_BITS);
        tmp = factory.generateSecret (spec);
        SecretKey secret = new SecretKeySpec (tmp.getEncoded(), "AES");

        /* Create the Encryption cipher object and store as a member variable
         */
        mEcipher = Cipher.getInstance ("AES/CBC/PKCS5Padding");
        mEcipher.init (Cipher.ENCRYPT_MODE, secret);
        AlgorithmParameters params = mEcipher.getParameters ();

        // get the initialization vectory and store as member var 
        mInitVec = params.getParameterSpec (IvParameterSpec.class).getIV();

        Db ("mInitVec is :" + Hex.encodeHexString (mInitVec));
    }



    /**
     * If a file is being decrypted, we need to know the pasword, the salt and the initialization vector (iv). 
     * We have the password from initializing the class. pass the iv and salt here which is
     * obtained when encrypting the file initially.
     *   
     * @param initvec
     * @param salt
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeySpecException
     * @throws NoSuchPaddingException
     * @throws InvalidKeyException
     * @throws InvalidAlgorithmParameterException
     * @throws DecoderException
     */
    public void setupDecrypt (String initvec, String salt) throws NoSuchAlgorithmException, 
                                                                                       InvalidKeySpecException, 
                                                                                       NoSuchPaddingException, 
                                                                                       InvalidKeyException, 
                                                                                       InvalidAlgorithmParameterException, 
                                                                                       DecoderException
    {
        SecretKeyFactory factory = null;
        SecretKey tmp = null;
        SecretKey secret = null;

        // since we pass it as a string of input, convert to a actual byte buffer here
        mSalt = Hex.decodeHex (salt.toCharArray ());
       Db ("got salt " + Hex.encodeHexString (mSalt));

        // get initialization vector from passed string
        mInitVec = Hex.decodeHex (initvec.toCharArray ());
        Db ("got initvector :" + Hex.encodeHexString (mInitVec));


        /* Derive the key, given password and salt. */
        // in order to do 256 bit crypto, you have to muck with the files for Java's "unlimted security"
        // The end user must also install them (not compiled in) so beware. 
        // see here: 
      // http://www.javamex.com/tutorials/cryptography/unrestricted_policy_files.shtml
        factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
        KeySpec spec = new PBEKeySpec(mPassword.toCharArray (), mSalt, ITERATIONS, KEYLEN_BITS);

        tmp = factory.generateSecret(spec);
        secret = new SecretKeySpec(tmp.getEncoded(), "AES");

        /* Decrypt the message, given derived key and initialization vector. */
        mDecipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        mDecipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(mInitVec));
    }


    /**
     * This is where we write out the actual encrypted data to disk using the Cipher created in setupEncrypt().
     * Pass two file objects representing the actual input (cleartext) and output file to be encrypted.
     * 
     * there may be a way to write a cleartext header to the encrypted file containing the salt, but I ran
     * into uncertain problems with that. 
     *  
     * @param input - the cleartext file to be encrypted
     * @param output - the encrypted data file
     * @throws IOException
     * @throws IllegalBlockSizeException
     * @throws BadPaddingException
     */
    public void WriteEncryptedFile (File input, File output) throws 
                                                                                          IOException, 
                                                                                          IllegalBlockSizeException, 
                                                                                          BadPaddingException
    {
        FileInputStream fin;
        FileOutputStream fout;
        long totalread = 0;
        int nread = 0;
        byte [] inbuf = new byte [MAX_FILE_BUF];

        fout = new FileOutputStream (output);
        fin = new FileInputStream (input);

        while ((nread = fin.read (inbuf)) > 0 )
        {
            Db ("read " + nread + " bytes");
            totalread += nread;

            // create a buffer to write with the exact number of bytes read. Otherwise a short read fills inbuf with 0x0
            // and results in full blocks of MAX_FILE_BUF being written. 
            byte [] trimbuf = new byte [nread];
            for (int i = 0; i < nread; i++)
                trimbuf[i] = inbuf[i];

            // encrypt the buffer using the cipher obtained previosly
            byte [] tmp = mEcipher.update (trimbuf);

            // I don't think this should happen, but just in case..
            if (tmp != null)
                fout.write (tmp);
        }

        // finalize the encryption since we've done it in blocks of MAX_FILE_BUF
        byte [] finalbuf = mEcipher.doFinal ();
        if (finalbuf != null)
            fout.write (finalbuf);

        fout.flush();
        fin.close();
        fout.close();

        Db ("wrote " + totalread + " encrypted bytes");
    }


    /**
     * Read from the encrypted file (input) and turn the cipher back into cleartext. Write the cleartext buffer back out
     * to disk as (output) File.
     * 
     * I left CipherInputStream in here as a test to see if I could mix it with the update() and final() methods of encrypting
     *  and still have a correctly decrypted file in the end. Seems to work so left it in.
     *  
     * @param input - File object representing encrypted data on disk 
     * @param output - File object of cleartext data to write out after decrypting
     * @throws IllegalBlockSizeException
     * @throws BadPaddingException
     * @throws IOException
     */
    public void ReadEncryptedFile (File input, File output) throws 
                                                                                                                                            IllegalBlockSizeException, 
                                                                                                                                            BadPaddingException, 
                                                                                                                                            IOException
    {
        FileInputStream fin; 
        FileOutputStream fout;
        CipherInputStream cin;
        long totalread = 0;
        int nread = 0;
        byte [] inbuf = new byte [MAX_FILE_BUF];

        fout = new FileOutputStream (output);
        fin = new FileInputStream (input);

        // creating a decoding stream from the FileInputStream above using the cipher created from setupDecrypt()
        cin = new CipherInputStream (fin, mDecipher);

        while ((nread = cin.read (inbuf)) > 0 )
        {
            Db ("read " + nread + " bytes");
            totalread += nread;

            // create a buffer to write with the exact number of bytes read. Otherwise a short read fills inbuf with 0x0
            byte [] trimbuf = new byte [nread];
            for (int i = 0; i < nread; i++)
                trimbuf[i] = inbuf[i];

            // write out the size-adjusted buffer
            fout.write (trimbuf);
        }

        fout.flush();
        cin.close();
        fin.close ();       
        fout.close();   

        Db ("wrote " + totalread + " encrypted bytes");
    }


    /**
     * adding main() for usage demonstration. With member vars, some of the locals would not be needed
     */
    public static void main(String [] args)
    {

        // create the input.txt file in the current directory before continuing
        File input = new File ("input.txt");
        File eoutput = new File ("encrypted.aes");
        File doutput = new File ("decrypted.txt");
        String iv = null;
        String salt = null;
        Crypto en = new Crypto ("mypassword");

        /*
         * setup encryption cipher using password. print out iv and salt
         */
        try
      {
          en.setupEncrypt ();
          iv = Hex.encodeHexString (en.getInitVec ()).toUpperCase ();
          salt = Hex.encodeHexString (en.getSalt ()).toUpperCase ();
      }
      catch (InvalidKeyException e)
      {
          e.printStackTrace();
      }
      catch (NoSuchAlgorithmException e)
      {
          e.printStackTrace();
      }
      catch (InvalidKeySpecException e)
      {
          e.printStackTrace();
      }
      catch (NoSuchPaddingException e)
      {
          e.printStackTrace();
      }
      catch (InvalidParameterSpecException e)
      {
          e.printStackTrace();
      }
      catch (IllegalBlockSizeException e)
      {
          e.printStackTrace();
      }
      catch (BadPaddingException e)
      {
          e.printStackTrace();
      }
      catch (UnsupportedEncodingException e)
      {
          e.printStackTrace();
      }

        /*
         * write out encrypted file
         */
        try
      {
          en.WriteEncryptedFile (input, eoutput);
          System.out.printf ("File encrypted to " + eoutput.getName () + "\niv:" + iv + "\nsalt:" + salt + "\n\n");
      }
      catch (IllegalBlockSizeException e)
      {
          e.printStackTrace();
      }
      catch (BadPaddingException e)
      {
          e.printStackTrace();
      }
      catch (IOException e)
      {
          e.printStackTrace();
      }


        /*
         * decrypt file
         */
        Crypto dc = new Crypto ("mypassword");
        try
      {
          dc.setupDecrypt (iv, salt);
      }
      catch (InvalidKeyException e)
      {
          e.printStackTrace();
      }
      catch (NoSuchAlgorithmException e)
      {
          e.printStackTrace();
      }
      catch (InvalidKeySpecException e)
      {
          e.printStackTrace();
      }
      catch (NoSuchPaddingException e)
      {
          e.printStackTrace();
      }
      catch (InvalidAlgorithmParameterException e)
      {
          e.printStackTrace();
      }
      catch (DecoderException e)
      {
          e.printStackTrace();
      }

        /*
         * write out decrypted file
         */
        try
      {
          dc.ReadEncryptedFile (eoutput, doutput);
          System.out.println ("decryption finished to " + doutput.getName ());
      }
      catch (IllegalBlockSizeException e)
      {
          e.printStackTrace();
      }
      catch (BadPaddingException e)
      {
          e.printStackTrace();
      }
      catch (IOException e)
      {
          e.printStackTrace();
      }
   }


}

13
এটি মূলত এরিকসনের মতোই একই উত্তর, এটি একটি - এর সাথে-ভাল-প্রোগ্রামড-ইন-আমার মতামত - মোড়ক দ্বারা ঘেরাও নয়। printStackTrace()
মার্টেন বোদেউয়েস

2
@ আওলস্টেড - এটি একটি দুর্দান্ত উত্তর। এটি মেমরিতে সমস্ত কিছু না রেখে বাইট বাফারকে এনক্রিপ্ট করে কীভাবে একটি স্ট্রিম এনক্রিপ্ট করবেন তা দেখায়। এরিকসনের উত্তর বড় ফাইলগুলির জন্য কাজ করবে না, যা মেমরির সাথে খাপ খায় না। সুতরাং +1 wufoo করতে। :)
ডিনামোকাজ

2
ব্যবহারের @dynamokaj CipherInputStreamএবং CipherOutputStreamঅনেক সময় একটি সমস্যা নয়। টেবিলের নীচে সমস্ত ব্যতিক্রম বদলানো একটি সমস্যা। হঠাৎ লবণের ক্ষেত্র হয়ে উঠেছে এবং চতুর্থ প্রয়োজনীয়তা এটি একটি সমস্যা। এটি জাভা কোডিং কনভেনশনগুলি অনুসরণ করে না এমন সমস্যা। এবং এটি কেবল ফাইলগুলিতে কাজ করে যখন এটি জিজ্ঞাসা করা হয়নি এটি একটি সমস্যা। এবং বাকী কোডটি মূলত একটি অনুলিপিও সহায়তা করে না। তবে সম্ভবত এটি আরও উন্নত করার জন্য আমি এটি টুইট করব, যেমনটি পরামর্শ দেওয়া হয়েছে ...
মার্টেন বোদেউইস

@ ওয়ালস্টেড আমি সম্মত হই যে কোডিংটি আরও ভাল দেখতে পেতাম আমি এটিকে 1/4 বা কিছুতে কেটে ফেলেছি তবে আমি পছন্দ করি যে তিনি আমাকে সিফার ইনপুটস্ট্রিম এবং সাইফার আউটপুট স্ট্রিমের সাথে পরিচয় করিয়েছিলেন, যেহেতু গতকাল আমার যা প্রয়োজন তা ছিল! ;)
ডায়নামোকাজ

দুবার কেন? fout.close (); fout.close ();
মারিয়ান প্যাডজিওচ

7

বাইট অ্যারে থেকে আপনার নিজস্ব কী তৈরি করা সহজ:

byte[] raw = ...; // 32 bytes in size for a 256 bit key
Key skey = new javax.crypto.spec.SecretKeySpec(raw, "AES");

তবে 256-বিট কী তৈরি করা যথেষ্ট নয়। কী জেনারেটর যদি আপনার জন্য 256-বিট কী তৈরি করতে না পারে তবে Cipherক্লাসটি সম্ভবত এএস 256-বিটকে সমর্থন করে না। আপনি বলছেন যে আপনার কাছে সীমাহীন এখতিয়ার প্যাচ ইনস্টল করা আছে, সুতরাং AES-256 সাইফারটিকে সমর্থন করা উচিত (তবে 256-বিট কীগুলি খুব বেশি হওয়া উচিত, তাই এটি কনফিগারেশন সমস্যা হতে পারে)।

Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, skey);
byte[] encrypted = cipher.doFinal(plainText.getBytes());

AES-256 সহায়তার অভাবে কাজ করার জন্য হ'ল AES-256 এর অবাধে উপলভ্য বাস্তবায়ন নেওয়া এবং এটি কাস্টম সরবরাহকারী হিসাবে ব্যবহার করা। এর মধ্যে আপনার নিজের Providerসাবক্লাস তৈরি করা এবং এটি ব্যবহার করা জড়িত Cipher.getInstance(String, Provider)। তবে এটি একটি জড়িত প্রক্রিয়া হতে পারে।


5
আপনার সর্বদা মোড এবং প্যাডিং অ্যালগরিদম নির্দেশ করা উচিত। জাভা ডিফল্টরূপে অনিরাপদ ইসিবি মোড ব্যবহার করে।
মার্টেন বোদেউয়েস

আপনি নিজের সরবরাহকারী তৈরি করতে পারবেন না, সরবরাহকারীদের স্বাক্ষর করতে হবে (আমি বিশ্বাস করতে পারি না আমি এই ভুলটি প্রথমে পড়েছি)। এমনকি যদি আপনি পারতেন তবে কী আকারের সীমাবদ্ধতা প্রয়োগকারীর মধ্যে রয়েছে Cipher, সরবরাহকারী নিজেই নয়। আপনি জাভা 8 এবং নিম্নে AES-256 ব্যবহার করতে পারেন তবে আপনার মালিকানাধীন API ব্যবহার করা দরকার। বা একটি রানটাইম যা অবশ্যই মূল আকারের উপর বিধিনিষেধ সৃষ্টি করে না।
মার্টেন বোদেউয়েস

ওপেনজেডিকে (এবং অ্যান্ড্রয়েড) এর সাম্প্রতিক সংস্করণগুলিতে আপনার নিজের সুরক্ষা / ক্রিপ্টো সরবরাহকারী যুক্ত করার ক্ষেত্রে কোনও বিধিনিষেধ নেই। তবে আপনি অবশ্যই নিজের ঝুঁকিতে এটি করেন। আপনি যদি নিজের লাইব্রেরিগুলিকে টু ডেট রাখতে ভুলে যান তবে আপনি নিজেকে সুরক্ষা ঝুঁকিতে ফেলতে পারেন।
মার্টেন বোদেউয়েস

1
@ মার্টেনবোডওয়েস + ওপেনজেডিকে 'সীমাবদ্ধ ক্রিপ্টো নীতি' ইস্যুটি প্রথম স্থানে ছিল না এবং ওরাকল জেডিকে এক বছর আগে এটি 8u161 এবং 9 এর জন্য সরিয়ে নিয়েছিল (এবং সম্ভবত কিছুটা এখনই কেবল বেতন-প্রদানের সংস্করণ রয়েছে তবে আমি সেগুলি পরীক্ষা করে দেখিনি)
dave_thompson_085

6

আমি অতীতে যা করেছি তা হ্যাশ হ'ল SHA256 এর মতো কোনও কিছুর মাধ্যমে হ্যাশ থেকে বাইটগুলি কী কী বাইটে বের করুন []।

আপনার বাইট করার পরে [] আপনি সহজভাবে এটি করতে পারেন:

SecretKeySpec key = new SecretKeySpec(keyBytes, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] encryptedBytes = cipher.doFinal(clearText.getBytes());

12
অন্যদের জন্য: এটি খুব নিরাপদ পদ্ধতি নয়। আপনার পিকেসিএস # 5 এ নির্দিষ্ট করা PBKDF 2 ব্যবহার করা উচিত। এরিকসন কীভাবে উপরে এটি করবেন তা বলেছেন। ডার্কস্কুইডের পদ্ধতিটি পাসওয়ার্ড আক্রমণে ঝুঁকিপূর্ণ এবং আপনার প্লেইলেস্টেক্সের আকারটি এইএসের ব্লক আকারের একাধিক (128 বিট) না হওয়া পর্যন্ত কাজ করবে না কারণ সে প্যাডিং ছেড়েছে। এছাড়াও এটি মোড নির্দিষ্ট করে না; উদ্বেগের জন্য উইকিপিডিয়ায় ব্লক সাইফার অপারেশন মোডগুলি পড়ুন।
Hut8

1
@ ডার্কস্কুইড Cipher aes256 = Cipher.getInstance("AES/OFB/NoPadding"); MessageDigest keyDigest = MessageDigest.getInstance("SHA-256"); byte[] keyHash = keyDigest.digest(secret.getBytes("UTF-8")); SecretKeySpec key = new SecretKeySpec(keyHash, "AES"); aes256.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(initializationVector)); আমিও আপনার উত্তরের পরামর্শ অনুসারে একই কাজ করছি তবে আমি এখনও এই জাভা.সিকিউরিটিটি দিয়ে শেষ করছি n অবৈধ কেই এক্সেপশন: অবৈধ মূল আকারটি কি জেসিই পলিসি ফাইলটি ডাউনলোড করা বাধ্যতামূলক?
নিরঞ্জন সুব্রমনিয়ান

2
যে কোনও ধরনের উত্পাদন পরিবেশে এই পদ্ধতিটি ব্যবহার করবেন না। পাসওয়ার্ড-ভিত্তিক এনক্রিপশন দিয়ে শুরু করার সময় প্রচুর ব্যবহারকারী কোডের দেয়াল দেখে অভিভূত হন এবং অভিধান আক্রমণ এবং অন্যান্য সহজ হ্যাকগুলি কীভাবে কাজ করে তা বুঝতে পারেন না। যদিও এটি শিখতে হতাশ হতে পারে, এটি গবেষণা করার জন্য এটি সার্থক বিনিয়োগ। এখানে একটি ভাল প্রাথমিক নিবন্ধ: adambard.com/blog/3-wrong-ways-to-store-a-password
আইসডড্যান্ট

1

@ উইফুর সম্পাদনাগুলিতে যুক্ত করে, নিম্নলিখিত সংস্করণটি বিভিন্ন ফাইলগুলির সাথে কাজ করা আরও সহজ করার জন্য ফাইলগুলির চেয়ে ইনপুট স্ট্রিম ব্যবহার করে। এটি ফাইলের শুরুতে IV এবং সল্ট সংরক্ষণ করে, যাতে এটি কেবল পাসওয়ার্ড ট্র্যাক করার প্রয়োজন হয় to যেহেতু চতুর্থ এবং লবণের গোপনীয়তার প্রয়োজন নেই, তাই এটি জীবনকে একটু সহজ করে তোলে।

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

import java.security.AlgorithmParameters;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.InvalidParameterSpecException;
import java.security.spec.KeySpec;

import java.util.logging.Level;
import java.util.logging.Logger;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;

public class AES {
    public final static int SALT_LEN     = 8;
    static final String     HEXES        = "0123456789ABCDEF";
    String                  mPassword    = null;
    byte[]                  mInitVec     = null;
    byte[]                  mSalt        = new byte[SALT_LEN];
    Cipher                  mEcipher     = null;
    Cipher                  mDecipher    = null;
    private final int       KEYLEN_BITS  = 128;    // see notes below where this is used.
    private final int       ITERATIONS   = 65536;
    private final int       MAX_FILE_BUF = 1024;

    /**
     * create an object with just the passphrase from the user. Don't do anything else yet
     * @param password
     */
    public AES(String password) {
        mPassword = password;
    }

    public static String byteToHex(byte[] raw) {
        if (raw == null) {
            return null;
        }

        final StringBuilder hex = new StringBuilder(2 * raw.length);

        for (final byte b : raw) {
            hex.append(HEXES.charAt((b & 0xF0) >> 4)).append(HEXES.charAt((b & 0x0F)));
        }

        return hex.toString();
    }

    public static byte[] hexToByte(String hexString) {
        int    len = hexString.length();
        byte[] ba  = new byte[len / 2];

        for (int i = 0; i < len; i += 2) {
            ba[i / 2] = (byte) ((Character.digit(hexString.charAt(i), 16) << 4)
                                + Character.digit(hexString.charAt(i + 1), 16));
        }

        return ba;
    }

    /**
     * debug/print messages
     * @param msg
     */
    private void Db(String msg) {
        System.out.println("** Crypt ** " + msg);
    }

    /**
     * This is where we write out the actual encrypted data to disk using the Cipher created in setupEncrypt().
     * Pass two file objects representing the actual input (cleartext) and output file to be encrypted.
     *
     * there may be a way to write a cleartext header to the encrypted file containing the salt, but I ran
     * into uncertain problems with that.
     *
     * @param input - the cleartext file to be encrypted
     * @param output - the encrypted data file
     * @throws IOException
     * @throws IllegalBlockSizeException
     * @throws BadPaddingException
     */
    public void WriteEncryptedFile(InputStream inputStream, OutputStream outputStream)
            throws IOException, IllegalBlockSizeException, BadPaddingException {
        try {
            long             totalread = 0;
            int              nread     = 0;
            byte[]           inbuf     = new byte[MAX_FILE_BUF];
            SecretKeyFactory factory   = null;
            SecretKey        tmp       = null;

            // crate secureRandom salt and store  as member var for later use
            mSalt = new byte[SALT_LEN];

            SecureRandom rnd = new SecureRandom();

            rnd.nextBytes(mSalt);
            Db("generated salt :" + byteToHex(mSalt));
            factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");

            /*
             *  Derive the key, given password and salt.
             *
             * in order to do 256 bit crypto, you have to muck with the files for Java's "unlimted security"
             * The end user must also install them (not compiled in) so beware.
             * see here:  http://www.javamex.com/tutorials/cryptography/unrestricted_policy_files.shtml
             */
            KeySpec spec = new PBEKeySpec(mPassword.toCharArray(), mSalt, ITERATIONS, KEYLEN_BITS);

            tmp = factory.generateSecret(spec);

            SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");

            /*
             *  Create the Encryption cipher object and store as a member variable
             */
            mEcipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            mEcipher.init(Cipher.ENCRYPT_MODE, secret);

            AlgorithmParameters params = mEcipher.getParameters();

            // get the initialization vectory and store as member var
            mInitVec = params.getParameterSpec(IvParameterSpec.class).getIV();
            Db("mInitVec is :" + byteToHex(mInitVec));
            outputStream.write(mSalt);
            outputStream.write(mInitVec);

            while ((nread = inputStream.read(inbuf)) > 0) {
                Db("read " + nread + " bytes");
                totalread += nread;

                // create a buffer to write with the exact number of bytes read. Otherwise a short read fills inbuf with 0x0
                // and results in full blocks of MAX_FILE_BUF being written.
                byte[] trimbuf = new byte[nread];

                for (int i = 0; i < nread; i++) {
                    trimbuf[i] = inbuf[i];
                }

                // encrypt the buffer using the cipher obtained previosly
                byte[] tmpBuf = mEcipher.update(trimbuf);

                // I don't think this should happen, but just in case..
                if (tmpBuf != null) {
                    outputStream.write(tmpBuf);
                }
            }

            // finalize the encryption since we've done it in blocks of MAX_FILE_BUF
            byte[] finalbuf = mEcipher.doFinal();

            if (finalbuf != null) {
                outputStream.write(finalbuf);
            }

            outputStream.flush();
            inputStream.close();
            outputStream.close();
            outputStream.close();
            Db("wrote " + totalread + " encrypted bytes");
        } catch (InvalidKeyException ex) {
            Logger.getLogger(AES.class.getName()).log(Level.SEVERE, null, ex);
        } catch (InvalidParameterSpecException ex) {
            Logger.getLogger(AES.class.getName()).log(Level.SEVERE, null, ex);
        } catch (NoSuchAlgorithmException ex) {
            Logger.getLogger(AES.class.getName()).log(Level.SEVERE, null, ex);
        } catch (NoSuchPaddingException ex) {
            Logger.getLogger(AES.class.getName()).log(Level.SEVERE, null, ex);
        } catch (InvalidKeySpecException ex) {
            Logger.getLogger(AES.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    /**
     * Read from the encrypted file (input) and turn the cipher back into cleartext. Write the cleartext buffer back out
     * to disk as (output) File.
     *
     * I left CipherInputStream in here as a test to see if I could mix it with the update() and final() methods of encrypting
     *  and still have a correctly decrypted file in the end. Seems to work so left it in.
     *
     * @param input - File object representing encrypted data on disk
     * @param output - File object of cleartext data to write out after decrypting
     * @throws IllegalBlockSizeException
     * @throws BadPaddingException
     * @throws IOException
     */
    public void ReadEncryptedFile(InputStream inputStream, OutputStream outputStream)
            throws IllegalBlockSizeException, BadPaddingException, IOException {
        try {
            CipherInputStream cin;
            long              totalread = 0;
            int               nread     = 0;
            byte[]            inbuf     = new byte[MAX_FILE_BUF];

            // Read the Salt
            inputStream.read(this.mSalt);
            Db("generated salt :" + byteToHex(mSalt));

            SecretKeyFactory factory = null;
            SecretKey        tmp     = null;
            SecretKey        secret  = null;

            factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");

            KeySpec spec = new PBEKeySpec(mPassword.toCharArray(), mSalt, ITERATIONS, KEYLEN_BITS);

            tmp    = factory.generateSecret(spec);
            secret = new SecretKeySpec(tmp.getEncoded(), "AES");

            /* Decrypt the message, given derived key and initialization vector. */
            mDecipher = Cipher.getInstance("AES/CBC/PKCS5Padding");

            // Set the appropriate size for mInitVec by Generating a New One
            AlgorithmParameters params = mDecipher.getParameters();

            mInitVec = params.getParameterSpec(IvParameterSpec.class).getIV();

            // Read the old IV from the file to mInitVec now that size is set.
            inputStream.read(this.mInitVec);
            Db("mInitVec is :" + byteToHex(mInitVec));
            mDecipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(mInitVec));

            // creating a decoding stream from the FileInputStream above using the cipher created from setupDecrypt()
            cin = new CipherInputStream(inputStream, mDecipher);

            while ((nread = cin.read(inbuf)) > 0) {
                Db("read " + nread + " bytes");
                totalread += nread;

                // create a buffer to write with the exact number of bytes read. Otherwise a short read fills inbuf with 0x0
                byte[] trimbuf = new byte[nread];

                for (int i = 0; i < nread; i++) {
                    trimbuf[i] = inbuf[i];
                }

                // write out the size-adjusted buffer
                outputStream.write(trimbuf);
            }

            outputStream.flush();
            cin.close();
            inputStream.close();
            outputStream.close();
            Db("wrote " + totalread + " encrypted bytes");
        } catch (Exception ex) {
            Logger.getLogger(AES.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    /**
     * adding main() for usage demonstration. With member vars, some of the locals would not be needed
     */
    public static void main(String[] args) {

        // create the input.txt file in the current directory before continuing
        File   input   = new File("input.txt");
        File   eoutput = new File("encrypted.aes");
        File   doutput = new File("decrypted.txt");
        String iv      = null;
        String salt    = null;
        AES    en      = new AES("mypassword");

        /*
         * write out encrypted file
         */
        try {
            en.WriteEncryptedFile(new FileInputStream(input), new FileOutputStream(eoutput));
            System.out.printf("File encrypted to " + eoutput.getName() + "\niv:" + iv + "\nsalt:" + salt + "\n\n");
        } catch (IllegalBlockSizeException | BadPaddingException | IOException e) {
            e.printStackTrace();
        }

        /*
         * decrypt file
         */
        AES dc = new AES("mypassword");

        /*
         * write out decrypted file
         */
        try {
            dc.ReadEncryptedFile(new FileInputStream(eoutput), new FileOutputStream(doutput));
            System.out.println("decryption finished to " + doutput.getName());
        } catch (IllegalBlockSizeException | BadPaddingException | IOException e) {
            e.printStackTrace();
        }
    }
}

1
এই সমাধানটি কিছু বিশ্রী বাফার হ্যান্ডলিং এবং একেবারে সাব-পার-ব্যতিক্রম হ্যান্ডলিং ব্যবহার করে বলে মনে হচ্ছে, মূলত তাদের লগইন করা এবং তারপরে সেগুলি ভুলে যাওয়া। সতর্কতা অবলম্বন করুন যে সিবিসি ব্যবহার করা ফাইলগুলির জন্য ঠিক আছে তবে পরিবহন সুরক্ষার জন্য নয়। PBKDF2 এবং AES ব্যবহার করে অবশ্যই রক্ষা করা যেতে পারে, সেই দিক থেকে এটি কোনও সমাধানের জন্য একটি ভাল ভিত্তি হতে পারে।
মার্টেন বোদেউয়েস

1

(অন্যদের জন্য অনুরূপ প্রয়োজন সহকারী হতে পারে)

AES-256-CBCজাভাতে এনক্রিপ্ট এবং ডিক্রিপ্ট ব্যবহার করার জন্য আমার অনুরূপ প্রয়োজনীয়তা ছিল ।

256-বাইট এনক্রিপশন / ডিক্রিপশন অর্জন করতে (বা নির্দিষ্ট করতে), Java Cryptography Extension (JCE)নীতিতে সেট করা উচিত"Unlimited"

এটি (জেডিকে জন্য) বা (জেআরই এর জন্য ) java.securityঅধীনে ফাইলটিতে সেট করা যেতে পারে$JAVA_HOME/jre/lib/security$JAVA_HOME/lib/security

crypto.policy=unlimited

অথবা কোড হিসাবে

Security.setProperty("crypto.policy", "unlimited");

জাভা 9 এবং পরবর্তী সংস্করণগুলিতে এটি ডিফল্টরূপে সক্ষম হয়েছে।


0

এনক্রিপ্টর 4 জে ব্যবহার করার বিষয়টি বিবেচনা করুন যার মধ্যে আমি লেখক।

প্রথমে নিশ্চিত হয়ে নিন যে আপনার এগিয়ে যাওয়ার আগে আপনার সীমাহীন শক্তি এখতিয়ার নীতি ফাইল ইনস্টল করা আছে যাতে আপনি 256-বিট AES কীগুলি ব্যবহার করতে পারেন।

তারপরে নিম্নলিখিতটি করুন:

String password = "mysupersecretpassword"; 
Key key = KeyFactory.AES.keyFromPassword(password.toCharArray());
Encryptor encryptor = new Encryptor(key, "AES/CBC/PKCS7Padding", 16);

আপনি এখন আপনার বার্তা এনক্রিপ্ট করতে এনক্রিপ্টর ব্যবহার করতে পারেন। আপনি চাইলে স্ট্রিমিং এনক্রিপশনও সম্পাদন করতে পারেন। এটি স্বয়ংক্রিয়ভাবে আপনার সুবিধার জন্য একটি সুরক্ষিত IV উত্পন্ন এবং প্রেন্ডেন্ড করে।

যদি এটি এমন কোনও ফাইল যা আপনি সঙ্কুচিত করতে চান তবে এই উত্তরটি একবার দেখুন, আরও সহজ পদ্ধতির জন্য জাভা ব্যবহার করে এইএসের সাহায্যে একটি বৃহত ফাইল এনক্রিপ্ট করা


2
হাই মার্টিন, আপনি সর্বদা ইঙ্গিত করা উচিত যে আপনি লাইব্রেরির লেখক যদি এটি উল্লেখ করতে চান তবে। ক্রিপ্টো মোড়কের ওডলগুলি জিনিসগুলি সহজ করার চেষ্টা করছে। এটির কি কোনও সুরক্ষা পত্র রয়েছে বা এটি আমাদের মূল্যবান করার জন্য কোনও পর্যালোচনা পেয়েছে?
মার্টেন বোদেউয়েস

-1

এনক্রিপশনের জন্য এই শ্রেণিটি ব্যবহার করুন। এটা কাজ করে।

public class ObjectCrypter {


    public static byte[] encrypt(byte[] ivBytes, byte[] keyBytes, byte[] mes) 
            throws NoSuchAlgorithmException,
            NoSuchPaddingException,
            InvalidKeyException,
            InvalidAlgorithmParameterException,
            IllegalBlockSizeException,
            BadPaddingException, IOException {

        AlgorithmParameterSpec ivSpec = new IvParameterSpec(ivBytes);
        SecretKeySpec newKey = new SecretKeySpec(keyBytes, "AES");
        Cipher cipher = null;
        cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, newKey, ivSpec);
        return  cipher.doFinal(mes);

    }

    public static byte[] decrypt(byte[] ivBytes, byte[] keyBytes, byte[] bytes) 
            throws NoSuchAlgorithmException,
            NoSuchPaddingException,
            InvalidKeyException,
            InvalidAlgorithmParameterException,
            IllegalBlockSizeException,
            BadPaddingException, IOException, ClassNotFoundException {

        AlgorithmParameterSpec ivSpec = new IvParameterSpec(ivBytes);
        SecretKeySpec newKey = new SecretKeySpec(keyBytes, "AES");
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, newKey, ivSpec);
        return  cipher.doFinal(bytes);

    }
}

এবং এগুলি আইভাইটস এবং একটি এলোমেলো কী;

String key = "e8ffc7e56311679f12b6fc91aa77a5eb";

byte[] ivBytes = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
keyBytes = key.getBytes("UTF-8");

10
"এটি কাজ করে" .... হ্যাঁ, তবে এটি কোনও ক্রিপ্টোগ্রাফিক সুরক্ষিত সমাধান তৈরি করার প্রয়োজনীয়তা পূরণ করে না (এটি আমার মতে ব্যতিক্রম পরিচালনার ক্ষেত্রে জাভা কোডিং মানকেও পূরণ করে না)।
মার্টেন বোদেউইস

2
চতুর্থ শূন্যে আরম্ভ করা হয়। বিস্ট এবং এসিপিএ আক্রমণগুলির জন্য অনুসন্ধান করুন।
মিশেল জিউসেপ ফাদদা

ওয়াজুর ব্যতিক্রম, "এলোমেলো" কী উত্পন্ন করার পদ্ধতি এবং একটি শূন্য IV এই বাস্তবায়নের ক্ষেত্রে একটি সমস্যা, তবে এই সমস্যাগুলি সংশোধন করা তুচ্ছ। +1 টি।
ফিল
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.