android verifiziere Signatur der Datei mit .der öffentlichem Schlüssel
Ich versuche die Signatur einer Datei zu überprüfen. Ich habe die folgenden Anweisungen befolgt, um ein Zertifikat zu erstellen:
// generate a private key with size of 2048 bits
openssl genrsa -out private_key.pem 2048
// derive a public key from the above private key
openssl rsa -in private_key.pem -out public_key.pem -outform PEM -pubout
// iOS will not import PEM encoded data so it needs to be converted to DER encoded data
openssl rsa -pubin -inform PEM -outform DER -in public_key.pem -out public_key.der
// generate a self-signed certificate for testing
openssl req -new -x509 -key private_key.pem -out test_cert.pem -days 1095
// show the content of the original certificate
openssl x509 -in test_cert.pem -text -noout
// convert the certificate to DER format
openssl x509 -in test_cert.pem -outform der -out test_cert.der
// show the content of the new certificate
openssl x509 -in test_cert.der -inform der -text -noout
Ich habe das Beispiel bei verwendetdieser Link um einige Daten zu hashen und zu überprüfen, ob alles in Ordnung ist (ich habe die Schritte 2 - 5 ausgeführt).
Jetzt versuche ich, die .der-Datei, die Signaturdatei und die Datendatei in eine Android-Anwendung zu integrieren und zu überprüfen, ob alles wieder in Ordnung ist. Ich erhalte keine Fehler, aber ich erhalte keine Fehler. Unten ist der Code, den ich geschrieben habe:
import android.app.Activity;
import android.os.Bundle;
import android.os.Environment;
import android.util.Base64;
import android.util.Log;
import android.widget.TextView;
import java.io.*;
import java.security.*;
import java.security.cert.CertificateFactory;
import java.security.cert.Certificate;
// Most of the below is taken from:
// http://www.herongyang.com/JDK/Digital-Signature-JcaVerify-Signature-Verification-Program.html
public class MyActivity extends Activity {
String input = Environment.getExternalStorageDirectory() + "/data.txt";
String signFile = Environment.getExternalStorageDirectory() + "/signature";
String signAlgo = "SHA1withRSA";
int keyFile = R.raw.test_cert_josh;
String TAG = "VERIFY";
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
TextView textView = (TextView) findViewById(R.id.textView);
try {
PublicKey pubKey = readPublicKey(keyFile);
byte[] sign = readSignature(signFile);
textView.setText(verify(input, signAlgo, sign, pubKey) + "");
} catch (Exception e) {
e.printStackTrace();
}
}
PublicKey readPublicKey(int cert_id) throws Exception {
InputStream in = MyActivity.this.getResources().openRawResource(cert_id);
byte[] buff = new byte[4000];
int bytesRead;
ByteArrayOutputStream out = new ByteArrayOutputStream();
while((bytesRead = in.read(buff)) != -1) {
out.write(buff, 0, bytesRead);
Log.i(TAG, "bytes read: " + bytesRead);
}
byte[] publicKeyBytes = out.toByteArray();
CertificateFactory cf = CertificateFactory.getInstance("X509");
Certificate cert = cf.generateCertificate(new ByteArrayInputStream(publicKeyBytes));
PublicKey pubKey = cert.getPublicKey();
Log.i(TAG, "Public Key Info: ");
Log.i(TAG, "Algorithm = " + pubKey.getAlgorithm());
Log.i(TAG, "toString = " + pubKey.toString());
return pubKey;
}
byte[] readSignature(String input) throws Exception {
FileInputStream signStream = new FileInputStream(input);
byte[] signBytes = new byte[signStream.available()];
signStream.read(signBytes);
signStream.close();
return signBytes;
}
boolean verify(String input, String algorithm, byte[] sign, PublicKey pubKey) throws Exception {
Signature sg = Signature.getInstance(algorithm);
sg.initVerify(pubKey);
Log.i(TAG, "Signature Object Info: ");
Log.i(TAG, "Algorithm = "+sg.getAlgorithm());
Log.i(TAG, "Provider = "+sg.getProvider());
FileInputStream in = new FileInputStream(input);
byte[] buff = new byte[in.available()];
in.read(buff);
sg.update(buff);
boolean ok = sg.verify(sign);
Log.i(TAG, "Verify Processing Info: ");
Log.i(TAG, "Verification result = "+ok);
return ok;
}
}
Nach allem, was ich gelesen habe, stimmt mein Code. Ich denke, der Teil über das Herausholen des öffentlichen Schlüssels ist richtig, weil der Modul mit dem in der tatsächlichen .der-Datei übereinstimmt.
Bitte helfen Sie!
BEARBEITEN: Ich denke, es hat entweder damit zu tun, wie ich die Signaturdatei oder die Datendatei einlese. Ich bin mir ziemlich sicher, dass ich alles über den öffentlichen Schlüssel richtig verstehe, da ich zusätzliche Informationen darüber ausgedruckt habe und sie mit denen übereinstimmen openssl Ausgabe
BEARBEITEN Gemäß Nikolays Vorschlag unten habe ich versucht, die gleichen Daten in der Android-App zu signieren, die ich mit diesem Code in openssl signiert habe:
// testing code to sign it myself
// read the data file in
FileInputStream dataStream = new FileInputStream(input);
byte[] dataBytes = new byte[dataStream.available()];
dataStream.read(dataBytes);
dataStream.close();
// hash the data file, like i do with openssl
// per Nikolay's comments, this is not needed
MessageDigest digest = MessageDigest.getInstance("SHA-1");
// digest.update(dataBytes, 0, dataBytes.length);
// dataBytes = digest.digest();
Log.i(TAG, "data from file: " + new String(dataBytes));
// read the private key in
FileInputStream fis = new FileInputStream(Environment.getExternalStorageDirectory() + "/phaero/private_key.pem");
byte[] keyBytes = new byte[fis.available()];
fis.read(keyBytes);
fis.close();
// clean up the private key and decode it
String temp = new String(keyBytes);
Log.i(TAG, "private key: " + temp);
String privKeyPEM = temp.replace("-----BEGIN RSA PRIVATE KEY-----\n", "");
privKeyPEM = privKeyPEM.replace("-----END RSA PRIVATE KEY-----", "");
byte[] decoded = Base64.decode(privKeyPEM.getBytes(), Base64.DEFAULT);
// create the private key object from the private key data
PKCS8EncodedKeySpec private_spec = new PKCS8EncodedKeySpec(decoded);
KeyFactory kf = KeyFactory.getInstance("RSA");
PrivateKey privateKey = kf.generatePrivate(private_spec);
// set up for signing
Signature signer = Signature.getInstance(signAlgo);
signer.initSign(privateKey);
signer.update(dataBytes, 0, dataBytes.length);
// sign, and hash again so i can compare against openssl output
byte[] signed = signer.sign();
digest.update(signed, 0, signed.length);
Log.i(TAG, new BigInteger(1, digest.digest()).toString(16));
Kurzer Hinweis: Wenn Sie den obigen Code in Jelly Bean verwenden, müssen Sie beim Erstellen der KeyFactory "BC" angeben.
Dann habe ich das Signaturergebnis gehasht, um zu sehen, ob es mit dem Hash der mit openssl generierten Signaturdatei übereinstimmt, und sie stimmen nicht überein. Ich weiß also nicht, was das bedeutet, aber ich weiß, dass es etwas bedeutet! Ich gehe davon aus, dass ich beim Erstellen der Signaturdatei in openssl eine zusätzliche Option angeben muss.
BEARBEITEN:
Laut Nikolays Kommentar unten habe ich meinen Testcode so aktualisiert, dass er nicht signiert, aber der Hash der in Java erstellten Signatur stimmt immer noch nicht mit dem Hash der mit openssl erstellten Signaturdatei überein. Ich bin nicht sicher, was los ist, Java, OpenSSL oder ich.