RSA_SHA256数字签名
RSA_SHA256数字签名
------------------ rsa 加密与解密 -----------------------------
数论知识的实际应用: rsa加密
把问题归结为对数字的加密。 被加密的数字为明文。 RSA加密通过公钥对明文进行加密, 得到密文。 网络中传输的都是密文。接收方收到密文, 必须有私钥才能把密文解开。即RSA解密算法通过私钥对密文进行解密。
公钥都是公开的。 私钥只有指定接收方才有。
私钥是根据公钥取的一个数,要想猜出这个数的难度非常大。
看如何生成公钥:
取两个互质的大素数,分别记为p, q. 设t=(p-1)*(q-1). 取一个与t互质的一个素数记为e。
那么公钥就是(e, p*q).
现在通过公钥取一个数, 记为d,
--------------------- 用处 -------------
rsa加密有两种使用方式,
第一是对文件内容加密,这种用途需要发送方用公钥对文件加密, 接收方用私钥对文件解密。
这种方式下,文件在网络传输中都是密文, 那么在发送方要用rsa公钥加密. 接收方用私钥解密. 所以只有私钥的接收方才能解密,看到原文. 这是rsa单纯用于文件加密的用途.
第二是对文件的sha256签名进行加密, 这种方式下,发送方要用私钥对签名进行加密,接收方用公钥进行解密。
这种方式下, 原文件不加密, rsa与sha265签名算法, 生成的密文放在文件的开头。 可完成对文件的验证. 即该文件在传输过程中有没有被修改过. 如果被修改过, 即验证失败. 而crc校验, 只能验证文件的完整性. 如果被修改, 则验证不出来.
rsa还可做ssh身份验证. git仓库的验证用户的合法性 就是用rsa身份验证. id_pub是rsa加密后的.
------------------ Rsa_sha256数字签名验证 ------------------------------
利用编译时间,把要点总结一下,也梳理一下思路。
总的思路: 发送方用sha256算法对原文件生成一个签名文件,即32个字节的hash码。 然后用rsa加密算法对此算法加密。
接收方对加密的签名解密,得到一个32个字节的hash码。 对原文件进行sha256签名计算,得到32字节的hash. 将这两个hash码比较,是否相等。 若相等, 即Rsa_sha256数字签名验证通过。
原理: 不同文件生成的hash值一定不同。
生成私钥
用openssl标准命令,
openssl genrsa -out private.pem
另一种生成私钥的方式是用x509方式,即生成一个包含公钥和其他信息的证书, 和一个公钥。但是生成x509证书与私钥,必须设置密码。 用这个私钥生成数字签名时,就输入密码。
从私钥中提取公钥
用openssl标准命令,
opesnssl rsa -in private.pem -pubout -out public.pem生成签名文件
用openssl标准命令,
openssl dgst -sha256 -sign private.pem -out cw.signature cw.origin公钥字串解析
用openssl java库写解析程序
X509EncodedKeySpec pubkeySpec = new X509EncodedKeySpec(new BASE64Decoder().decodeBuffer(keyString));
KeyFactory keyFactory = KeyFactory.getInstance(“RSA”);
PublicKey key = keyFactory.generatePublic(pubkeySpec);
程序里的keyString字串, 来自于公钥pem文件,但要去掉文件中第一行和最后一行。
这个在网上找了好长时间。一开始的示例,没有base64decoder编码, 结果显示invalide format.
得到publickey, 即可输出到文件, 文件再由load_keys解析。
数字签名验证
用命令方式验证: openssl dgst -sha256 -verify public.pem -signature cw.signature cw.origin
用程序方式rsa_sha256数字签名验证, 有两个可选方法:
一, 用google libmicrypt库,进行rsa_sha256数字签名验证
直接调用这个库的接口函数, 一直没过. 把这个函数从库里邻出来, 加上了log.
根据rsa解密后的签名与原文件sha256签名,两个所得到的32个字节的hash码相同,就验证通过. 改写了这个函数. 最后达到符合我们要求的函数.
从log中可以看出思路:
the hash calculated from origin file:
C3, 56, 28, 8, D4, 37, C6, B2, 77, 1A, E2, 21, D8, EA, 93, B1, 5C, E3, A6, 9C, B
B, 9A, B5, 3C, 76, 37, FD, DF, 3C, 15, A6, F,
the hash decrypted from signature:
C3, 56, 28, 8, D4, 37, C6, B2, 77, 1A, E2, 21, D8, EA, 93, B1, 5C, E3, A6, 9C, B
B, 9A, B5, 3C, 76, 37, FD, DF, 3C, 15, A6, F, cw.crc rsa_sha256 check pass.
二, 使用开源标准openssl库的做法:
加载静态库, 进程本身体积变大
安装openssl, 可以直接调用gcc a.c -lssl, 来引用静态库, 静态库会嵌入到进程中, 会使进程
变大. 动态库以单独文件的方式存在, 多个进程可以同时引用. 不增加使用进程的体积. 以下是直接由程序生成公钥和私钥, 再读取私钥做sha1数字签名验证。
复制代码
#include <stdio.h>
#include <openssl/sha.h>
#include <openssl/rsa.h>
#include <openssl/rand.h>
#include <openssl/objects.h>
#include <assert.h>
int main()
{
unsigned char hash[ SHA_DIGEST_LENGTH ];
#ifndef XINPUT_LEN
#define XINPUT_LEN (2*1024)
#endif
#ifndef XRSA_KEY_BITS
#define XRSA_KEY_BITS (1024)
#endif#define XRSA_KEY_BITS 2048
unsigned char *input = "ccccccccc " ; //[ XINPUT_LEN ];
unsigned char sign [ XRSA_KEY_BITS/8];
unsigned sign_len = sizeof( sign );RSA* rsa_pri_key = RSA_generate_key( XRSA_KEY_BITS , 3 , NULL , NULL );RSA* rsa_pub_key; // = RSAPublicKey_dup( rsa_pri_key );FILE *fp = fopen("private.key", "wb");PEM_write_RSAPrivateKey(fp, rsa_pri_key, NULL, NULL, XRSA_KEY_BITS, NULL, NULL);fclose(fp);fp = fopen("public.key", "wb");PEM_write_RSAPublicKey(fp, rsa_pri_key);fclose(fp);fp = fopen("/home/ligang/rsa/public.key", "rb");rsa_pub_key = PEM_read_RSAPublicKey(fp, NULL, NULL, NULL);fclose(fp);int r = RSA_sign( NID_sha256WithRSAEncryption, input , SHA_DIGEST_LENGTH , sign , &sign_len , rsa_pri_key );assert( 0 != r && sizeof( sign ) == sign_len );printf("%d \n", __LINE__);if (RSA_verify( NID_sha256WithRSAEncryption , input, SHA_DIGEST_LENGTH , sign , sign_len , rsa_pub_key ) == 1 ) { printf(" rsa verify ok \n");}else{ printf(" rsa verify faile \n");}RSA_free( rsa_pub_key );RSA_free( rsa_pri_key );return 0;12345678910111213141516171819202122232425262728293031
}
复制代码
----------------------- java程序将public.pem解析成数组,被google的rsa_verify函数 -------------------
复制代码
/*
Copyright © 2008 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the “License”);
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
1
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an “AS IS” BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/package com.android.dumpkey;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import java.io.FileInputStream;
import java.math.BigInteger;
import java.security.cert.CertificateFactory;
import java.security.cert.; //X509Certificate;import java.security.cert.Certificate;
import java.security.KeyStore;
import java.security.Key;
import java.security.; //PublicKey;import java.security.Security;
import java.security.interfaces.ECPublicKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.ECPoint;
import java.io.;
import java.nio.;
import java.security.KeyFactory;
import java.security.spec.KeySpec;
import java.security.spec.; //X509EncodedKeySpec;import sun.misc.;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
/**
Command line tool to extract RSA public keys from X.509 certificates
and output source code with data initializers for the keys.
@hide
/class DumpPublicKey {
/*/**
/**
/**
BigInteger N = key.getModulus(); StringBuilder result = new StringBuilder(); int nwords = N.bitLength() / 32; // # of 32 bit integers in modulusif (version > 1) { result.append("v"); result.append(Integer.toString(version)); result.append(" "); } result.append("{"); result.append(nwords); BigInteger B = BigInteger.valueOf(0x100000000L); // 2^32 BigInteger N0inv = B.subtract(N.modInverse(B)); // -1 / N[0] mod 2^32 result.append(",0x"); result.append(N0inv.toString(16)); BigInteger R = BigInteger.valueOf(2).pow(N.bitLength()); BigInteger RR = R.multiply(R).mod(N); // 2^4096 mod N // Write out modulus as little endian array of integers. result.append(",{"); for (int i = 0; i < nwords; ++i) { long n = N.mod(B).longValue(); result.append(n); if (i != nwords - 1) { result.append(","); } N = N.divide(B); } result.append("}"); // Write R^2 as little endian array of integers. result.append(",{"); for (int i = 0; i < nwords; ++i) { long rr = RR.mod(B).longValue(); result.append(rr); if (i != nwords - 1) { result.append(","); } RR = RR.divide(B); } result.append("}"); result.append("}"); return result.toString();
}
/**
StringBuilder result = new StringBuilder(); result.append("v"); result.append(Integer.toString(version)); result.append(" "); BigInteger X = key.getW().getAffineX(); BigInteger Y = key.getW().getAffineY(); int nbytes = key.getParams().getCurve().getField().getFieldSize() / 8; // # of 32 bit integers in X coordinate result.append("{"); result.append(nbytes); BigInteger B = BigInteger.valueOf(0x100L); // 2^8 // Write out Y coordinate as array of characters. result.append(",{"); for (int i = 0; i < nbytes; ++i) { long n = X.mod(B).longValue(); result.append(n); if (i != nbytes - 1) { result.append(","); } X = X.divide(B); } result.append("}"); // Write out Y coordinate as array of characters. result.append(",{"); for (int i = 0; i < nbytes; ++i) { long n = Y.mod(B).longValue(); result.append(n); if (i != nbytes - 1) { result.append(","); } Y = Y.divide(B); } result.append("}"); result.append("}"); return result.toString();
}
static String print(PublicKey key, boolean useSHA256) throws Exception {
if (key instanceof RSAPublicKey) {
return printRSA((RSAPublicKey) key, useSHA256);
} else if (key instanceof ECPublicKey) {
return printEC((ECPublicKey) key);
} else {
throw new Exception("Unsupported key class: " + key.getClass().getName());
}
}private static byte[] toBytes(String str) {
if(str == null) {
throw new IllegalArgumentException(“binary string is null”);
}
char[] chs = str.toCharArray();
byte[] bys = new byte[chs.length / 2];
int offset = 0;
int k = 0;
while(k < chs.length) {
bys[offset++] = (byte)((toInt(chs[k++]) << 4) | toInt(chs[k++]));
}
return bys;
}private static int toInt(char a) {
if(a >= ‘0’ && a <= ‘9’) {
return a - ‘0’;
}
if(a >= ‘a’ && a <= ‘f’) {
return a - ‘a’ + 10;
}
if(a >= ‘A’ && a <= ‘F’) {
return a - ‘A’ + 10;
}
throw new IllegalArgumentException("parameter “” + a + "“is not hex number!”);
}private static byte[] getData(String fileName) {
File f = new File(fileName);
InputStreamReader isr;
ArrayList strarr = new ArrayList ();
try {
isr = new InputStreamReader(new FileInputStream(f));
BufferedReader br = new BufferedReader(isr);
String line;
try {
while((line = br.readLine()) != null) {
strarr.add(line);
}
} catch (IOException e) {
// TODO Auto-generated catch block e.printStackTrace();
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block e.printStackTrace();
}StringBuilder sb = new StringBuilder(); for (int i = 1; i < strarr.size() - 1; i++) {
1
2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
@param key to output
@return a String representing this public key. If the key is a
version 1 key, the string will be a C initializer; this is
not true for newer key versions.
*/static String printEC(ECPublicKey key) throws Exception {
int version = checkEC(key);1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
@param key to output
@return a String representing this public key. If the key is a
version 1 key, the string will be a C initializer; this is
not true for newer key versions.
*/static String printRSA(RSAPublicKey key, boolean useSHA256) throws Exception {
int version = check(key, useSHA256);Perform sanity check on public key.
*/static int check(PublicKey key, boolean useSHA256) throws Exception {
if (key instanceof RSAPublicKey) {
return checkRSA((RSAPublicKey) key, useSHA256);
} else if (key instanceof ECPublicKey) {
if (!useSHA256) {
throw new Exception(“Must use SHA-256 with EC keys!”);
}
return checkEC((ECPublicKey) key);
} else {
throw new Exception("Unsupported key class: " + key.getClass().getName());
}
}1
@param key to perform sanity checks on
@return version number of key. Supported versions are:
5: 256-bit EC key with curve NIST P-256
@throws Exception if the key has the wrong size or public exponent
*/static int checkEC(ECPublicKey key) throws Exception {
if (key.getParams().getCurve().getField().getFieldSize() != 256) {
throw new Exception(“Curve must be NIST P-256”);
}return 5;
}1
1
1
1
@param key to perform sanity checks on
@return version number of key. Supported versions are:
1: 2048-bit RSA key with e=3 and SHA-1 hash
2: 2048-bit RSA key with e=65537 and SHA-1 hash
3: 2048-bit RSA key with e=3 and SHA-256 hash
4: 2048-bit RSA key with e=65537 and SHA-256 hash
@throws Exception if the key has the wrong size or public exponent
*/static int checkRSA(RSAPublicKey key, boolean useSHA256) throws Exception {
BigInteger pubexp = key.getPublicExponent();
BigInteger modulus = key.getModulus();
int version;if (pubexp.equals(BigInteger.valueOf(3))) {
version = useSHA256 ? 3 : 1;
} else if (pubexp.equals(BigInteger.valueOf(65537))) {
version = useSHA256 ? 4 : 2;
} else {
throw new Exception("Public exponent should be 3 or 65537 but is " +
pubexp.toString(10) + “.”);
}if (modulus.bitLength() != 2048) {
throw new Exception(“Modulus should be 2048 bits long but is " +
modulus.bitLength() + " bits.”);
}return version;
}
// Log.i(“xxx”, strarr.get(i)); sb.append(strarr.get(i));
}
return sb.toString().getBytes();
}
public static byte[] toByteArray(String filename) throws IOException{ File f = new File(filename); if(!f.exists()){ throw new FileNotFoundException(filename); } ByteArrayOutputStream bos = new ByteArrayOutputStream((int)f.length()); BufferedInputStream in = null; try{ in = new BufferedInputStream(new FileInputStream(f)); int buf_size = 1024; byte[] buffer = new byte[buf_size]; int len = 0; while(-1 != (len = in.read(buffer,0,buf_size))){ bos.write(buffer,0,len); } return bos.toByteArray(); }catch (IOException e) { e.printStackTrace(); throw e; }finally{ try{ in.close(); }catch (IOException e) { e.printStackTrace(); } bos.close(); } } public static void main(String[] args) { if (args.length < 1) { System.err.println("Usage: DumpPublicKey certfile ... > source.c"); System.exit(1); } try { byte[] bytes = getData(args[0]); String keyString = ""; for(int i= 0; i< bytes.length; i++){ keyString += (char)bytes[i]; } X509EncodedKeySpec pubkeySpec = new X509EncodedKeySpec(new BASE64Decoder().decodeBuffer(keyString)); KeyFactory keyFactory = KeyFactory.getInstance("RSA"); PublicKey key = keyFactory.generatePublic(pubkeySpec); check(key, true); System.out.print(print(key, true)); } catch (Exception e) { e.printStackTrace(); System.exit(1); } System.exit(0);}12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455
}
复制代码
Android.mk 文件:
复制代码
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := dumpkey
LOCAL_SRC_FILES := DumpPublicKey.java
LOCAL_JAR_MANIFEST := DumpPublicKey.mf
LOCAL_STATIC_JAVA_LIBRARIES := bouncycastle-host
include $(BUILD_HOST_JAVA_LIBRARY)
复制代码
用./mk mm 编译,得到dumpkey.jar文件,chmod 777 dumpkey.jar. 然后dumpkey.jar public.pem即输出被google的rsa_verify函数使用
---------------- recovery.c 中添加rsa_sha256验证 ---------------------
复制代码
#ifdef HTC_COTA_SUPPORT
#include “mincrypt/rsa.h”
#include “mincrypt/sha.h”
#include “mincrypt/sha256.h”
typedef struct Certificate {
int hash_len; // SHA_DIGEST_SIZE (SHA-1) or SHA256_DIGEST_SIZE (SHA-256)
RSAPublicKey* public_key;
} Certificate;
#endif
#ifdef HTC_COTA_SUPPORT
FILE *log_f=NULL;
unsigned long cnCRC_32 = 0x04C11DB7;
unsigned long Table_CRC32[256];
static const uint8_t sha256_padding[RSANUMBYTES] = {
0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0x00, 0x30, 0x31, 0x30,
0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65,
0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20,
// 32 bytes of hash go here.0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12
};
char *find_str(const char *path, const char *match, int seek_pos)
{
FILE *fp = NULL;
unsigned int length = 0;
const char *p = NULL;
unsigned int count = 0;
char buf = 1;
char *result = NULL;
fp = fopen(path, "r");if( fp == NULL ) { fprintf(log_f, "%s, open %s error \n", __func__, path); return NULL;}p = match;while( *p != '\0'){ length++; p++; }p = match;fseek(fp, seek_pos, SEEK_SET);while( (buf != '\0') && !feof(fp)){ fread(&buf, sizeof(char), 1, fp); if( buf == *p ){ count++; p++; }else{ count = 0; p = match; } if( count == length ){ break; }}seek_pos = (int) ftell(fp);count = 0;do{ fread(&buf, sizeof(char), 1, fp); ++count; fprintf(log_f, "%c, %0X \n", buf, buf);}while( buf >= 0x21 && buf <= 0x7E && buf != '\0' && !feof(fp) );result = (char *) malloc( sizeof(char) * count);fseek(fp, seek_pos, SEEK_SET);fread(result, sizeof(char), count, fp);*(result + count -1) = '\0';fprintf(log_f, "%s, result=%s, count=%d \n", __func__, result, count);fclose(fp);return result;12345678910111213141516171819202122232425262728293031323334353637383940414243444546
}
unsigned long int Reflect(unsigned long int ref, char ch)
{
unsigned long int value=0;
int i;
for (i=1; i<(ch+1); i++)
{
if (ref & 1)
value |= 1 << (ch - i);
ref >>= 1;
}
return value;
}
void creat_table(void)
{
unsigned long i32,j32;
unsigned long nData32;
unsigned long nAccum32;
for (i32=0; i32<256; i32++)
{
nData32 = (unsigned long)(i32 << 24);
nAccum32 = 0;
for (j32=0; j32<8; j32++)
{
if ((nData32 ^ nAccum32) & 0x80000000)
nAccum32 = (nAccum32 << 1) ^ cnCRC_32;
else
nAccum32 <<= 1;
nData32 <<= 1;
}
Table_CRC32[i32] = nAccum32;
}
}
unsigned long crc32(unsigned char *buf, unsigned long size)
{
unsigned long i;
unsigned char *point;
unsigned char chtemp;
unsigned long ii;unsigned long CRC32_1;CRC32_1 = 0x0;point = buf;ii = 0;creat_table();while (size--){ chtemp = *point++; chtemp = (unsigned char)Reflect(chtemp, 8); CRC32_1 = ((CRC32_1 << 8) | chtemp) ^Table_CRC32[(CRC32_1 >> 24) & 0xFF]; ii++; if (ii==4) CRC32_1 = CRC32_1 ^ 0xffffffff;}for (i=0; i<4; i++){ CRC32_1 = ((CRC32_1 << 8)) ^ Table_CRC32[(CRC32_1 >> 24) & 0xFF]; ii++; if (ii==4) CRC32_1 = CRC32_1 ^ 0xffffffff;}CRC32_1 = Reflect(CRC32_1, 32);CRC32_1 = CRC32_1 ^ 0xffffffff;return CRC32_1;123456789101112131415161718192021222324252627
}
int get_crc( char *path)
{
FILE *fp;
unsigned char *buf;
unsigned long checksum = 0;
fpos_t fpos;
int readnum = 0;
int file_size;
int i;
int ret;
fp = fopen(path ,"r");if( fp == NULL ) { printf(" %s, open %s error \n" , __func__, path); return -1;}ret = fseek(fp, 0, SEEK_END);file_size = (int)ftell(fp);//file_size = fpos;buf = (unsigned char *)malloc(file_size);ret = fseek(fp, 0, SEEK_SET);readnum = fread(buf, 1, file_size, fp);fclose(fp);//for (i=0; i<file_size; i++)// checksum += buf[i];checksum = crc32(buf, readnum);return checksum;1234567891011121314151617181920
}
void copy_file(const char *src, const char *dest)
{
FILE *src_fp;
FILE *dest_fp;
char buf = 1;
src_fp = fopen(src, "r");if( src_fp == NULL) { printf("%s, open %s error. \n", __func__, src); return;}dest_fp = fopen(dest, "w");if( dest_fp == NULL) { printf("%s, open %s error. \n", __func__, dest); return;}while (! feof(src_fp)) { fread(&buf, sizeof(char), 1, src_fp); fwrite(&buf, sizeof(char), 1, dest_fp);}fclose(src_fp);fclose(dest_fp);123456789101112131415161718
}
static Certificate*
load_keys(const char* filename, int* numKeys) {
Certificate* out = NULL;
*numKeys = 0;
FILE* f = fopen(filename, "r");if (f == NULL) { LOGE("opening %s: %s\n", filename, strerror(errno)); goto exit;}{ int i; bool done = false; while (!done) { ++*numKeys; out = (Certificate*)realloc(out, *numKeys * sizeof(Certificate)); Certificate* cert = out + (*numKeys - 1); cert->public_key = (RSAPublicKey*)malloc(sizeof(RSAPublicKey)); char start_char; if (fscanf(f, " %c", &start_char) != 1) goto exit; if (start_char == '{') { // a version 1 key has no version specifier. cert->public_key->exponent = 3; cert->hash_len = SHA_DIGEST_SIZE; } else if (start_char == 'v') { int version; if (fscanf(f, "%d {", &version) != 1) goto exit; switch (version) { case 2: cert->public_key->exponent = 65537; cert->hash_len = SHA_DIGEST_SIZE; break; case 3: cert->public_key->exponent = 3; cert->hash_len = SHA256_DIGEST_SIZE; break; case 4: cert->public_key->exponent = 65537; cert->hash_len = SHA256_DIGEST_SIZE; break; default: goto exit; } } RSAPublicKey* key = cert->public_key; if (fscanf(f, " %i , 0x%x , { %u", &(key->len), &(key->n0inv), &(key->n[0])) != 3) { goto exit; } if (key->len != RSANUMWORDS) { printf("key length (%d) does not match expected size\n", key->len); goto exit; } for (i = 1; i < key->len; ++i) { if (fscanf(f, " , %u", &(key->n[i])) != 1) goto exit; } if (fscanf(f, " } , { %u", &(key->rr[0])) != 1) goto exit; for (i = 1; i < key->len; ++i) { if (fscanf(f, " , %u", &(key->rr[i])) != 1) goto exit; } fscanf(f, " } } "); // if the line ends in a comma, this file has more keys.switch (fgetc(f)) { case ',': // more keys to come.break; case EOF: done = true; break; default: LOGE("unexpected character between keys\n"); goto exit; } LOGI("read key e=%d hash=%d\n", key->exponent, cert->hash_len); }}fclose(f);return out;12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
exit:
if (f) fclose(f);
free(out);
*numKeys = 0;
return NULL;
}
static void subM(const RSAPublicKey* key,
uint32_t* a) {
int64_t A = 0;
int i;
for (i = 0; i < key->len; ++i) {
A += (uint64_t)a[i] - key->n[i];
a[i] = (uint32_t)A;
A >>= 32;
}
}
// return a[] >= modstatic int geM(const RSAPublicKey* key,
const uint32_t* a) {
int i;
for (i = key->len; i;) {
–i;
if (a[i] < key->n[i]) return 0;
if (a[i] > key->n[i]) return 1;
}
return 1; // equal}
// montgomery c[] += a * b[] / R % modstatic void montMulAdd(const RSAPublicKey* key,
uint32_t* c,
const uint32_t a,
const uint32_t* b) {
uint64_t A = (uint64_t)a * b[0] + c[0];
uint32_t d0 = (uint32_t)A * key->n0inv;
uint64_t B = (uint64_t)d0 * key->n[0] + (uint32_t)A;
int i;
for (i = 1; i < key->len; ++i) { A = (A >> 32) + (uint64_t)a * b[i] + c[i]; B = (B >> 32) + (uint64_t)d0 * key->n[i] + (uint32_t)A; c[i - 1] = (uint32_t)B;}A = (A >> 32) + (B >> 32);c[i - 1] = (uint32_t)A;if (A >> 32) { subM(key, c);}12345678910111213
}
// montgomery c[] = a[] * b[] / R % modstatic void montMul(const RSAPublicKey* key,
uint32_t* c,
const uint32_t* a,
const uint32_t* b) {
int i;
for (i = 0; i < key->len; ++i) {
c[i] = 0;
}
for (i = 0; i < key->len; ++i) {
montMulAdd(key, c, a[i], b);
}
}
// In-place public exponentiation.
// Input and output big-endian byte array in inout.static void modpow(const RSAPublicKey* key,
uint8_t* inout) {
uint32_t a[RSANUMWORDS];
uint32_t aR[RSANUMWORDS];
uint32_t aaR[RSANUMWORDS];
uint32_t* aaa = 0;
int i;
// Convert from big endian byte array to little endian word array.for (i = 0; i < key->len; ++i) { uint32_t tmp = (inout[((key->len - 1 - i) * 4) + 0] << 24) | (inout[((key->len - 1 - i) * 4) + 1] << 16) | (inout[((key->len - 1 - i) * 4) + 2] << 8) | (inout[((key->len - 1 - i) * 4) + 3] << 0); a[i] = tmp;}if (key->exponent == 65537) { aaa = aaR; // Re-use location. montMul(key, aR, a, key->rr); // aR = a * RR / R mod Mfor (i = 0; i < 16; i += 2) { montMul(key, aaR, aR, aR); // aaR = aR * aR / R mod M montMul(key, aR, aaR, aaR); // aR = aaR * aaR / R mod M } montMul(key, aaa, aR, a); // aaa = aR * a / R mod M} else if (key->exponent == 3) { aaa = aR; // Re-use location. montMul(key, aR, a, key->rr); /* aR = a * RR / R mod M */ montMul(key, aaR, aR, aR); /* aaR = aR * aR / R mod M */ montMul(key, aaa, aaR, a); /* aaa = aaR * a / R mod M */}// Make sure aaa < mod; aaa is at most 1x mod too large.if (geM(key, aaa)) { subM(key, aaa);}// Convert to bigendian byte arrayfor (i = key->len - 1; i >= 0; --i) { uint32_t tmp = aaa[i]; *inout++ = tmp >> 24; *inout++ = tmp >> 16; *inout++ = tmp >> 8; *inout++ = tmp >> 0;}123456789101112131415161718192021222324252627282930313233
}
int RSA_verify1(const RSAPublicKey *key,
const uint8_t *signature,
const int len,
const char *origin,
const int origin_length,
const int hash_len) {
uint8_t buf[RSANUMBYTES];
int i;const uint8_t* padding_hash; uint8_t origin_hash[32]; if (key->len != RSANUMWORDS) { return 0; // Wrong key passed in. }if (len != sizeof(buf)) { return 0; // Wrong input length. }if (hash_len != SHA_DIGEST_SIZE && hash_len != SHA256_DIGEST_SIZE) { return 0; // Unsupported hash. }if (key->exponent != 3 && key->exponent != 65537) { fprintf(log_f, "%s, %d \n", __func__, __LINE__); return 0; // Unsupported exponent. }SHA256_hash(origin, origin_length, origin_hash);uint8_t* p_hash = origin_hash;fprintf(log_f,"\n the hash calculated from origin file: \n");for( i=0; i< 32; i++){ fprintf(log_f, "%0X, ", *p_hash); p_hash++;}for (i = 0; i < len; ++i) { // Copy input to local workspace. buf[i] = signature[i];}modpow(key, buf); // In-place exponentiation.for( i=0; i < len - hash_len; ++i){ if( buf[i] != sha256_padding[i] ){ printf("padding: buf[%d]=%0X \n", i, buf[i]); return 0; }}fprintf(log_f, "\n the hash decrypted from signature: \n");for (i = len - hash_len; i < len; ++i) { fprintf(log_f, "%0X, ", buf[i]); if( buf[i] != origin_hash[i -( len - hash_len)] ){ fprintf(log_f, "hash: buf[%d]=%0X, origin_hash[%d]=%0X \n", i, buf[i], i -( len - hash_len), origin_hash[i -( len - hash_len)]); return 0; }}return 1; // All checked out OK.}12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849
unsigned char check_rsa_sha256(char *file_name){
FILE *fp = NULL;
FILE *fp1 = NULL;
unsigned char buf [256];
char *origin_buf;
unsigned char result;
char *signature_file = “cw_signature”;
char *origin_file = “cw_origin”;
char c = 1;
chdir("/data/media/0");fp = fopen(file_name, "r");if( fp == NULL ) { printf(" %s, open %s error \n" , __func__, file_name); return -1;}// read signature into filefp1 = fopen(signature_file, "w");fread(buf, sizeof(char), 256, fp);fwrite(buf, sizeof(char), 256, fp1);fclose(fp1);// read origin into filefp1 = fopen(origin_file, "w");do { if( fread(&c, sizeof(char), 1, fp) != 0 ) { fwrite(&c, sizeof(char), 1, fp1); fprintf(log_f, "%c", c); }}while ( ! feof(fp) ) ;fclose(fp1); fclose(fp);fp1 = fopen(origin_file, "r");fseek(fp1, 0, SEEK_END);int origin_size =(int)ftell(fp1);fseek(fp1, 0, SEEK_SET);origin_buf = (char *) malloc ( sizeof(char) * origin_size);fread(origin_buf, sizeof(char), origin_size, fp1);fclose(fp1);int num_keys = 1;Certificate* cert = NULL;if(ensure_path_mounted("/system") == 0 ){ cert = load_keys("/system/etc/key_file", &num_keys); fprintf(log_f, "mount system partision success, load keys finish. \n"); ensure_path_unmounted("/system");}else{ fprintf(log_f, "mount system partision fail. \ n"); ensure_path_unmounted("/system"); return 0;}RSAPublicKey* test_key = cert->public_key;12345678910111213141516171819202122232425262728293031323334353637383940414243444546
/*
SHA256_CTX sha256_ctx;
SHA256_init(&sha256_ctx);
SHA256_update(&sha256_ctx, origin_buf, 32);
const uint8_t* hash = SHA256_final(&sha256_ctx);
*/
fprintf(log_f, “begin rsa sha256 verification. \n”);
result = RSA_verify1(test_key, buf , RSANUMBYTES, origin_buf, origin_size, 32);
free(origin_buf);remove("/data/media/0/cw_origin");remove("/data/media/0/cw_signature");return result;123456
}
static void copy_file_to_data()
{
if(ensure_path_mounted("/data") == 0 ){
copy_file("/data/media/0/cwpkg.zip", “/data/data/cwtemp/cwpkg.zip”);
copy_file("/data/media/0/cw.prop", “/data/data/cwtemp/cw.prop”);
fprintf(log_f, “copy cwpkg.zip and cw.prop to /data/data/cwtemp/ finish. \n”);
}else{
fprintf(log_f, “mount /data failure. \n”);
}
ensure_path_unmounted("/data");
}
static int verify_file1()
{
//if ( (ensure_path_mounted("/sdcard") == 0 ) ) {if(access("/data/media/0/cw.crc", 0) == 0 &&
access("/data/media/0/cw.prop", 0) == 0 && access("/data/media/0/cwpkg.zip", 0) == 0 ) {
fprintf(log_f, “<---------- cota check --------------> \n”);
char *path= NULL; char *str = NULL; char *device = NULL; unsigned long crc_r = 0; unsigned long crc_c = 0; unsigned int check = 0 ; char cwd[80]; // rsa-sha256if ( check_rsa_sha256("cw.crc") == 1){ check |= 0x0001; fprintf(log_f, "cw.crc rsa_sha256 check pass. \n"); }else{ check &= ~0x0001; fprintf(log_f, "cw.crc rsa_sha256 check not pass. \n"); //goto check_exit; } if ( check_rsa_sha256("cw.prop") == 1){ check |= 0x0010; fprintf(log_f, "cw.prop rsa_sha256 check pass. \n"); }else{ check &= ~0x0010; fprintf(log_f, "cw.prop rsa_sha256 check not pass. \n"); //goto check_exit; } // check project path="/data/media/0/cw.crc"; str = find_str(path, "project:", 256); if(ensure_path_mounted("/system") == 0 ){ device = find_str("/system/build.prop", "ro.product.device=", 0); if(strcmp(str, device)==0){ check |= 0x0002; fprintf(log_f, "project check pass. project:%s, ro.product.device=%s \n", str, device); }else{ check &= ~0x0002; fprintf(log_f, "project check not pass. project:%s, ro.product.device=%s \n", str, device); //goto check_exit; } free(device); }else{ fprintf(log_f, "mount system partion fail \n"); //goto check_exit; } ensure_path_unmounted("/system") ; free(str); // check cid path="/data/media/0/cw.crc"; str = find_str(path, "cid:", 256); if(ensure_path_mounted("/system") == 0 ){ device = find_str("/system/build.prop", "ro.cid=", 0); if(strcmp(str, device)==0){ check |= 0x0020; fprintf(log_f, "cid check pass. cid:%s, ro.cid=%s \n", str, device); }else{ check &= ~0x0020; //check |= 0x0020; fprintf(log_f, "cid check not pass. cid:%s, ro.cid=%s \n", str, device); //goto check_exit; } free(device); }else{ fprintf(log_f, "mount system partion fail \n"); //goto check_exit; } ensure_path_unmounted("/system") ; free(str); // check cwpkg.zip crc str = find_str(path, "cwpkg.zip==0x", 256); sscanf(str, "%0x", &crc_r); crc_c = get_crc("/data/media/0/cwpkg.zip"); if( crc_r == crc_c ){ check |= 0x0004; fprintf(log_f, "cwpkg.zip check pass. crc_r=%0x, crc_c=%0x. \n ", crc_r, crc_c); }else{ check &= ~0x0004; fprintf(log_f, "cwpkg.zip check not pass. crc_r=%0x, crc_c=%0x. \n ", crc_r, crc_c); //goto check_exit; } free(str); // check cw.prop crc str = find_str(path, "cw.prop==0x", 256); sscanf(str, "%0x", &crc_r); crc_c = get_crc("/data/media/0/cw.prop"); if( crc_r == crc_c ){ check |= 0x0008; fprintf(log_f, "cw.prop check pass. crc_r=%0x, crc_c=%0x. \n ", crc_r, crc_c); }else{ check &= ~0x0008; fprintf(log_f, "cw.prop check not pass. crc_r=%0x, crc_c=%0x. \n ", crc_r, crc_c); //goto check_exit; } free(str); fprintf(log_f, "check=%0X \n", check); if( check == 0x003F ) { goto check_success; }else{ goto check_exit; } }else{ fprintf(log_f, "cota file not exist. \n"); }//} 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
check_exit:
fprintf(log_f, “verification fail. \n”);
return 0;
check_success:
fprintf(log_f, “all verification success. \n” );
return 1;
}
#endifswitch (chosen_item) {
#ifdef HTC_COTA_SUPPORT
case Device::APPLY_COTA_UPDATE:
ensure_path_mounted("/data");
log_f = fopen("/data/data/recover_log", “w”);
fprintf(log_f, “aplly cota update. \n”);
if(verify_file1() == 1 ) {
copy_file_to_data();
}
fclose(log_f);
ensure_path_unmounted("/data");
return;