手动给android APK签名

一、下载openssl-for-windows
例如下载:
下载完毕后直接解压缩,cmd命令进入bin目录下:
openssl genrsa -3 -out testkey.pem 2048
成功生成:testkey.pem  [– 包含私钥的pem文件]
openssl req -new -x509 -key testkey.pem -out testkey.x509.pem -days 10000
[包含公钥的x509 pem文件]
输出错误信息:
Unable to load config info from c:/openssl/ssl/openssl.cnf
只要把openssl目录下的openssl.cnf文件复制到c:/openssl/ssl/目录下即可(目录不存在则手动创建之)。
然后再次输入上述命令后输出:
Loading ‘screen’ into random state – done
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter ‘.’, the field will be left blank.
—–
Country Name (2 letter code) [AU]:cn
State or Province Name (full name) [Some-State]:zhejiang
Locality Name (eg, city) []:hangzhou
Organization Name (eg, company) [Internet Widgits Pty Ltd]:sing
Organizational Unit Name (eg, section) []:sing
Common Name (eg, YOUR name) []:netease
Email Address []:test@163.com
成功生成:testkey.x509.pem
openssl pkcs8 -in testkey.pem -topk8 -outform DER -out testkey.pk8 -nocrypt

成功生成:testkey.pk8 [将私钥pem转为pk8格式]

二、签名
 
signapk.jar testkey.x509.pem  testkey.pk8 HelloJni_test.apk HelloJni_test_signed.apk
 [使用公私钥对apk进行签名]
三、创建批处理命令对APK文件自动化签名
四、验证
import sun.security.pkcs.PKCS7;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

public class Test {
     public static void main(String[] args) throws CertificateException, IOException {
             if(args.length < 1){
                 System.out.println("Error arguments");
                 System.exit(-1);
             }
            FileInputStream fis = new FileInputStream(args[0]);
            PKCS7 pkcs7 = new PKCS7(fis);
            X509Certificate publicKey = pkcs7.getCertificates()[0];

            System.out.println("issuer1:" + publicKey.getIssuerDN());
            System.out.println("subject2:" + publicKey.getSubjectDN());
            System.out.println(publicKey.getPublicKey());
        }
}

输出:

issuer1:EMAILADDRESS=test@163.com, CN=netease, OU=sing, O=sing, L=hangzhou, ST=zhejiang, C=cn
subject2:EMAILADDRESS=test@163.com, CN=netease, OU=sing, O=sing, L=hangzhou, ST=zhejiang, C=cn
Sun RSA public key, 2048 bits
  modulus: 22676173355286459097573334286481325549679742508291213299264044486977814024339605340628711274677072768829606315047576874911034554527084043177679494350712443522287175454777833436168772665418404933643096476891010605269397100182350607109602567424649311950932263840379746712271144600813750815453035262110486680532806609381313030573833526182249935950105614529180848998274172532233764292631298041869124308804566439799309159573665297279480681980653336799995434022140192702337503587221467398087020249337183520598982287860366619939017957775007220964826029614540987113512464831360539897307371766206991936881303261221737921332207
  public exponent: 3
注意:
如果代码出现找不到sun.security.pkcs.PKCS7时,解决方法是:右键工程-Build Path-Config Build Path
点Edit:
点Add,选择Accessible,添加规则:**

How does Android’s app/signature verification work?

from : http://stackoverflow.com/questions/10938298/how-does-androids-app-signature-verification-work/10942302#comment18434028_10942302

I want to preface this question with two things so I can narrow down where my actual question is:

a) I’ve done software dev before, though never for android

b) I’m familiar with PKI and encryptions and hashing and digital signatures and blah blah blah

That being said I’m having trouble tracking down more information about where and how Android verifies app creators. I’ve heard a lot of different information so I’m trying to synthesize to get a better idea of the workflow.

I know that every app developer gets their own private/public key pair and they sign their apps by hashing the APK (with SHA-1 most of the time if I’m not mistaken) and there you go. You upload it and (I believe) the public key goes in META INF inside the APK. This much I understand.

My question is how this relates to when a user downloads the app itself. I know the phone checks to make sure that the app is validly signed, and that the signature also has information about author and etc included. But I’ve also read that apps are self signed and that Google Play (or whatever they’re calling the Market now) doesn’t implement a CA, and that there’s no identity authentication? But my question is what, then, stops people from uploading an app under another developers name (crowdsourcing aside)?

If the phone only checks for valid signatures does that imply that the only means of authentication is done when the app is uploaded? And if that’s the case how does the app market check it? Is it the usual – use the private key on file and verify the signature? Or does the developer have to provide the market with their private key to authenticate?

asked Jun 7 ’12 at 19:08
Fewmitz
17518
When you sign the apk you have to provide the private password. So in order for someone to post an app “as someone else” They would need access to their keystore / key files and passwords. And access to the Google Account that is linked to the market. –  FoamyGuy Jun 7 ’12 at 19:17
@Tim: I think he is asking: What is to prevent someone else from creating their own keypair and a self-signed certificate that also says “Fewmitz” in it. Is it somehow linked to an account somewhere? –  GregS Jun 7 ’12 at 22:36

add comment

In short, Android and Google Play essentially don’t care about what’s in actual certificate. Google Play will validate it indeed, and check if it is valid for 30 years or more, but they don’t really use (at least currently, AFAIK) the actual info in the cert. You could use your own name/company name in the CN, but no one will validate this, and users won’t see this info at all. What Android does is:

  • check the signature to make sure the APK hasn’t been tampered with
  • then compare the singing certificate as a binary blob to the one of the currently installed version of the app to make sure that the two versions have been signed with the same key/certificate (e.g., by the same person/company)
  • it does the same thing to enforce permission if you are using using sharedUid or signature permissions with two or more apps.

So, to answer your question, someone can easily create a certificate with your name on it, but Android and Google Play don’t really care. As long as they don’t have your private key, they won’t be able produce an app signature that is the same as yours and thus they wouldn’t be able to overwrite/update your app with theirs, or get any special permissions.

answered Jun 8 ’12 at 2:19
Nikolay Elenkov
30.8k33046
So, does that mean that if use two certificates with the same public-private key pair but different subject names, they both would be valid? Basically when I sign my app with my private key, are my details like subject name etc taken into account anywhere? –  Ashwin Nov 20 ’12 at 13:55
It doesn’t care about the actual ‘details’ (certificate DN, serial number, etc.), but just compares the certificates as binary blobs. Since they are different, you can’t update an app originally signed with cert1 with another signed with cert2. –  Nikolay Elenkov Nov 20 ’12 at 14:04
By saying “It doesn’t care about the actual ‘details’ (certificate DN, serial number, etc.),” do you mean that those details are never used? Because ultimately as you yourself told “compares the certificates as binary blobs” – that means it takes the certificate details into account. –  Ashwin Nov 20 ’12 at 14:07
Of course it means no such thing. Think memcmp() or Arrays.equals(). Do those take certificate details into account? –  Nikolay Elenkov Nov 20 ’12 at 14:11
yeah ok. So the certificates are compared, but the details are never used(other than for comparison) right? Thanks:) –  Ashwin Nov 20 ’12 at 14:30

show 2 more comments

Android APK的数字签名的作用和意义

1. 什么是数字签名?
 
数字签名就是为你的程序打上一种标记,来作为你自己的标识,当别人看到签名的时候会知道它是与你相关的
2. 为什么要数字签名?
 最简单直接的回答: 系统要求的。
 Android系统要求每一个Android应用程序必须要经过数字签名才能够安装到系统中,也就是说如果一个Android应用程序没有经过数字签名,是没有办法安装到系统中的!
 Android通过数字签名来标识应用程序的作者和在应用程序之间建立信任关系,不是用来决定最终用户可以安装哪些应用程序。
 这个数字签名由应用程序的作者完成,并不需要权威的数字证书签名机构认证,它只是用来让应用程序包自我认证的。 
3. 数字证书的机制?
Android使用Java的数字证书相关的机制来给apk加盖数字证书,要理解android的数字证书,需要先了解以下数字证书的概念和java的数字证书机制。
4. 程序使用相同的数字证书的好处
(1)有利于程序升级
当新版程序和旧版程序的数字证书相同时,Android系统才会认为这两个程序是同一个程序的不同版本。如果新版程序和旧版程序的数字证书不相同,则Android系统认为他们是不同的程序,并产生冲突,会要求新程序更改包名。
(2)有利于程序的模块化设计和开发。
Android系统允许拥有同一个数字签名的程序运行在一个进程中,Android程序会将他们视为同一个程序。所以开发者可以将自己的程序分模块开发,而用户只需要在需要的时候下载适当的模块。
(3)可以通过权限(permission)的方式在多个程序间共享数据和代码。
Android提供了基于数字证书的权限赋予机制,应用程序可以和其他的程序共享概功能或者数据给那那些与自己拥有相同数字证书的程序。如果某个权限(permission)的protectionLevel是signature,则这个权限就只
能授予那些跟该权限所在的包拥有同一个数字证书的程序。

5. 在签名时,需要考虑数字证书的有效期

(1)数字证书的有效期要包含程序的预计生命周期,一旦数字证书失效,持有改数字证书的程序将不能正常升级。

(2)如果多个程序使用同一个数字证书,则该数字证书的有效期要包含所有程序的预计生命周期。

(3)Android Market强制要求所有应用程序数字证书的有效期要持续到2033年10月22日以后。
6. 数字证书的要点:

Android数字证书包含以下几个要点:

             (1)所有的应用程序都必须有数字证书,Android系统不会安装一个没有数字证书的应用程序

             (2)Android程序包使用的数字证书可以是自签名的,不需要一个权威的数字证书机构签名认证

             (3)如果要正式发布一个Android ,必须使用一个合适的私钥生成的数字证书来给程序签名,而不能使用adt插件或者ant工具生成的调试证书来发布。

             (4)数字证书都是有有效期的,Android只是在应用程序安装的时候才会检查证书的有效期。如果程序已经安装在系统中,即使证书过期也不会影响程序的正常功能。

             (5)Android使用标准的java工具 Keytool and Jarsigner 来生成数字证书,并给应用程序包签名。

              6)使用zipalign优化程序。
数字签名的两种模式
我们都知道Android系统不会安装运行任何一款未经数字签名的apk程序,无论是在模拟器上还是在实际的物理设备上。所以我们会有一个疑问,为何在日常开发过程中我没有进行任何签名的操作,程序都会在模拟器和真机上运行?下面我们来讲讲
APK程序的两种模式: 调试模式(debug mode)和发布模式(release mode)

1. 调试模式(debug mode)  : 在调试模式下, ADT会自动的使用debug密钥为应用程序签名,因此我们可以直接运行程序。

debug密钥:   一个名为debug.keystore的文件
存放位置 :     C:\Users\Xiaopeng\.android\debug.keystore        Xiaopeng对应替换为自己操作系统的用户名
两个风险:
      debug签名的应用程序有这样两个风险:
     1)debug签名的应用程序不能在Android Market上架销售,它会强制你使用自己的签名;
     2)debug.keystore在不同的机器上所生成的可能都不一样,就意味着如果你换了机器进行apk版本升级,那么将会出现上面那种程序不能覆盖安装的问题。
          不要小视这个问题,如果你开发的程序只有你自己使用,当然无所谓,卸载再安装就可以了。但要是你的软件有很多使用客户,这就是大问题了,就相当于软件不具备升级功能! 
所以一定要有自己的数字证书来签名;
2. 发布模式(release mode) : 当要发布程序时,开发者就需要使用自己的数字证书给apk包签名
 
使用自己的数字证书给APK签名的两种方法:
 

(1)通过DOS命令来对APK签名。

(2)使用ADT Export Wizard进行签名
转载请注明来源: 毕小朋 — http://blog.csdn.net/wirelessqa

Android APK 签名比对

转载请注明出处:http://www.blogjava.net/zh-weir/archive/2011/07/19/354663.html

Android APK 签名比对

发布过Android应用的朋友们应该都知道,Android APK的发布是需要签名的。签名机制在Android应用和框架中有着十分重要的作用。

例如,Android系统禁止更新安装签名不一致的APK;如果应用需要使用system权限,必须保证APK签名与Framework签名一致,等等。在《APK Crack》一文中,我们了解到,要破解一个APK,必然需要重新对APK进行签名。而这个签名,一般情况无法再与APK原先的签名保持一致。(除非APK原作者的私钥泄漏,那已经是另一个层次的软件安全问题了。)

简单地说,签名机制标明了APK的发行机构。因此,站在软件安全的角度,我们就可以通过比对APK的签名情况,判断此APK是否由“官方”发行,而不是被破解篡改过重新签名打包的“盗版软件”。

Android签名机制

为了说明APK签名比对对软件安全的有效性,我们有必要了解一下Android APK的签名机制。为了更易于大家理解,我们从Auto-Sign工具的一条批处理命令说起。

《APK Crack》一文中,我们了解到,要签名一个没有签名过的APK,可以使用一个叫作Auto-sign的工具。Auto-sign工具实际运行的是一个叫做Sign.bat的批处理命令。用文本编辑器打开这个批处理文件,我们可以发现,实现签名功能的命令主要是这一行命令:

 

    java -jar signapk.jar testkey.x509.pem testkey.pk8 update.apk update_signed.apk

这条命令的意义是:通过signapk.jar这个可执行jar包,以“testkey.x509.pem”这个公钥文件和“testkey.pk8”这个私钥文件对“update.apk”进行签名,签名后的文件保存为“update_signed.apk”。    对于此处所使用的私钥和公钥的生成方式,这里就不做进一步介绍了。这方面的资料大家可以找到很多。我们这里要讲的是signapk.jar到底做了什么。

signapk.jar是Android源码包中的一个签名工具。由于Android是个开源项目,所以,很高兴地,我们可以直接找到signapk.jar的源码!路径为/build/tools/signapk/SignApk.java。

对比一个没有签名的APK和一个签名好的APK,我们会发现,签名好的APK包中多了一个叫做META-INF的文件夹。里面有三个文件,分别名为MANIFEST.MF、CERT.SF和CERT.RSA。signapk.jar就是生成了这几个文件(其他文件没有任何改变。因此我们可以很容易去掉原有签名信息)。

通过阅读signapk源码,我们可以理清签名APK包的整个过程。
1、 生成MANIFEST.MF文件:

程序遍历update.apk包中的所有文件(entry),对非文件夹非签名文件的文件,逐个生成SHA1的数字签名信息,再用Base64进行编码。具体代码见这个方法:

 

    private static Manifest addDigestsToManifest(JarFile jar)

关键代码如下:

 1     for (JarEntry entry: byName.values()) {
2         String name = entry.getName();
3         if (!entry.isDirectory() && !name.equals(JarFile.MANIFEST_NAME) &&
4             !name.equals(CERT_SF_NAME) && !name.equals(CERT_RSA_NAME) &&
5                (stripPattern == null ||!stripPattern.matcher(name).matches())) {
6                 InputStream data = jar.getInputStream(entry);
7                 while ((num = data.read(buffer)) > 0) {
8                     md.update(buffer, 0, num);
9                 }
10                 Attributes attr = null;
11                 if (input != null) attr = input.getAttributes(name);
12                 attr = attr != null ? new Attributes(attr) : new Attributes();
13                 attr.putValue(“SHA1-Digest”, base64.encode(md.digest()));
14                 output.getEntries().put(name, attr);
15           }
16     }

之后将生成的签名写入MANIFEST.MF文件。关键代码如下:

 

1     Manifest manifest = addDigestsToManifest(inputJar);
2     je = new JarEntry(JarFile.MANIFEST_NAME);
3     je.setTime(timestamp);
4     outputJar.putNextEntry(je);
5     manifest.write(outputJar);

这里简单介绍下SHA1数字签名。简单地说,它就是一种安全哈希算法,类似于MD5算法。它把任意长度的输入,通过散列算法变成固定长度的输出(这里我们称作“摘要信息”)。你不能仅通过这个摘要信息复原原来的信息。另外,它保证不同信息的摘要信息彼此不同。因此,如果你改变了apk包中的文件,那么在apk安装校验时,改变后的文件摘要信息与MANIFEST.MF的检验信息不同,于是程序就不能成功安装。
2、 生成CERT.SF文件:

对前一步生成的Manifest,使用SHA1-RSA算法,用私钥进行签名。关键代码如下:

1     Signature signature = Signature.getInstance(“SHA1withRSA”);
2     signature.initSign(privateKey);
3     je = new JarEntry(CERT_SF_NAME);
4     je.setTime(timestamp);
5     outputJar.putNextEntry(je);
6     writeSignatureFile(manifest,
7     new SignatureOutputStream(outputJar, signature));

RSA是一种非对称加密算法。用私钥通过RSA算法对摘要信息进行加密。在安装时只能使用公钥才能解密它。解密之后,将它与未加密的摘要信息进行对比,如果相符,则表明内容没有被异常修改。
3、 生成CERT.RSA文件:

生成MANIFEST.MF没有使用密钥信息,生成CERT.SF文件使用了私钥文件。那么我们可以很容易猜测到,CERT.RSA文件的生成肯定和公钥相关。

CERT.RSA文件中保存了公钥、所采用的加密算法等信息。核心代码如下:

 

1     je = new JarEntry(CERT_RSA_NAME);
2     je.setTime(timestamp);
3     outputJar.putNextEntry(je);
4     writeSignatureBlock(signature, publicKey, outputJar);

其中writeSignatureBlock的代码如下:

 

 1     private static void writeSignatureBlock(
2         Signature signature, X509Certificate publicKey, OutputStream out)
3             throws IOException, GeneralSecurityException {
4                 SignerInfo signerInfo = new SignerInfo(
5                 new X500Name(publicKey.getIssuerX500Principal().getName()),
6                 publicKey.getSerialNumber(),
7                 AlgorithmId.get(“SHA1”),
8                 AlgorithmId.get(“RSA”),
9                 signature.sign());
10
11         PKCS7 pkcs7 = new PKCS7(
12             new AlgorithmId[] { AlgorithmId.get(“SHA1”) },
13             new ContentInfo(ContentInfo.DATA_OID, null),
14             new X509Certificate[] { publicKey },
15             new SignerInfo[] { signerInfo });
16
17         pkcs7.encodeSignedData(out);
18     }

好了,分析完APK包的签名流程,我们可以清楚地意识到:

1、 Android签名机制其实是对APK包完整性和发布机构唯一性的一种校验机制。

2、 Android签名机制不能阻止APK包被修改,但修改后的再签名无法与原先的签名保持一致。(拥有私钥的情况除外)。

3、 APK包加密的公钥就打包在APK包内,且不同的私钥对应不同的公钥。换句话言之,不同的私钥签名的APK公钥也必不相同。所以我们可以根据公钥的对比,来判断私钥是否一致。

APK签名比对的实现方式

好了,通过Android签名机制的分析,我们从理论上证明了通过APK公钥的比对能判断一个APK的发布机构。并且这个发布机构是很难伪装的,我们暂时可以认为是不可伪装的。

有了理论基础后,我们就可以开始实践了。那么如何获取到APK文件的公钥信息呢?因为Android系统安装程序肯定会获取APK信息进行比对,所以我们可以通过Android源码获得一些思路和帮助。

源码中有一个隐藏的类用于APK包的解析。这个类叫PackageParser,路径为frameworks\base\core\java\android\content\pm\PackageParser.java。当我们需要获取APK包的相关信息时,可以直接使用这个类,下面代码就是一个例子函数:

 

 1     private PackageInfo parsePackage(String archiveFilePath, int flags){
2
3         PackageParser packageParser = new PackageParser(archiveFilePath);
4         DisplayMetrics metrics = new DisplayMetrics();
5         metrics.setToDefaults();
6         final File sourceFile = new File(archiveFilePath);
7         PackageParser.Package pkg = packageParser.parsePackage(
8                 sourceFile, archiveFilePath, metrics, 0);
9         if (pkg == null) {
10             return null;
11         }
12
13         packageParser.collectCertificates(pkg, 0);
14
15         return PackageParser.generatePackageInfo(pkg, null, flags, 0, 0);
16     }

其中参数archiveFilePath指定APK文件路径;flags需设置PackageManager.GET_SIGNATURES位,以保证返回证书签名信息。

具体如何通过PackageParser获取签名信息在此处不做详述,具体代码请参考PackageParser中的public boolean collectCertificates(Package pkg, int flags)和private Certificate[] loadCertificates(JarFile jarFile, JarEntry je, byte[] readBuffer)方法。至于如何在Android应用开发中使用隐藏的类及方法,可以参看我的这篇文章:《Android应用开发中如何使用隐藏API》

紧接着,我们就可以通过packageInfo.signatures来访问到APK的签名信息。还需要说明的是 Android中Signature和Java中Certificate的对应关系。它们的关系如下面代码所示:

 

1     pkg.mSignatures = new Signature[certs.length];
2     for (int i=0; i<N; i++) {
3         pkg.mSignatures[i] = new Signature(
4         certs[i].getEncoded());
5     }

也就是说signature = new Signature(certificate.getEncoded()); certificate证书中包含了公钥和证书的其他基本信息。公钥不同,证书肯定互不相同。我们可以通过certificate的getPublicKey方法获取公钥信息。所以比对签名证书本质上就是比对公钥信息。

OK,获取到APK签名证书之后,就剩下比对了。这个简单,功能函数如下所示:

 1     private boolean IsSignaturesSame(Signature[] s1, Signature[] s2) {
2             if (s1 == null) {
3                 return false;
4             }
5             if (s2 == null) {
6                 return false;
7             }
8             HashSet<Signature> set1 = new HashSet<Signature>();
9             for (Signature sig : s1) {
10                 set1.add(sig);
11             }
12             HashSet<Signature> set2 = new HashSet<Signature>();
13             for (Signature sig : s2) {
14                 set2.add(sig);
15             }
16             // Make sure s2 contains all signatures in s1.
17             if (set1.equals(set2)) {
18                 return true;
19             }
20             return false;
21         }

APK签名比对的应用场景

经过以上的论述,想必大家已经明白签名比对的原理和我的实现方式了。那么什么时候什么情况适合使用签名对比来保障Android APK的软件安全呢?

个人认为主要有以下三种场景:

1、 程序自检测。在程序运行时,自我进行签名比对。比对样本可以存放在APK包内,也可存放于云端。缺点是程序被破解时,自检测功能同样可能遭到破坏,使其失效。

2、 可信赖的第三方检测。由可信赖的第三方程序负责APK的软件安全问题。对比样本由第三方收集,放在云端。这种方式适用于杀毒安全软件或者APP Market之类的软件下载市场。缺点是需要联网检测,在无网络情况下无法实现功能。(不可能把大量的签名数据放在移动设备本地)。

3、 系统限定安装。这就涉及到改Android系统了。限定仅能安装某些证书的APK。软件发布商需要向系统发布上申请证书。如果发现问题,能追踪到是哪个软件发布商的责任。适用于系统提供商或者终端产品生产商。缺点是过于封闭,不利于系统的开放性。

以上三种场景,虽然各有缺点,但缺点并不是不能克服的。例如,我们可以考虑程序自检测的功能用native method的方法实现等等。软件安全是一个复杂的课题,往往需要多种技术联合使用,才能更好的保障软件不被恶意破坏。

 

参考资料

Android源码

《Android中的签名机制》

 

 
转载请注明出处:http://www.blogjava.net/zh-weir/archive/2011/07/19/354663.html

Java与数字签名

本文中介绍了Java

 

数字签名的基本知识, 发布与验证过程, 数字证书的构成,各个部分的含义.

使用keytool工具生成,导入,导出数字证书的命令, 制作keystore的过程等.

使用jarsigner对jar文件进行签名的命令,过程.

使用信任签名的证书签名后的applet可以访问读写本地文件.

 

原文链接: http://www.blogjava.net/sylilzy/articles/javaadndigtalsign.html

 

sylilzy@163.com
版权所有,转载请注明出处

关键字:Java 数字签名 PKI Keystore 数字证书 keytool jarsigner

摘要:本文介绍了数字签名的相关基础知识,并介绍了如何用java实现数字签名。

字签名作为一种电子身份的认证的手段,被普遍用于网上银行,安全网络通信等领域.数字签名是电子签名的一种特定形式.本文不对数字签名的原理作介绍,只对相关概念作一些简单的介绍,详细讲解了在java中如何对jar文件进行数字签名.

数字签名的相关概念

实际上数字签名又称作基于PKI的电子签名, PKI的核心机构是电子认证服务提供者,即通称的认证机构CA,PKI签名的核心元素是由CA签发的数字证书,数字证书就如同日常生活中的身份证一样,用来标识网上实体的身份,CA就是对网上实体进行认证的第三方机构.数字证书就是CA机构对网上实体进行认证而产生的电子证书,它是数据签名的基础技术保障.CA机构对电子证书的有效性,有效期等提供查询服务.数字证书所包含公钥用来对使用对应的私钥加密的数据信息进行验证.

数字签名实现的具体原理是:
1、 将报文按双方约定的HASH算法计算得到一个固定位数的报文摘要。在数学上保证,只要改动报文中任何一位,重新计算出的报文摘要值就会与原先的值不相符。这样就保证了报文的不可更改性。(详见参考资料的”公钥密码技术原理”章节)
2、 将该报文摘要值用发送者的私人密钥加密,然后连同原报文和数字证书(包含公钥)一起发送给接收者而产生的报文即称数字签名。
3、接收方收到数字签名后,用同样的HASH算法对报文计算摘要值,然后与用发送者的公开密钥进行解密解开的报文摘要值相比较,如相等则说明报文确实来自所称的发送者。
4、同时通过证书颁发机构CA确认证书的有效性即可确认发送的真实身份。

数字证书的技术实现:
数字证书是公钥的载体,是PKI的核心元素.数字证书符合X.509标准,现行的PIK机制一般为又证书,即一个实体一般有两个证书,两个密码对,一个用于电子签名,一个用于加密通信.按照X.509标准,一个标准和数字证书的格式为:

CA《A》=CA{V,SN,AI,CA,UCA,A,UA,Ap,Ta}

它将包含证书颁发机构和标识及用户的标识,证书ID,有效期等信息(详见参考资料),另外还包含CA对此证书内容的进行了数字签名,以验证此证书的有效性.在验证一个数字证书的过程中,对数字证书的数字签名的验证将递归进行,只到找到双方共同可信任的CA根证书为止.

如何获取数字证书

数字证书可向专门的CA机构申请,有免费的数字证书和付费的数字证书.比如:中国数字认证网(http://www.ca365.com)、广东省电子商务认证中心(http://www.cnca.net/)就可申请到有效期为一年的免费数字证书.注意申请的证书是以该CA的证书作为申请的个人证书的根证书,所以如果想要申请的证书有效,需要下载并安装相应CA的根证书.另外,其它一些工具也可生成个人使用的数字证书,如微软的makecert(下载地址http://www.microsoft.com/downloads/details.aspx?familyid=2b742795-d0f0-4a66-b27f-22a95fcd3425&displaylang=en)),JDK中包含的keytool工具(以下会详细介绍如何使用)都可生成没有经过认证的数字证书.

Java如何实现数字签名

JDK有部分工具和API提供了对数字签名的支持:keytool,jarsigner,policytool等.

KeyTool工具可生成,导入,导出数字证书,支持的证书的格式为当前流行的

生成证书:keytool -genkey -alias mykey -keystore mystore

导入证书:keytool -import -alias abc -file ABCCA.cer -keystore mystore

导出证书: keytool -export -alias mykey -file MJ.cer -keystore mystore

对jar文件进行签名使用的工具是jarsigner:

格式如下:jarsigner -keystore keystoreFile jarfile alias

例如:jarsigner -keystore sylilzyKeystore.dat test.jar sylilzy

验证一个jar文件如下:

jarsigner -verify jarfile

以下步骤演示了一个完整的由获取数字证书到签名jar文件,然后访问该jar文件时显示签名信息的全过程:

上面提到,数字证书可由以下方式生成,第一,去http://www.ca365.com申请一个免费的数字证书,下载后为test.der

也可用keytool -genkey -alias mykey -keystore mystore生成,运行此命令后,提示相关信息,并填写完毕,如下:

E:\temp>keytool -genkey -alias mykey -keystore mystore
输入keystore密码: 111111
您的名字与姓氏是什么?
[Unknown]: shi
您的组织单位名称是什么?
[Unknown]: eshore
您的组织名称是什么?
[Unknown]: de
您所在的城市或区域名称是什么?
[Unknown]: gz
您所在的州或省份名称是什么?
[Unknown]: gd
该单位的两字母国家代码是什么
[Unknown]: cn
CN=shi, OU=eshore, O=de, L=gz, ST=gd, C=cn 正确吗?
[否]: y
输入<mykey>的主密码
(如果和 keystore 密码相同,按回车):

到此,我们则生成了一个名为mystore的keystore文件,该文件中保存有别名为mykey的数字证书.输入以下命令即可查看此数字证书:

E:\temp>keytool -list -alias mykey -keystore mystore
输入keystore密码: 111111
mykey, 2006-7-5, keyEntry,
认证指纹 (MD5): A1:A9:A7:C6:D8:E5:E5:20:EA:80:59:AF:C2:65:B4:17

或者带上-v参数显示详细信息

E:\temp>keytool -list -alias mykey -keystore mystore -v
输入keystore密码: 111111
别名名称: mykey
创建日期: 2006-7-5
输入类型:KeyEntry
认证链长度: 1
认证 [1]:
Owner: CN=shi, OU=eshore, O=de, L=gz, ST=gd, C=cn
发照者: CN=shi, OU=eshore, O=de, L=gz, ST=gd, C=cn
序号: 44ab3fb8
有效期间: Wed Jul 05 12:27:36 CST 2006 至: Tue Oct 03 12:27:36 CST 2006
认证指纹:
MD5: A1:A9:A7:C6:D8:E5:E5:20:EA:80:59:AF:C2:65:B4:17
SHA1: AC:8D:AA:9D:A7:62:48:70:ED:F4:28:4C:DC:DE:56:CE:41:FE:52:C9

以上为创建的一个证书,我们可以将它从keystore文件中导出:

E:\temp>keytool -export -keystore mystore -alias mykey -file my.cer
输入keystore密码: 111111
保存在文件中的认证 <my.cer>

我们也可将前面从网上申请的电子证书导入keystore文件:

E:\temp>keytool -import -alias sily -file test.der -keystore mystore
输入keystore密码: 111111
Owner: CN=施祖阳, OU=develop, O=eshore, L=广州, ST=广东, C=CN
发照者: CN=CA365 Free Root Certificate, O=CA365, L=Beijing, ST=Beijing, C=CN
序号: 653e1a63bb003fb3
有效期间: Tue Jul 04 12:02:25 CST 2006 至: Wed Jul 04 12:02:25 CST 2007
认证指纹:
MD5: 4A:AA:63:2A:8A:E2:8D:76:4B:2B:73:E9:F3:03:CD:6F
SHA1: 02:B3:9E:D0:7E:BB:9E:C4:B3:B0:79:19:FA:89:B6:93:DB:0F:4A:88
信任这个认证? [否]: y
认证已添加至keystore中

现在查看mystore中已经存了两个证书:

E:\temp>keytool -list -keystore mystore
输入keystore密码: 111111
Keystore 类型: jks
Keystore 提供者: SUN
您的 keystore 包含 2 输入
sily, 2006-7-5, trustedCertEntry,
认证指纹 (MD5): 4A:AA:63:2A:8A:E2:8D:76:4B:2B:73:E9:F3:03:CD:6F
mykey, 2006-7-5, keyEntry,
认证指纹 (MD5): A1:A9:A7:C6:D8:E5:E5:20:EA:80:59:AF:C2:65:B4:17

现在,我们开始利用前面生成的数字证书给jar文件签名.由于applet在浏览器中运行时的权限是受限的,不能对本地文件进行读写,但是如果applet所在的jar文件如果是经过数字签名,并且用户信任该签名,那此applet则可对本地文件进行读写,下面给出一个写本地文件的applet:

 

 * Created on 2004-7-16
package   com.applet;

import   java.applet.Applet;

public   class   TestSecurity   extends   Applet   {
/**
*
*/
private   static   final   long   serialVersionUID   =   1L;

public   TestSecurity()   {
System. out .println( “this is good! ” );
}

public   void   init()   {
JButton   button   =   new   JButton( “Create a file” );
button.addActionListener( new   ActionListener()   {
public   void   actionPerformed(ActionEvent   evt)   {
File   file   =   new   File( “c:\\a.txt” );
try   {
file.createNewFile();
JOptionPane. showMessageDialog ( null ,   ” 成功创建文件c:\\a.txt” ,   “消息” ,
JOptionPane. INFORMATION_MESSAGE );
}   catch   (Exception   ex)   {
JOptionPane. showMessageDialog ( null ,  ex.getMessage(),   “错误” ,   JOptionPane. ERROR_MESSAGE );
}
}
});
add(button);
}
}

 

将此文件编译后生成在com\applet生成两个class文件,用jar打包:

E:\sylilzy\documents\project\tjava\classes>jar -cvf test.jar com
标明清单(manifest)
增加:com/(读入= 0) (写出= 0)(存储了 0%)

会发现在当前目录下会生成一个”test.jar”文件,将此文件copy到与mystore同一个目录,准备对该文件进行电子签名.

E:\temp>jarsigner -keystore mystore test.jar mykey
输入密钥库的口令短语: 111111
警告: 签名者证书将在六个月内过期。

则test.jar已经被签名,编码一个简单的html文件对其进行访问,html如下:

						
Created with Colorer-take5 Library. Type 'html'

<html><head><metahttp-equiv="Content-Type"content="text/html; charset=GB2312"><title>
			HTML Test Page
		</title></head><body>
		test.Applet1 will appear below in a Java enabled browser.<br><appletcodebase="."code="com.applet.TestSecurity"name="TestApplet"width="400"height="300"hspace="0"vspace="0"align="middle"archive="test.jar"></applet></body></html>

 

将以上html文件与test.jar文件放在同一目录,用IE打开,则可看到IE弹出安全警告: The application’s digital signature is invalid.Do you want to run the application?

用户可查看test.jar的签名信息,如果选择取消息,然后点击create a file 按钮,则提示:access denied(java.io.FilePermission c:\a.txt write)

如果在IE弹出安全警告选择”始终信任此发行者的内容”,然后点击运行,再点击create a file 按钮,则提示:成功创建文件c:\a.txt

上面给test.jar签名的数字证书是未经验证的,现在我们使用从网上申请的经过验证的数字证书给test.jar签名,看会出现什么结果:

E:\temp>jarsigner -keystore mystore test.jar sily
输入密钥库的口令短语: 111111
jarsigner: 找不到 sily 的证书链。sily 必须引用包含专用密钥和相应的公共密钥证书链的有效密钥库密钥条目。

这是因为sily的证书链不存在导致的,我们需要导入sily的证书链才可形成完整的sily的证书链,可以通过keytool -certreq生成证书链的PKCS#10格式的请求,然后再导入请求的PKCS#7格式的回复即可,由于名为sily的key是从cer文件导入的,它在keystore中是以trusted certificate entries类型存储的,没有私钥,所以不能生成证书链的请求.我们可以将前面名为mykey的key导出证书请求,或者导出mykey的证书,然后将此证书安装至”受信任的根证书颁发机构”,然后访问用此证书签名过的文件,则IE将不再弹出安全警告窗口.


 

公告

参考资料:
http://www.qqread.com/net-saft/z532114081.html 电子签名的技术实现
http://www.qqread.com/java/w292768600.html JAVA对数字证书的常用操作
http://java.sun.com/j2se/1.5.0/docs/index.html JDK 5.0 Documentation

 

 

作者简介

施祖阳,网名sylilzy,1979年生。
2002年起从事软件开发工作,主要研究JAVA、Linux及相关技术。
你可通过sylilzy@163.com与作者联系。

[Android]使用platform密钥来给apk文件签名的命令

1.使用platform密钥对apk进行签名

1.1.进入/build/target/product/security,找到【platform.pk8】和【platform.x509.pem】系统密钥。
1.2.进入/build/tools/signapk找到SignApk.java,运行javac编译成SignApk.class
1.3.执行命令java com.android.signapk.SignApk platform.x509.pem platform.pk8 input.apk output.apk
至此,完成。

2. 对1的补充:
/build/target/product/security下有多对密钥,详细如下:

The following commands were used to generate the test key pairs:

development/tools/make_key testkey ‘/C=US/ST=California/L=Mountain View/O=Android/OU=Android/CN=Android/emailAddress=android@android.com’
development/tools/make_key platform ‘/C=US/ST=California/L=Mountain View/O=Android/OU=Android/CN=Android/emailAddress=android@android.com’
development/tools/make_key shared ‘/C=US/ST=California/L=Mountain View/O=Android/OU=Android/CN=Android/emailAddress=android@android.com’
development/tools/make_key media ‘/C=US/ST=California/L=Mountain View/O=Android/OU=Android/CN=Android/emailAddress=android@android.com’

The following standard test keys are currently included:

testkey — a generic key for packages that do not otherwise specify a key.
platform — a test key for packages that are part of the core platform.
shared — a test key for things that are shared in the home/contacts process.
media — a test key for packages that are part of the media/download system.

These test keys are used strictly in development, and should never be assumed
to convey any sort of validity. When $BUILD_SECURE=true, the code should not
honor these keys in any context.

signing using the openssl commandline (for boot/system images)
————————————————————–

1. convert pk8 format key to pem format
% openssl pkcs8 -inform DER -nocrypt -in testkey.pk8 -out testkey.pem

2. create a signature using the pem format key
% openssl dgst -binary -sha1 -sign testkey.pem FILE > FILE.sig

extracting public keys for embedding
————————————
it’s a Java tool
but it generates C code
take a look at commands/recovery/Android.mk
you’ll see it running $(HOST_OUT_JAVA_LIBRARIES)/dumpkey.jar

3.对3的补充:
在运行第三步的命令前,请在你当前的工作目录下新建如下结构的文件夹:com.android.signapk,然后将第二步编译生成的SignApk放入该目录下。或者也可以将SignApk.java的package声明删除后再运行javac编译。

命令java com.android.signapk.SignApk platform.x509.pem platform.pk8 input.apk output.apk
不单可以对apk文件进行重签名,也可以对所有的zip文件进行重签名,包括ROM文件。

本文内容归CSDN博客博主Sodino 所有
转载请注明出处: http://blog.csdn.net/sodino/archive/2010/11/17/6016706.aspx