การเข้ารหัสข้อมูลและการถอดรหัสโดยใช้คีย์สาธารณะและส่วนตัว RSA ที่สร้างโดย OpenSSL ใน Java
RSA คืออะไร: อัลกอริทึมการเข้ารหัสคีย์สาธารณะ RSA ได้รับการพัฒนาในปี 1977 โดย Ron Rivest, Adi Shamirh และ Len Adleman ที่ (Massachusetts Institute of Technology) การตั้งชื่อ RSA มาจากชื่อที่พัฒนาทั้งสามคน RSA เป็นอัลกอริทึมการเข้ารหัสคีย์สาธารณะที่มีอิทธิพลมากที่สุดในปัจจุบัน มันสามารถต้านทานการโจมตีการเข้ารหัสทั้งหมดที่รู้จักและได้รับการแนะนำโดย ISO เป็นมาตรฐานการเข้ารหัสข้อมูลคีย์สาธารณะ ในปัจจุบันวิธีการเข้ารหัสนี้ใช้กันอย่างแพร่หลายในธนาคารออนไลน์ลายเซ็นดิจิตอลและโอกาสอื่น ๆ อัลกอริทึม RSA นั้นขึ้นอยู่กับความจริงของทฤษฎีจำนวนง่ายมาก: มันง่ายมากที่จะคูณตัวเลขขนาดใหญ่สองตัว แต่มันก็ยากมากที่จะแยกตัวประกอบผลิตภัณฑ์ในเวลานั้นดังนั้นผลิตภัณฑ์จึงสามารถเปิดเผยได้ว่าเป็นคีย์การเข้ารหัส
OPENSSL คืออะไร: อัลกอริทึมการเข้ารหัสลับจำนวนมากมาตรฐานโครงสร้างพื้นฐานคีย์สาธารณะและโปรโตคอล SSL และคุณสมบัติที่น่าสนใจเหล่านี้อาจทำให้คุณมีความคิดในการใช้อัลกอริทึมและมาตรฐานทั้งหมดเหล่านี้ ถ้าเป็นเช่นนั้นในขณะที่แสดงความชื่นชมฉันก็ยังไม่สามารถช่วยได้ แต่เตือนคุณ: นี่เป็นกระบวนการที่น่ากลัว งานนี้ไม่ง่ายเหมือนการอ่านเอกสารการเข้ารหัสและเอกสารโปรโตคอล แต่เข้าใจรายละเอียดทุกอย่างของอัลกอริทึมมาตรฐานและเอกสารโปรโตคอลทั้งหมดเหล่านี้และการใช้คำจำกัดความเหล่านี้ เราไม่รู้ว่าคุณต้องใช้เวลานานแค่ไหนในการทำงานที่สนุกและน่ากลัว แต่ก็ไม่ใช่ปัญหาหนึ่งหรือสองปี OpenSSL เป็นคอลเลกชันอัลกอริทึมที่รวมอัลกอริทึมความปลอดภัยจำนวนมากเขียนโดยชายผู้ยิ่งใหญ่สองคน Eric A. Young และ Tim J. Hudson ตั้งแต่ปี 1995 ผ่านคำสั่งหรือห้องสมุดการพัฒนาเราสามารถใช้แอปพลิเคชันอัลกอริทึมสาธารณะมาตรฐานได้อย่างง่ายดาย
หนึ่งในแอปพลิเคชั่นสมมุติฐานของฉัน:
ด้วยความนิยมของอินเทอร์เน็ตบนมือถือแอปพลิเคชันที่พัฒนาขึ้นสำหรับอุปกรณ์มือถือกำลังเกิดขึ้นหลังจากนั้นอีก แอปพลิเคชันเหล่านี้มักจะมาพร้อมกับฟังก์ชั่นการลงทะเบียนผู้ใช้และฟังก์ชั่นการตรวจสอบรหัสผ่าน มีอันตรายที่ซ่อนอยู่ในความปลอดภัยใน "การส่งเครือข่าย" และ "การเข้าถึงบันทึกแอปพลิเคชัน" รหัสผ่านเป็นข้อมูลที่ละเอียดอ่อนสำหรับผู้ใช้และนักพัฒนาจำเป็นต้องใช้ความปลอดภัยด้านความปลอดภัยก่อนที่จะมีการเปิดตัวแอปพลิเคชัน การจัดการที่ไม่เหมาะสมอาจทำให้เกิดปัญหาเช่นการโจมตีที่เป็นอันตรายโดยคู่แข่งทางธุรกิจและการดำเนินคดีโดยพันธมิตรบุคคลที่สาม
แม้ว่าอัลกอริทึม RSA จะมีประโยชน์มากมาย แต่ก็ไม่มีตัวอย่างที่สมบูรณ์บนอินเทอร์เน็ตเพื่อแสดงวิธีการใช้งานพวกเขา ให้ฉันแนะนำด้านล่าง:
1. ใช้ OpenSSL เพื่อสร้างกุญแจส่วนตัวและสาธารณะ
ฉันใช้ระบบ Linux และติดตั้งแพ็คเกจ OpenSSL โปรดตรวจสอบว่ามีการติดตั้ง OpenSSL บนเครื่องของคุณ ข้อมูลต่อไปนี้ควรปรากฏขึ้นเมื่อเรียกใช้คำสั่ง:
[root@chaijunkun ~]# openssl เวอร์ชัน -a openssl 1.0.0 -fips 29 มี.ค. 2010 สร้างขึ้นบน: พุธ 25 มกราคม 02:17:15 GMT 2012 แพลตฟอร์ม: Linux -X86_64 ตัวเลือก: BN (64,64) MD2 (int) RC4 (16x, int) -dopenssl_pic -dzlib -dopenssl_threads -d_reentrant -ddso_dlfcn -dhave_dlfcn_h -dkrb5_mit -m64 -dl_endian -dtermio -wall -o2 -g -pipe -param = ssp -buffer -size = 4 -m64 -mtune = generic -wa, -noexecstack -dmd32_reg_t = int -dopenssl_ia32_sse2 -dopenssl_bn_asm_mont -dsha1_asm -dsha256_asm -dsha256_asm -dwhirlpool_asm openssldir: "/etc/pki/tls" เครื่องยนต์: Aesni Dynamic
ก่อนสร้างคีย์ส่วนตัว:
[root@chaijunkun ~]# openssl genrsa -out rsa_private_key.pem 1024 การสร้างคีย์ส่วนตัว RSA, 1024 ความยาวโมดูลัส .................. ++++++ .. ++++++++++
คำสั่งนี้อนุญาตให้ OpenSSL สร้างคีย์ส่วนตัวแบบสุ่มและความยาวการเข้ารหัสคือ 1024 บิต ความยาวที่เข้ารหัสหมายถึงขีด จำกัด ทางทฤษฎีของความยาว "ข้อมูลที่เข้ารหัส" สูงสุดที่อนุญาตนั่นคือขีดจำกัดความยาวของข้อความธรรมดา เมื่อพารามิเตอร์นี้เพิ่มขึ้น (ตัวอย่างเช่น 2048) ความยาวของข้อความธรรมดาที่อนุญาตจะเพิ่มขึ้นเช่นกัน แต่ก็จะทำให้ความซับซ้อนในการคำนวณเพิ่มขึ้นอย่างรวดเร็ว ความยาวที่แนะนำคือ 1024 บิต (128 ไบต์)
มาดูเนื้อหาของคีย์ส่วนตัว:
[root@chaijunkun ~]# cat rsa_private_key.pem ----- เริ่มต้น RSA ส่วนตัว ----- miicwwibaakbgqchdzcjw/rwgfwnxunbkp7/4e8w/umxx2jk6qeen69t6n2r1i/l1i mcydt1xr/t2ahgoixnq5v8w4icaaenawi7ajarhtvx1uoh/2u378fsceeseg8xdq ll0gcfb1/tjki2aitvszoxotrs8kyggu78f7vmdngxilk3gdhnzhidrshidrs8 AOGAAEKK76CSSP7K90MWYWP18GHLZRU+VEHFFT9BPV67CGLG1OWFBNTFYQSPVSTFM U2LWN5HD/ICV+EGAJ4FOLXDM43KT4WYZNOABSCKKKXS6URCIU8NOBS Phu2Te7vi4ldkw9df1fya+dscslnadaun3ohb5jqgl+ls5ecqqdufuxxn3uqgykk znrkj0j6py27hrfromehgxbjnnnapcq71szjqam7777777777777777777777777777777777777777777777 ihysll9lakeawgh4jxxxeiaufmsgjoi3QPJQGVUMKX0W96MCPCWV3FSEW7W1/MSI SUTKJP5BBVJFVFWFMAHYLJDP7W+NEBWKBWJAYBZ/EB5NAZAA egplwsji/mkhrb484xz2vyuiciwywnmfxpa3ydgqwskqdgy3rrl9lv8/aqjacjli ifigur ++ njxa8c4xy0czsobj76k710wde1mpgr5wgqfqfqf1mpgre5 /YBXBD16QVIXJVNT6QJABLI6ZX9GYRWNU6AKPDAHD8QJWONNNFNLQHUE4WEPEVKM CYSG+IBS2GGSXNTRZLWJLFX7VHMPQNTC8YNMX1KFW == -----
เนื้อหาเป็นอักขระ ASCII มาตรฐานทั้งหมดที่มีเครื่องหมายชัดเจนในจุดเริ่มต้นและบรรทัดสิ้นสุดและข้อมูลคีย์ส่วนตัวที่แท้จริงคืออักขระที่ผิดปกติตรงกลาง
เพิ่มเติมเมื่อวันที่ 24 มีนาคม 2558: ไฟล์คีย์จะจัดเก็บข้อมูลผ่านการเข้ารหัส Base64 ในที่สุด คุณจะเห็นว่าความยาวของแต่ละบรรทัดของเนื้อหาไฟล์คีย์ด้านบนเป็นเรื่องปกติมาก นี่เป็นเพราะบทบัญญัติใน RFC2045: สตรีมเอาต์พุตที่เข้ารหัสจะต้องแสดงเป็นบรรทัดไม่เกิน 76 อักขระแต่ละตัว กล่าวคือข้อมูลที่เข้ารหัสโดย Base64 จะไม่เกิน 76 อักขระต่อบรรทัดและจะต้องหารด้วยแถวสำหรับข้อมูลที่ยาวเป็นพิเศษ
ถัดไปสร้างคีย์สาธารณะตามคีย์ส่วนตัว:
[root@chaijunkun ~]# openssl rsa -in rsa_private_key.pem -out rsa_public_key.pem -pubout การเขียนคีย์ RSA
มาดูเนื้อหาของคีย์สาธารณะ:
[root@chaijunkun ~]# cat rsa_public_ley.pem ----- เริ่มกุญแจสาธารณะ ----- MIGFMA0GCSQGSIB3DQEBAQUAA4GNADCBIQKBGQCHDZCJW/RWGFWNXUNBKP7/4E8W /umxx2jk6qeen69t6n2r1i/lmcydt1xr/t2ahgoixnq5v8w4icaaenawi7ajarht vx1uoh/2u378fsceeseg8xdqll0gcfb1 XILK3GDHNZH+UOEQYWIDAQAB ---- End Public Key ---- สิ้นสุด ----
ในเวลานี้คีย์ส่วนตัวไม่สามารถใช้โดยตรงได้ดังนั้นจึงจำเป็นต้องมีการเข้ารหัส PKCS#8:
[root@chaijunkun ~]# openssl pkcs8 -topk8 -in rsa_private_key.pem -out pkcs8_rsa_private_key.pem -nocrypt
คำสั่งระบุว่าไฟล์คีย์ส่วนตัวอินพุตคือ rsa_private_key.pem และไฟล์คีย์ส่วนตัวเอาต์พุตคือ pkcs8_rsa_private_key.pem และไม่มีการเข้ารหัสรอง (-Nocrypt)
มาดูกันว่าไฟล์คีย์ส่วนตัวที่เข้ารหัสนั้นแตกต่างจากไฟล์คีย์ส่วนตัวก่อนหน้านี้หรือไม่:
[root@chaijunkun ~]# cat pkcs8_rsa_private_key.pem
----- เริ่มต้นคีย์ส่วนตัว ----- miicdqaBadanbgkqhkig9w0baqefaascal8wggjbageaaogbakepnypd+taaxcfg 6dsqnv/h7zd9szfhaotqoqsfr23o3zhwl8uzzinpxgv9pyacya 1RCLTOLPGG1XHW44F/ZTFVX+XWQRIQBXCOQWXQYJ8HX9OMOJZQK1VLNC61GZYRIA ZTVX/TWYM2BCIWTEB2GFOH66GRDLAGMBAAECGYBYB4QTVOJTVEBDLAGMBAYBGYBGYBGYBGYBPONQMBYBYBYBGYBGYBPYBYBGYBINQMBYBYBGYBGYBINGMBAYBGYBINGMBYBYBGYBYBGYBINQMYBYBYBGYBYBGYBGYBGYBTABGYB U768SF9P0GLXRTWYUDWJAVUE0VHBI9WXMWZTAVAFKCP8HXX4QZQPH84TD0ZJCQ3J DLOEGAFJKIORGZQ5FYK7YDBOU1TLJFV459C8DTZMTU MBQ3C4CHMOOYV4UZKQJBANR+7FC3E6OZGQTOESQPSPQLJBSDF9E4X4EDFUOECCKJ DVVLOOAZVTHFAIUP+H3FK4HXRPALINBEHIIDHIIDHIIDHIUX2UCQQQDCCHIPHIPHIPHIPHIPHIPHIPHIPHIPHIPHIPHIPHIPHIPHIPHIPHIPHIPHIPHIPHIPHIPHIPHIPHIPHIPHIPHIPHIPHIPHIPHIPHIPHIPHIPHIPHIPHIPHIPHIPHIPHIPHIPHIPHIPHIPHIPHIPHIPHICHIMBD 6LEQKMOA+6YPFRB3OXYKLBXCWX7DTBX+AYKY5OQMNKEG+MW8XB8WADIUL0/TB6CQ FARVAKBHVP94HK0DMDINFVHLWYJ3XY4PONGSA8VCYMJ+ASGTVKHLWYJ3XY4PONGSA8VCYMJ 2Z9EKDFIOBBAWQP2DLDGUX2VXZ8BAKBYMUIH+KBSV76CNEDWLHFLQJLKGENVQTVX TB0TUW8AVLABAXW34/5SI fae7oaqkmad3xcny6ec180tae57hz6ks+sylkwb4ggzyacxc222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222
ณ จุดนี้มีการสร้างคู่คีย์ที่มีอยู่ คีย์ส่วนตัวใช้ PKCS8_RSA_PRIVATE_KEY.PEM และคีย์สาธารณะใช้ RSA_PUBLIC_KEY.PEM
เพิ่มเมื่อวันที่ 20 พฤษภาคม 2014: เมื่อเร็ว ๆ นี้ฉันพบความจำเป็นในการเข้ารหัส RSA และอีกฝ่ายต้องการให้พวกเขาสามารถใช้ไฟล์คีย์ส่วนตัวที่ไม่ได้เข้ารหัสโดย PKCS#8 ที่สร้างขึ้นในขั้นตอนแรก ต่อมาฉันตรวจสอบเอกสารที่เกี่ยวข้องและเรียนรู้ว่าไฟล์คีย์ส่วนตัวที่สร้างขึ้นในขั้นตอนแรกคือรูปแบบ PKCS#1 รูปแบบนี้ได้รับการสนับสนุนโดย Java จริง ๆ แต่ฉันเพิ่งเขียนรหัสอีกสองบรรทัด:
rsaprivateKeyStructure ASN1PRIVKEY = ใหม่ rsAprivateKeyStructure ((ASN1Sequence) ASN1SECTEM.FROMBYTEARRAY (PRIKEYDATA)); rsaprivatekeyspec rsaprivkeyspec = ใหม่ rsaprivatekeyspec (asn1privkey.getModulus (), asn1privkey.getPrivateExponent ()); keyFactory keyFactory = keyFactory.getInstance ("RSA"); PrivateKey prikey = keyFactory.generatePrivate (rsaprivkeyspec); ก่อนอื่นอ่านไฟล์คีย์ส่วนตัวของ PKCS#1 (โปรดทราบว่าคุณลบเนื้อหาความคิดเห็นที่จุดเริ่มต้นของเครื่องหมายลบ) จากนั้นใช้ BASE64 เพื่อถอดรหัสสตริงอ่านเพื่อรับ prikeydata ซึ่งเป็นพารามิเตอร์ในบรรทัดแรกของรหัส บรรทัดสุดท้ายได้รับคีย์ส่วนตัว ไม่มีความแตกต่างในการใช้งานครั้งต่อไป
ข้อมูลอ้างอิง: https://community.oracle.com/thread/1529240?start=0&tstart=0
2. เขียนรหัส Java เพื่อทดสอบ
ภาคผนวก 23 กุมภาพันธ์ 2555: JDK มาตรฐานมีการระบุเฉพาะใน JCE (JCE (JCE (Java Cryptography Extension) เป็นชุดของแพ็คเกจที่ให้กรอบและการใช้งานสำหรับการเข้ารหัสการสร้างคีย์และการเจรจาต่อรอง วัตถุ) แต่การใช้งานภายในต้องจัดทำด้วยตนเองหรือโดยบุคคลที่สาม ภายใต้เวอร์ชัน JDK อื่น ๆ คุณสามารถค้นหาเวอร์ชันที่เกี่ยวข้องในหน้าดาวน์โหลดก่อนหน้า
มาดูรหัสที่ฉันใช้:
แพ็คเกจ net.csdn.blog.chaijunkun; นำเข้า java.io.bufferedreader; นำเข้า java.io.ioException; นำเข้า Java.io.InputStream; นำเข้า Java.io.InputStreamReader; นำเข้า Java.security.invalidkeyException; นำเข้า Java.security.keyfactory; นำเข้า Java.security.keypair; นำเข้า java.security.keypairgenerator; นำเข้า java.security.nosuchalgorithmexception; นำเข้า Java.security.Securerandom; นำเข้า java.security.interfaces.rsaprivatekey; นำเข้า java.security.interfaces.rsapublickey; นำเข้า java.security.spec.invalidkeyspecexception; นำเข้า java.security.spec.pkcs8encodedkeyspec; นำเข้า java.security.spec.x509encodedkeyspec; นำเข้า Javax.crypto.badpaddingexception; นำเข้า Javax.crypto.cipher; นำเข้า Javax.crypto.illegalblockseexception; นำเข้า Javax.crypto.nosuchpaddingexception; นำเข้า org.bouncycastle.jce.provider.bouncycastleprovider; นำเข้า Sun.misc.base64decoder; คลาสสาธารณะ rsaencrypt {สตริงคงสุดท้ายคงที่เริ่มต้น _public_key = "migfma0gcsqgsib3dqebaquaaaaa4gnadcbiqkbgqchdzcjw/rwgfwnxunbkp7/4e8w" + "/r" "/UMXX2JK6QEEN69T6N2R1I/LMCYDT1XR/T2AHGOIXNQ5V8W4ICAAAANAWI7AJARHT" + "/R" + "VX1UOH/2U378FSCEESEG8XDQLL0GCFB1/TJKI2Ait2 "/r" + "xilk3gdhnzh + uoeqywidaqab" + "/r"; สตริงสุดท้ายคงที่ส่วนตัว default_private_key = "miicdqibadanbgkqhkig9w0baqefaascal8wggjbageaaogbakepnypnypd + taaxcfg" + "/r" + "6DSQNV/H7ZD9SZFHAOTQOQSFR23O3ZHWL8UZZINPXGV9PYACY6JC1DLXXBIIJPP4" + "/R" + "1RCLTOLPGG1XHW44F/ZTFVX + XWQRIQBXCOQWXQYJ8HX9OMOJZQK1VLNC61GZYRIA" + "/R" + "ZTVX/TWYM2BCIWTEB2GFOH66GRDLAGMBAAECGYBP4QTVOJKYNUT3SBDJY/XWAETM" + "/R" + "U768SF9P0GLXRTWYUDWJAVUE0VHBI9WXMWZTAVAFKCP8HXX4QZQZQPH84TD0ZJCQ3J" + "/R" + "dloegafjkiorgzq5fyk7ydbou1tljfv459c8dtzmtu + lgsotd11/v/jr4njxiudo" + "/r" + "MBQ3C4CHMOOYV4UZKQJBANR + 7FC3E6OZGQTOESQPSPQLJBSDF9E4X4EDFUOOCCKJ" + "/R" + "DVVLOOAZVTHFAIUP + H3FK4HXRPALINBEHIIDHIAUNCUNUC2UC2UC2UC2UC2UC2UC "/r" +"6LEQKMOA +6YPFRB3OXYKLBXCWX7DTBX +AYKY5OQMNKEG +MW8XB8WADIUL0/TB6CQ" +"/R" + "FARVAKBHVP94HK0DMDINFVHLWYJ3XY4PONGSA8VCYMJ + ASGTVJZJFNZXK4GIJBJA" + "/R" + "2Z9EKDFIOBBAWQP2DLDGUX2VXZ8BAKBYMUIHiH "/r" + "tb0tuw8avlabaxw34/5si + nub1hmbgytk/t/ifcepxpbwlgo + e3pakagwlpnh0zh" + "/r" + "fae7oaqkmad3xcny6ec180tae57hz6ks + sylkwb4ggzyacxc222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222 / *** คีย์ส่วนตัว*/ ส่วนตัว rsaprivatekey Private Key; / *** คีย์สาธารณะ*/ Private Rsapublickey PublicKey; / *** ตั้งค่าส่วนตัวเป็นสตริง*/ ส่วนตัวคงที่ถ่านสุดท้าย [] hex_char = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' / *** รับคีย์ส่วนตัว* @return วัตถุคีย์ส่วนตัวปัจจุบัน*/ สาธารณะ rsaprivatekey getPrivateKey () {return privateKey; } / *** รับคีย์สาธารณะ* @return วัตถุคีย์สาธารณะปัจจุบัน* / สาธารณะ rsapublickey getPublickey () {return publicKey; } / *** คู่คีย์ที่สร้างขึ้นแบบสุ่ม* / โมฆะสาธารณะ Genkeypair () {KeypairGenerator Keypairgen = null; ลอง {keypairgen = keypairgenerator.getInstance ("RSA"); } catch (nosuchalgorithmexception e) {e.printstacktrace (); } keypairgen.initialize (1024, ใหม่ securerandom ()); KEYPAIR KEYPAIR = KEYPAIRGEN.GenerateKeyPair (); this.privatekey = (rsaprivatekey) keypair.getPrivate (); this.publickey = (rsapublickey) keypair.getPublic (); } / *** โหลดคีย์สาธารณะจากสตรีมอินพุตในไฟล์* @param ในสตรีมอินพุตของคีย์สาธารณะ* @throws ข้อยกเว้นข้อยกเว้นที่สร้างขึ้นเมื่อโหลดคีย์สาธารณะ* / โมฆะสาธารณะ loadpublickey (อินพุตสตรีม) สตริง readline = null; StringBuilder sb = new StringBuilder (); ในขณะที่ ((readline = br.readline ())! = null) {ถ้า (readline.charat (0) == '-') {ดำเนินการต่อ; } else {sb.append (readline); sb.append ('/r'); }} loadpublickey (sb.toString ()); } catch (ioexception e) {โยนข้อยกเว้นใหม่ ("ข้อผิดพลาดในการอ่านข้อมูลสตรีมข้อมูลสาธารณะ"); } catch (nullpointerexception e) {โยนข้อยกเว้นใหม่ ("สตรีมอินพุตคีย์สาธารณะว่างเปล่า"); }} / *** โหลดคีย์สาธารณะจากสตริง* @param publickeystr สตริงข้อมูลคีย์สาธารณะ* @throws ยกเว้นข้อยกเว้นที่สร้างขึ้นเมื่อโหลดคีย์สาธารณะ* / โมฆะสาธารณะ loadpublickey (สตริง publickeystr) โยนข้อยกเว้น {ลอง {base64decoder base64decoder = new base64decoder (); Byte [] buffer = base64decoder.decodeBuffer (publickeystr); keyFactory keyFactory = keyFactory.getInstance ("RSA"); X509ENCODEDKEYSPEC KEYSPEC = ใหม่ X509ENCODEDKEYSPEC (บัฟเฟอร์); this.publickey = (rsapublickey) keyfactory.generatePublic (KeySpec); } catch (nosuchalgorithmexception e) {โยนข้อยกเว้นใหม่ ("ไม่มีอัลกอริทึม"); } catch (invalidkeyspecexception e) {โยนข้อยกเว้นใหม่ ("คีย์สาธารณะผิดกฎหมาย"); } catch (ioexception e) {โยนข้อยกเว้นใหม่ ("ข้อผิดพลาดการอ่านเนื้อหาข้อมูลคีย์สาธารณะ"); } catch (nullpointerexception e) {โยนข้อยกเว้นใหม่ ("ข้อมูลคีย์สาธารณะว่างเปล่า"); }} / *** โหลดคีย์ส่วนตัวจากไฟล์* @param keyfilename ชื่อคีย์ส่วนตัวชื่อ* @return ไม่ว่าจะประสบความสำเร็จ* @throws Exception* / โมฆะสาธารณะ loadprivatekey (inputstream) โยนข้อยกเว้น {ลอง {bufferedreader br = bufferedreader ใหม่ สตริง readline = null; StringBuilder sb = new StringBuilder (); ในขณะที่ ((readline = br.readline ())! = null) {ถ้า (readline.charat (0) == '-') {ดำเนินการต่อ; } else {sb.append (readline); sb.append ('/r'); }} loadprivatekey (sb.toString ()); } catch (ioexception e) {โยนข้อยกเว้นใหม่ ("ข้อผิดพลาดการอ่านข้อมูลส่วนตัว")); } catch (nullpointerexception e) {โยนข้อยกเว้นใหม่ ("สตรีมอินพุตคีย์ส่วนตัวว่างเปล่า"); }} โมฆะสาธารณะ loadprivateKey (String PrivateKeyStr) โยนข้อยกเว้น {ลอง {base64Decoder base64Decoder = ใหม่ base64Decoder (); Byte [] buffer = base64decoder.decodeBuffer (PrivateKeyStr); PKCS8ENCODEDKEYSPEC KEYSPEC = ใหม่ PKCS8ENCODEDKEYSPEC (บัฟเฟอร์); keyFactory keyFactory = keyFactory.getInstance ("RSA"); this.privatekey = (rsaprivatekey) keyfactory.generatePrivate (KeySpec); } catch (nosuchalgorithmexception e) {โยนข้อยกเว้นใหม่ ("ไม่มีอัลกอริทึมนี้"); } catch (invalidkeyspecexception e) {โยนข้อยกเว้นใหม่ ("คีย์ส่วนตัวผิดกฎหมาย"); } catch (ioexception e) {โยนข้อยกเว้นใหม่ ("ข้อผิดพลาดการอ่านเนื้อหาข้อมูลคีย์ส่วนตัว"); } catch (nullpointerexception e) {โยนข้อยกเว้นใหม่ ("ข้อมูลคีย์ส่วนตัวว่างเปล่า"); }} / *** กระบวนการเข้ารหัส* @param PublicKey Key* @param plaintextdata ข้อมูล plaintext* @return* @throws ยกเว้นข้อมูลยกเว้นระหว่างกระบวนการเข้ารหัส* / ไบต์สาธารณะ [] เข้ารหัส (rsapublickey publickey, byte [] plaintexta) } cipher cipher = null; ลอง {cipher = cipher.getInstance ("RSA", ใหม่ bouncycastleprovider ()); cipher.init (cipher.encrypt_mode, PublicKey); ไบต์ [] เอาต์พุต = cipher.dofinal (plaintextdata); เอาต์พุตกลับ; } catch (nosuchalgorithmexception e) {โยนข้อยกเว้นใหม่ ("อัลกอริทึมการเข้ารหัส nothis"); } catch (nosuchpaddingexception e) {e.printstacktrace (); คืนค่า null; } catch (InvalidKeyException E) {โยนข้อยกเว้นใหม่ ("รหัสสาธารณะเข้ารหัสผิดกฎหมายโปรดตรวจสอบ"); } catch (unlegalblocksizeException e) {โยนข้อยกเว้นใหม่ ("ความยาว placktext ผิดกฎหมาย"); } catch (badpaddingexception e) {โยนข้อยกเว้นใหม่ ("ข้อมูล placktext เสียหาย"); }} / *** กระบวนการถอดรหัส* @param PrivateKey คีย์ส่วนตัว* @param cipherdata ciphertext ข้อมูล* @return plaintext* @throws ข้อมูลยกเว้นข้อยกเว้นในระหว่างกระบวนการถอดรหัส* / ไบต์สาธารณะ [] decrypt (rsaprivatekey privatekey, byte [] cipherdata ชุด"); } cipher cipher = null; ลอง {cipher = cipher.getInstance ("RSA", ใหม่ bouncycastleprovider ()); cipher.init (cipher.decrypt_mode, PrivateKey); ไบต์ [] เอาต์พุต = cipher.dofinal (cipherdata); เอาต์พุตกลับ; } catch (nosuchalgorithmexception e) {โยนข้อยกเว้นใหม่ ("ไม่มีการถอดรหัสอัลกอริทึม"); } catch (nosuchpaddingexception e) {e.printstacktrace (); คืนค่า null; } catch (InvalidKeyException E) {โยนข้อยกเว้นใหม่ ("คีย์เอกชนถอดรหัสผิดกฎหมายโปรดตรวจสอบ"); } catch (unlegalblocksizeException e) {โยนข้อยกเว้นใหม่ ("ความยาว cryptotext ผิดกฎหมาย"); } catch (badpaddingexception e) {โยนข้อยกเว้นใหม่ ("ข้อมูล cryptotext เสียหาย"); }} / *** ข้อมูลไบต์ไปยัง hexadecimal string* @param ข้อมูลอินพุตข้อมูล* @return เนื้อหา hexadecimal* / สตริงคงที่สาธารณะ byteArrayToString (byte [] data) {StringBuilder StringBuilder = StringBuilder ใหม่ (); สำหรับ (int i = 0; i <data.length; i ++) {// นำตัวเลขสี่หลักของไบต์เป็นดัชนีเพื่อรับตัวระบุ hexadecimal ที่สอดคล้องกันหมายเหตุว่าสตริงกะที่ไม่ได้ลงนาม // นำบิตที่ต่ำกว่าสี่บิตเป็นดัชนีเพื่อรับ hexadecimal identifier stringbuilder.append (hex_char [(data [i] & 0x0f)]); if (i <data.length-1) {stringbuilder.append (''); }} return stringbuilder.toString (); } โมฆะคงที่สาธารณะหลัก (สตริง [] args) {rsaencrypt rsaencrypt = new rsaencrypt (); //rsaencrypt.genkeypair (); // โหลดคีย์สาธารณะลอง {rsaencrypt.loadpublickey (rsaencrypt.default_public_key); System.out.println ("การโหลดคีย์สาธารณะประสบความสำเร็จ"); } catch (exception e) {system.err.println (e.getMessage ()); System.err.println ("การโหลดคีย์สาธารณะล้มเหลว"); } // การโหลดคีย์ส่วนตัวลอง {rsaencrypt.loadprivatekey (rsaencrypt.default_private_key); System.out.println ("การโหลดคีย์ส่วนตัวประสบความสำเร็จ"); } catch (exception e) {system.err.println (e.getMessage ()); System.err.println ("การโหลดคีย์ส่วนตัวล้มเหลว"); } // ทดสอบสตริงสตริง EncryptStr = "ทดสอบสตริง chaijunkun"; ลอง {// เข้ารหัสไบต์ [] cipher = rsaencrypt.encrypt (rsaencrypt.getpublickey (), encryptstr.getBytes ()); // decrypt byte [] plaintext = rsaencrypt.decrypt (rsaencrypt.getPrivateKey (), cipher); System.out.println ("ความยาว ciphertext:"+ cipher.length); System.out.println (rsaencrypt.bytearraytoString (cipher)); System.out.println ("ความยาวข้อความธรรมดา:"+ plaintext.length); System.out.println (rsaencrypt.bytearraytoString (plaintext)); System.out.println (สตริงใหม่ (plaintext)); } catch (exception e) {system.err.println (e.getMessage ()); - ในรหัสฉันมีสองวิธีในการโหลดกุญแจสาธารณะและส่วนตัว
อ่านโดยสตรีม: เหมาะสำหรับวิธีการรับอินพุทสตรีมโดยทรัพยากรการจัดทำดัชนี ID ในแอปพลิเคชัน Android;
อ่านโดยสตริง: ดังที่แสดงในรหัสจัดเก็บเนื้อหาคีย์โดยบรรทัดลงในค่าคงที่คงที่และนำเข้าคีย์ตามประเภทสตริง
เรียกใช้รหัสด้านบนและข้อมูลต่อไปนี้จะปรากฏขึ้น:
1 64 57 C8 E3 46 A7 CE 57 31 AC CD 21 89 89 8F C1 24 C1 22 0C CB 70 6A 0D FA C9 38 80 BA 2E E1 29 02 ED 45 9E 88 E9 23 09 87 AF AB AC CB 61 03 3C A1 81 56 A5 9f fd 22 87 9e de b1 f4 e8 b2 ความยาวข้อความธรรมดา: 22 54 65 73 74 20 53 74 72 69 6e 67 20 63 68 61 69 6a 75 6e 6b 75 6e ทดสอบสตริง Chaijunkun
ในฟังก์ชั่นหลักฉันแสดงความคิดเห็นว่า "rsaencrypt.genkeypair ()" ซึ่งใช้ในการสร้างคู่คีย์แบบสุ่ม (เฉพาะสร้างใช้ไม่ใช่เก็บ) เมื่อไม่ได้ใช้คีย์ไฟล์คุณสามารถแสดงความคิดเห็นรหัสที่โหลดคีย์เปิดใช้งานวิธีนี้หรือเรียกใช้รหัส
ความแตกต่างระหว่างการโหลดคีย์สาธารณะและการโหลดคีย์ส่วนตัวคือเมื่อโหลดคีย์สาธารณะ X509ENCODEDKEYSPEC (คำสั่งคีย์ที่เข้ารหัส X509) และเมื่อโหลดคีย์ส่วนตัว PKCS8ENCODEDKEYSPEC (คำสั่ง KEY ที่เข้ารหัสรหัส 8)
เพิ่มเมื่อวันที่ 22 กุมภาพันธ์ 2012: ในระหว่างการพัฒนาซอฟต์แวร์ Android พบว่ารหัสข้างต้นไม่ทำงานอย่างถูกต้อง เหตุผลหลักคือคลาส Sun.misc.base64decoder ไม่มีอยู่ในแพ็คเกจการพัฒนา Android ดังนั้นคุณต้องค้นหาซอร์สโค้ดของ RT.JAR บนอินเทอร์เน็ต สำหรับซอร์สโค้ดใน SRC.ZIP ของ JDK นี่เป็นเพียงส่วนหนึ่งของซอร์สโค้ดใน JDK และรหัสของคลาสข้างต้นไม่มีอยู่ หลังจากค้นหาและเพิ่มรหัสด้านบนทำงานได้ดีในแอปพลิเคชัน Android สิ่งนี้มีรหัสที่สอดคล้องกันสำหรับคลาสนี้ นอกจากนี้คลาสนี้ยังขึ้นอยู่กับ ceformatexception, cestreamexineded, ตัวละครและคลาส actrialEncoder และคำจำกัดความข้อยกเว้น
เพิ่มเมื่อวันที่ 23 กุมภาพันธ์ 2012: ตอนแรกฉันเขียนบทความนี้เพื่อใช้การเข้ารหัสและการถอดรหัส RSA โดยไม่ต้องพึ่งพาแพ็คเกจบุคคลที่สามใด ๆ แต่ฉันพบปัญหาในภายหลัง เนื่องจากต้องสร้างวัตถุ Cipher ทั้งในวิธีการเข้ารหัสการเข้ารหัสและ Decrypt Decrypt วัตถุนี้สามารถรับอินสแตนซ์ผ่าน GetInstance เท่านั้น มีสองประเภท: สิ่งแรกคือการระบุเฉพาะอัลกอริทึมและไม่ใช่ผู้ให้บริการ ประการที่สองคือการระบุทั้งสอง ในตอนแรกรหัสยังสามารถทำงานได้ แต่คุณจะพบว่าผลลัพธ์ของการเข้ารหัสแต่ละครั้งนั้นแตกต่างกัน ต่อมามีการค้นพบว่าคีย์สาธารณะและส่วนตัวที่ใช้โดยวัตถุ Cipher นั้นถูกสร้างขึ้นแบบสุ่มภายในไม่ใช่คีย์สาธารณะและส่วนตัวที่ระบุไว้ในรหัส น่าแปลกที่รหัสนี้ที่ไม่ได้ระบุผู้ให้บริการสามารถเรียกใช้แอปพลิเคชัน Android และผลลัพธ์ของการเข้ารหัสแต่ละครั้งก็เหมือนกัน ฉันคิดว่านอกเหนือจากฟังก์ชั่นการพัฒนาระบบบางอย่างใน Android SDK แล้วมันยังใช้ฟังก์ชั่นของ JDK มันอาจให้ผู้ให้บริการที่สอดคล้องกันใน JDK ของตัวเองซึ่งทำให้ผลการเข้ารหัสเหมือนกันทุกครั้ง เมื่อฉันเพิ่มผู้ให้บริการ bouncycastle เช่นรหัสตัวอย่างบนอินเทอร์เน็ตผลลัพธ์ของการเข้ารหัสแต่ละครั้งจะเหมือนกัน
ขอบคุณสำหรับการอ่านฉันหวังว่ามันจะช่วยคุณได้ ขอบคุณสำหรับการสนับสนุนเว็บไซต์นี้!