JavaRush /مدونة جافا /Random-AR /هندسة تشفير جافا: المقدمة الأولى
Viacheslav
مستوى

هندسة تشفير جافا: المقدمة الأولى

نشرت في المجموعة
يعد أمن تبادل البيانات من أهم خصائص التطبيقات الحديثة. منذ العصور القديمة، توصل الناس إلى أساليب الماكرة، والتي مع تطور البشرية أصبحت علم التشفير بأكمله. وبطبيعة الحال، لم تقف Java جانباً وعرضت على المطورين بنية Java Cryptography Architecture (JCA). يجب أن تعطي هذه المراجعة فكرة أولية عن كيفية عملها.

مقدمة

أقترح السفر عبر الزمن. أمامنا روما القديمة. وأمامنا جايوس يوليوس قيصر الذي يرسل رسالة إلى قادته. دعونا نرى ما هو موجود في هذه الرسالة:
هندسة تشفير جافا: المقدمة الأولى - 2
ماذا يمكن أن يعني هذا: "ЕСКЕУГЬГМХИФЯ Е УЛП"؟ لنفتح Java Online Compiler، على سبيل المثال: repl.it
class Main {
  public static void main(String[] args) {
    String code = "ЕСКЕУГЬГМХИФЯ Е УЛП";
    for (char symbol : code.toCharArray()) {
      if (symbol != ' ') {
        symbol = (char) (symbol - 3);
      }
      System.out.print(symbol);
    }
  }
}
أمامنا أبسط تطبيق لشفرة قيصر. وفقًا لكتاب المؤرخ الروماني القديم سوتونيوس بعنوان "حياة القياصرة الاثني عشر"، فإن هذه هي بالضبط الطريقة التي قام بها قيصر بتشفير الرسائل إلى جنرالاته. وهذه واحدة من أقدم المراجع لاستخدام شيء مثل التشفير . كلمة "التشفير" تأتي من الكلمات اليونانية القديمة "مخفي" و"اكتب"، أي. إنه علم تقنيات الخصوصية. تتمتع Java بدعمها الخاص للتشفير ويطلق عليها اسم Java Cryptography Architecture (JCA). يمكن العثور على الوصف في الوثائق الرسمية من Oracle - " Java Cryptography Architecture (JCA) ". أقترح عليك إلقاء نظرة على الفرص التي نحصل عليها بفضل JCA.
هندسة تشفير جافا: المقدمة الأولى - 3

J.C.A.

كما تعلمنا سابقًا، تقدم Java بنية تشفير Java (JCA) للعمل مع التشفير. تحتوي هذه البنية على واجهة برمجة التطبيقات (أي مجموعة معينة من الواجهات) ومقدمي الخدمات (الذين يقومون بتنفيذها):
هندسة تشفير جافا: المقدمة الأولى - 4
كما تقول الوثائق، " تتضمن منصة Java عددًا من موفري الخدمات المضمنين ". أي أن منصة Java توفر مجموعة من موفري الخدمات المضمنين الذين يمكن توسيعهم إذا لزم الأمر. يمكنك أن ترى هذا بنفسك:
import java.security.Provider;
import java.security.Security;
class Main {
  public static void main(String[] args) {
    Provider[] providers = Security.getProviders();
    for (Provider p : providers) {
      System.out.println(p.getName());
    }
  }
}
يعد تسجيل مزود طرف ثالث أمرًا سهلاً للغاية. على سبيل المثال: Security.addProvider(new BouncyCastleProvider()); يربط هذا المثال أحد أشهر مقدمي الخدمة - BouncyCastle . ولكن في هذه المراجعة سوف نستخدم الأدوات الأساسية فقط، دون مكتبات الطرف الثالث. وثيقتنا الرئيسية: " هندسة تشفير جافا (JCA) ". إن فهم كيفية عمل JCA سيساعدك على فهم التقنيات التي يتم فيها استخدام JCA نفسه بشكل أكثر سهولة. على سبيل المثال: HTTPS (راجع " من HTTP إلى HTTPS ").
هندسة تشفير جافا: المقدمة الأولى - 5

رسالة دايجست

أول شيء مذكور في وثائق JCA هوMessageDigest. بشكل عام، سيكون الملخص باللغة الروسية هو نفسه - الملخص يتوافق في المعنى مع "الملخص". لكن في علم التشفير، الملخص عبارة عن مجموع تجزئة. يمكنك أيضًا أن تتذكر بسهولة أنه في English Digest يمكن أيضًا ترجمته على أنه ملخص. يمكن العثور على مزيد من التفاصيل في وثائق JCA في قسم " MessageDigest ". كما هو مذكور في التوثيق، يقوم تطبيقMessageDigest بإنشاء نتيجة ذات حجم ثابت تسمى "Digest" أو "Hash". التجزئة هي وظيفة ذات اتجاه واحد، أي. إذا قمنا بتجزئة شيء ما، فمن النتيجة (أي من التجزئة) لا يمكننا الحصول على المصدر الأصلي. ولكن إذا تم تجزئة كائنات متطابقة (على سبيل المثال، سلاسل من أحرف متطابقة)، فيجب أن تتطابق التجزئة الخاصة بها. كما هو مذكور في الوثائق، يُطلق على هذا التجزئة أحيانًا اسم "المجموع الاختباري" أو "البصمة الرقمية" للبيانات. يمكن إجراء التجزئة باستخدام خوارزميات مختلفة. يمكن الاطلاع على الخوارزميات المتاحة في المستند " وثائق اسم الخوارزمية القياسية لهندسة تشفير Java لـ JDK 8 ". لنقم بإجراء التجزئة وطباعة التجزئة إلى وحدة التحكم:
import javax.xml.bind.DatatypeConverter;
import java.security.*;
public class Main {
  public static void main(String[] args) {
    try {
      MessageDigest digester = MessageDigest.getInstance("SHA-512");
      byte[] input = "Secret string".getBytes();
      byte[] digest = digester.digest(input);
      System.out.println(DatatypeConverter.printHexBinary(digest));
    } catch (NoSuchAlgorithmException e) {
      throw new IllegalStateException(e);
    }
  }
}
يمكن أن يكون التجزئة مفيدًا، على سبيل المثال، عند تخزين كلمات المرور. نظرًا لأنه يمكن التحقق من تجزئة كلمة المرور المدخلة مقابل تجزئة محفوظة مسبقًا. إذا كانت التجزئة متطابقة، فإن كلمة المرور متطابقة أيضًا. للحصول على تجزئة أكثر أمانًا، يتم استخدام مفهوم يسمى "الملح". يمكن تنفيذ الملح باستخدام فئة SecureRandom . قبل تنفيذ طريقة الملخص، دعونا نصف إضافة "الملح":
byte[] salt = new byte[16];
SecureRandom.getInstanceStrong().nextBytes(salt);
digester.update(salt);
لكن التجزئة هي وظيفة ذات اتجاه واحد. ولكن ماذا لو كنت تريد أن تكون قادرًا على التشفير وفك التشفير؟
هندسة تشفير جافا: المقدمة الأولى - 6

تشفير المفتاح المتماثل

التشفير المتماثل هو تشفير يستخدم نفس المفتاح للتشفير وفك التشفير. من أجل استخدام التشفير المتماثل نحتاج إلى مفتاح. للحصول عليه نستخدم KeyGenerator . بالإضافة إلى ذلك، سنحتاج إلى فئة تمثل التشفير ( Cipher ). كما هو مذكور في وثائق JCA في القسم " إنشاء كائن تشفير "، لإنشاء تشفير، لا تحتاج إلى تحديد خوارزمية فحسب، بل "تحويل" في السطر. يبدو وصف التحويل كما يلي: "الخوارزمية/الوضع/الحشوة":
  • الخوارزمية : هنا نلقي نظرة على الأسماء القياسية لـ " خوارزميات التشفير (التشفير) ". يوصى باستخدام AES.
  • الوضع : وضع التشفير. على سبيل المثال: البنك المركزي الأوروبي أو CBC (سنتحدث عن هذا بعد قليل)
  • المسافة البادئة/التقسيم : يتم تشفير كل كتلة من البيانات بشكل منفصل. تحدد هذه المعلمة مقدار البيانات التي يتم حسابها ككتلة واحدة.
على سبيل المثال، خذ التحويل التالي: "AES/ECB/PKCS5Padding". أي أن خوارزمية التشفير هي AES، ووضع التشفير هو ECB (اختصار لـ Electronic Codebook)، وحجم الكتلة هو PKCS5Padding. يقول PKCS5Padding أن حجم الكتلة الواحدة هو 2 بايت (16 بت). يتضمن وضع تشفير كتاب الرموز الإلكتروني تشفيرًا تسلسليًا لكل كتلة:
هندسة تشفير جافا: المقدمة الأولى - 7
قد يبدو مثل هذا في الكود:
import javax.xml.bind.DatatypeConverter;
import javax.crypto.*;
import java.security.Key;
public class Main {
  public static void main(String[] args) throws Exception {
    String text = "secret!!secret!!secret!!secret!!";
    // Generate new key
    KeyGenerator keygen = KeyGenerator.getInstance("AES");
    keygen.init(256);
    Key key = keygen.generateKey();
    // Encrypt with key
    String transformation = "AES/ECB/PKCS5Padding";
    Cipher cipher = Cipher.getInstance(transformation);
    cipher.init(Cipher.ENCRYPT_MODE, key);
    byte[] encrypted = cipher.doFinal(text.getBytes());
    System.out.println(DatatypeConverter.printHexBinary(encrypted));
    // Decrypt with key
    cipher.init(Cipher.DECRYPT_MODE, key);
    String result = new String(cipher.doFinal(encrypted));
    System.out.println(result);
  }
}
إذا قمنا بالتنفيذ، فسوف نتوقع رؤية تكرار، لأن حددنا 32 حرفا. تشكل هذه الأحرف كتلتين من 16 بت:
هندسة تشفير جافا: المقدمة الأولى - 8
لتجنب إعادة التشغيل في هذه الحالة، يجب عليك استخدام وضع آخر - Cipher Block Chaining (CBC). يقدم هذا الوضع مفهوم متجه التهيئة (الممثل بفئة IvParameterSpec). وبفضل هذا الوضع أيضًا، سيتم استخدام نتيجة إنشاء الكتلة الأخيرة لإنشاء الكتلة التالية:
هندسة تشفير جافا: المقدمة الأولى - 9
لنكتب الآن هذا بالكود:
import javax.xml.bind.DatatypeConverter;
import javax.crypto.*;
import java.security.*;
import javax.crypto.spec.IvParameterSpec;
public class Main {
  public static void main(String[] args) throws Exception {
    // Initialization Vector
    SecureRandom random = SecureRandom.getInstanceStrong();
    byte[] rnd = new byte[16];
    random.nextBytes(rnd);
    IvParameterSpec ivSpec = new IvParameterSpec(rnd);
    // Prepare key
    KeyGenerator keygen = KeyGenerator.getInstance("AES");
    keygen.init(256);
    Key key = keygen.generateKey();
    // CBC
    String text = "secret!!secret!!secret!!secret!!";
    String transformation = "AES/CBC/PKCS5Padding";
    Cipher cipher = Cipher.getInstance(transformation);
    cipher.init(Cipher.ENCRYPT_MODE, key, ivSpec);
    byte[] enc = cipher.doFinal(text.getBytes());
    System.out.println(DatatypeConverter.printHexBinary(enc));
    // Decrypt
    cipher.init(Cipher.DECRYPT_MODE, key, ivSpec);
    String result = new String(cipher.doFinal(enc));
    System.out.println(result);
  }
}
كما نرى، نتيجة لذلك، لا نرى كتل تشفير متكررة. لهذا السبب، لا ينصح بوضع البنك المركزي الأوروبي، لأنه يجعل من الممكن رؤية التكرارات واستخدام هذه المعرفة لفك التشفير. لمزيد من المعلومات حول البنك المركزي الأوروبي وCBC، أنصحك بقراءة المادة: " وضع دفتر الرموز الإلكتروني ". لكن التشفير المتماثل لديه مشكلة واضحة - تحتاج إلى نقل المفتاح بطريقة أو بأخرى من الشخص الذي يقوم بالتشفير إلى الشخص الذي يقوم بالتشفير. وعلى طول هذا المسار، يمكن اعتراض هذا المفتاح ومن ثم سيكون من الممكن اعتراض البيانات. وتم تصميم التشفير غير المتماثل لحل هذه المشكلة.
هندسة تشفير جافا: المقدمة الأولى - 10

التشفير غير المتماثل

التشفير غير المتماثل أو تشفير المفتاح العام هو طريقة تشفير تستخدم زوجًا من المفاتيح: مفتاح خاص (يظل سرًا عن الجميع) ومفتاح عام (متاح للعامة). يعد هذا الفصل ضروريًا من أجل تبادل المفتاح العام بشكل آمن بين أطراف تبادل المعلومات، مع الحفاظ على أمان المفتاح السري. عند إنشاء زوج مفاتيح، لم يعد KeyGenerator كافيًا بالنسبة لنا، فنحن بحاجة إلى KeyPairGenerator . لنلقي نظرة على مثال:
import javax.crypto.*;
import java.security.*;
public class Main {
  public static void main(String[] args) throws Exception {
    KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
    generator.initialize(1024);
    KeyPair keyPair = generator.generateKeyPair();
    // Encrypt with PRIVATE KEY
    Cipher cipher = Cipher.getInstance("RSA");
    cipher.init(Cipher.ENCRYPT_MODE, keyPair.getPublic());
    byte[] data = cipher.doFinal("Hello!".getBytes());
    // Decrypt with PUBLIC KEY
    cipher.init(Cipher.DECRYPT_MODE, keyPair.getPrivate());
    byte[] result = cipher.doFinal(data);
    System.out.println(new String(result));
  }
}
من المهم أن نفهم هنا أنه عند استخدام التشفير غير المتماثل، نستخدم دائمًا KeyPair لاستخدام مفتاح واحد للتشفير وآخر لفك التشفير. ولكن الهدف من التشفير هو أن المستلم فقط هو الذي يمكنه فك تشفيره؛ فهو مشفر بمفتاح عام، ولا يتم فك تشفيره إلا بمفتاح خاص.
هندسة تشفير جافا: التعارف الأول - 11

توقيع إلكتروني

كما رأينا أعلاه، بمعرفة المفتاح العام، يمكنك إرسال البيانات بحيث لا يتمكن سوى مالك المفتاح الخاص من فك تشفيرها. وهذا يعني أن جوهر التشفير غير المتماثل هو أن أي شخص يقوم بالتشفير، لكننا نقرأ فقط. هناك أيضًا إجراء عكسي - التوقيع الرقمي، الذي تمثله فئة التوقيع . يمكن للتوقيع الرقمي استخدام الخوارزميات التالية: " خوارزميات التوقيع ". تقترح وثائق JCA إلقاء نظرة فاحصة على هذين الاثنين: DSAwithMD5 وRSAwithMD5 ما هو أفضل من DSA أو RSA وما هو الفرق بينهما يمكنك قراءته هنا: " ما هو الأفضل لعمليات نقل الملفات المشفرة - RSA أم DSA؟ ". أو اقرأ المناقشات هنا: " RSA vs. DSA لمفاتيح مصادقة SSH ". لذلك، التوقيع الرقمي. سنحتاج، كما كان من قبل، إلى KeyPair وفئة Signature جديدة. إذا كنت قد اختبرت حتى الآن المترجمين عبر الإنترنت، فقد يكون المثال التالي صعبًا إلى حد ما بالنسبة لهم. تم تشغيل المثال الخاص بي هنا فقط: rextester.com . نقوم باستيراد الفئات التي نحتاجها:
import javax.crypto.*;
import java.security.*;
سنقوم أيضًا بإعادة كتابة الطريقة الرئيسية:
public static void main(String[] args) throws Exception {
    // Generate keys
    KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
    SecureRandom random = SecureRandom.getInstanceStrong();
    generator.initialize(2048, random);
    KeyPair keyPair = generator.generateKeyPair();
    // Digital Signature
    Signature dsa = Signature.getInstance("SHA256withRSA");
    dsa.initSign(keyPair.getPrivate());
    // Update and sign the data
    Cipher cipher = Cipher.getInstance("RSA");
    cipher.init(Cipher.ENCRYPT_MODE, keyPair.getPublic());
    byte[] data = cipher.doFinal("Hello!".getBytes());
    dsa.update(data);
    byte[] signature = dsa.sign();
    // Verify signature
    dsa.initVerify(keyPair.getPublic());
    dsa.update(data);
    boolean verifies = dsa.verify(signature);
    System.out.println("Signature is ok: " + verifies);
    // Decrypt if signature is correct
    if (verifies) {
      cipher.init(Cipher.DECRYPT_MODE, keyPair.getPrivate());
      byte[] result = cipher.doFinal(data);
      System.out.println(new String(result));
    }
}
هذه هي الطريقة التي يعمل بها التوقيع الرقمي. التوقيع الرقمي موضوع مثير للاهتمام. أنصحك بالاطلاع على التقرير حول هذا الموضوع:
هندسة تشفير جافا: التعارف الأول - 12
أعلاه رأينا كيف يتبادل الطرفان البيانات. ألا توجد واجهة قياسية لهذا التفاعل متوفرة في JCA؟ اتضح أن هناك. دعونا ننظر في الأمر.
هندسة تشفير جافا: التعارف الأول - 13

اتفاقية المفتاح

تقدم Java Cryptography Architecture أداة مهمة - اتفاقية المفتاح هي بروتوكول. يتم تمثيله بواسطة فئة KeyAgreement . كما هو مذكور في وثائق JCA، يسمح هذا البروتوكول لأطراف متعددة بتعيين نفس مفتاح التشفير دون مشاركة أي معلومات سرية بين الأطراف. يبدو غريبا؟ ثم دعونا ننظر إلى مثال:
// 1. Одна из сторон (Алиса) генерирует пару ключей. Encoded публичный ключ отдаёт.
KeyPairGenerator generator = KeyPairGenerator.getInstance("DH");
KeyPair aliceKeyPair = generator.generateKeyPair();
byte[] alicePubKeyEncoded = aliceKeyPair.getPublic().getEncoded();

// 2. Другая сторона (например, Боб) получает открытый ключ Алисы
KeyFactory bobKeyFactory = KeyFactory.getInstance("DH");
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(alicePubKeyEncoded);
PublicKey alicePubKey = bobKeyFactory.generatePublic(x509KeySpec);
// Параметры, которые использовала Алиса при генерации ключей
DHParameterSpec dhParamFromAlicePubKey = ((DHPublicKey)alicePubKey).getParams();
// Создаёт свою пару ключей. Отдаёт свой Encoded открытый ключ
KeyPairGenerator bobKpairGen = KeyPairGenerator.getInstance("DH");
bobKpairGen.initialize(dhParamFromAlicePubKey);
KeyPair bobKeyPair = bobKpairGen.generateKeyPair();
byte[] bobPubKeyEncoded = bobKeyPair.getPublic().getEncoded();

Теперь, у Алисы есть открытый ключ Боба, а у Боба есть открытый ключ Алисы. What дальше?
Как сказано в documentации JCA, у нас есть инструмент KeyAgreement, https://docs.oracle.com/javase/8/docs/technotes/guides/security/crypto/CryptoSpec.html#KeyAgreement который позволяет установить одинаковые ключи шифрования без необходимости обмениваться секретной информацией (т.е. без обмена private key). Соглашение выглядит следующим образом:
// 3. Соглашение по протоколу Диффи-Хеллмана (Diffie–Hellman, DH)
KeyAgreement aliceKeyAgree = KeyAgreement.getInstance("DH");
aliceKeyAgree.init(aliceKeyPair.getPrivate());
// Алиса на основе ключа боба и своего private key создаёт общий shared ключ
KeyFactory aliceKeyFactory = KeyFactory.getInstance("DH");
x509KeySpec = new X509EncodedKeySpec(bobPubKeyEncoded);
PublicKey bobPubKey = aliceKeyFactory.generatePublic(x509KeySpec);
aliceKeyAgree.doPhase(bobPubKey, true);
byte[] aliceSharedSecret = aliceKeyAgree.generateSecret();
SecretKeySpec aliceAesKey = new SecretKeySpec(aliceSharedSecret, 0, 16, "AES");
// Боб на основе ключа Алисы и своего private key создаёт общий shared ключ
KeyAgreement bobKeyAgree = KeyAgreement.getInstance("DH");
bobKeyAgree.init(bobKeyPair.getPrivate());
bobKeyAgree.doPhase(alicePubKey, true);
byte[] bobSharedSecret = bobKeyAgree.generateSecret();
SecretKeySpec bobAesKey = new SecretKeySpec(bobSharedSecret, 0, 16, "AES");
// Общий ключ у Алисы и Боба одинаков
System.out.println("Shared keys are equals: " + Arrays.equals(aliceSharedSecret, bobSharedSecret));

Далее Боб и Алиса, используя общий ключ, про который больше никто не знает, обмениваются зашифрованными данными:
// 4. Боб шифрует сообщение для Алисы
Cipher bobCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
bobCipher.init(Cipher.ENCRYPT_MODE, bobAesKey);
byte[] ciphertext = bobCipher.doFinal("Hello, Alice!".getBytes());
// Передаёт Алисе параметры, с которыми выполнялась шифровка
byte[] encodedParamsFromBob = bobCipher.getParameters().getEncoded();

// 5. Алиса принимает сообщение и расшифровывает его
AlgorithmParameters aesParams = AlgorithmParameters.getInstance("AES");
aesParams.init(encodedParamsFromBob);
Cipher aliceCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
aliceCipher.init(Cipher.DECRYPT_MODE, aliceAesKey, aesParams);
byte[] recovered = aliceCipher.doFinal(ciphertext);
System.out.println(new String(recovered));
تم أخذ هذا المثال من مثال وثائق JCA: " تبادل مفاتيح Diffie-Hellman بين طرفين ". هذا هو تقريبًا ما يبدو عليه التشفير غير المتماثل في Java Cryptography Architecture باستخدام بروتوكول اتفاقية المفتاح. لمزيد من المعلومات حول التشفير غير المتماثل، مقاطع الفيديو الموصى بها:
هندسة تشفير جافا: التعارف الأول - 14

الشهادات

حسنًا، بالنسبة للحلوى، لا يزال لدينا شيء لا يقل أهمية - الشهادات. عادة، يتم إنشاء الشهادات باستخدام الأداة المساعدة keytool المضمنة مع jdk. يمكنك قراءة المزيد من التفاصيل، على سبيل المثال، هنا: " إنشاء شهادة SSL موقعة ذاتيًا باستخدام أمر Java keytool ". يمكنك أيضًا قراءة الأدلة من Oracle. على سبيل المثال، هنا: " لاستخدام أداة المفاتيح لإنشاء شهادة خادم ". على سبيل المثال، لنستخدم Tutorialspoint Java Online Compiler :
import sun.security.tools.keytool.CertAndKeyGen;
import sun.security.x509.*;
import java.security.cert.*;
import java.security.*;
// Compiler args: -XDignore.symbol.file
public class Main {
  public static void main(String[] args) throws Exception {
    CertAndKeyGen certGen = new CertAndKeyGen("RSA", "SHA256WithRSA", null);
    // generate it with 2048 bits
    certGen.generate(2048);
    PrivateKey privateKey = certGen.getPrivateKey();
    X509Key publicKey = certGen.getPublicKey();
    // prepare the validity of the certificate
    long validSecs = (long) 365 * 24 * 60 * 60; // valid for one year
    // enter your details according to your application
    X500Name principal = new X500Name("CN=My Application,O=My Organisation,L=My City,C=DE");
    // add the certificate information, currently only valid for one year.
    X509Certificate cert = certGen.getSelfCertificate(principal, validSecs);
    // Public Key from Cert equals Public Key from generator
    PublicKey publicKeyFromCert = cert.getPublicKey();
    System.out.println(publicKeyFromCert.equals(publicKey));
  }
}
كما نرى، توفر الشهادة القدرة على توفير مفتاح عام. هذه الطريقة لها عيب - فنحن نستخدمها sun.security، والتي تعتبر محفوفة بالمخاطر، لأن... هذه الحزمة ليست جزءًا من Java API العامة. ولهذا السبب من الضروري أثناء التجميع تحديد المعلمة - XDignore.symbol.file. هناك طريقة أخرى - لإنشاء شهادة يدويًا. الجانب السلبي هو أنه يستخدم واجهة برمجة تطبيقات داخلية غير موثقة. ومع ذلك، من المفيد معرفة ذلك. على الأقل، لأنه من الواضح كيف يتم استخدام مواصفات RFC-2459: " البنية التحتية للمفتاح العام لـ Internet X.509 ". هنا مثال:
// 1. Генерируем пару ключей
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(4096);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
// 2. Определяем данные сертификата
// Определяем срок действия сертификата
Date from = new Date();
Date to = new Date(from.getTime() + 365 * 1000L * 24L * 60L * 60L);
CertificateValidity interval = new CertificateValidity(from, to);
// Определяем subject name, т.е. Name того, с чем ассоциирован публичный ключ
// CN = Common Name. Через точку с запятой могут быть указаны также другие атрибуты
// См. https://docs.oracle.com/cd/E24191_01/common/tutorials/authz_cert_attributes.html
X500Name owner = new X500Name("cn=Unknown");
// Уникальный в пределах CA, т.е. Certificate Authority (тот, кто выдаёт сертификат) номер
BigInteger number = new BigInteger(64, new SecureRandom());
CertificateSerialNumber serialNumber = new CertificateSerialNumber(number);
// Определяем алгоритм подписи сертификата
AlgorithmId algorithmId = new AlgorithmId(AlgorithmId.md5WithRSAEncryption_oid);
CertificateAlgorithmId certificateAlgorithmId = new CertificateAlgorithmId(algorithmId);
// 3. По подготовленной информации создаём сертификат
X509CertInfo info = new X509CertInfo();
info.set(X509CertInfo.VALIDITY, interval);
info.set(X509CertInfo.SERIAL_NUMBER, serialNumber);
info.set(X509CertInfo.SUBJECT, owner);
info.set(X509CertInfo.ISSUER, owner);
info.set(X509CertInfo.KEY, new CertificateX509Key(keyPair.getPublic()));
info.set(X509CertInfo.VERSION, new CertificateVersion(CertificateVersion.V3));
info.set(X509CertInfo.ALGORITHM_ID, certificateAlgorithmId);
// 4. Подписываем сертификат
X509CertImpl certificate = new X509CertImpl(info);
certificate.sign(keyPair.getPrivate(), "SHA256withRSA");
// 5. Проверка сертификата
try {
	// В случае ошибки здесь будет брошено исключение. Например: java.security.SignatureException
	certificate.verify(keyPair.getPublic());
} catch (Exception e) {
	throw new IllegalStateException(e);
}
هندسة تشفير جافا: المقدمة الأولى - 15

مخزن المفاتيح (متجر المفاتيح)

آخر شيء أود التحدث عنه هو مخزن المفاتيح والشهادات، والذي يسمى KeyStore. من الواضح أن إنشاء الشهادات والمفاتيح باستمرار أمر مكلف ولا معنى له. لذلك، يجب تخزينها بطريقة آمنة. هناك أداة لهذا - KeyStore. تم وصف مخزن المفاتيح في وثائق JCA في فصل " KeyManagement ". واجهة برمجة التطبيقات للعمل معها واضحة جدًا. إليك مثال صغير:
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(null, null);
String alias = "EntityAlias";
java.security.cert.Certificate[] chain = {certificate};
keyStore.setKeyEntry(alias, keyPair.getPrivate(), "keyPassword".toCharArray(), chain);
// Загрузка содержимого (Private Key + Certificate)
Key key = keyStore.getKey(alias, "keyPassword".toCharArray());
Certificate[] certificateChain = keyStore.getCertificateChain(alias);
// Сохранение KeyStore на диск
File file = File.createTempFile("security_", ".ks");
System.out.println(file.getAbsolutePath());
try (FileOutputStream fos = new FileOutputStream(file)) {
	keyStore.store(fos, "keyStorePassword".toCharArray());
}
كما ترون من المثال، يتم تنفيذه أولاً loadلـ KeyStore. لكن في حالتنا، حددنا السمة الأولى على أنها خالية، أي. لا يوجد مصدر لـ KeyStore. وهذا يعني أنه تم إنشاء KeyStore فارغًا لحفظه بشكل أكبر. المعلمة الثانية فارغة أيضًا، لأن نحن نقوم بإنشاء KeyStore جديد. إذا كنا نقوم بتحميل KeyStore من ملف، فسنحتاج إلى تحديد كلمة مرور هنا (على غرار طريقة KeyStore التي تسمى store).

الحد الأدنى

لذلك قمنا بمراجعة الإجراءات الأساسية والأولية معك في إطار بنية تشفير Java (المعروفة أيضًا باسم JCA). لقد رأينا ما هو التشفير المتماثل وغير المتماثل وكيف يتم تنفيذه في JCA. لقد رأينا كيف يتم إنشاء الشهادات والتوقيعات الرقمية وكيفية استخدامها. هذه كلها مجرد الأساسيات، والتي يوجد خلفها العديد من الأشياء الأكثر تعقيدًا وإثارة للاهتمام. آمل أن تكون مادة المراجعة هذه مفيدة وستثير اهتمامك بإجراء مزيد من الدراسة في هذا المجال.
تعليقات
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION