使用AndroidKeyStore

如何解决使用AndroidKeyStore

我想使用AndroidKeyStore在Android中计算RSA数字签名。我有两个解决方案,第一个使用java.security.Signature,第二个使用javax.crypto.Cipher。首先,我尝试使用Signature对象并成功计算签名,但是我遇到了问题。签名对象根据我的数据进行摘要,所以我的第一个问题是:

1-是否可以通过禁用计算哈希来使用Signature对象?

然后我通过下面的代码选择了第二个解决方案(使用Cipher对象):

// *** Creating Key
            KeyPairGenerator spec = KeyPairGenerator.getInstance(
                    // *** Specified algorithm here
                    // *** Specified: Purpose of key here
                    KeyProperties.KEY_ALGORITHM_RSA,"AndroidKeyStore");
            spec.initialize(new KeyGenParameterSpec.Builder(
                    alias,KeyProperties.PURPOSE_DECRYPT | KeyProperties.PURPOSE_ENCRYPT)
                    .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1) //  RSA/ECB/PKCS1Padding
                    .setKeySize(2048)
                    // *** Replaced: setStartDate
                    .setKeyValidityStart(notBefore.getTime())
                    // *** Replaced: setEndDate
                    .setKeyValidityEnd(notAfter.getTime())
                    // *** Replaced: setSubject
                    .setCertificateSubject(new X500Principal("CN=test"))
                    // *** Replaced: setSerialNumber
                    .setCertificateSerialNumber(BigInteger.ONE)
                    .build());
            KeyPair keyPair = spec.generateKeyPair();

并使用密钥:

Cipher inCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding","AndroidKeyStoreBCWorkaround");
inCipher.init(Cipher.ENCRYPT_MODE,privateKey);

但是在“ inCipher.init”函数中,出现此错误:

java.security.InvalidKeyException: Keystore operation failed
caused by: android.security.KeyStoreException: Incompatible purpose`

我的第二个问题是:2-问题是什么? (我必须说,我可以通过公钥进行加密,但不能通过私钥进行加密来计算签名)

我使用不带androidKeyStore的私钥加密了一条消息,并成功。代码在下面:

KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
        kpg.initialize(2048);
        KeyPair kp = kpg.generateKeyPair();
        PublicKey pub = kp.getPublic();
        PrivateKey pvt = kp.getPrivate();

        Cipher inCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
        inCipher.init(Cipher.ENCRYPT_MODE,pvt);
        byte[] x = new byte[]{0x01,0x01,0x01};
        byte[] result = inCipher.doFinal(x,x.length);

解决方法

关于第一个问题:

如果如您评论中所述,消息已被散列(例如,使用SHA256)并且仅需要使用PKCS#1 v1.5填充进行签名,则可以使用{{ 3}}。但是,必须在关键属性中指定不使用摘要。
如果签名也应符合标准,即应该可以使用SHA256withRSA进行验证,则摘要ID(更确切地说是DigestInfo值的DER编码)必须放在散列消息的前面。以下代码(基于发布的代码)针对SHA256(针对Android P / API 28测试)显示了此代码:

// Load keystore
KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
keyStore.load(null);

// Create key (if not already in keystore)
String alias = "Some Alias";
if (!keyStore.containsAlias(alias)) {

    Calendar notBefore = Calendar.getInstance();
    Calendar notAfter = Calendar.getInstance();
    notAfter.add(Calendar.YEAR,1);

    KeyPairGenerator spec = KeyPairGenerator.getInstance(KeyProperties.KEY_ALGORITHM_RSA,"AndroidKeyStore");
    spec.initialize(new KeyGenParameterSpec.Builder(alias,KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY)              // for signing / verifying
            .setSignaturePaddings(KeyProperties.SIGNATURE_PADDING_RSA_PKCS1)        // use RSASSA-PKCS1-v1_5
            .setDigests(KeyProperties.DIGEST_NONE)                                  // apply no digest
            .setKeySize(2048)
            .setKeyValidityStart(notBefore.getTime())
            .setKeyValidityEnd(notAfter.getTime())
            .setCertificateSubject(new X500Principal("CN=test"))
            .setCertificateSerialNumber(BigInteger.ONE)
            .build());

    spec.generateKeyPair();
}

// Retrieve key
KeyStore.PrivateKeyEntry privateKeyEntry = (KeyStore.PrivateKeyEntry) keyStore.getEntry(alias,null);
PrivateKey privateKey = privateKeyEntry.getPrivateKey();
PublicKey publicKey = privateKeyEntry.getCertificate().getPublicKey();

// Hash message (hashedMessage corresponds to your message)
MessageDigest digest = MessageDigest.getInstance("SHA-256");                        // SHA256 as digest assumed
byte[] message = "The quick brown fox jumps over the lazy dog".getBytes(StandardCharsets.UTF_8);
byte[] hashedMessage = digest.digest(message);

// Concatenate ID (in this example for SHA256) and message in this order
byte[] id = new byte[]{0x30,0x31,0x30,0x0d,0x06,0x09,0x60,(byte) 0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x05,0x00,0x20};
byte[] idHashedMessage = new byte[id.length + hashedMessage.length];
System.arraycopy(id,idHashedMessage,id.length);
System.arraycopy(hashedMessage,id.length,hashedMessage.length);

// Sign with NONEwithRSA
Signature signing = Signature.getInstance("NONEwithRSA");
signing.initSign(privateKey);
signing.update(idHashedMessage);
byte[] signature = signing.sign();

// Verify with SHA256withRSA
Signature verifying = Signature.getInstance("SHA256withRSA");                       // Apply algorithm that corresponds to the digest used,here SHA256withRSA
verifying.initVerify(publicKey);
verifying.update(message);
boolean verified = verifying.verify(signature);
System.out.println("Verification: " + verified);

添加摘要ID是必要的,因为根据NONEwithRSA,使用PKCS#1 v1.5进行签名时会使用RSASSA-PKCS1-v1_5填充,其中包括摘要ID。


关于第二个问题:

简单公式“使用私钥进行签名等于加密”仅在不使用填充的情况下有效(教科书RSA),s。还有RFC 8017。但是,实际上,出于安全原因,必须始终应用填充。对于加密和签名,需要使用不同的填充:对于使用PKCS#1 v1.5填充的加密,将应用变量here;对于使用PKCS#1 v1.5填充的签名,将使用变量RSAES-PKCS1-v1_5
使用私有密钥加密时,所应用的填充变量可能会因库而异(如果完全支持私有密钥加密),这通常会导致不兼容。可能是为了避免此类问题,Android密钥库可能不支持私钥加密(至少我没有找到使之成为可能的配置)。

不带密钥库的Java API和Android API均支持私钥加密。因此,最后发布的代码有效。此外,对于PKCS#1 v1.5填充,使用变体RSASSA-PKCS1-v1_5。如果此处传递了(例如,带有SHA256的)散列消息并将摘要的ID放在其前面,则可以使用算法SHA256withRSA验证生成的签名(如上面的发布代码所示)。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams['font.sans-serif'] = ['SimHei'] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -> systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping("/hires") public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate<String
使用vite构建项目报错 C:\Users\ychen\work>npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-
参考1 参考2 解决方案 # 点击安装源 协议选择 http:// 路径填写 mirrors.aliyun.com/centos/8.3.2011/BaseOS/x86_64/os URL类型 软件库URL 其他路径 # 版本 7 mirrors.aliyun.com/centos/7/os/x86
报错1 [root@slave1 data_mocker]# kafka-console-consumer.sh --bootstrap-server slave1:9092 --topic topic_db [2023-12-19 18:31:12,770] WARN [Consumer clie
错误1 # 重写数据 hive (edu)> insert overwrite table dwd_trade_cart_add_inc > select data.id, > data.user_id, > data.course_id, > date_format(
错误1 hive (edu)> insert into huanhuan values(1,'haoge'); Query ID = root_20240110071417_fe1517ad-3607-41f4-bdcf-d00b98ac443e Total jobs = 1
报错1:执行到如下就不执行了,没有显示Successfully registered new MBean. [root@slave1 bin]# /usr/local/software/flume-1.9.0/bin/flume-ng agent -n a1 -c /usr/local/softwa
虚拟及没有启动任何服务器查看jps会显示jps,如果没有显示任何东西 [root@slave2 ~]# jps 9647 Jps 解决方案 # 进入/tmp查看 [root@slave1 dfs]# cd /tmp [root@slave1 tmp]# ll 总用量 48 drwxr-xr-x. 2
报错1 hive> show databases; OK Failed with exception java.io.IOException:java.lang.RuntimeException: Error in configuring object Time taken: 0.474 se
报错1 [root@localhost ~]# vim -bash: vim: 未找到命令 安装vim yum -y install vim* # 查看是否安装成功 [root@hadoop01 hadoop]# rpm -qa |grep vim vim-X11-7.4.629-8.el7_9.x
修改hadoop配置 vi /usr/local/software/hadoop-2.9.2/etc/hadoop/yarn-site.xml # 添加如下 <configuration> <property> <name>yarn.nodemanager.res