2015-12-03 5 views
5

मैं एक एंड्रॉइड एप्लिकेशन विकसित कर रहा हूं जिसके लिए डिजिटली हस्ताक्षर एचटीएमएल दस्तावेज़ की आवश्यकता है। दस्तावेज़ जेएसओएन फॉर्म में डीबी में रहता है। मैं दस्तावेज पर हस्ताक्षर करने कर रहा हूँ स्थानीय स्तर पर एक bash स्क्रिप्ट मैं कुछ अन्य तो सवाल पर पाया का उपयोग कर:एंड्रॉइड पर डिजिटल हस्ताक्षर सत्यापित करें

openssl dgst -sha1 someHTMLDoc.html > hash openssl rsautl -sign -inkey privateKey.pem -keyform PEM -in hash > signature.bin

निजी कुंजी का उपयोग कर बनाया गया:

openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -pkeyopt rsa_keygen_pubexp:3 -out privateKey.pem 

सार्वजनिक कुंजी का उपयोग कर बनाया गया:

openssl pkey -in privateKey.pem -out publicKey.pem -pubout 

मैं कुछ HTMLDoc.html में डेटा के साथ Signature.bin में बनाए गए हस्ताक्षर को सत्यापित करना चाहता हूं, वें ई आवेदन इस प्रकार

{ "data" : "<html><body></body></html>", "signature":"6598 13a9 b12b 21a9 ..... " } 

एंड्रॉयड आवेदन साझा वरीयता में PublicKey रखती है::

मैं दोनों एचटीएमएल और के रूप में JSON वस्तु पूर्व हस्ताक्षर भेज रहा हूँ

-----BEGIN PUBLIC KEY----- MIIBIDANBgkqhkiG9w0AAAEFAAOCAQ0AvniCAKCAQEAvni/NSEX3Rhx91HkJl85 \nx1noyYET ......

सूचना "\ n" (न्यूलाइन) वहां (स्वचालित रूप से publicKey.pem से स्ट्रिंग को Android Gradle Config में स्ट्रिंग की प्रतिलिपि बनाते समय स्वचालित रूप से जोड़ा गया था।

ठीक है, सभी तैयारी के बाद, अब सवाल है। मैं बिना किसी सफलता के कुंजी को सत्यापित करने की कोशिश कर रहा हूं।

private boolean verifySignature(String data, String signature) { 
    InputStream is = null; 
    try { 
     is = new ByteArrayInputStream(Config.getDogbarPublic().getBytes("UTF-8")); //Read DogBar Public key 

     BufferedReader br = new BufferedReader(new InputStreamReader(is)); 
     List<String> lines = new ArrayList<String>(); 
     String line; 
     while ((line = br.readLine()) != null) 
      lines.add(line); 

     // removes the first and last lines of the file (comments) 
     if (lines.size() > 1 && lines.get(0).startsWith("-----") && lines.get(lines.size() - 1).startsWith("-----")) { 
      lines.remove(0); 
      lines.remove(lines.size() - 1); 
     } 

     // concats the remaining lines to a single String 
     StringBuilder sb = new StringBuilder(); 
     for (String aLine : lines) 
      sb.append(aLine); 
     String key = sb.toString(); 

     byte[] keyBytes = Base64.decode(key.getBytes("utf-8"), Base64.DEFAULT); 
     X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes); 
     KeyFactory keyFactory = KeyFactory.getInstance("RSA"); 
     PublicKey publicKey = keyFactory.generatePublic(spec); 

     Signature signCheck = Signature.getInstance("SHA1withRSA"); //Instantiate signature checker object. 
     signCheck.initVerify(publicKey); 
     signCheck.update(data.getBytes()); 
     return signCheck.verify(signature.getBytes()); //verify signature with public key 
    } catch (Exception e) { 
     e.printStackTrace(); 
     return false; 
    } 
} 

किसी को भी मदद कर सकते हैं:

मैं निम्नलिखित कोड का उपयोग कर रहा हूँ? मैं क्या गलत कर रहा हूं ?

क्या मुझे कुछ बाइट रूपांतरण याद आ रहा है? शायद JSON ऑब्जेक्ट हस्ताक्षर को प्रभावित कर रहा है?

क्या हस्ताक्षर में \ n (लाइनब्रेक) होना चाहिए जिसमें मूल फ़ाइल में JSON फ़ाइल के बिना होना चाहिए या होना चाहिए?

सभी मदद के लिए अग्रिम धन्यवाद, इसकी अत्यधिक सराहना की गई।

S = E(H(C)) 

हस्ताक्षर सत्यापन लेता है:

+0

मैं बिना किसी सफलता के विभिन्न तरीकों का प्रयास करता रहता हूं, JSON ऑब्जेक्ट से लाइन ब्रेक को हटाने का प्रयास किया है, GetBytes ("ASCII") को प्राप्त करने का प्रयास किया है और बाइट्स ("यूटीएफ -8") प्राप्त करें। – Noxymon

+1

क्या आपको कोई अपवाद मिला? कौनसा? – Henry

+0

मुझे कोई अपवाद नहीं मिला, यह सिर्फ 'signCheck.verify() ' – Noxymon

उत्तर

3

डिजिटल हस्ताक्षर डाइजेस्ट डेटा (सी) के (समारोह एच) कंप्यूटिंग और (समारोह ई) असममित एन्क्रिप्शन एल्गोरिथ्म के साथ एन्क्रिप्ट करने बीजलेख पाठ (एस) का उत्पादन करने की एक प्रक्रिया है हस्ताक्षर दिए गए हस्ताक्षर (फ़ंक्शन डी) को अस्वीकार करता है - जिसके परिणामस्वरूप एच (सी) केवल तभी होता है जब डिक्रिप्शन में उपयोग की जाने वाली सार्वजनिक कुंजी को एन्क्रिप्शन में उपयोग की जाने वाली निजी कुंजी के साथ जोड़ा जाता है, और यह जांचने के लिए डेटा की पाचन की गणना करता है कि दो डायजेस्ट मैच हैं:

H(C) == D(E(H(C))) 

यह इस टी से स्पष्ट है हैश फ़ंक्शन (सी) को दिए गए बाइट्स को हस्ताक्षर करने के लिए हस्ताक्षर के लिए बिल्कुल वही होना चाहिए।

आपके मामले में वे नहीं हैं, क्योंकि आप डाइजेस्ट कंप्यूटिंग रहे हैं जब openssl dgst उत्पादन (एच (सी) दाईं ओर) का उपयोग करते हुए सचमुच की तरह कुछ है:

SHA1(someHTMLDoc.html)= 22596363b3de40b06f981fb85d82312e8c0ed511 

और यह करने के लिए इनपुट है आरएसए एन्क्रिप्शन।

और जब आप हस्ताक्षर सत्यापित कर रहे हैं, डाइजेस्ट (एच (सी) बाईं ओर) के उत्पादन में कच्चे बाइट्स, उदाहरण के लिए हेक्स में कर रहे हैं:

22596363b3de40b06f981fb85d82312e8c0ed511 

तो तुम अंत निर्माण करने के लिए बाइट्स को एनक्रिप्ट (एच (सी) दाईं ओर):

0000000: 5348 4131 2873 6f6d 6548 746d 6c44 6f63 SHA1(someHtmlDoc 
0000010: 2e68 746d 6c29 3d20 3232 3539 3633 3633 .html)= 22596363 
0000020: 6233 6465 3430 6230 3666 3938 3166 6238 b3de40b06f981fb8 
0000030: 3564 3832 3331 3265 3863 3065 6435 3131 5d82312e8c0ed511 
0000040: 0a          . 

और बाइट्स के खिलाफ की तुलना (एच (सी) बाईं ओर):

0000000: 2259 6363 b3de 40b0 6f98 1fb8 5d82 312e "[email protected]].1. 
0000010: 8c0e d511        .... 

उचित आउटपुट प्रारूप (Difference between openSSL rsautl and dgst देखें) के लिए आपको -signopenssl dgst के साथ उपयोग करने की आवश्यकता है।

OpenSSL तरफ

तो कार्य करें:

openssl dgst -sha1 -sign privateKey.pem someHTMLDoc.html > signature.bin 

जावा तरफ कार्य करें:

import java.io.FileInputStream; 
import java.io.FileNotFoundException; 
import java.io.InputStream; 
import java.io.InputStreamReader; 
import java.security.KeyFactory; 
import java.security.Signature; 
import java.security.interfaces.RSAPublicKey; 
import java.security.spec.X509EncodedKeySpec; 

import org.spongycastle.util.io.pem.PemObject; 
import org.spongycastle.util.io.pem.PemReader; 

public class VerifySignature { 
    public static void main(final String[] args) throws Exception { 
     try (PemReader reader = publicKeyReader(); InputStream data = data(); InputStream signatureData = signature()) { 
      final PemObject publicKeyPem = reader.readPemObject(); 
      final byte[] publicKeyBytes = publicKeyPem.getContent(); 
      final KeyFactory keyFactory = KeyFactory.getInstance("RSA"); 
      final X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(publicKeyBytes); 
      final RSAPublicKey publicKey = (RSAPublicKey) keyFactory.generatePublic(publicKeySpec); 

      final Signature signature = Signature.getInstance("SHA1withRSA"); 
      signature.initVerify(publicKey); 

      final byte[] buffy = new byte[16 * 1024]; 
      int read = -1; 
      while ((read = data.read(buffy)) != -1) { 
       signature.update(buffy, 0, read); 
      } 

      final byte[] signatureBytes = new byte[publicKey.getModulus().bitLength()/8]; 
      signatureData.read(signatureBytes); 

      System.out.println(signature.verify(signatureBytes)); 
     } 
    } 

    private static InputStream data() throws FileNotFoundException { 
     return new FileInputStream("someHTMLDoc.html"); 
    } 

    private static PemReader publicKeyReader() throws FileNotFoundException { 
     return new PemReader(new InputStreamReader(new FileInputStream("publicKey.pem"))); 
    } 

    private static InputStream signature() throws FileNotFoundException { 
     return new FileInputStream("signature.bin"); 
    } 
} 

मैं सार्वजनिक कुंजी का पीईएम डिकोडिंग के लिए Spongy Castle का उपयोग किया है चीज़ें थोड़ी अधिक पठनीय बनाने के लिए और उपयोग करने में आसान है।

+0

के लिए गलत है, मुझे यकीन नहीं है कि मैं पूरी तरह से समझता हूं .. आप एन्क्रिप्टिंग के बारे में कैसे जा सकते हैं? क्या मुझे dgst फ़ंक्शन का केवल '22596363b3de40b06f981fb85d82312e8c0ed511' भाग लेना चाहिए और उसके साथ साइन इन करना चाहिए? क्या आप कृपया बता सकते हैं कि मैंने जो गलती की है, उसके बजाय मुझे क्या करना चाहिए? मुझे यह समझने में कठिनाई हो रही है कि लिखे गए बारे में कैसे जाना है। – Noxymon

+1

मेरा संपादित उत्तर देखें, आपको जेसीई में हस्ताक्षर कार्यान्वयन द्वारा आवश्यक बाइनरी आउटपुट का उत्पादन करने के लिए 'openssl dgst'' -sign' विकल्प के साथ उपयोग करना चाहिए। –

+0

इस आदमी को एक कुकी दे दो! आप महोदय एक प्रतिभाशाली हैं! बहुत बहुत धन्यवाद। – Noxymon

संबंधित मुद्दे