Web crypto api javascript

Web Crypto API

The Web Crypto API is an interface allowing a script to use cryptographic primitives in order to build systems using cryptography.

Note: This feature is available in Web Workers

Secure context: This feature is available only in secure contexts (HTTPS), in some or all supporting browsers.

Warning: The Web Crypto API provides a number of low-level cryptographic primitives. It’s very easy to misuse them, and the pitfalls involved can be very subtle.

Even assuming you use the basic cryptographic functions correctly, secure key management and overall security system design are extremely hard to get right, and are generally the domain of specialist security experts.

Errors in security system design and implementation can make the security of the system completely ineffective.

Please learn and experiment, but don’t guarantee or imply the security of your work before an individual knowledgeable in this subject matter thoroughly reviews it. The Crypto 101 Course can be a great place to start learning about the design and implementation of secure systems.

Interfaces

Some browsers implemented an interface called Crypto without having it well defined or being cryptographically sound. In order to avoid confusion, methods and properties of this interface have been removed from browsers implementing the Web Crypto API, and all Web Crypto API methods are available on a new interface: SubtleCrypto . The Crypto.subtle property gives access to an object implementing it.

Specifications

Browser compatibility

BCD tables only load in the browser

Found a content problem with this page?

This page was last modified on Feb 19, 2023 by MDN contributors.

Your blueprint for a better internet.

Источник

Web Cryptography API: пример использования

В этом туториале мы рассмотрим Web Cryptography API: интерфейс шифрования данных на стороне клиента. Данный туториал основан на этой статье. Предполагается, что вы немного знакомы с шифрованием.

Читайте также:  Set system proxy java

Что конкретно мы будем делать? Мы напишем простой сервер, который будет принимать зашифрованные данные от клиента и возвращать их ему по запросу. Сами данные будут обрабатываться на стороне клиента.

Сервер будет реализован на Node.js с помощью Express, клиент — на JavaScript. Для стилизации будет использоваться Bootstrap.

Если вам это интересно, прошу следовать за мной.

Подготовка

Создаем директорию crypto-tut :

Заходим в нее и инициализируем проект:

crypto-tut --node_modules --src --client.js --index.html --style.css --package-lock.json --package.json --server.js 
     

Web Cryptography API Tutorial

h3, .btn-box < margin: .5em; text-align: center; >input, output < display: block; margin: 1em auto; text-align: center; >output span

Сервер

Приступаем к созданию сервера.

Подключаем express и создаем экземпляры приложения и маршрутизатора:

const express = require('express') const app = express() const router = express.Router() 

Подключаем middleware (промежуточный слой между запросом и ответом):

// разбор запроса app.use(express.json(< type: ['application/json', 'text/plain'] >)) // подключение роутера app.use(router) // директория со статическими файлами app.use(express.static('src')) 

Создаем переменную для хранения данных:

Обрабатываем получение данных от клиента:

router.post('/secure-api', (req, res) => < // получаем данные из тела запроса data = req.body // выводим данные в терминал console.log(data) // закрываем соединение res.end() >) 

Обрабатываем отправку данных клиенту:

router.get('/secure-api', (req, res) => < // данные отправляются в формате JSON, // после чего соединение автоматически закрывается res.json(data) >) 
app.listen(3000, () => console.log('Server ready')) 

Выполняем команду npm start . В терминале появляется сообщение «Server ready». Открываем http://localhost:3000 :

На этом с сервером мы закончили, переходим к клиентской части приложения.

Клиент

Здесь начинается самое интересное.

Для шифрования данных будет использоваться симметричный алгоритм AES-GCM. Такие алгоритмы позволяют использовать один и тот же ключ для шифрования и расшифровки.

Создаем функцию генерации симметричного ключа:

// https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/generateKey const generateKey = async () => window.crypto.subtle.generateKey(< name: 'AES-GCM', length: 256, >, true, ['encrypt', 'decrypt']) 

Перед шифрованием данные необходимо закодировать в поток байтов. Это легко сделать с помощью класса TextEncoder:

// https://developer.mozilla.org/en-US/docs/Web/API/TextEncoder const encode = data =>

Далее, нам нужен вектор исполнения (вектор инициализации, initialization vector, IV), представляющий собой случайную или псевдослучайную последовательность символов, которую добавляют к ключу шифрования для повышения его безопасности:

// https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues const generateIv = () => // https://developer.mozilla.org/en-US/docs/Web/API/AesGcmParams window.crypto.getRandomValues(new Uint8Array(12)) 

После создания вспомогательных функций, мы можем реализовать функцию шифрования. Данная функция должна возвращать шифр и IV для того, чтобы шифр можно было впоследствии декодировать:

const encrypt = async (data, key) => < const encoded = encode(data) const iv = generateIv() const cipher = await window.crypto.subtle.encrypt(< name: 'AES-GCM', iv >, key, encoded) return < cipher, iv >> 

После шифрования данных с помощью SubtleCrypto, они представляют собой буферы необработанных двоичных данных. Это не лучший формат для передачи и хранения. Давайте это исправим.

Читайте также:  Run application using python

Данные, обычно, передаются в формате JSON и хранятся в базе данных. Поэтому имеет смысл упаковать данные в портируемый формат. Одним из способов это сделать является конвертация данных в строки в формате base64:

// https://developers.google.com/web/updates/2012/06/How-to-convert-ArrayBuffer-to-and-from-String const pack = buffer => window.btoa( String.fromCharCode.apply(null, new Uint8Array(buffer)) ) 

После получения данных необходимо выполнить обратный процесс, т.е. преобразовать строки в кодировке base64 в буферы необработанных двоичных данных:

// https://developers.google.com/web/updates/2012/06/How-to-convert-ArrayBuffer-to-and-from-String const unpack = packed => < const string = window.atob(packed) const buffer = new ArrayBuffer(string.length) const bufferView = new Uint8Array(buffer) for (let i = 0; i < string.length; i++) < bufferView[i] = string.charCodeAt(i) >return buffer > 

Остается расшифровать полученные данные. Однако, после расшифровки нам необходимо декодировать поток байтов в исходный формат. Это можно сделать с помощью класса TextDecoder:

// https://developer.mozilla.org/en-US/docs/Web/API/TextDecoder const decode = byteStream =>

Функция расшифровки представляет собой инверсию функции шифрования:

// https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/decrypt const decrypt = async (cipher, key, iv) => < const encoded = await window.crypto.subtle.decrypt(< name: 'AES-GCM', iv >, key, cipher) return decode(encoded) > 

На данном этапе содержимое client.js выглядит так:

const generateKey = async () => window.crypto.subtle.generateKey(< name: 'AES-GCM', length: 256, >, true, ['encrypt', 'decrypt']) const encode = data => < const encoder = new TextEncoder() return encoder.encode(data) >const generateIv = () => window.crypto.getRandomValues(new Uint8Array(12)) const encrypt = async (data, key) => < const encoded = encode(data) const iv = generateIv() const cipher = await window.crypto.subtle.encrypt(< name: 'AES-GCM', iv >, key, encoded) return < cipher, iv >> const pack = buffer => window.btoa( String.fromCharCode.apply(null, new Uint8Array(buffer)) ) const unpack = packed => < const string = window.atob(packed) const buffer = new ArrayBuffer(string.length) const bufferView = new Uint8Array(buffer) for (let i = 0; i < string.length; i++) < bufferView[i] = string.charCodeAt(i) >return buffer > const decode = byteStream => < const decoder = new TextDecoder() return decoder.decode(byteStream) >const decrypt = async (cipher, key, iv) => < const encoded = await window.crypto.subtle.decrypt(< name: 'AES-GCM', iv >, key, cipher) return decode(encoded) > 

Теперь реализуем отправку и получение данных.

// поле для ввода сообщения, которое будет зашифровано const input = document.querySelector('input') // контейнер для вывода результатов const output = document.querySelector('output') // ключ let key 

Шифрование и отправка данных:

const encryptAndSendMsg = async () => < const msg = input.value // шифрование key = await generateKey() const < cipher, iv >= await encrypt(msg, key) // упаковка и отправка await fetch('http://localhost:3000/secure-api', < method: 'POST', body: JSON.stringify(< cipher: pack(cipher), iv: pack(iv) >) >) output.innerHTML = `Сообщение "$" зашифровано.
Данные отправлены на сервер.` >

Получение и расшифровка данных:

const getAndDecryptMsg = async () => < const res = await fetch('http://localhost:3000/secure-api') const data = await res.json() // выводим данные в консоль console.log(data) // распаковка и расшифровка const msg = await decrypt(unpack(data.cipher), key, unpack(data.iv)) output.innerHTML = `Данные от сервера получены.
Сообщение "$" расшифровано.` >
document.querySelector('.btn-box').addEventListener('click', e => < if (e.target.classList.contains('btn-send')) < encryptAndSendMsg() e.target.nextElementSibling.removeAttribute('disabled') >else if (e.target.classList.contains('btn-get')) < getAndDecryptMsg() >>) 

На всякий случай перезапускаем сервер. Открываем http://localhost:3000 . Нажимаем на кнопку «Send message»:

Читайте также:  String too long python

Видим данные, полученные сервером, в терминале:

Нажимаем на кнопку «Get message»:

Видим те же самые данные, полученные клиентом, в консоли:

Web Cryptography API открывает перед нами интересные возможности по защите конфиденциальной информации на стороне клиента. Еще один шаг в сторону бессерверной веб-разработки.

Поддержка данной технологии на сегодняшний день составляет 96%:

Надеюсь, статья вам понравилась. Благодарю за внимание.

Источник

Оцените статью