- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
我正在尝试验证文件的签名。我按照这些说明生成证书:
// 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
我使用了 this link 中的示例散列一些数据并验证一切正常(我执行了步骤 2 - 5)。
现在我正在尝试将 .der 文件、签名文件和数据文件放入 Android 应用程序中,并再次验证它是否一切正常。我没有收到任何错误,但我没有出错。下面是我编写的代码:
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;
}
}
我读过的所有内容都表明我的代码是正确的。我认为关于获取公钥的部分是正确的,因为模数与实际 .der 文件中的模数匹配。
请帮忙!
编辑:我认为这与我读取签名文件或数据文件的方式有关。我很确定我正确地获取了有关公钥的所有信息,因为我打印了有关它的其他信息并且它与openssl 输出
编辑根据下面 Nikolay 的建议,我尝试使用以下代码在 Android 应用程序中签署与我在 openssl 中签署的相同数据:
// 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));
注意事项:在 Jelly Bean 中使用上述代码,您必须在创建 KeyFactory 时指定“BC”。
然后我对签名结果进行哈希处理,看它是否与使用 openssl 生成的签名文件的哈希匹配,但它们不匹配.. 所以我不知道那是什么意思,但我知道这意味着什么!我假设在 openssl 中创建签名文件时需要指定某种附加选项?
编辑:
根据下面 Nikolay 的评论,我更新了我的测试代码以不签名,但是在 java 中创建的签名的哈希值仍然与使用 openssl 创建的签名文件的哈希值不匹配......不确定是什么问题,Java,OpenSSL,或者我。
最佳答案
在@NikolayElenkov 的大量帮助下,我终于弄清楚出了什么问题。尝试不同的谷歌搜索,我偶然发现了 this stackoverflow question ,那家伙说你可以运行两个不同的签名命令。当我创建我所有的签名时,我使用的是我上面链接的东西:
// create a hash
echo 'data to sign' > data.txt
openssl dgst -sha1 < data.txt > hash
// sign it
openssl rsautl -sign -inkey private.pem -keyform PEM -in hash > signature
// verify it
openssl rsautl -verify -inkey public.pem -keyform PEM -pubin -in signature > verified
diff -s verified hash
从我今天找到的帖子中,我尝试了:
openssl dgst -sha1 -sign privateKey.pem -out signature1 someInputFile
正如那个人所说,它创建了一个不同的签名文件。这就是我的 Android 代码所需要的!所以,验证这个的答案是我需要改变我生成签名文件的方式! (如果没有@NikolayElenkov,我不会走到这一步,非常感谢!)
关于android 使用 .der 公钥验证文件签名,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13807267/
在 JSF2 应用程序中遇到验证属性的问题时,有两种主要方法。 使用 Annotation 在 ManagedBean 上定义验证 @ManagedBean public class MyBean {
我想实现一个不常见的功能,我认为 jquery 验证插件将是最好的方法(如果您在没有插件的情况下建议和回答,我们也会欢迎)。我想在用户在输入字段中输入正确的单词后立即隐藏表单。我试过这个: $("
我有几个下拉菜单(类名为month_dropdown),并且下拉菜单的数量不是恒定的。我怎样才能为它们实现 NotEqual 验证。我正在使用 jQuery 验证插件。 这就是我写的 - jQuery
我设法制作了这个网址验证代码并且它起作用了。但我面临着一个问题。我认为 stackoverflow 是获得解决方案的最佳场所。 function url_followers(){ var url=do
我目前正在使用后端服务,该服务允许用户在客户端应用程序上使用 Google Games 库登录。 用户可以通过他们的 gplay ID 向我们发送信息,以便登录或恢复旧帐户。用户向我们发送以下内容,包
我正在尝试验证输入以查看它是否是有效的 IP 地址(可能是部分地址)。 可接受的输入:172、172.112、172.112.113、172.112.113.114 Not Acceptable 输入
我从 Mongoose 验证中得到这条消息: 'Validator failed for path phone with value ``' 这不应该发生,因为不需要电话。 这是我的模型架构: var
我一直在尝试使用Python-LDAP (版本 2.4.19)在 MacOS X 10.9.5 和 Python 2.7.9 下 我想在调用 .start_tls_s() 后验证与给定 LDAP 服务
我正在处理一个仅与 IE6 兼容的旧 javascript 项目(抱歉...),我想仅在 VS 2017 中禁用此项目的 ESLint/CSLint/Javascript 验证/CSS 验证。 我知道
我正在寻找一种方法来验证 Spring 命令 bean 中的 java.lang.Double 字段的最大值和最小值(一个值必须位于给定的值范围之间),例如, public final class W
我正在尝试在 springfuse(JavaEE 6 + Spring Framework (针对 Jetty、Tomcat、JBoss 等)) 和 maven 的帮助下构建我的 webapps 工作
我试图在我们的项目中使用 scalaz 验证,但遇到了以下情况: def rate(username: String, params: Map[String, String]): Validation
我有一个像这样的 Yaml 文件 name: hhh_aaa_bbb arguments: - !argument name: inputsss des
我有一个表单,人们可以单击并向表单添加字段,并且我需要让它在单击时验证这些字段中的值。 假设我单击它两次并获取 2 个独立的字段集,我需要旋转 % 以确保它在保存时等于 100。 我已放入此函数以使其
在我的页面中有一个选项可以创建新的日期字段输入框。用户可以根据需要创建尽可能多的“截止日期”和“起始日期”框。就像, 日期_to1 || date_from1 日期到2 ||日期_from2 date
我有一个像这样的 Yaml 文件 name: hhh_aaa_bbb arguments: - !argument name: inputsss des
有没有办法在动态字段上使用 jquery 验证表单。 我想将其设置为必填字段 我正在使用 Jsp 动态创建表单字段。 喜欢 等等...... 我想使用必需的表单字段验证此表单字段。 最佳答
嗨,任何人都可以通过提供 JavaScript 代码来帮助我验证用户名文本框不应包含数字,它只能包含一个字符。 最佳答案 使用正则表达式: (\d)+ 如果找到匹配项,则字符串中就有一个数字。 关于J
我有两个输入字段holidayDate和Description(id=tags) $(document).ready(function() {
我遇到了这个问题,这些验证从电子邮件验证部分开始就停止工作。 我只是不明白为什么即使经过几天的观察,只是想知道是否有人可以在这里指出我的错误? Javascript部分: function valid
我是一名优秀的程序员,十分优秀!