חתימות דיגיטליות בג'אווה

ג'אווה טופ

רק הכרזתי על החדש למד אביב קורס, המתמקד ביסודות האביב 5 ומגף האביב 2:

>> בדוק את הקורס

1. סקירה כללית

במדריך זה, אנו הולכים ללמוד על מנגנון חתימה דיגיטלית וכיצד נוכל ליישם אותו באמצעות Java Cryptography Architecture (JCA). נחקור את KeyPair, MessageDigest, Cipher, KeyStore, Certificate, ו חֲתִימָה ממשקי API של JCA.

נתחיל בהבנה מהי חתימה דיגיטלית, כיצד ליצור זוג מפתחות וכיצד לאשר את המפתח הציבורי מרשות אישורים (CA). לאחר מכן נראה כיצד ליישם חתימה דיגיטלית באמצעות ממשקי ה- API של JCA ברמה נמוכה וברמה גבוהה.

2. מהי חתימה דיגיטלית?

2.1. הגדרת חתימה דיגיטלית

חתימה דיגיטלית היא טכניקה להבטחת:

  • שלמות: ההודעה לא שונתה במעבר
  • אותנטיות: מחבר ההודעה הוא באמת מי שהם טוענים שהוא
  • אי-דחייה: מחבר ההודעה לא יכול להכחיש אחר כך שהם המקור

2.2. שליחת הודעה בחתימה דיגיטלית

דיבור טכני, אחתימה דיגיטלית היא ה- hash המוצפן (עיכול, בדיקת בדיקה) של הודעה. כלומר אנו מייצרים hash מההודעה ומצפינים אותו במפתח פרטי על פי אלגוריתם שנבחר.

ההודעה, הגיבוב המוצפן, המפתח הציבורי המתאים והאלגוריתם נשלחים. זה מסווג כהודעה עם החתימה הדיגיטלית שלה.

2.3. קבלה ובדיקה של חתימה דיגיטלית

כדי לבדוק את החתימה הדיגיטלית, מקלט ההודעות מייצר hash חדש מההודעה שהתקבלה, מפענח את ה- Hash המוצפן שהתקבל באמצעות המפתח הציבורי ומשווה ביניהם. אם הם תואמים, נאמר כי החתימה הדיגיטלית מאומתת.

עלינו לציין כי אנו מצפינים רק את חשיש ההודעה, ולא את ההודעה עצמה. במילים אחרות, חתימה דיגיטלית לא מנסה לשמור את ההודעה בסוד. החתימה הדיגיטלית שלנו מוכיחה רק שההודעה לא שונתה במעבר.

לאחר אימות החתימה, אנו בטוחים שרק הבעלים של המפתח הפרטי יכול להיות מחבר ההודעה.

3. תעודה דיגיטלית וזהות מפתח ציבורי

תעודה היא מסמך המקשר זהות למפתח ציבורי נתון. אישורים חתומים על ידי גורם צד שלישי הנקרא רשות אישורים (CA).

אנו יודעים שאם החשיש שאנו מפענחים עם המפתח הציבורי שפורסם תואם את החשיש בפועל, אז ההודעה נחתמת. עם זאת, כיצד נדע שהמפתח הציבורי באמת הגיע מהישות הנכונה? זה נפתר על ידי שימוש בתעודות דיגיטליות.

תעודה דיגיטלית מכילה מפתח ציבורי והיא חתומה בעצמה על ידי ישות אחרת. ניתן לאמת את החתימה של אותה ישות על ידי ישות אחרת וכן הלאה. בסופו של דבר יש לנו מה שאנו מכנים שרשרת אישורים. כל ישות עליונה מאשרת את המפתח הציבורי של הישות הבאה. הישות ברמה הגבוהה ביותר היא חתימה עצמית, כלומר המפתח הציבורי שלו חתום על ידי המפתח הפרטי שלו.

ה- X.509 הוא פורמט האישור הנפוץ ביותר, והוא נשלח כפורמט בינארי (DER) או כפורמט טקסט (PEM). JCA כבר מספקת יישום לכך באמצעות X509 תעודה מעמד.

4. ניהול KeyPair

מכיוון ש- Digital Signature משתמש במפתח פרטי וציבורי, נשתמש בשיעורי JCA מפתח פרטי ו מפתח ציבורי לחתימה ובדיקת הודעה בהתאמה.

4.1. השגת KeyPair

ליצירת צמד מפתחות של מפתח פרטי וציבורי, נשתמש בג'אווה כלי מפתחות.

בואו ניצור זוג מפתח באמצעות ה- genkeypair פקודה:

keytool -genkeypair -alias senderKeyPair -keyalg RSA -keysize 2048 \ -dname "CN = Baeldung" -validity 365 -story type PKCS12 \ -keystore sender_keystore.

זה יוצר עבורנו מפתח פרטי והמפתח הציבורי המתאים לו. המפתח הציבורי עטוף בתעודת X.509 בחתימה עצמית העטופה בתור לשרשרת אישורים יחידה. אנו שומרים את שרשרת האישורים ואת המפתח הפרטי בקובץ קייסטור sender_keystore.p12, שאנו יכולים לעבד באמצעות ממשק ה- API של KeyStore.

כאן השתמשנו בפורמט חנות המפתח PKCS12, מכיוון שהוא הסטנדרטי והמומלץ על פני פורמט JKS הקנייני של Java. כמו כן, עלינו לזכור את הסיסמה והכינוי, שכן נשתמש בהן בסעיף המשנה הבא בעת טעינת קובץ ה- Keystore.

4.2. טוען את המפתח הפרטי לחתימה

על מנת לחתום על הודעה, אנו זקוקים למופע של ה- מפתח פרטי.

משתמש ב KeyStore API, וקובץ ה- Keystore הקודם, sender_keystore.p12, אנחנו יכולים להשיג מפתח פרטי לְהִתְנַגֵד:

KeyStore keyStore = KeyStore.getInstance ("PKCS12"); keyStore.load (FileInputStream חדש ("sender_keystore.p12"), "changeit"); PrivateKey privateKey = (PrivateKey) keyStore.getKey ("senderKeyPair", "changeit");

4.3. פרסום המפתח הציבורי

לפני שנוכל לפרסם את המפתח הציבורי, עלינו להחליט תחילה אם נשתמש באישור בחתימה עצמית או באישור חתום על ידי CA.

בעת שימוש באישור בחתימה עצמית, עלינו לייצא אותו רק מקובץ קייסטור. אנחנו יכולים לעשות זאת עם exportcert פקודה:

keytool -exportcert -alias senderKeyPair -storetype PKCS12 \ -keystore sender_keystore.p12-file \ sender_certificate.cer -rfc -storepass changeit

אחרת, אם נעבוד עם אישור חתום על CA, עלינו ליצור בקשה לחתימת אישורים (CSR). אנו עושים זאת עם certreq פקודה:

keytool -certreq -alias senderKeyPair -storetype PKCS12 \ -keystore sender_keystore.p12-file -rfc \ -storepass changeit> sender_certificate.csr

קובץ ה- CSR, sender_certificate.csr, לאחר מכן נשלח לרשות אישורים לצורך חתימה. בסיום זה נקבל מפתח ציבורי חתום עטוף בתעודת X.509, בפורמט בינארי (DER) או טקסט (PEM). הנה, השתמשנו ב- rfc אפשרות לפורמט PEM.

המפתח הציבורי שקיבלנו מ- CA, sender_certificate.cer, נחתם כעת על ידי CA והוא יכול להיות זמין ללקוחות.

4.4. טוען מפתח ציבורי לאימות

כשיש גישה למפתח הציבורי, יכול מקלט לטעון אותו לקיסטור שלו באמצעות ה- importcert פקודה:

keytool -importcert -alias receiverKeyPair -storetype PKCS12 \ -keystore receiver_keystore.p12 -file \ sender_certificate.cer -rfc -storepass changeit

ושימוש ב- KeyStore ממשק API כמו בעבר, אנו יכולים להשיג מפתח ציבורי למשל:

KeyStore keyStore = KeyStore.getInstance ("PKCS12"); keyStore.load (FileInputStream חדש ("receiver_keytore.p12"), "changeit"); תעודת תעודה = keyStore.getCertificate ("receiverKeyPair"); PublicKey publicKey = certificate.getPublicKey ();

עכשיו שיש לנו מפתח פרטי מופע בצד השולח, ומופע של מפתח ציבורי בצד המקלט נוכל להתחיל בתהליך החתימה והאימות.

5. חתימה דיגיטלית עם MessageDigest ו צוֹפֶן שיעורים

כפי שראינו, החתימה הדיגיטלית מבוססת על hashing והצפנה.

בדרך כלל אנו משתמשים ב- MessageDigest כיתה עם SHA או MD5 עבור hashing ואת צוֹפֶן מחלקה להצפנה.

עכשיו נתחיל ליישם את מנגנוני החתימה הדיגיטלית.

5.1. יצירת מסר Hash

הודעה יכולה להיות מחרוזת, קובץ או כל נתונים אחרים. אז בואו ניקח את התוכן של קובץ פשוט:

בתים [] messageBytes = Files.readAllBytes (Paths.get ("message.txt"));

עכשיו, באמצעות MessageDigest, בואו נשתמש ב- לְעַכֵּל שיטה ליצירת hash:

MessageDigest md = MessageDigest.getInstance ("SHA-256"); בייט [] messageHash = md.digest (messageBytes);

כאן השתמשנו באלגוריתם SHA-256, שהוא הנפוץ ביותר. חלופות אחרות הן MD5, SHA-384 ו- SHA-512.

5.2. הצפנת ה- Hash שנוצר

כדי להצפין הודעה אנו זקוקים לאלגוריתם ולמפתח פרטי. כאן נשתמש באלגוריתם RSA. אלגוריתם DSA הוא אפשרות נוספת.

בואו ניצור צוֹפֶן מופע ואתחל אותו להצפנה. ואז נקרא doFinal () שיטה להצפנת ההודעה הקודמת:

צופן צופן = Cipher.getInstance ("RSA"); cipher.init (Cipher.ENCRYPT_MODE, privateKey); בייט [] digitalSignature = cipher.doFinal (messageHash);

ניתן לשמור את החתימה בקובץ לשליחתה מאוחר יותר:

Files.write (Paths.get ("digital_signature_1"), digitalSignature);

בשלב זה, ההודעה, החתימה הדיגיטלית, המפתח הציבורי והאלגוריתם נשלחים, והמקלט יכול להשתמש בפיסות המידע הללו כדי לאמת את תקינות ההודעה.

5.3. אימות חתימה

כאשר אנו מקבלים הודעה, עלינו לאמת את חתימתה. לשם כך אנו מפענחים את החשיש המוצפן שהתקבל ומשווים אותו עם גיבוב שאנו עושים מההודעה שהתקבלה.

בואו לקרוא את החתימה הדיגיטלית שהתקבלה:

בתים [] encryptedMessageHash = Files.readAllBytes (Paths.get ("digital_signature_1"));

לפענוח אנו יוצרים צוֹפֶן למשל. ואז אנו קוראים doFinal שיטה:

צופן צופן = Cipher.getInstance ("RSA"); cipher.init (Cipher.DECRYPT_MODE, publicKey); בתא [] decryptedMessageHash = cipher.doFinal (encryptedMessageHash);

לאחר מכן, אנו מייצרים hash הודעה חדשה מההודעה שהתקבלה:

בתים [] messageBytes = Files.readAllBytes (Paths.get ("message.txt")); MessageDigest md = MessageDigest.getInstance ("SHA-256"); בתא [] newMessageHash = md.digest (messageBytes);

ולבסוף, אנו בודקים אם חשיש ההודעה החדש שנוצר תואם לזה המוצפן:

בוליאני isCorrect = Arrays.equals (decryptedMessageHash, newMessageHash);

בדוגמה זו השתמשנו בקובץ הטקסט message.txt כדי לדמות מסר שאנו רוצים לשלוח, או את מיקום גוף ההודעה שקיבלנו. בדרך כלל היינו מצפים לקבל את ההודעה שלנו לצד החתימה.

6. חתימה דיגיטלית באמצעות חֲתִימָה מעמד

עד כה השתמשנו בממשקי ה- API ברמה נמוכה לבניית תהליך אימות חתימות דיגיטליות משלנו. זה עוזר לנו להבין איך זה עובד ומאפשר לנו להתאים אישית את זה.

עם זאת, JCA כבר מציעה ממשק API ייעודי בצורת ה- חֲתִימָה מעמד.

6.1. חתימה על הודעה

כדי להתחיל בתהליך החתימה, ראשית אנו יוצרים מופע של ה- חֲתִימָה מעמד. לשם כך אנו זקוקים לאלגוריתם חתימה. לאחר מכן אנו מאותחלים את חֲתִימָה עם המפתח הפרטי שלנו:

חתימת חתימה = Signature.getInstance ("SHA256withRSA"); signature.initSign (privateKey);

אלגוריתם החתימה שבחרנו, SHA256 עם RSA בדוגמה זו, הוא שילוב של אלגוריתם hashing ואלגוריתם הצפנה. חלופות אחרות כוללות SHA1 עם RSA, SHA1 עם DSA, ו MD5 עם RSA, בין היתר.

לאחר מכן, נמשיך לחתום על מערך בתים של ההודעה:

בתים [] messageBytes = Files.readAllBytes (Paths.get ("message.txt")); signature.update (messageBytes); בתא [] digitalSignature = signature.sign ();

אנו יכולים לשמור את החתימה בקובץ להעברה מאוחרת יותר:

Files.write (Paths.get ("digital_signature_2"), digitalSignature);

6.2. אימות החתימה

כדי לאמת את החתימה שהתקבלה, אנו יוצרים שוב חֲתִימָה למשל:

חתימת חתימה = Signature.getInstance ("SHA256withRSA");

לאחר מכן אנו מאותחלים את חֲתִימָה אובייקט לאימות על ידי קריאה ל- initVerify שיטה, שלוקחת מפתח ציבורי:

signature.initVerify (publicKey);

לאחר מכן, עלינו להוסיף את בתים ההודעה שהתקבלו לאובייקט החתימה על ידי הפעלת ה- עדכון שיטה:

בתים [] messageBytes = Files.readAllBytes (Paths.get ("message.txt")); signature.update (messageBytes);

ולבסוף, אנו יכולים לבדוק את החתימה על ידי התקשרות ל תאשר שיטה:

בוליאני isCorrect = signature.verify (receivedSignature);

7. מסקנה

במאמר זה בדקנו לראשונה כיצד עובדת חתימה דיגיטלית וכיצד ניתן לבסס אמון בתעודה דיגיטלית. ואז יישמנו חתימה דיגיטלית באמצעות ה- MessageDigest,צוֹפֶן, ו חֲתִימָה שיעורים מארכיטקטורת הקריפטוגרפיה של Java.

ראינו בפירוט כיצד לחתום על נתונים באמצעות המפתח הפרטי וכיצד לאמת את החתימה באמצעות מפתח ציבורי.

כמו תמיד, הקוד ממאמר זה זמין ב- GitHub.

תחתית Java

רק הכרזתי על החדש למד אביב קורס, המתמקד ביסודות האביב 5 ומגף האביב 2:

>> בדוק את הקורס

$config[zx-auto] not found$config[zx-overlay] not found