当前位置: 首页 > news >正文

Android KeyStore 秘钥导入

源码参考:
https://android.googlesource.com/platform/cts/+/master/tests/tests/keystore/src/android/keystore/cts/ImportWrappedKeyTest.java

辅助源码参考:
https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/security/keymaster/KeymasterDefs.java
https://android.googlesource.com/platform/hardware/interfaces/+/refs/heads/main/security/keymint/aidl/aidl_api/android.hardware.security.keymint/1/android/hardware/security/keymint/

源代码测试如下:

import android.security.keystore.KeyGenParameterSpec;
import android.security.keystore.KeyProperties;
import android.security.keystore.SecureKeyImportUnavailableException;
import android.security.keystore.WrappedKeyEntry;
import android.util.Log;import org.bouncycastle.asn1.ASN1Encoding;
import org.bouncycastle.asn1.DEREncodableVector;
import org.bouncycastle.asn1.DERInteger;
import org.bouncycastle.asn1.DERNull;
import org.bouncycastle.asn1.DEROctetString;
import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.asn1.DERSet;
import org.bouncycastle.asn1.DERTaggedObject;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.encoders.Hex;import java.security.Key;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Signature;
import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.MGF1ParameterSpec;import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.OAEPParameterSpec;
import javax.crypto.spec.PSource;
import javax.crypto.spec.SecretKeySpec;public class TestWrapKey {private static final String ALIAS = "my key";private static final String WRAPPING_KEY_ALIAS = "my_favorite_wrapping_key";public static final String TAG = "TestWrapKey";public static final int KM_TAG_PURPOSE = 536870913;public static final int KM_TAG_ALGORITHM = 268435458;public static final int KM_TAG_KEY_SIZE = 805306371;public static final int KM_TAG_DIGEST = 536870917;public static final int KM_TAG_NO_AUTH_REQUIRED = 1879048695;public static final int KM_PURPOSE_SIGN = 2;public static final int KM_PURPOSE_VERIFY = 3;public static final int KM_DIGEST_SHA_2_224 = 3;public static final int KM_DIGEST_SHA_2_256 = 4;public static final int KM_DIGEST_SHA_2_384 = 5;public static final int KM_DIGEST_SHA_2_512 = 6;public static final int KM_KEY_FORMAT_RAW = 3;public static final int KM_PURPOSE_ENCRYPT = 0;public static final int KM_PURPOSE_DECRYPT = 1;public static final int KM_MODE_ECB = 1;public static final int KM_MODE_CBC = 2;public static final int KM_TAG_BLOCK_MODE = 536870916;public static final int KM_PAD_PKCS7 = 64;public static final int KM_PAD_NONE = 1;public static final int KM_TAG_PADDING = 536870918;public static final int KM_ALGORITHM_AES = 32;private static final int GCM_TAG_SIZE = 128;private static final int WRAPPED_FORMAT_VERSION = 0;public static final int KM_KEY_FORMAT_PKCS8 = 1;public static final int KM_ALGORITHM_RSA = 1;public static final int KM_PAD_RSA_OAEP = 2;public static final int KM_PAD_RSA_PSS = 3;public static final int KM_PAD_RSA_PKCS1_1_5_ENCRYPT = 4;public static final int KM_PAD_RSA_PKCS1_1_5_SIGN = 5;public static final int KM_DIGEST_NONE = 0;public static final int KM_DIGEST_MD5 = 1;public static final int KM_DIGEST_SHA1 = 2;SecureRandom random = new SecureRandom();private void showMessage(String message) {Log.d(TAG, message);}// 构建秘钥对private KeyPair genKeyPair(String alias, boolean isStrongBoxBacked) throws Exception {KeyPairGenerator kpg =KeyPairGenerator.getInstance(KeyProperties.KEY_ALGORITHM_RSA, "AndroidKeyStore");kpg.initialize(new KeyGenParameterSpec.Builder(alias, KeyProperties.PURPOSE_WRAP_KEY).setDigests(KeyProperties.DIGEST_SHA256).setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_OAEP).setBlockModes(KeyProperties.BLOCK_MODE_ECB).setIsStrongBoxBacked(isStrongBoxBacked).build());return kpg.generateKeyPair();}private int removeTagType(int tag) {int kmTagTypeMask = 0x0FFFFFFF;return tag & kmTagTypeMask;}private DERSequence makeRsaAuthList(int size) {DEREncodableVector allPurposes = new DEREncodableVector();allPurposes.add(new DERInteger(KM_PURPOSE_ENCRYPT));allPurposes.add(new DERInteger(KM_PURPOSE_DECRYPT));allPurposes.add(new DERInteger(KM_PURPOSE_SIGN));allPurposes.add(new DERInteger(KM_PURPOSE_VERIFY));DERSet purposeSet = new DERSet(allPurposes);DERTaggedObject purpose =new DERTaggedObject(true, removeTagType(KM_TAG_PURPOSE), purposeSet);DERTaggedObject algorithm =new DERTaggedObject(true, removeTagType(KM_TAG_ALGORITHM),new DERInteger(KM_ALGORITHM_RSA));DERTaggedObject keySize =new DERTaggedObject(true, removeTagType(KM_TAG_KEY_SIZE), new DERInteger(size));DEREncodableVector allBlockModes = new DEREncodableVector();allBlockModes.add(new DERInteger(KM_MODE_ECB));allBlockModes.add(new DERInteger(KM_MODE_CBC));DERSet blockModeSet = new DERSet(allBlockModes);DERTaggedObject blockMode =new DERTaggedObject(true, removeTagType(KM_TAG_BLOCK_MODE), blockModeSet);DEREncodableVector allDigests = new DEREncodableVector();allDigests.add(new DERInteger(KM_DIGEST_NONE));allDigests.add(new DERInteger(KM_DIGEST_MD5));allDigests.add(new DERInteger(KM_DIGEST_SHA1));allDigests.add(new DERInteger(KM_DIGEST_SHA_2_224));allDigests.add(new DERInteger(KM_DIGEST_SHA_2_256));allDigests.add(new DERInteger(KM_DIGEST_SHA_2_384));allDigests.add(new DERInteger(KM_DIGEST_SHA_2_512));DERSet digestSet = new DERSet(allDigests);DERTaggedObject digest =new DERTaggedObject(true, removeTagType(KM_TAG_DIGEST), digestSet);DEREncodableVector allPaddings = new DEREncodableVector();allPaddings.add(new DERInteger(KM_PAD_PKCS7));allPaddings.add(new DERInteger(KM_PAD_NONE));allPaddings.add(new DERInteger(KM_PAD_RSA_OAEP));allPaddings.add(new DERInteger(KM_PAD_RSA_PSS));allPaddings.add(new DERInteger(KM_PAD_RSA_PKCS1_1_5_ENCRYPT));allPaddings.add(new DERInteger(KM_PAD_RSA_PKCS1_1_5_SIGN));DERSet paddingSet = new DERSet(allPaddings);DERTaggedObject padding =new DERTaggedObject(true, removeTagType(KM_TAG_PADDING), paddingSet);DERTaggedObject noAuthRequired =new DERTaggedObject(true, removeTagType(KM_TAG_NO_AUTH_REQUIRED), DERNull.INSTANCE);// Build sequenceDEREncodableVector allItems = new DEREncodableVector();allItems.add(purpose);allItems.add(algorithm);allItems.add(keySize);allItems.add(blockMode);allItems.add(digest);allItems.add(padding);allItems.add(noAuthRequired);return new DERSequence(allItems);}private DERSequence makeAesAuthList(int size) {return makeSymKeyAuthList(size, KM_ALGORITHM_AES);}private DERSequence makeSymKeyAuthList(int size, int algo) {DEREncodableVector allPurposes = new DEREncodableVector();allPurposes.add(new DERInteger(KM_PURPOSE_ENCRYPT));allPurposes.add(new DERInteger(KM_PURPOSE_DECRYPT));DERSet purposeSet = new DERSet(allPurposes);DERTaggedObject purpose =new DERTaggedObject(true, removeTagType(KM_TAG_PURPOSE), purposeSet);DERTaggedObject algorithm =new DERTaggedObject(true, removeTagType(KM_TAG_ALGORITHM), new DERInteger(algo));DERTaggedObject keySize =new DERTaggedObject(true, removeTagType(KM_TAG_KEY_SIZE), new DERInteger(size));DEREncodableVector allBlockModes = new DEREncodableVector();allBlockModes.add(new DERInteger(KM_MODE_ECB));allBlockModes.add(new DERInteger(KM_MODE_CBC));DERSet blockModeSet = new DERSet(allBlockModes);DERTaggedObject blockMode =new DERTaggedObject(true, removeTagType(KM_TAG_BLOCK_MODE), blockModeSet);DEREncodableVector allPaddings = new DEREncodableVector();allPaddings.add(new DERInteger(KM_PAD_PKCS7));allPaddings.add(new DERInteger(KM_PAD_NONE));DERSet paddingSet = new DERSet(allPaddings);DERTaggedObject padding =new DERTaggedObject(true, removeTagType(KM_TAG_PADDING), paddingSet);DERTaggedObject noAuthRequired =new DERTaggedObject(true, removeTagType(KM_TAG_NO_AUTH_REQUIRED), DERNull.INSTANCE);// Build sequenceDEREncodableVector allItems = new DEREncodableVector();allItems.add(purpose);allItems.add(algorithm);allItems.add(keySize);allItems.add(blockMode);allItems.add(padding);allItems.add(noAuthRequired);return new DERSequence(allItems);}public byte[] wrapKey(PublicKey publicKey, byte[] keyMaterial, byte[] mask,int keyFormat, DERSequence authorizationList) throws Exception {return wrapKey(publicKey, keyMaterial, mask, keyFormat, authorizationList, true);}public byte[] wrapKey(PublicKey publicKey, byte[] keyMaterial, byte[] mask,int keyFormat, DERSequence authorizationList, boolean correctWrappingRequired)throws Exception {// Build descriptionDEREncodableVector descriptionItems = new DEREncodableVector();descriptionItems.add(new DERInteger(keyFormat));descriptionItems.add(authorizationList);DERSequence wrappedKeyDescription = new DERSequence(descriptionItems);// Generate 12 byte initialization vectorbyte[] iv = new byte[12];random.nextBytes(iv);// Generate 256 bit AES key. This is the ephemeral key used to encrypt the secure key.byte[] aesKeyBytes = new byte[32];random.nextBytes(aesKeyBytes);// Encrypt ephemeral keysOAEPParameterSpec spec = new OAEPParameterSpec("SHA-256", "MGF1", MGF1ParameterSpec.SHA1, PSource.PSpecified.DEFAULT);Cipher pkCipher = Cipher.getInstance("RSA/ECB/OAEPPadding");if (correctWrappingRequired) {pkCipher.init(Cipher.ENCRYPT_MODE, publicKey, spec);} else {// Use incorrect OAEPParameters while initializing cipher. By default, main digest and// MGF1 digest are SHA-1 here.pkCipher.init(Cipher.ENCRYPT_MODE, publicKey);}byte[] encryptedEphemeralKeys = pkCipher.doFinal(aesKeyBytes);// Encrypt secure keyCipher cipher = Cipher.getInstance("AES/GCM/NoPadding");SecretKeySpec secretKeySpec = new SecretKeySpec(aesKeyBytes, "AES");GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(GCM_TAG_SIZE, iv);cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, gcmParameterSpec);byte[] aad = wrappedKeyDescription.getEncoded();cipher.updateAAD(aad);byte[] encryptedSecureKey = cipher.doFinal(keyMaterial);// Get GCM tag. Java puts the tag at the end of the ciphertext data :(int len = encryptedSecureKey.length;int tagSize = (GCM_TAG_SIZE / 8);byte[] tag = Arrays.copyOfRange(encryptedSecureKey, len - tagSize, len);// Remove GCM tag from end of outputencryptedSecureKey = Arrays.copyOfRange(encryptedSecureKey, 0, len - tagSize);// Build ASN.1 DER encoded sequence WrappedKeyWrapperDEREncodableVector items = new DEREncodableVector();items.add(new DERInteger(WRAPPED_FORMAT_VERSION));items.add(new DEROctetString(encryptedEphemeralKeys));items.add(new DEROctetString(iv));items.add(wrappedKeyDescription);items.add(new DEROctetString(encryptedSecureKey));items.add(new DEROctetString(tag));return new DERSequence(items).getEncoded(ASN1Encoding.DER);}public void importWrappedKey(byte[] wrappedKey, String wrappingKeyAlias) throws Exception {KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");keyStore.load(null, null);AlgorithmParameterSpec spec = new KeyGenParameterSpec.Builder(wrappingKeyAlias,KeyProperties.PURPOSE_WRAP_KEY).setDigests(KeyProperties.DIGEST_SHA256).build();KeyStore.Entry wrappedKeyEntry = new WrappedKeyEntry(wrappedKey, wrappingKeyAlias,"RSA/ECB/OAEPPadding", spec);keyStore.setEntry(ALIAS, wrappedKeyEntry, null);}public void importWrappedKey(byte[] wrappedKey) throws Exception {importWrappedKey(wrappedKey, WRAPPING_KEY_ALIAS);}public void testRSA() throws Exception{KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");// Both TEE and Strongbox must support 2048-bit keys.int keySize = 2048;kpg.initialize(keySize);KeyPair kp = kpg.generateKeyPair();PublicKey publicKey = kp.getPublic();showMessage("publicKey:"+Hex.toHexString(publicKey.getEncoded()));PrivateKey privateKey = kp.getPrivate();showMessage("privateKey:"+Hex.toHexString(privateKey.getEncoded()));byte[] keyMaterial = privateKey.getEncoded();byte[] mask = new byte[32]; // Zero masktry {importWrappedKey(wrapKey(genKeyPair(WRAPPING_KEY_ALIAS, false).getPublic(),keyMaterial,mask,KM_KEY_FORMAT_PKCS8,makeRsaAuthList(keySize)));} catch (SecureKeyImportUnavailableException e) {e.printStackTrace();}// Use KeyKeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");keyStore.load(null, null);if(!keyStore.containsAlias(ALIAS)){showMessage("fail to import RSA key");return;}String plaintext = "hello, world";Key importedKey = keyStore.getKey(ALIAS, null);// Encrypt with KS private key, then decrypt with local public key.Cipher c = Cipher.getInstance("RSA/ECB/PKCS1Padding");c.init(Cipher.ENCRYPT_MODE, importedKey);byte[] encrypted = c.doFinal(plaintext.getBytes());c.init(Cipher.DECRYPT_MODE, publicKey);showMessage("is same:"+(new String(c.doFinal(encrypted))).equals(plaintext));// Encrypt with local public key, then decrypt with KS private key.c.init(Cipher.ENCRYPT_MODE, publicKey);encrypted = c.doFinal(plaintext.getBytes());c.init(Cipher.DECRYPT_MODE, importedKey);showMessage("is same:"+(new String(c.doFinal(encrypted))).equals(plaintext));// Sign with KS private key, then verify with local public key.Signature s = Signature.getInstance("SHA256withRSA");s.initSign((PrivateKey) importedKey);s.update(plaintext.getBytes());byte[] signature = s.sign();s.initVerify(publicKey);s.update(plaintext.getBytes());showMessage("result:"+(s.verify(signature)));}public void testAES() throws Exception {// 构建原始的AES秘钥KeyGenerator kg = KeyGenerator.getInstance("AES");kg.init(256);Key swKey = kg.generateKey();byte[] keyMaterial = swKey.getEncoded();showMessage("keyMaterialHex:" + Hex.toHexString(keyMaterial));// 构建包装的RSA秘钥KeyPair keyPair = genKeyPair(WRAPPING_KEY_ALIAS, true);PublicKey aPublic = keyPair.getPublic();byte[] aPublicBytes = aPublic.getEncoded();showMessage("aPublic:" + Hex.toHexString(aPublicBytes));byte[] mask = new byte[32]; // Zero maskDERSequence asn1Encodables = makeAesAuthList(keyMaterial.length * 8);byte[] bytes = wrapKey(aPublic, keyMaterial, mask, KM_KEY_FORMAT_RAW, asn1Encodables);// 导入importWrappedKey(bytes);// Use KeyKeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");keyStore.load(null, null);if(!keyStore.containsAlias(ALIAS)){showMessage("fail to import AES key");return;}Key importedKey = keyStore.getKey(ALIAS, null);String plaintext = "hello, world";Cipher c = Cipher.getInstance("AES/ECB/PKCS7Padding");c.init(Cipher.ENCRYPT_MODE, importedKey);byte[] encrypted = c.doFinal(plaintext.getBytes());// Decrypt using key imported into keystore.c = Cipher.getInstance("AES/ECB/PKCS7Padding");c.init(Cipher.DECRYPT_MODE, importedKey);showMessage("is same:"+(new String(c.doFinal(encrypted)).equals(plaintext)));// Decrypt using local software copy of the key.c = Cipher.getInstance("AES/ECB/PKCS7Padding");c.init(Cipher.DECRYPT_MODE, swKey);showMessage("is same:"+(new String(c.doFinal(encrypted)).equals(plaintext)));}
}

需要依赖的包:

implementation files('libs/bcpkix-jdk15to18-1.64.jar')
implementation files('libs/bcprov-jdk15to18-1.64.jar')

相关文章:

Android KeyStore 秘钥导入

源码参考: https://android.googlesource.com/platform/cts//master/tests/tests/keystore/src/android/keystore/cts/ImportWrappedKeyTest.java 辅助源码参考: https://android.googlesource.com/platform/frameworks/base//master/core/java/android…...

TDengine+OpenVINO+AIxBoard,助力时序数据分类

时间序列数据分析在工业,能源,医疗,交通,金融,零售等多个领域都有广泛应用。其中时间序列数据分类是分析时序数据的常见任务之一。本文将通过一个具体的案例,介绍 Intel 团队如何使用 TDengine 作为基础软件…...

设计模式——16. 迭代器模式

1. 说明 迭代器模式(Iterator Pattern)是一种行为型设计模式,它用于提供一种访问聚合对象(如列表、数组、集合等)元素的统一接口,而不需要了解底层数据结构的具体实现。迭代器模式将遍历聚合对象的操作封装在一个独立的迭代器对象中,这样可以隔离遍历算法和数据结构,使…...

flink redis connector需要防止包冲突

1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 <dependency><groupId>org.apache.bahir</groupId><artifactId...

socket can查看详细信息 命令 ip -details -statistics link show can0

ip -details -statistics link show can0 ip -details link show can0 ip -statistics link show can0 也可以像第一行那样结合使用...

打造虚拟企业展厅,开启商务活动新时代

引言: 虚拟企业展厅是一种基于数字技术的全新商务模式&#xff0c;正在改变传统商务活动的方式&#xff0c;它比传统的企业展厅更便利&#xff0c;也更能凸显企业优势&#xff0c;展示企业风貌。 一&#xff0e;虚拟企业展厅的好处 1.打破地域限制 传统的商务活动通常需要参…...

03黑马店评-添加商户缓存和商户类型的缓存到Redis

商户查询缓存 什么是缓存 实际开发过程中数据量可以达到几千万,缓存可以作为避震器防止过高的数据访问猛冲系统,避免系统内的操作线程无法及时处理信息而瘫痪 缓存(Cache)就是数据交换的缓冲区(储存临时数据的地方),我们俗称的"缓存"实际就是缓冲区内的数据(一般从…...

LabVIEW玩转魔方

LabVIEW玩转魔方 使用LabVIEW创建一个3D魔方&#xff0c;并找出解谜题的秘密&#xff0c;给朋友留下深刻深刻的印象。游戏中内置的机制使每张脸都能独立转动&#xff0c;从而混合颜色。要解决难题&#xff0c;每个面必须是相同的纯色 魔方的奥秘在于它的简单性和不可解性。这是…...

大数据学习(1)-Hadoop

&&大数据学习&& &#x1f525;系列专栏&#xff1a; &#x1f451;哲学语录: 承认自己的无知&#xff0c;乃是开启智慧的大门 &#x1f496;如果觉得博主的文章还不错的话&#xff0c;请点赞&#x1f44d;收藏⭐️留言&#x1f4dd;支持一下博>主哦&#x…...

常用时序模型

常用时序模型 RNN (Recurrent Neural Network): 基本概念: RNN是一种可以处理序列数据的神经网络。它在每一时间步都接收一个新的输入,并将前一个时间步的隐藏状态作为额外的输入。问题: 它的主要问题是在处理长序列时遇到的梯度消失和梯度爆炸。这使得RNN难以捕获长期依赖关…...

阿里云/腾讯云国际站:私服服务器:什么是游戏虚拟服务器及用途讲解?

游戏虚拟服务器是一种新兴的技术&#xff0c;它可以为玩家提供更好的游戏体验。私服服务器它可以将游戏服务器的负载分散到多台服务器上&#xff0c;从而提高游戏的流畅度和稳定性。此外&#xff0c;游戏虚拟服务器还可以提供更多的游戏功能&#xff0c;比如游戏聊天室、游戏排…...

ssti 前置学习

python venv环境 可以把它想象成一个容器&#xff0c;该容器供你用来存放你的Python脚本以及安装各种Python第三方模块&#xff0c;容器里的环境和本机是完全分开的 创建venv环境安装flask #apt install python3.10-venv #cd /opt #python3 -m venv flask1 #cd /opt 选…...

uni-app:服务器端数据绘制echarts图标(renderjs解决手机端无法显示问题)

效果 代码 <template><view click"echarts.onClick" :prop"option" :change:prop"echarts.updateEcharts" id"echarts" class"echarts"></view> </template><script>export default {data()…...

Python集合魔法:解锁数据去重技巧

更多资料获取 &#x1f4da; 个人网站&#xff1a;涛哥聊Python 在Python编程的魔法世界中&#xff0c;有一种数据类型几乎被忽视&#xff0c;但却拥有强大的超能力&#xff0c;那就是集合&#xff08;Set&#xff09;。 集合是一种无序、唯一的数据类型&#xff0c;它以其独…...

flutter开发实战-inappwebview实现flutter与Javascript的交互JSBridge

flutter开发实战-inappwebview实现flutter与Javascript的交互JSBridge 在使用webview中&#xff0c;需要实现flutter与Javascript交互&#xff0c;在使用webview_flutter插件的时候&#xff0c;整理了一下webview与Javascript的交互JSBridge&#xff0c;具体可以查看 https:/…...

私有云盘:lamp部署nextcloud+高可用集群

目录 一、实验准备&#xff1a; 二、配置mariadb主从复制 三台主机下载mariadb 1&#xff09;主的操作 2&#xff09;从的操作 3&#xff09;测试数据是否同步 三、配置nfs让web服务挂载 1、安装 2、配置nfs服务器 3、配置web服务的httpd 4、测试 四、web 服务器 配…...

在线制作课程表

失业在家&#xff0c;开启一天一个应用的创作节奏&#xff0c;最近学了uniapp&#xff0c;特别想做点啥&#xff0c;正好家里小孩子要打印课程表&#xff0c;而且课程表还有调课的需求&#xff0c;就寻思做一个方便大家&#xff0c;到目前位置服务完全免费的&#xff0c;新鲜上…...

聊聊分布式架构06——[NIO入门]简单的Netty NIO示例

目录 Java NIO和Netty NIO比较 Java NIO&#xff1a; Netty&#xff1a; Netty NIO中的主要模块 Transport&#xff08;传输层&#xff09; Buffer&#xff08;缓冲区&#xff09; Codec&#xff08;编解码器&#xff09; Handler&#xff08;处理器&#xff09; Even…...

H5逆向之远程RPC

引言前一讲说过H5 怎么去抓包,逆向分析。其中说到RPC。这一节详细讲一下。有一种情况,JS 比较复杂,混淆的厉害。 这个时候就用到RPC。原理就是,hook web 浏览器,直接调用js 里边的方法。 Node 服务。为什么用到Node 服务,先来看下这架构 Node 对外提供各种接口,外部可以…...

解决Ubuntu18.04安装好搜狗输入法后无法打出中文的问题

首先下载安装 搜狗拼音输入法 &#xff0c;下载选择&#xff1a; x86_64 在ubuntu中设置 fcitx 最后发现安装好了&#xff0c;图标有了 &#xff0c;但是使用时不能输入中文&#xff0c;使用下面的命令解决&#xff1a; sudo apt install libqt5qml5 libqt5quick5 libqt5qu…...

Ubuntu LabelMe AI 识别

1.创建虚拟环境 conda create -n labelme python3.9 2.激活虚拟环境 conda activate labelme 3.安装labelme pip install pyqt5 -i https://pypi.tuna.tsinghua.edu.cn/simple pip install pillow -i https://pypi.tuna.tsinghua.edu.cn/simple pip install labelme -i ht…...

基于FPGA的图像缩小算法实现,包括tb测试文件和MATLAB辅助验证

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 5.算法完整程序工程 1.算法运行效果图预览 将FPGA的处理结果导出到matlab中显示图像效果&#xff1a; 2.算法运行软件版本 vivado2019.2 matlab2022a 3.部分核心程序 timescale 1ns / 1p…...

黑马店评-04缓存更新策略,保证MySQL数据库中的数据和Redis中缓存的数据一致性

缓存更新策略(数据一致) 更新策略 缓存更新是Redis为了节约内存而设计出来的机制,当我们向Redis插入太多数据时就会导致缓存中的数据过多,所以Redis会对部分数据进行更新即淘汰 低一致性需求(数据长久不发生变化): 使用内存淘汰机制,例如店铺类型信息的查询缓存,因为这部分…...

matlab相机标定实验

实验原理 1. 相机标定坐标系 相机的参数对目标的识别、定位精度有很大的影响&#xff0c;相机标定就是为了求出相机的内外参数。标定中有3个不同层次的坐标系&#xff1a;世界坐标系、相机坐标系和图像坐标系&#xff08;图像物理坐标系和图像像素坐标系&#xff09;。世界坐…...

【每日一题Day343】LC2731移动机器人 | 脑筋急转弯+数学

移动机器人【LC2731】 有一些机器人分布在一条无限长的数轴上&#xff0c;他们初始坐标用一个下标从 0 开始的整数数组 nums 表示。当你给机器人下达命令时&#xff0c;它们以每秒钟一单位的速度开始移动。 给你一个字符串 s &#xff0c;每个字符按顺序分别表示每个机器人移动…...

疯狂java 1.7垃圾回收机制

内存泄漏&#xff1a;如果一些分配出去的内存得不到及时回收&#xff0c;就会引起系统运行速度下降&#xff0c;甚至导致程序瘫痪 Java程序的内存分配和回收都是由JRE在后台自动进行的。JRE会负责回收哪些不再使用的内存&#xff0c;这种机制被称为垃圾回收&#xff08;Garbag…...

day01_基础

零、今日内容 1 jdk 2 idea使用 3 HelloWorld程序 4 变量 5 数据类型 6 String 一、JDK安装 JDK java开发工具包,敲代码的环境 1.1 卸载 控制面板 -> 卸载程序 -> 选择jdk,右键卸载 1.2 安装 注意: 现在安装的是JDK8版本,虽然最新的版本是21版本,但是工作市场中最流行的…...

RabbitMQ开启消息发送确认和消费手动确认

开启RabbitMQ的生产者发送消息到RabbitMQ服务端的接收确认&#xff08;ACK&#xff09;和消费者通过手动确认或者丢弃消费的消息。 通过配置 publisher-confirm-type: correlated 和publisher-returns: true开启生产者确认消息。 server:port: 8014spring:rabbitmq:username: …...

嵌入式系统开发【深入浅出】 GPIO 类设备的驱动程序

目录 GPIO管脚的输出功能相当于控制、输入相当于检测 使用GPIO基本流程 对于某一个管脚来说最多有几种功能&#xff1f; 拓展 【定时器与系统定时器】 决定定时长短的因素: 普通定时器 系统定时器 STM32F103RBT6的时钟源有哪五种 sysclk 的时钟频率由哪个时钟源提供基…...

项目管理必备的22个公式

大家好&#xff0c;我是老原。 趁着国庆时间比较空闲&#xff0c;给你们整理了一些项目管理必备的计算公式&#xff0c;一共22个。 每一个公式都给你们标注了适用情况和使用方法&#xff0c;为了方便你们理解&#xff0c;也加了一些例子&#xff0c;保准你看了就会。 觉得不…...