我在客户端生成一对公钥/私钥,并将publickey
发送到服务器,后端将在其一侧生成sharedkey
,并响应我一个publickey
,这也帮助我在客户端生成一个sharedkey
,用于加密/解密。因此,我在Nodejs上用AES-256-GCM加密消息,并在客户端上解密消息。
后端:
export function encrypt(sharedKey: string, message: string) {
const firstIv = getRandomIV();
const cipher = crypto.createCipheriv(
'aes-256-gcm',
Buffer.from(sharedKey, 'base64'),
firstIv
);
const encrypted = cipher.update(message, 'utf8');
return Buffer.from(encrypted + cipher.final()).toString('base64');
}
function getRandomIV() {
return crypto.randomBytes(12);
}
客户端:
async function decrypt(encryptedData: Uint8Array) {
const aesKey = await generateAesKey();
const nonce = encryptedData.subarray(0, SERVER_ENCRYPTION_IV_LENGTH);
const data = encryptedData.subarray(SERVER_ENCRYPTION_IV_LENGTH);
const decrypted = await crypto.subtle.decrypt(
{
name: 'AES-GCM',
iv: nonce,
},
aesKey,
data
);
return {
decrypted: new Uint8Array(decrypted),
decryptedString: new TextDecoder().decode(decrypted),
};
}
async function generateAesKey() {
const publicKey = await getServerPublicKey();
const privateKey = await getPrivateKey();
const sharedSecret = await crypto.subtle.deriveBits(
{
name: 'ECDH',
public: publicKey!,
},
privateKey,
256
);
const aesSecret = await crypto.subtle.digest('SHA-256', sharedSecret);
return crypto.subtle.importKey('raw', aesSecret, 'AES-GCM', true, [
'encrypt',
'decrypt',
]);
}
现在,我无法解密客户端中的服务器加密响应,并且遇到domexception
错误,我不知道为什么?
GCM使用由NodeJS/crypto单独处理的身份验证标记,而WebCrypto自动将其与密文连接起来。
因此,在NodeJS代码中,必须显式地确定标记并将其附加到密文。这在当前的NodeJS代码中是缺失的,可以考虑如下。注意用cipher.getAuthTag()
及其连接确定标记:
var crypto = require('crypto');
function encrypt(key, plaintext) {
var nonce = getRandomIV();
var cipher = crypto.createCipheriv('aes-256-gcm', key, nonce);
var nonceCiphertextTag = Buffer.concat([
nonce,
cipher.update(plaintext),
cipher.final(),
cipher.getAuthTag() // Fix: Get tag with cipher.getAuthTag() and concatenate: nonce|ciphertext|tag
]);
return nonceCiphertextTag.toString('base64');
}
function getRandomIV() {
return crypto.randomBytes(12);
}
var message = Buffer.from('The quick brown fox jumps over the lazy dog', 'utf8');
var sharedKey = Buffer.from('MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDE=', 'base64');
var ciphertext = encrypt(sharedKey, message);
console.log(ciphertext); // wRE5KM6FG81QSMNvG0xR+iaIeF77cyyeBceGS5NkcYaD17K9nL0/helnqRBOkD9pLVoWM/nRAcaKg/YdvfNJcO1Zn/7ZM0k=
一个可能的输出是
wRE5KM6FG81QSMNvG0xR+iaIeF77cyyeBceGS5NkcYaD17K9nL0/helnqRBOkD9pLVoWM/nRAcaKg/YdvfNJcO1Zn/7ZM0k=
以下用于在WebCrypto端解密的代码基本上基于您的代码(没有从共享秘密派生密钥,这与当前问题无关):
(async () => {
var nonceCiphertextTag = base64ToArrayBuffer('wRE5KM6FG81QSMNvG0xR+iaIeF77cyyeBceGS5NkcYaD17K9nL0/helnqRBOkD9pLVoWM/nRAcaKg/YdvfNJcO1Zn/7ZM0k=');
var nonceCiphertextTag = new Uint8Array(nonceCiphertextTag);
var decrypted = await decrypt(nonceCiphertextTag);
console.log(decrypted); // The quick brown fox jumps over the lazy dog
})();
async function decrypt(nonceCiphertextTag) {
const SERVER_ENCRYPTION_IV_LENGTH = 12; // For GCM a nonce length of 12 bytes is recommended!
var nonce = nonceCiphertextTag.subarray(0, SERVER_ENCRYPTION_IV_LENGTH);
var ciphertextTag = nonceCiphertextTag.subarray(SERVER_ENCRYPTION_IV_LENGTH);
var aesKey = base64ToArrayBuffer('MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDE=');
aesKey = await window.crypto.subtle.importKey('raw', aesKey, 'AES-GCM', true, ['encrypt', 'decrypt']);
var decrypted = await crypto.subtle.decrypt({name: 'AES-GCM', iv: nonce}, aesKey, ciphertextTag);
return new TextDecoder().decode(decrypted);
}
// Helper
// https://stackoverflow.com/a/21797381/9014097
function base64ToArrayBuffer(base64) {
var binary_string = window.atob(base64);
var len = binary_string.length;
var bytes = new Uint8Array(len);
for (var i = 0; i < len; i++) {
bytes[i] = binary_string.charCodeAt(i);
}
return bytes.buffer;
}
一面-2023年5月6日 ios客户端,大前端、object-c 自我介绍。有点背稿的感觉。 聊一个项目。说了OSG的项目。提到内存管理。 开始八股。内存:只能指针。 多态,静态、动态。模板、虚函数。静态的除了模板还有啥。析构函数为什么要添加虚函数。 空类size的大小。 struct/class的区别。 堆/栈/BSS几个内存类别 TCP四次挥手。 ipv4地址空间这么小怎么够用,NAT。用同一
二面-2023年5月8日 第一次迟到了面试.. 自我介绍。刚开始没准备各种结巴,语言不顺。整体还是讲完了。 项目。疯狂问项目、但是又不是挖,就是让自己讲。讲了好几个项目。看起来不是特别满意。一个是我自己准备项目拿普通横向项目准备的亮点肯定不够不到位,另外岗位是客户端,没有什么相关的。 岗位匹配度上,问了好几遍和原技术栈不匹配,自己的个人想法。(一开始也是你捞的我,我有啥想法 手撕算法。快排。这两面
本文向大家介绍php实现读取手机客户端浏览器的类,包括了php实现读取手机客户端浏览器的类的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了php实现读取手机客户端浏览器的类。分享给大家供大家参考。具体分析如下: 这里介绍的手机信息函数类有取手机号码,浏览器报头信息,取得手机类型,取得手机IP等功能。 希望本文所述对大家的php程序设计有所帮助。
免责声明:我知道这个问题有重复(一、二、三),但是: null 我的代码: 这将打印: (所有3个请求返回200个http代码) 我有JVM选项: (在我的keystore.jks中添加了vk.com证书) 下面是http-client的内部日志 当然,上面的测试是在关闭内部日志记录的情况下执行的,因为它会给每个请求增加大约50毫秒的额外时间。 我已经读了三遍所有的apache http-clie
Spring Security文档显示: “当您使用CSRF保护时?我们建议对正常用户可以通过浏览器处理的任何请求使用CSRF保护。如果您只创建非浏览器客户端使用的服务,则可能需要禁用CSRF保护。” 如果我的服务将被"浏览器"和"非浏览器"客户端(如第三方外部服务)使用,Spring Security是否提供了一种仅针对某些类型的客户端禁用CSRF的方法?
我知道这是不好的做法和特征识别应该是建设网站的方式。然而,这不是我的用例。 我有我的浏览器扩展的不同发行版,我想根据他们当前的浏览器更改下载按钮。 我试过使用,事实证明这是非常没用的,因为大多数浏览器都设置了所有流行的用户代理。例如chrome就有这个。 我见过很多网站的下载按钮上都有这个功能。如何做到这一点呢? 编辑:我现在了解了为什么“mozzila/x.x”位于userAgent字符串开头的