PHP WebShell
Текущая директория: /opt/BitGoJS/modules/bitgo/test/v2/unit/internal
Просмотр файла: opengpgUtils.ts
import * as openpgp from 'openpgp';
import * as should from 'should';
import * as crypto from 'crypto';
import * as assert from 'assert';
import { openpgpUtils } from '@bitgo/sdk-core';
import { ecc as secp256k1 } from '@bitgo/utxo-lib';
import * as sinon from 'sinon';
const sodium = require('libsodium-wrappers-sumo');
describe('OpenGPG Utils Tests', function () {
let senderKey: { publicKey: string; privateKey: string };
let recipientKey: { publicKey: string; privateKey: string };
let otherKey: { publicKey: string; privateKey: string };
before(async function () {
openpgp.config.rejectCurves = new Set();
senderKey = await openpgp.generateKey({
userIDs: [
{
name: 'sender',
email: 'sender@username.com',
},
],
curve: 'secp256k1',
});
recipientKey = await openpgp.generateKey({
userIDs: [
{
name: 'recipient',
email: 'recipient@username.com',
},
],
curve: 'secp256k1',
});
otherKey = await openpgp.generateKey({
userIDs: [
{
name: 'other',
email: 'other@username.com',
},
],
curve: 'secp256k1',
});
});
describe('createShareProof', function () {
it('should create an Ed share proof', async function () {
const uValue = crypto.randomBytes(32).toString('hex');
const proof = await openpgpUtils.createShareProof(senderKey.privateKey, uValue, 'eddsa');
// verify proof
const decodedProof = await openpgp.readKey({ armoredKey: proof }).should.be.fulfilled();
const decodedPubKey = await openpgp.readKey({ armoredKey: senderKey.publicKey }).should.be.fulfilled();
const isValid = (await decodedProof.verifyPrimaryUser([decodedPubKey]))[0].valid;
isValid.should.be.true();
const proofSubkeys = decodedProof.getSubkeys()[1];
const decodedUValueProof = Buffer.from(proofSubkeys.keyPacket.publicParams.Q.slice(1)).toString('hex');
const rawUValueProof = Buffer.from(
sodium.crypto_scalarmult_ed25519_base_noclamp(Buffer.from(uValue, 'hex'))
).toString('hex');
decodedUValueProof.should.equal(rawUValueProof);
});
it('should create an Ec share proof', async function () {
const uValue = crypto.randomBytes(32).toString('hex');
const proof = await openpgpUtils.createShareProof(senderKey.privateKey, uValue, 'ecdsa');
// verify proof
const decodedProof = await openpgp.readKey({ armoredKey: proof }).should.be.fulfilled();
const decodedPubKey = await openpgp.readKey({ armoredKey: senderKey.publicKey }).should.be.fulfilled();
const isValid = (await decodedProof.verifyPrimaryUser([decodedPubKey]))[0].valid;
isValid.should.be.true();
const proofSubkeys = decodedProof.getSubkeys()[1];
const decodedUValueProof = proofSubkeys.keyPacket.publicParams.Q;
const rawUValueProof = secp256k1.pointFromScalar(Buffer.from(uValue, 'hex'), false);
equal(decodedUValueProof, rawUValueProof).should.be.true();
});
});
describe('verifyPrimaryUserWrapper', function () {
it('should verify primary user with a date check', async function () {
const uValue = crypto.randomBytes(32).toString('hex');
const proof = await openpgpUtils.createShareProof(senderKey.privateKey, uValue, 'eddsa');
// verify proof
const decodedProof = await openpgp.readKey({ armoredKey: proof }).should.be.fulfilled();
const decodedPubKey = await openpgp.readKey({ armoredKey: senderKey.publicKey }).should.be.fulfilled();
const isValid = (await openpgpUtils.verifyPrimaryUserWrapper(decodedProof, decodedPubKey, true))[0].valid;
should.exist(isValid);
if (isValid !== null) {
isValid.should.be.true();
}
});
it('should verify primary user without a date check', async function () {
const uValue = crypto.randomBytes(32).toString('hex');
const proof = await openpgpUtils.createShareProof(senderKey.privateKey, uValue, 'eddsa');
// verify proof
const decodedProof = await openpgp.readKey({ armoredKey: proof }).should.be.fulfilled();
const decodedPubKey = await openpgp.readKey({ armoredKey: senderKey.publicKey }).should.be.fulfilled();
const isValid = (await openpgpUtils.verifyPrimaryUserWrapper(decodedProof, decodedPubKey, false))[0].valid;
should.exist(isValid);
if (isValid !== null) {
isValid.should.be.true();
}
});
});
describe('verifyShareProof EdDSA', function () {
it('should be able to verify a valid proof', async function () {
const uValue = crypto.randomBytes(32).toString('hex');
const proof = await openpgpUtils.createShareProof(senderKey.privateKey, uValue, 'eddsa');
const isValid = await openpgpUtils.verifyShareProof(senderKey.publicKey, proof, uValue, 'eddsa');
isValid.should.be.true();
});
it('should be able to detect sender is an attacker', async function () {
const uValue = crypto.randomBytes(32).toString('hex');
const proof = await openpgpUtils.createShareProof(otherKey.privateKey, uValue, 'eddsa');
const isValid = await openpgpUtils.verifyShareProof(senderKey.publicKey, proof, uValue, 'eddsa');
isValid.should.be.false();
});
it('should be able to detect u value is corrupted', async function () {
const uValue = crypto.randomBytes(32).toString('hex');
const proof = await openpgpUtils.createShareProof(senderKey.privateKey, uValue, 'eddsa');
const uValueCorrupted = crypto.randomBytes(32).toString('hex');
const isValid = await openpgpUtils.verifyShareProof(senderKey.publicKey, proof, uValueCorrupted, 'eddsa');
isValid.should.be.false();
});
});
describe('verifyShareProof ECDSA', function () {
it('should be able to verify a valid proof', async function () {
const uValue = crypto.randomBytes(32).toString('hex');
const proof = await openpgpUtils.createShareProof(senderKey.privateKey, uValue, 'ecdsa');
const isValid = await openpgpUtils.verifyShareProof(senderKey.publicKey, proof, uValue, 'ecdsa');
isValid.should.be.true();
});
it('should be able to detect sender is an attacker', async function () {
const uValue = crypto.randomBytes(32).toString('hex');
const proof = await openpgpUtils.createShareProof(otherKey.privateKey, uValue, 'ecdsa');
const isValid = await openpgpUtils.verifyShareProof(senderKey.publicKey, proof, uValue, 'ecdsa');
isValid.should.be.false();
});
it('should be able to detect u value is corrupted', async function () {
const uValue = crypto.randomBytes(32).toString('hex');
const proof = await openpgpUtils.createShareProof(senderKey.privateKey, uValue, 'ecdsa');
const uValueCorrupted = crypto.randomBytes(32).toString('hex');
const isValid = await openpgpUtils.verifyShareProof(senderKey.publicKey, proof, uValueCorrupted, 'ecdsa');
isValid.should.be.false();
});
});
describe('verifySharedDataProof and createSharedDataProof test', function () {
it('should be able to detect if proof value is corrupted or not', async function () {
const sharedData1 = crypto.randomBytes(32).toString('hex');
const sharedData2 = crypto.randomBytes(32).toString('hex');
const dataToProofArray = [
{ name: 's1', value: sharedData1 },
{ name: 's2', value: sharedData2 },
];
const proof = await openpgpUtils.createSharedDataProof(
senderKey.privateKey,
otherKey.publicKey,
dataToProofArray
);
let isValid = await openpgpUtils.verifySharedDataProof(senderKey.publicKey, proof, dataToProofArray);
isValid.should.be.true();
// tamper with the data
dataToProofArray[0].value = 'tampered data';
isValid = await openpgpUtils.verifySharedDataProof(senderKey.publicKey, proof, dataToProofArray);
isValid.should.be.false();
});
it('should be able verify data proof if created in the future', async function () {
const sharedData1 = crypto.randomBytes(32).toString('hex');
const sharedData2 = crypto.randomBytes(32).toString('hex');
const dataToProofArray = [
{ name: 's1', value: sharedData1 },
{ name: 's2', value: sharedData2 },
];
const proof = await openpgpUtils.createSharedDataProof(
senderKey.privateKey,
otherKey.publicKey,
dataToProofArray
);
const clock = sinon.useFakeTimers(new Date('2001-02-14T12:00:00Z').getTime());
const isValid = await openpgpUtils.verifySharedDataProof(senderKey.publicKey, proof, dataToProofArray);
isValid.should.be.true();
clock.restore();
});
});
describe('encrypt and decrypt with signing', function () {
it('should successfully encrypt, sign, and decrypt', async function () {
const text = 'original message';
const signedMessage = await openpgpUtils.encryptAndSignText(text, recipientKey.publicKey, senderKey.privateKey);
const decryptedMessage = await openpgpUtils.readSignedMessage(
signedMessage,
senderKey.publicKey,
recipientKey.privateKey
);
decryptedMessage.should.equal(text);
});
it('should fail on verification with wrong public key', async function () {
const text = 'original message';
const signedMessage = await openpgpUtils.encryptAndSignText(text, recipientKey.publicKey, senderKey.privateKey);
await openpgpUtils
.readSignedMessage(signedMessage, otherKey.publicKey, recipientKey.privateKey)
.should.be.rejected();
});
it('should fail on decryption with wrong private key', async function () {
const text = 'original message';
const signedMessage = await openpgpUtils.encryptAndSignText(text, recipientKey.publicKey, senderKey.privateKey);
await openpgpUtils
.readSignedMessage(signedMessage, senderKey.publicKey, otherKey.privateKey)
.should.be.rejectedWith('Error decrypting message: Session key decryption failed.');
});
it('should encrypt, sign, and decrypt without previously clearing rejectedCurves', async function () {
openpgp.config.rejectCurves = new Set([openpgp.enums.curve.secp256k1]);
const text = 'original message';
const signedMessage = await openpgpUtils.encryptAndSignText(text, recipientKey.publicKey, senderKey.privateKey);
const decryptedMessage = await openpgpUtils.readSignedMessage(
signedMessage,
senderKey.publicKey,
recipientKey.privateKey
);
decryptedMessage.should.equal(text);
openpgp.config.rejectCurves = new Set();
});
});
describe('signatures and verification', function () {
it('should verify signature', async function () {
const text = 'some payload';
const signature = await openpgpUtils.signText(text, senderKey.privateKey);
const isValidSignature = await openpgpUtils.verifySignature(text, signature, senderKey.publicKey);
isValidSignature.should.be.true();
});
it('should fail verification if public key is incorrect', async function () {
const text = 'some payload';
const signature = await openpgpUtils.signText(text, senderKey.privateKey);
const isValidSignature = await openpgpUtils.verifySignature(text, signature, recipientKey.publicKey);
isValidSignature.should.be.false();
});
it('should fail verification if message is incorrect', async function () {
const text = 'some payload';
const signature = await openpgpUtils.signText(text, senderKey.privateKey);
const isValidSignature = await openpgpUtils.verifySignature('something else', signature, senderKey.publicKey);
isValidSignature.should.be.false();
});
});
describe('GPG key generation', function () {
it('should generate a a GPG key for secp256k1 with random name and email', async function () {
const gpgKey = await openpgpUtils.generateGPGKeyPair('secp256k1');
should.exist(gpgKey);
should.exist(gpgKey.privateKey);
should.exist(gpgKey.publicKey);
});
it('should generate a a GPG key for with random name and email', async function () {
const gpgKey = await openpgpUtils.generateGPGKeyPair('ed25519');
should.exist(gpgKey);
should.exist(gpgKey.privateKey);
should.exist(gpgKey.publicKey);
});
it('should generate a a GPG key with provided name and email', async function () {
const userName = 'John Doe';
const userEmail = 'john.doe@example.com';
const gpgKey = await openpgpUtils.generateGPGKeyPair('secp256k1', userName, userEmail);
should.exist(gpgKey);
should.exist(gpgKey.privateKey);
should.exist(gpgKey.publicKey);
const parsedKey = await openpgp.readKey({ armoredKey: gpgKey.publicKey });
should.exist(parsedKey);
assert(parsedKey);
const primaryUser = await parsedKey.getPrimaryUser();
primaryUser.user.userID?.name?.should.equal(userName);
primaryUser.user.userID?.email?.should.equal(userEmail);
});
it('should fail to generate a a GPG key for unknown curve', async function () {
await openpgpUtils
.generateGPGKeyPair('unknownCurve' as openpgp.EllipticCurveName)
.should.be.rejectedWith('Error generating keypair: Unknown curve');
});
});
function equal(buf1, buf2) {
if (buf1.byteLength != buf2.byteLength) return false;
const dv1 = new Int8Array(buf1);
const dv2 = new Int8Array(buf2);
for (let i = 0; i != buf1.byteLength; i++) {
if (dv1[i] != dv2[i]) return false;
}
return true;
}
});
Выполнить команду
Для локальной разработки. Не используйте в интернете!