Added wasm code and some log examples

This commit is contained in:
Satsuoni 2021-07-29 13:03:40 +09:00
commit 1aae32eb80
53 changed files with 87502 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
.vscode/*

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2020 Tomer
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

54
README.md Normal file
View File

@ -0,0 +1,54 @@
# Trying to extract Widewine key: A journey to FaIlUrE
## Notes
- This work is based (obviously) on the [widevine-l3-decryptor extension](https://github.com/cryptonek/widevine-l3-decryptor). Many parts are the same, parts of Readme are a verbatim copy, etc.
- I have no working knowledge of Chrome extension structure.
- Some parts of code are copied from RFC documents, wikipedia, etc. *shrug*
- Tldr: The result seems to work, but relies on code lifting into wasm module and lots of brute-forcing, resulting in about 15-minute wait for a single RSA decryption.
- I am too lazy to improve on this.
## Introduction
[Widevine](https://www.widevine.com/solutions/widevine-drm) is a Google-owned DRM system that's in use by many popular streaming services (Netflix, Spotify, etc.) to prevent media content from being downloaded.
But Widevine's least secure security level, L3, as used in most browsers and PCs, is implemented 100% in software (i.e no hardware TEEs), thereby making it reversible and bypassable.
This Chrome extension demonstrates how it's possible to bypass Widevine DRM by hijacking calls to the browser's [Encrypted Media Extensions (EME)](https://www.html5rocks.com/en/tutorials/eme/basics) and (very slowly) decrypting all Widevine content keys transferred - effectively turning it into a clearkey DRM.
## Usage
To see this concept in action, just load the extension in Developer Mode and browse to any website that plays Widevine-protected content, such as https://bitmovin.com/demos/drm _[Update: link got broken?]_.
First, extension will try to brute-force input encoding for the code-lifted part, dumping progess to console. Then, assuming it succeeds, keys will be logged in plaintext to the javascript console.
e.g:
```
WidevineDecryptor: Found key: 100b6c20940f779a4589152b57d2dacb (KID=eb676abbcb345e96bbcf616630f1a3da)
```
Decrypting the media itself is then just a matter of using a tool that can decrypt MPEG-CENC streams, like `ffmpeg`.
e.g:
```
ffmpeg -decryption_key 100b6c20940f779a4589152b57d2dacb -i encrypted_media.mp4 -codec copy decrypted_media.mp4
```
**NOTE**: The extension currently supports the Windows platform only.
## How I got here
### Starting point
### Reverse enginering and emulating
### Extracting part of the exponent
### Descending into despair
### Code lifting
### FaIlUrEs uPoN fAiLuReS
### Conclusion

1
build_wasm.bat Normal file
View File

@ -0,0 +1 @@
emcc wasm_src/allocate.cpp wasm_src/misc.cpp wasm_src/integer.cpp wasm_src/algebra.cpp wasm_src/codelift.cpp -Os -s TOTAL_MEMORY=18743296 -Wno-implicitly-unsigned-literal -I "./wasm_src" -s WASM=1 -s LLD_REPORT_UNDEFINED -s "MODULARIZE=1" -s "EXPORT_NAME='WasmDsp'" -s "BINARYEN_METHOD='native-wasm'" -s "EXPORTED_FUNCTIONS=['_guessInput','_freeStr','_getOutput','_getDeoaep']" -s "EXPORTED_RUNTIME_METHODS=['stringToUTF8','UTF8ToString','stackSave','writeArrayToMemory','stackAlloc','stackRestore']" -o wasm/wasm_gsr.js

361
content_key_decryption.js Normal file
View File

@ -0,0 +1,361 @@
/*
This is where the magic happens
*/
var WidevineCrypto = {};
var _freeStr, stringToUTF8, writeArrayToMemory, UTF8ToString, stackSave, stackRestore, stackAlloc;
// Convert a hex string to a byte array
function hexToBytes(hex) {
for (var bytes = [], c = 0; c < hex.length; c += 2)
bytes.push(parseInt(hex.substr(c, 2), 16));
return bytes;
}
// Convert a byte array to a hex string
function bytesToHex(bytes) {
for (var hex = [], i = 0; i < bytes.length; i++) {
var current = bytes[i] < 0 ? bytes[i] + 256 : bytes[i];
hex.push((current >>> 4).toString(16));
hex.push((current & 0xF).toString(16));
}
return hex.join("");
}
(async function() {
// The public 2048-bit RSA key Widevine uses for Chrome devices in L3, on Windows
WidevineCrypto.Module= await WasmDsp();
await WidevineCrypto.Module.ready;
_freeStr=WidevineCrypto.Module._freeStr;
stringToUTF8=WidevineCrypto.Module.stringToUTF8;
writeArrayToMemory=WidevineCrypto.Module.writeArrayToMemory;
UTF8ToString=WidevineCrypto.Module.UTF8ToString;
stackSave=WidevineCrypto.Module.stackSave;
stackRestore=WidevineCrypto.Module.stackRestore;
stackAlloc=WidevineCrypto.Module.stackAlloc;
WidevineCrypto.getCFunc = function (ident) {
return this.Module[`_${ident}`]; // closure exported function
}
WidevineCrypto.scall = function (ident, returnType, argTypes, args, opts) {
const toC = {
string (str) {
let ret = 0;
if (str !== null && str !== undefined && str !== 0) {
const len = (str.length << 2) + 1;
ret = stackAlloc(len);
stringToUTF8(str, ret, len);
}
return ret;
},
array (arr) {
const ret = stackAlloc(arr.length);
writeArrayToMemory(arr, ret);
return ret;
}
};
function convertReturnValue (ret) {
if (returnType === 'string') return UTF8ToString(ret);
if (returnType === 'boolean') return Boolean(ret);
return ret;
}
const func = this.getCFunc(ident);
const cArgs = [];
let stack = 0;
if (args) {
for (let i = 0; i < args.length; i++) {
const converter = toC[argTypes[i]];
if (converter) {
if (stack === 0) stack = stackSave();
cArgs[i] = converter(args[i]);
} else {
cArgs[i] = args[i];
}
}
}
const _ret = func.apply(null, cArgs);
const ret = convertReturnValue(_ret);
_freeStr(_ret);
if (stack !== 0) stackRestore(stack);
return ret;
}
WidevineCrypto.swrap=function (ident, returnType, argTypes, opts) {
argTypes = argTypes || [];
const numericArgs = argTypes.every((type) => type === 'number');
const numericRet = returnType !== 'string';
if (numericRet && numericArgs && !opts) {
return this.getCFunc(ident);
}
return function () {
return this.scall(ident, returnType, argTypes, arguments, opts);
};
}
WidevineCrypto.guessInput = WidevineCrypto.swrap('guessInput', 'string', ['string']);
WidevineCrypto.getOutput = WidevineCrypto.swrap('getOutput', 'string', ['string']);
WidevineCrypto.getDeoaep = WidevineCrypto.swrap('getDeoaep', 'string', ['string']);
WidevineCrypto.chromeRSAPublicKey =
`-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvKg9eT9JPEnfVYYS50x3
MZirSQHyA2m/rxWY1x42LvE6ub47TU1zxjN4VC0jvrpWrU1YnB5/FR4lz296OPj/
H/SR1dLfyXFhe22VWUBuOlEnsq693qll4N/PTFCuJByvnoe/4zsNthm1w5XjmG4x
CjJ4+ZC0E5pCGvdLPk4VSCUN7I8XVbA45hBp4lR5g+2Th4VJtKn1+qG+9yp1qZKf
pyQPseRrlYcXDvmTwpw18fFF5Vv+wN6F0rlAnWWZscNIv3bdRBq9UwM0deMmf5Fk
fCWE2XTTrXuMDDNxFVbWws8jv3kFsXpoxiKgWApiPBr59EYpTV8t5Qch2F619Jtw
EwIDAQAB
-----END PUBLIC KEY-----`;
// The private 2048-bit RSA key Widevine uses for authenticating Chrome devices in L3, on Windows
// Could not extract it completely, so resorted to clumsy code lifting
WidevineCrypto.initializeKeys = async function()
{
// load the device RSA keys for various purposes
this.publicKeyEncrypt = await crypto.subtle.importKey('spki', PEM2Binary(this.chromeRSAPublicKey), {name: 'RSA-OAEP', hash: { name: 'SHA-1' },}, true, ['encrypt']);
this.publicKeyVerify = await crypto.subtle.importKey('spki', PEM2Binary(this.chromeRSAPublicKey), {name: 'RSA-PSS', hash: { name: 'SHA-1' },}, true, ['verify']);
this.keysInitialized = true;
}
WidevineCrypto.guessKey=async function(encKey)
{
let buf=new Uint8Array(1026);
for(let i = 0; i < 1026; i++)
{buf[i]=0;}
let hex=bytesToHex(encKey);
let res="";
console.log(hex);
let o=2;
while(o<1026)
{
let bt = Math.floor((o-2)/4);
let offs = (o-2)%4;
let desired=(encKey[encKey.length-bt-1]>>(offs*2))&3;
let destail=hex.substr(hex.length-bt*2,bt*2);
let val="";
let j=0;
for( j= buf[o]; j < 8; j++)
{
buf[o]=j;
let st=bytesToHex(buf);
val=await this.guessInput(st);
let sub=parseInt(val.substr(val.length-bt*2-2,2),16);
let got=(sub>>(offs*2))&3;
let gtail=val.substr(hex.length-bt*2,bt*2);
if (got===desired && gtail===destail)
{
if(o%16==2)
console.log(val);
break;
}
}
if (j == 8)
{
buf[o] = 0;
o--;
if (o < 2)
{
console.log("Could not match input");
throw "Could not find proper input encoding";
}
buf[o]++;
while (buf[o] == 8)
{
buf[o] = 0;
o--;
if (o < 2)
{
console.log("Could not match input");
throw "Could not find proper input encoding";
}
buf[o]++;
}
}
else
o++;
};
console.log("Output");
let st=bytesToHex(buf);
let outp=await this.getDeoaep(st);
console.log(outp);
if(outp.length<10)
{
throw "Could not remove padding, probably invalid key"
}
console.log(st);
return new Uint8Array(hexToBytes(outp));
}
WidevineCrypto.decryptContentKey = async function(licenseRequest, licenseResponse)
{
licenseRequest = SignedMessage.read(new Pbf(licenseRequest));
licenseResponse = SignedMessage.read(new Pbf(licenseResponse));
//console.log("Decrypting?")
//console.log("Request (from us)")
console.log(licenseRequest)
//console.log("Response")
console.log(licenseResponse)
if (licenseRequest.type != SignedMessage.MessageType.LICENSE_REQUEST.value) return;
license = License.read(new Pbf(licenseResponse.msg));
if (!this.keysInitialized) await this.initializeKeys();
// make sure the signature in the license request validates under the private key
var signatureVerified = await window.crypto.subtle.verify({name: "RSA-PSS", saltLength: 20,}, this.publicKeyVerify,
licenseRequest.signature, licenseRequest.msg)
if (!signatureVerified)
{
console.log("Can't verify license request signature; either the platform is wrong or the key has changed!");
return null;
}
var sessionKey=await this.guessKey(licenseResponse.session_key);
// decrypt the session key
// = await crypto.subtle.decrypt({name: "RSA-OAEP"}, this.privateKeyDecrypt, licenseResponse.session_key);
// calculate context_enc
var encoder = new TextEncoder();
var keySize = 128;
var context_enc = concatBuffers([[0x01], encoder.encode("ENCRYPTION"), [0x00], licenseRequest.msg, intToBuffer(keySize)]);
// calculate encrypt_key using CMAC
var encryptKey = wordToByteArray(
CryptoJS.CMAC(arrayToWordArray(new Uint8Array(sessionKey)),
arrayToWordArray(new Uint8Array(context_enc))).words);
// iterate the keys we got to find those we want to decrypt (the content key(s))
var contentKeys = []
for (currentKey of license.key)
{
if (currentKey.type != License.KeyContainer.KeyType.CONTENT.value) continue;
var keyId = currentKey.id;
var keyData = currentKey.key.slice(0, 16);
var keyIv = currentKey.iv.slice(0, 16);
// finally decrypt the content key
var decryptedKey = wordToByteArray(
CryptoJS.AES.decrypt({ ciphertext: arrayToWordArray(keyData) }, arrayToWordArray(encryptKey), { iv: arrayToWordArray(keyIv) }).words);
contentKeys.push(decryptedKey);
console.log("WidevineDecryptor: Found key: " + toHexString(decryptedKey) + " (KID=" + toHexString(keyId) + ")");
}
return contentKeys[0];
}
//
// Helper functions
//
async function isRSAConsistent(publicKey, privateKey)
{
// See if the data is correctly decrypted after encryption
var testData = new Uint8Array([0x41, 0x42, 0x43, 0x44]);
var encryptedData = await crypto.subtle.encrypt({name: "RSA-OAEP"}, publicKey, testData);
var testDecryptedData = await crypto.subtle.decrypt({name: "RSA-OAEP"}, privateKey, encryptedData);
return areBuffersEqual(testData, testDecryptedData);
}
function areBuffersEqual(buf1, buf2)
{
if (buf1.byteLength != buf2.byteLength) return false;
var dv1 = new Int8Array(buf1);
var dv2 = new Int8Array(buf2);
for (var i = 0 ; i != buf1.byteLength ; i++)
{
if (dv1[i] != dv2[i]) return false;
}
return true;
}
function concatBuffers(arrays)
{
// Get the total length of all arrays.
let length = 0;
arrays.forEach(item => {
length += item.length;
});
// Create a new array with total length and merge all source arrays.
let mergedArray = new Uint8Array(length);
let offset = 0;
arrays.forEach(item => {
mergedArray.set(new Uint8Array(item), offset);
offset += item.length;
});
return mergedArray;
}
// CryptoJS format to byte array
function wordToByteArray(wordArray)
{
var byteArray = [], word, i, j;
for (i = 0; i < wordArray.length; ++i) {
word = wordArray[i];
for (j = 3; j >= 0; --j) {
byteArray.push((word >> 8 * j) & 0xFF);
}
}
return byteArray;
}
// byte array to CryptoJS format
function arrayToWordArray(u8Array)
{
var words = [], i = 0, len = u8Array.length;
while (i < len) {
words.push(
(u8Array[i++] << 24) |
(u8Array[i++] << 16) |
(u8Array[i++] << 8) |
(u8Array[i++])
);
}
return {
sigBytes: len,
words: words
};
}
const toHexString = bytes => bytes.reduce((str, byte) => str + byte.toString(16).padStart(2, '0'), '');
const intToBuffer = num =>
{
let b = new ArrayBuffer(4);
new DataView(b).setUint32(0, num);
return Array.from(new Uint8Array(b));
}
function PEM2Binary(pem)
{
var encoded = '';
var lines = pem.split('\n');
for (var i = 0; i < lines.length; i++) {
if (lines[i].indexOf('-----') < 0) {
encoded += lines[i];
}
}
var byteStr = atob(encoded);
var bytes = new Uint8Array(byteStr.length);
for (var i = 0; i < byteStr.length; i++) {
bytes[i] = byteStr.charCodeAt(i);
}
return bytes.buffer;
}
}());

25
content_script.js Normal file
View File

@ -0,0 +1,25 @@
injectScripts();
var Module=null;
async function injectScripts()
{
await injectScript('lib/pbf.3.0.5.min.js');
await injectScript('lib/cryptojs-aes_0.2.0.min.js');
await injectScript('protobuf-generated/license_protocol.proto.js');
await injectScript('wasm/wasm_gsr.js');
await injectScript('content_key_decryption.js');
await injectScript('eme_interception.js');
}
function injectScript(scriptName)
{
return new Promise(function(resolve, reject)
{
var s = document.createElement('script');
s.src = chrome.extension.getURL(scriptName);
s.onload = function() {
this.parentNode.removeChild(this);
resolve(true);
};
(document.head||document.documentElement).appendChild(s);
});
}

Binary file not shown.

407
eme_interception.js Normal file
View File

@ -0,0 +1,407 @@
/**
* Hooks EME calls and forwards them for analysis and decryption.
*
* Most of the code here was borrowed from https://github.com/google/eme_logger/blob/master/eme_listeners.js
*/
var lastReceivedLicenseRequest = null;
var lastReceivedLicenseResponse = null;
/** Set up the EME listeners. */
function startEMEInterception()
{
var listener = new EmeInterception();
listener.setUpListeners();
}
/**
* Gets called whenever an EME method is getting called or an EME event fires
*/
EmeInterception.onOperation = function(operationType, args)
{
//console.log(operationType);
//console.log(args);
if (operationType == "GenerateRequestCall")
{
// got initData
//console.log(args);
//console.log(args[1]);
}
else if (operationType == "MessageEvent")
{
var licenseRequest = args.message;
lastReceivedLicenseRequest = licenseRequest;
}
else if (operationType == "UpdateCall")
{
var licenseResponse = args[0];
var lmsg=SignedMessage.read(new Pbf(licenseResponse));
//console.log(lmsg)
lastReceivedLicenseResponse = licenseResponse;
// OK, let's try to decrypt it, assuming the response correlates to the request
WidevineCrypto.decryptContentKey(lastReceivedLicenseRequest, lastReceivedLicenseResponse);
}
};
/**
* Manager for EME event and method listeners.
* @constructor
*/
function EmeInterception()
{
this.unprefixedEmeEnabled = Navigator.prototype.requestMediaKeySystemAccess ? true : false;
this.prefixedEmeEnabled = HTMLMediaElement.prototype.webkitGenerateKeyRequest ? true : false;
}
/**
* The number of types of HTML Media Elements to track.
* @const {number}
*/
EmeInterception.NUM_MEDIA_ELEMENT_TYPES = 3;
/**
* Sets up EME listeners for whichever type of EME is enabled.
*/
EmeInterception.prototype.setUpListeners = function()
{
if (!this.unprefixedEmeEnabled && !this.prefixedEmeEnabled) {
// EME is not enabled, just ignore
return;
}
if (this.unprefixedEmeEnabled) {
this.addListenersToNavigator_();
}
if (this.prefixedEmeEnabled) {
// Prefixed EME is enabled
}
this.addListenersToAllEmeElements_();
};
/**
* Adds listeners to the EME methods on the Navigator object.
* @private
*/
EmeInterception.prototype.addListenersToNavigator_ = function()
{
if (navigator.listenersAdded_)
return;
var originalRequestMediaKeySystemAccessFn = EmeInterception.extendEmeMethod(
navigator,
navigator.requestMediaKeySystemAccess,
"RequestMediaKeySystemAccessCall");
navigator.requestMediaKeySystemAccess = function()
{
var options = arguments[1];
// slice "It is recommended that a robustness level be specified" warning
var modifiedArguments = arguments;
var modifiedOptions = EmeInterception.addRobustnessLevelIfNeeded(options);
modifiedArguments[1] = modifiedOptions;
var result = originalRequestMediaKeySystemAccessFn.apply(null, modifiedArguments);
// Attach listeners to returned MediaKeySystemAccess object
return result.then(function(mediaKeySystemAccess)
{
this.addListenersToMediaKeySystemAccess_(mediaKeySystemAccess);
return Promise.resolve(mediaKeySystemAccess);
}.bind(this));
}.bind(this);
navigator.listenersAdded_ = true;
};
/**
* Adds listeners to the EME methods on a MediaKeySystemAccess object.
* @param {MediaKeySystemAccess} mediaKeySystemAccess A MediaKeySystemAccess
* object to add listeners to.
* @private
*/
EmeInterception.prototype.addListenersToMediaKeySystemAccess_ = function(mediaKeySystemAccess)
{
if (mediaKeySystemAccess.listenersAdded_) {
return;
}
mediaKeySystemAccess.originalGetConfiguration = mediaKeySystemAccess.getConfiguration;
mediaKeySystemAccess.getConfiguration = EmeInterception.extendEmeMethod(
mediaKeySystemAccess,
mediaKeySystemAccess.getConfiguration,
"GetConfigurationCall");
var originalCreateMediaKeysFn = EmeInterception.extendEmeMethod(
mediaKeySystemAccess,
mediaKeySystemAccess.createMediaKeys,
"CreateMediaKeysCall");
mediaKeySystemAccess.createMediaKeys = function()
{
var result = originalCreateMediaKeysFn.apply(null, arguments);
// Attach listeners to returned MediaKeys object
return result.then(function(mediaKeys) {
mediaKeys.keySystem_ = mediaKeySystemAccess.keySystem;
this.addListenersToMediaKeys_(mediaKeys);
return Promise.resolve(mediaKeys);
}.bind(this));
}.bind(this);
mediaKeySystemAccess.listenersAdded_ = true;
};
/**
* Adds listeners to the EME methods on a MediaKeys object.
* @param {MediaKeys} mediaKeys A MediaKeys object to add listeners to.
* @private
*/
EmeInterception.prototype.addListenersToMediaKeys_ = function(mediaKeys)
{
if (mediaKeys.listenersAdded_) {
return;
}
var originalCreateSessionFn = EmeInterception.extendEmeMethod(mediaKeys, mediaKeys.createSession, "CreateSessionCall");
mediaKeys.createSession = function()
{
var result = originalCreateSessionFn.apply(null, arguments);
result.keySystem_ = mediaKeys.keySystem_;
// Attach listeners to returned MediaKeySession object
this.addListenersToMediaKeySession_(result);
return result;
}.bind(this);
mediaKeys.setServerCertificate = EmeInterception.extendEmeMethod(mediaKeys, mediaKeys.setServerCertificate, "SetServerCertificateCall");
mediaKeys.listenersAdded_ = true;
};
/** Adds listeners to the EME methods and events on a MediaKeySession object.
* @param {MediaKeySession} session A MediaKeySession object to add
* listeners to.
* @private
*/
EmeInterception.prototype.addListenersToMediaKeySession_ = function(session)
{
if (session.listenersAdded_) {
return;
}
session.generateRequest = EmeInterception.extendEmeMethod(session,session.generateRequest, "GenerateRequestCall");
session.load = EmeInterception.extendEmeMethod(session, session.load, "LoadCall");
session.update = EmeInterception.extendEmeMethod(session,session.update, "UpdateCall");
session.close = EmeInterception.extendEmeMethod(session, session.close, "CloseCall");
session.remove = EmeInterception.extendEmeMethod(session, session.remove, "RemoveCall");
session.addEventListener('message', function(e)
{
e.keySystem = session.keySystem_;
EmeInterception.interceptEvent("MessageEvent", e);
});
session.addEventListener('keystatuseschange', EmeInterception.interceptEvent.bind(null, "KeyStatusesChangeEvent"));
session.listenersAdded_ = true;
};
/**
* Adds listeners to all currently created media elements (audio, video) and sets up a
* mutation-summary observer to add listeners to any newly created media
* elements.
* @private
*/
EmeInterception.prototype.addListenersToAllEmeElements_ = function()
{
this.addEmeInterceptionToInitialMediaElements_();
};
/**
* Adds listeners to the EME elements currently in the document.
* @private
*/
EmeInterception.prototype.addEmeInterceptionToInitialMediaElements_ = function()
{
var audioElements = document.getElementsByTagName('audio');
for (var i = 0; i < audioElements.length; ++i) {
this.addListenersToEmeElement_(audioElements[i], false);
}
var videoElements = document.getElementsByTagName('video');
for (var i = 0; i < videoElements.length; ++i) {
this.addListenersToEmeElement_(videoElements[i], false);
}
var mediaElements = document.getElementsByTagName('media');
for (var i = 0; i < mediaElements.length; ++i) {
this.addListenersToEmeElement_(mediaElements[i], false);
}
};
/**
* Adds method and event listeners to media element.
* @param {HTMLMediaElement} element A HTMLMedia element to add listeners to.
* @private
*/
EmeInterception.prototype.addListenersToEmeElement_ = function(element)
{
this.addEmeEventListeners_(element);
this.addEmeMethodListeners_(element);
console.info('EME listeners successfully added to:', element);
};
/**
* Adds event listeners to a media element.
* @param {HTMLMediaElement} element A HTMLMedia element to add listeners to.
* @private
*/
EmeInterception.prototype.addEmeEventListeners_ = function(element)
{
if (element.eventListenersAdded_) {
return;
}
if (this.prefixedEmeEnabled)
{
element.addEventListener('webkitneedkey', EmeInterception.interceptEvent.bind(null, "NeedKeyEvent"));
element.addEventListener('webkitkeymessage', EmeInterception.interceptEvent.bind(null, "KeyMessageEvent"));
element.addEventListener('webkitkeyadded', EmeInterception.interceptEvent.bind(null, "KeyAddedEvent"));
element.addEventListener('webkitkeyerror', EmeInterception.interceptEvent.bind(null, "KeyErrorEvent"));
}
element.addEventListener('encrypted', EmeInterception.interceptEvent.bind(null, "EncryptedEvent"));
element.addEventListener('play', EmeInterception.interceptEvent.bind(null, "PlayEvent"));
element.addEventListener('error', function(e) {
console.error('Error Event');
EmeInterception.interceptEvent("ErrorEvent", e);
});
element.eventListenersAdded_ = true;
};
/**
* Adds method listeners to a media element.
* @param {HTMLMediaElement} element A HTMLMedia element to add listeners to.
* @private
*/
EmeInterception.prototype.addEmeMethodListeners_ = function(element)
{
if (element.methodListenersAdded_) {
return;
}
element.play = EmeInterception.extendEmeMethod(element, element.play, "PlayCall");
if (this.prefixedEmeEnabled) {
element.canPlayType = EmeInterception.extendEmeMethod(element, element.canPlayType, "CanPlayTypeCall");
element.webkitGenerateKeyRequest = EmeInterception.extendEmeMethod(element, element.webkitGenerateKeyRequest, "GenerateKeyRequestCall");
element.webkitAddKey = EmeInterception.extendEmeMethod(element, element.webkitAddKey, "AddKeyCall");
element.webkitCancelKeyRequest = EmeInterception.extendEmeMethod(element, element.webkitCancelKeyRequest, "CancelKeyRequestCall");
}
if (this.unprefixedEmeEnabled) {
element.setMediaKeys = EmeInterception.extendEmeMethod(element, element.setMediaKeys, "SetMediaKeysCall");
}
element.methodListenersAdded_ = true;
};
/**
* Creates a wrapper function that logs calls to the given method.
* @param {!Object} element An element or object whose function
* call will be logged.
* @param {!Function} originalFn The function to log.
* @param {!Function} type The constructor for a logger class that will
* be instantiated to log the originalFn call.
* @return {!Function} The new version, with logging, of orginalFn.
*/
EmeInterception.extendEmeMethod = function(element, originalFn, type)
{
return function()
{
try
{
var result = originalFn.apply(element, arguments);
var args = [].slice.call(arguments);
EmeInterception.interceptCall(type, args, result, element);
}
catch (e)
{
console.error(e);
}
return result;
};
};
/**
* Intercepts a method call to the console and a separate frame.
* @param {!Function} constructor The constructor for a logger class that will
* be instantiated to log this call.
* @param {Array} args The arguments this call was made with.
* @param {Object} result The result of this method call.
* @param {!Object} target The element this method was called on.
* @return {!eme.EmeMethodCall} The data that has been logged.
*/
EmeInterception.interceptCall = function(type, args, result, target)
{
EmeInterception.onOperation(type, args);
return args;
};
/**
* Intercepts an event to the console and a separate frame.
* @param {!Function} constructor The constructor for a logger class that will
* be instantiated to log this event.
* @param {!Event} event An EME event.
* @return {!eme.EmeEvent} The data that has been logged.
*/
EmeInterception.interceptEvent = function(type, event)
{
EmeInterception.onOperation(type, event);
return event;
};
EmeInterception.addRobustnessLevelIfNeeded = function(options)
{
for (var i = 0; i < options.length; i++)
{
var option = options[i];
var videoCapabilities = option["videoCapabilities"];
var audioCapabilties = option["audioCapabilities"];
if (videoCapabilities != null)
{
for (var j = 0; j < videoCapabilities.length; j++)
if (videoCapabilities[j]["robustness"] == undefined) videoCapabilities[j]["robustness"] = "SW_SECURE_CRYPTO";
}
if (audioCapabilties != null)
{
for (var j = 0; j < audioCapabilties.length; j++)
if (audioCapabilties[j]["robustness"] == undefined) audioCapabilties[j]["robustness"] = "SW_SECURE_CRYPTO";
}
option["videoCapabilities"] = videoCapabilities;
option["audioCapabilities"] = audioCapabilties;
options[i] = option;
}
return options;
}
startEMEInterception();

43
lib/cryptojs-aes_0.2.0.min.js vendored Normal file

File diff suppressed because one or more lines are too long

1
lib/pbf.3.0.5.min.js vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

25142
log_parsing/exponentiation.log Normal file

File diff suppressed because one or more lines are too long

121
log_parsing/prfnd.py Normal file
View File

@ -0,0 +1,121 @@
# use on the appropriate log file produced by ghidra
import sys
fl=sys.argv[1]
def modInverse(a, m):
m0 = m
y = 0
x = 1
if (m == 1):
return 0
while (a > 1):
q = a // m
t = m
m = a % m
a = t
t = y
y = x - q * y
x = t
if (x < 0):
x = x + m0
return x
n=0xBCA83D793F493C49DF558612E74C773198AB4901F20369BFAF1598D71E362EF13AB9BE3B4D4D73C63378542D23BEBA56AD4D589C1E7F151E25CF6F7A38F8FF1FF491D5D2DFC971617B6D9559406E3A5127B2AEBDDEA965E0DFCF4C50AE241CAF9E87BFE33B0DB619B5C395E3986E310A3278F990B4139A421AF74B3E4E1548250DEC8F1755B038E61069E2547983ED93878549B4A9F5FAA1BEF72A75A9929FA7240FB1E46B9587170EF993C29C35F1F145E55BFEC0DE85D2B9409D6599B1C348BF76DD441ABD53033475E3267F91647C2584D974D3AD7B8C0C33711556D6C2CF23BF7905B17A68C622A0580A623C1AF9F446294D5F2DE50721D85EB5F49B7013
rt=0x79bad423a3b14693488f32a3f32ca9cf96dbdfc5b45c7d4bba04af8958f008e3b7468b33f0f868eccc0b5b0fac5c60d131c2491b43dda75af695cfc303086204cb656f24b02024adef05c5e3be2f4918b67f7c75d3b9150b78ba70f4785515bd64e2905517559033e69a4a36501604c371a37137f56d64444b269538b87152169bf581d560bab993e4a6010f39f41fc97396f57eaecef874a469d5159ab5a71f6c9c5e1e4e7e5de2a7436604f47c695572b7b8916116044ba223c95eccaad9c3747dcdc56e966b1978a17282d9911d9bf314f1ef52971d4c4f59c1fcde5c4deeeb8ce02816aa24b79091d81e70c11c3f12dafad70b74eee3aa4a902a2d76b2bc
r=(1<<2048)
ri=modInverse(r,n)
rii=modInverse(ri,n)
accs=["Collected as HasMulAdd ,a : ",
"Collected as SubN ,a : ",
"Collected as Plus ,b : " ,
"Collected as Plum? ,b : ",
"Collected as Plum res ,b : ",
"Collected as Plus ,a : ",
"Collected as YetAnother ,a : ",
"Collected as MbSubtr ,a : ",
"Collected as Upper ,a : ",
"Collected as MbSubtr ,b : ",
"Grabbed "
]
priors=[]
mults={}
pluses={}
minuses={}
sqms={}
sqms2={}
relations={}
def checkPriorRelation(nm):
global priors
if nm in priors: return
rel=False
if nm in mults:
relations[nm]=["mul",mults[nm]]
del mults[nm]
rel=True
if nm in pluses and not rel:
print("Sum")
relations[nm]=["sum",pluses[nm]]
del pluses[nm]
rel=True
if nm in minuses and not rel:
print("Neg")
relations[nm]=["neg",minuses[nm]]
del minuses[nm]
rel=True
if rel is False:
if nm in sqms:
relations[nm]=["sqm",sqms[nm]]
if rel is False:
if nm in sqms2:
print("Squam2")
relations[nm]=["sqm2",sqms2[nm]]
priors.append(nm)
for k in range(len(priors)):
p=priors[k]
mi=(p*nm*ri)%n
sqm=(p*mi*ri)%n
sqm2=(nm*mi*ri)%n
mp=(p+nm)%n
mn=(p-nm+n)%n
mn2=(nm-p+n)%n
if nm<0: mn+=n
if not mi in mults:
mults[mi]=[k,len(priors)-1]
if not mp in pluses:
pluses[mp]=[k,len(priors)-1]
if not mn in minuses:
minuses[mn]=[k,len(priors)-1]
if not mn2 in minuses:
minuses[mn2]=[len(priors)-1,k]
lnm=0
def save():
import json
st=json.dumps({"priors":priors, "relations":relations})
fl=open("exp_values.json","w")
fl.write(st)
fl.close()
cnt=0
prev=None
with open(fl,"r",encoding="utf-8") as fl:
for ln in fl:
for acc in accs:
if acc in ln:
if "Grabbed " in ln:
nm=int(ln.split(":")[1].strip(),16)%n
else:
nm=int(ln[len(acc):],16)%n
lnm=nm
if nm in priors:
print("Prior")
else:
pass
checkPriorRelation(nm)
prev=nm
cnt=cnt+1
if cnt>100:
cnt=0
save()
break
save()

274
log_parsing/prfold.py Normal file
View File

@ -0,0 +1,274 @@
# run this with json file from previous step
import sys
import json
def modInverse(a, m):
m0=m
y=0
x=1
if (m == 1):
return 0
while (a > 1):
q=a // m
t=m
m=a % m
a=t
t=y
y= x - q * y
x= t
if (x < 0):
x= x + m0
return x
fl=sys.argv[1]
with open(fl,"r") as f:
data=json.loads(f.read())
priors=data["priors"]
trees={}
n=0xBCA83D793F493C49DF558612E74C773198AB4901F20369BFAF1598D71E362EF13AB9BE3B4D4D73C63378542D23BEBA56AD4D589C1E7F151E25CF6F7A38F8FF1FF491D5D2DFC971617B6D9559406E3A5127B2AEBDDEA965E0DFCF4C50AE241CAF9E87BFE33B0DB619B5C395E3986E310A3278F990B4139A421AF74B3E4E1548250DEC8F1755B038E61069E2547983ED93878549B4A9F5FAA1BEF72A75A9929FA7240FB1E46B9587170EF993C29C35F1F145E55BFEC0DE85D2B9409D6599B1C348BF76DD441ABD53033475E3267F91647C2584D974D3AD7B8C0C33711556D6C2CF23BF7905B17A68C622A0580A623C1AF9F446294D5F2DE50721D85EB5F49B7013
r=(1<<2048)
ri=modInverse(r,n)
rii=modInverse(ri,n)
endpoint=priors[-1]
stp=pow(endpoint,65537,n)
donotexpand=[0] #,25,61,80,98,216
droot=5
class rootNode(object): #for single root with additions
def __init__(self):
self.snodes=[[droot,1]]
class expNode(object):
def __init__(self):
self.numconst=1
self.subnodes={}
def getVal(self):
vl=self.numconst
for sn in self.subnodes:
if sn>=0:
k=pow(priors[sn],self.subnodes[sn],n)%n
vl=vl*k%n
return vl%n
def asConst(self, cnst):
self.numconst=cnst
self.subnodes={}
return self
def asNode(self, nd):
self.numconst=1
self.subnodes={nd:1}
return self
def asCopy(self,other):
self.numconst=other.numconst
self.subnodes={}
for nd in other.subnodes:
self.subnodes[nd]=other.subnodes[nd]
return self
def canAdd(self,other):
if len(self.subnodes)!=len(other.subnodes): return False
for sn in self.subnodes:
if not sn in other.subnodes: return False
if self.subnodes[sn]!=other.subnodes[sn]: return False
return True
def add(self,other):
ret=expNode()
ret.numconst=(self.numconst+other.numconst)%n
ret.subnodes=self.subnodes.copy()
return ret
def convertToConst(self,num,val):
if not num in self.subnodes: return
pwr=pow(val,self.subnodes[num],n)*pow(ri,self.subnodes[num]-1,n)%n
self.numconst=(self.numconst*pwr)%n
del self.subnodes[num]
def __repr__(self):
return "{}".format(self.subnodes)
def mul(self,other):
ret=expNode()
ret.numconst=self.numconst*other.numconst*ri%n
st=set(self.subnodes.keys())|set(other.subnodes.keys())
for vl in st:
a1=self.subnodes.get(vl,0)
a2=other.subnodes.get(vl,0)
if vl>=0:
ret.subnodes[vl]=a1+a2
else:
if a1+a2<=1:
ret.subnodes[vl]=a1+a2
else:
ret.numconst=0
return ret
def reduceList(lst):
ret=[]
lc=list(lst)
while len(lc)>0:
cr=lc.pop()
rl=[]
for pt in lc:
if cr.canAdd(pt):
cr=cr.add(pt)
else:
rl.append(pt)
lc=rl
if cr.numconst>0:
ret.append(cr)
return ret
def mulList(ls1,ls2):
retl=[]
for a in ls1:
for b in ls2:
retl.append(a.mul(b))
if len(ls1)>0 and len(ls2)>0:
return reduceList(retl)
else:
return retl
class expVariable(object):
def __init__(self,num,nodes,priors,rel):
self.num=num
self.nodes=[]
if rel is None:
self.nodes=[expNode().asConst(priors[num])]
return
if rel=="root":
self.nodes=[expNode().asNode(num)]
return
if rel=="ism":
self.nodes=[expNode().asNode(-1),expNode().asNode(-2)]
return
nd1=nodes[rel[1][0]]
nd2=nodes[rel[1][1]]
if rel[0]=="mul":
self.nodes=mulList(nd1.nodes,nd2.nodes)
elif rel[0]=="sum":
ndlist=[expNode().asCopy(n) for n in nd1.nodes]+[expNode().asCopy(n) for n in nd2.nodes]
self.nodes=reduceList(ndlist)
elif rel[0]=="neg":
cnst=expNode().asConst((n-1)*r%n)
ndlist=[expNode().asCopy(n) for n in nd1.nodes]+[n.mul(cnst) for n in nd2.nodes]
self.nodes=reduceList(ndlist)
def spow(self):
ndlist=[kn.mul(expNode().asConst(r*r%n)) for kn in self.nodes]
ndlist2=mulList(ndlist,ndlist) # ^2
ndlist2=mulList(ndlist2,ndlist2)
ndlist2=mulList(ndlist2,ndlist2)
ndlist2=mulList(ndlist2,ndlist2)
ndlist2=mulList(ndlist2,ndlist2)
ndlist2=mulList(ndlist2,ndlist2)
ndlist2=mulList(ndlist2,ndlist2)
ndlist2=mulList(ndlist2,ndlist2)
ndlist2=mulList(ndlist2,ndlist2)
ndlist2=mulList(ndlist2,ndlist2)
ndlist2=mulList(ndlist2,ndlist2)
ndlist2=mulList(ndlist2,ndlist2)
ndlist2=mulList(ndlist2,ndlist2)
ndlist2=mulList(ndlist2,ndlist2)
ndlist2=mulList(ndlist2,ndlist2)
ndlist2=mulList(ndlist2,ndlist2)
ndlist=mulList(ndlist,ndlist2)
lst=[kn.mul(expNode().asConst(1)) for kn in ndlist]
print(lst)
print("{:x}".format(lst[0].numconst))
print("{:x}".format(lst[1].numconst))
ret=expVariable(-2,nodes,priors,None)
ret.nodes=lst
return ret
for p in priors:
print("{}: {:x}".format(priors.index(p),p))
print("> {:x}".format(p*ri%n))
print("> {:x}".format(modInverse(p*ri%n,n)))
if "relations" in data:
rels={}
for et in data["relations"]:
rels[int(et)]=data["relations"][et]
lst=[priors.index(endpoint)]
awl=set([])
while len(lst)>0:
kp=lst[0]
lst=lst[1:]
if kp in awl: continue
awl.add(kp)
kpp=priors[kp]
if kpp in rels:
for k in rels[kpp][1]:
if not k in awl:
lst.append(k)
nodes={}
disms=[]
for k in range(0,len(priors),1):
ld=expVariable(k,nodes,priors,rels.get(priors[k],None))
if len (ld.nodes)>100 and len(disms)==0:
donotexpand.append(k)
print("Adding as node {}".format(k))
if k in disms:
nd=expVariable(k,nodes,priors,"ism")
nd.nodes.append(expNode().asConst(priors[k]))
#nd=expVariable(k,nodes,priors,None)
elif k in donotexpand:
nd=expVariable(k,nodes,priors,"root")
else:
#print(rels.get(priors[k],None))
nd=expVariable(k,nodes,priors,rels.get(priors[k],None))
nodes[k]=nd
print("{}: {}".format(k,rels.get(priors[k],None)))
print("{}: {} -> {}".format(k,nd.nodes,len(nd.nodes)))
#if k==len(priors)-1:
for nod in nd.nodes:
print("{:x}".format(nod.numconst))
if len(nd.nodes)==1:
print("{:x}".format(nd.nodes[0].getVal()))
if False:#k==len(priors)-1:
ec=pow(12,65537,n)
a=priors[25]
for s in range(29,4385,1):
nd=nodes[s]
if len(nd.nodes)!=2: continue
print(s)
if len(nd.nodes[0].subnodes)==0:
res=nd.nodes[0].numconst
der=nd.nodes[1].numconst
else:
res=nd.nodes[1].numconst
der=nd.nodes[0].numconst
print("Res: {:x}".format(res))
print("Der: {:x}".format(der))
print("Aaa: {:x}".format(a))
dk=der*a*modInverse(res,n)%n
#dk=dk*ri%n
print("Hmm: {:x}".format(dk))
print(pow(ec,dk,n))
print("Ending")
sys.exit()
nd=nodes[len(priors)-1]
print("{:x}".format(nd.nodes[0].numconst))
print("{:x}".format(nd.nodes[1].numconst))
print("{:x}".format(nd.nodes[3].numconst))
dfx2=nd.nodes[3].numconst
rnd=nd.spow()
print("rn {:x}".format(rnd.nodes[0].numconst))
print("rn {:x}".format(rnd.nodes[1].numconst))
dx2=rnd.nodes[3].numconst
kn=3142033101700003260678755863863267700134374886049156296238778043258513471417667391237505300342672722921505586813412391537592394712287451780540489111338082979901966887630936873112829448279475520471433931949082770983040743133849146064289054900225131501940560027662491217132619227565578893295128589581903273904124801461070363532834633728769178636552784294153467969250254358604276515140477045217505629092433114246051368410587618590542410950189868285511930901887132942539241081579465767831350539339965000260768249119651905050152151634478714116343168832447694793716937575319879226685046081583200335708696821445923072794535
print("rx {:x}".format(kn*65537%n))
print("rrn {:x}".format(rnd.nodes[3].numconst))
x=rnd.nodes[0].numconst
fx=nd.nodes[0].numconst
dfa=nd.nodes[1].numconst*modInverse(rnd.nodes[1].numconst,n)%n
print("{:x}".format(dfa))
dfq=dfa*x*modInverse(fx,n)%n
print("{:x}".format(dfq))
print("{:x}".format(pow(x,dfq,n)))
#nd.nodes[0].numconst
#res=nd.nodes[0].numconst*2
#der=nd.nodes[1].numconst*2
#dk=der*pow(res,65537,n)*modInverse(res,n)%n
#kn=3142033101700003260678755863863267700134374886049156296238778043258513471417667391237505300342672722921505586813412391537592394712287451780540489111338082979901966887630936873112829448279475520471433931949082770983040743133849146064289054900225131501940560027662491217132619227565578893295128589581903273904124801461070363532834633728769178636552784294153467969250254358604276515140477045217505629092433114246051368410587618590542410950189868285511930901887132942539241081579465767831350539339965000260768249119651905050152151634478714116343168832447694793716937575319879226685046081583200335708696821445923072794535
#print("kn: {:x}".format(kn))
#print("{:x}".format(dk))
#print("{:x}".format(priors[3]))
#print("{:x}".format(pow(res,65537,n)))
#print(res)
for k in range(len(priors)):
print("{}: {}".format(k,rels.get(priors[k],None)))
sys.exit()

28598
log_parsing/relations.txt Normal file

File diff suppressed because one or more lines are too long

30
manifest.json Normal file
View File

@ -0,0 +1,30 @@
{
"manifest_version": 2,
"name": "Widevine Guesser",
"short_name": "WidevineGuesser",
"description": "Guesses at session key input and logs media keys from websites that use Widevine DRM",
"version": "1.0.0",
"permissions":
[
],
"icons":
{
},
"browser_action": {
},
"content_scripts":
[
{
"matches": ["https://*/*"],
"js": ["content_script.js"],
"css": [],
"run_at": "document_start",
"all_frames": true
}
],
"content_security_policy": "script-src 'self' 'wasm-eval'; object-src 'self'",
"web_accessible_resources": ["content_key_decryption.js", "eme_interception.js", "lib/*", "protobuf-generated/*","wasm/*"]
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
memory_dumps/Peri.gz Normal file

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,890 @@
'use strict'; // code generated by pbf v3.2.1
var LicenseType = self.LicenseType = {
"STREAMING": {
"value": 1,
"options": {}
},
"OFFLINE": {
"value": 2,
"options": {}
}
};
var ProtocolVersion = self.ProtocolVersion = {
"VERSION_2_0": {
"value": 20,
"options": {}
},
"VERSION_2_1": {
"value": 21,
"options": {}
}
};
// LicenseIdentification ========================================
var LicenseIdentification = self.LicenseIdentification = {};
LicenseIdentification.read = function (pbf, end) {
return pbf.readFields(LicenseIdentification._readField, {request_id: null, session_id: null, purchase_id: null, type: 0, version: 0, provider_session_token: null}, end);
};
LicenseIdentification._readField = function (tag, obj, pbf) {
if (tag === 1) obj.request_id = pbf.readBytes();
else if (tag === 2) obj.session_id = pbf.readBytes();
else if (tag === 3) obj.purchase_id = pbf.readBytes();
else if (tag === 4) obj.type = pbf.readVarint();
else if (tag === 5) obj.version = pbf.readVarint(true);
else if (tag === 6) obj.provider_session_token = pbf.readBytes();
};
LicenseIdentification.write = function (obj, pbf) {
if (obj.request_id) pbf.writeBytesField(1, obj.request_id);
if (obj.session_id) pbf.writeBytesField(2, obj.session_id);
if (obj.purchase_id) pbf.writeBytesField(3, obj.purchase_id);
if (obj.type) pbf.writeVarintField(4, obj.type);
if (obj.version) pbf.writeVarintField(5, obj.version);
if (obj.provider_session_token) pbf.writeBytesField(6, obj.provider_session_token);
};
// License ========================================
var License = self.License = {};
License.read = function (pbf, end) {
return pbf.readFields(License._readField, {id: null, policy: null, key: [], license_start_time: 0, remote_attestation_verified: false, provider_client_token: null}, end);
};
License._readField = function (tag, obj, pbf) {
if (tag === 1) obj.id = LicenseIdentification.read(pbf, pbf.readVarint() + pbf.pos);
else if (tag === 2) obj.policy = License.Policy.read(pbf, pbf.readVarint() + pbf.pos);
else if (tag === 3) obj.key.push(License.KeyContainer.read(pbf, pbf.readVarint() + pbf.pos));
else if (tag === 4) obj.license_start_time = pbf.readVarint(true);
else if (tag === 5) obj.remote_attestation_verified = pbf.readBoolean();
else if (tag === 6) obj.provider_client_token = pbf.readBytes();
};
License.write = function (obj, pbf) {
if (obj.id) pbf.writeMessage(1, LicenseIdentification.write, obj.id);
if (obj.policy) pbf.writeMessage(2, License.Policy.write, obj.policy);
if (obj.key) for (var i = 0; i < obj.key.length; i++) pbf.writeMessage(3, License.KeyContainer.write, obj.key[i]);
if (obj.license_start_time) pbf.writeVarintField(4, obj.license_start_time);
if (obj.remote_attestation_verified) pbf.writeBooleanField(5, obj.remote_attestation_verified);
if (obj.provider_client_token) pbf.writeBytesField(6, obj.provider_client_token);
};
// License.Policy ========================================
License.Policy = {};
License.Policy.read = function (pbf, end) {
return pbf.readFields(License.Policy._readField, {can_play: false, can_persist: false, can_renew: false, rental_duration_seconds: 0, playback_duration_seconds: 0, license_duration_seconds: 0, renewal_recovery_duration_seconds: 0, renewal_server_url: "", renewal_delay_seconds: 0, renewal_retry_interval_seconds: 0, renew_with_usage: false, renew_with_client_id: false}, end);
};
License.Policy._readField = function (tag, obj, pbf) {
if (tag === 1) obj.can_play = pbf.readBoolean();
else if (tag === 2) obj.can_persist = pbf.readBoolean();
else if (tag === 3) obj.can_renew = pbf.readBoolean();
else if (tag === 4) obj.rental_duration_seconds = pbf.readVarint(true);
else if (tag === 5) obj.playback_duration_seconds = pbf.readVarint(true);
else if (tag === 6) obj.license_duration_seconds = pbf.readVarint(true);
else if (tag === 7) obj.renewal_recovery_duration_seconds = pbf.readVarint(true);
else if (tag === 8) obj.renewal_server_url = pbf.readString();
else if (tag === 9) obj.renewal_delay_seconds = pbf.readVarint(true);
else if (tag === 10) obj.renewal_retry_interval_seconds = pbf.readVarint(true);
else if (tag === 11) obj.renew_with_usage = pbf.readBoolean();
else if (tag === 12) obj.renew_with_client_id = pbf.readBoolean();
};
License.Policy.write = function (obj, pbf) {
if (obj.can_play) pbf.writeBooleanField(1, obj.can_play);
if (obj.can_persist) pbf.writeBooleanField(2, obj.can_persist);
if (obj.can_renew) pbf.writeBooleanField(3, obj.can_renew);
if (obj.rental_duration_seconds) pbf.writeVarintField(4, obj.rental_duration_seconds);
if (obj.playback_duration_seconds) pbf.writeVarintField(5, obj.playback_duration_seconds);
if (obj.license_duration_seconds) pbf.writeVarintField(6, obj.license_duration_seconds);
if (obj.renewal_recovery_duration_seconds) pbf.writeVarintField(7, obj.renewal_recovery_duration_seconds);
if (obj.renewal_server_url) pbf.writeStringField(8, obj.renewal_server_url);
if (obj.renewal_delay_seconds) pbf.writeVarintField(9, obj.renewal_delay_seconds);
if (obj.renewal_retry_interval_seconds) pbf.writeVarintField(10, obj.renewal_retry_interval_seconds);
if (obj.renew_with_usage) pbf.writeBooleanField(11, obj.renew_with_usage);
if (obj.renew_with_client_id) pbf.writeBooleanField(12, obj.renew_with_client_id);
};
// License.KeyContainer ========================================
License.KeyContainer = {};
License.KeyContainer.read = function (pbf, end) {
return pbf.readFields(License.KeyContainer._readField, {id: null, iv: null, key: null, type: 0, level: {"value":1,"options":{}}, required_protection: null, requested_protection: null, key_control: null, operator_session_key_permissions: null, video_resolution_constraints: [], anti_rollback_usage_table: false}, end);
};
License.KeyContainer._readField = function (tag, obj, pbf) {
if (tag === 1) obj.id = pbf.readBytes();
else if (tag === 2) obj.iv = pbf.readBytes();
else if (tag === 3) obj.key = pbf.readBytes();
else if (tag === 4) obj.type = pbf.readVarint();
else if (tag === 5) obj.level = pbf.readVarint();
else if (tag === 6) obj.required_protection = License.KeyContainer.OutputProtection.read(pbf, pbf.readVarint() + pbf.pos);
else if (tag === 7) obj.requested_protection = License.KeyContainer.OutputProtection.read(pbf, pbf.readVarint() + pbf.pos);
else if (tag === 8) obj.key_control = License.KeyContainer.KeyControl.read(pbf, pbf.readVarint() + pbf.pos);
else if (tag === 9) obj.operator_session_key_permissions = License.KeyContainer.OperatorSessionKeyPermissions.read(pbf, pbf.readVarint() + pbf.pos);
else if (tag === 10) obj.video_resolution_constraints.push(License.KeyContainer.VideoResolutionConstraint.read(pbf, pbf.readVarint() + pbf.pos));
else if (tag === 11) obj.anti_rollback_usage_table = pbf.readBoolean();
};
License.KeyContainer.write = function (obj, pbf) {
if (obj.id) pbf.writeBytesField(1, obj.id);
if (obj.iv) pbf.writeBytesField(2, obj.iv);
if (obj.key) pbf.writeBytesField(3, obj.key);
if (obj.type) pbf.writeVarintField(4, obj.type);
if (obj.level != undefined && obj.level !== {"value":1,"options":{}}) pbf.writeVarintField(5, obj.level);
if (obj.required_protection) pbf.writeMessage(6, License.KeyContainer.OutputProtection.write, obj.required_protection);
if (obj.requested_protection) pbf.writeMessage(7, License.KeyContainer.OutputProtection.write, obj.requested_protection);
if (obj.key_control) pbf.writeMessage(8, License.KeyContainer.KeyControl.write, obj.key_control);
if (obj.operator_session_key_permissions) pbf.writeMessage(9, License.KeyContainer.OperatorSessionKeyPermissions.write, obj.operator_session_key_permissions);
if (obj.video_resolution_constraints) for (var i = 0; i < obj.video_resolution_constraints.length; i++) pbf.writeMessage(10, License.KeyContainer.VideoResolutionConstraint.write, obj.video_resolution_constraints[i]);
if (obj.anti_rollback_usage_table) pbf.writeBooleanField(11, obj.anti_rollback_usage_table);
};
License.KeyContainer.KeyType = {
"SIGNING": {
"value": 1,
"options": {}
},
"CONTENT": {
"value": 2,
"options": {}
},
"KEY_CONTROL": {
"value": 3,
"options": {}
},
"OPERATOR_SESSION": {
"value": 4,
"options": {}
}
};
License.KeyContainer.SecurityLevel = {
"SW_SECURE_CRYPTO": {
"value": 1,
"options": {}
},
"SW_SECURE_DECODE": {
"value": 2,
"options": {}
},
"HW_SECURE_CRYPTO": {
"value": 3,
"options": {}
},
"HW_SECURE_DECODE": {
"value": 4,
"options": {}
},
"HW_SECURE_ALL": {
"value": 5,
"options": {}
}
};
// License.KeyContainer.KeyControl ========================================
License.KeyContainer.KeyControl = {};
License.KeyContainer.KeyControl.read = function (pbf, end) {
return pbf.readFields(License.KeyContainer.KeyControl._readField, {key_control_block: null, iv: null}, end);
};
License.KeyContainer.KeyControl._readField = function (tag, obj, pbf) {
if (tag === 1) obj.key_control_block = pbf.readBytes();
else if (tag === 2) obj.iv = pbf.readBytes();
};
License.KeyContainer.KeyControl.write = function (obj, pbf) {
if (obj.key_control_block) pbf.writeBytesField(1, obj.key_control_block);
if (obj.iv) pbf.writeBytesField(2, obj.iv);
};
// License.KeyContainer.OutputProtection ========================================
License.KeyContainer.OutputProtection = {};
License.KeyContainer.OutputProtection.read = function (pbf, end) {
return pbf.readFields(License.KeyContainer.OutputProtection._readField, {hdcp: {"value":0,"options":{}}, cgms_flags: {"value":42,"options":{}}}, end);
};
License.KeyContainer.OutputProtection._readField = function (tag, obj, pbf) {
if (tag === 1) obj.hdcp = pbf.readVarint();
else if (tag === 2) obj.cgms_flags = pbf.readVarint();
};
License.KeyContainer.OutputProtection.write = function (obj, pbf) {
if (obj.hdcp != undefined && obj.hdcp !== {"value":0,"options":{}}) pbf.writeVarintField(1, obj.hdcp);
if (obj.cgms_flags != undefined && obj.cgms_flags !== {"value":42,"options":{}}) pbf.writeVarintField(2, obj.cgms_flags);
};
License.KeyContainer.OutputProtection.HDCP = {
"HDCP_NONE": {
"value": 0,
"options": {}
},
"HDCP_V1": {
"value": 1,
"options": {}
},
"HDCP_V2": {
"value": 2,
"options": {}
},
"HDCP_V2_1": {
"value": 3,
"options": {}
},
"HDCP_V2_2": {
"value": 4,
"options": {}
},
"HDCP_NO_DIGITAL_OUTPUT": {
"value": 255,
"options": {}
}
};
License.KeyContainer.OutputProtection.CGMS = {
"CGMS_NONE": {
"value": 42,
"options": {}
},
"COPY_FREE": {
"value": 0,
"options": {}
},
"COPY_ONCE": {
"value": 2,
"options": {}
},
"COPY_NEVER": {
"value": 3,
"options": {}
}
};
// License.KeyContainer.VideoResolutionConstraint ========================================
License.KeyContainer.VideoResolutionConstraint = {};
License.KeyContainer.VideoResolutionConstraint.read = function (pbf, end) {
return pbf.readFields(License.KeyContainer.VideoResolutionConstraint._readField, {min_resolution_pixels: 0, max_resolution_pixels: 0, required_protection: null}, end);
};
License.KeyContainer.VideoResolutionConstraint._readField = function (tag, obj, pbf) {
if (tag === 1) obj.min_resolution_pixels = pbf.readVarint();
else if (tag === 2) obj.max_resolution_pixels = pbf.readVarint();
else if (tag === 3) obj.required_protection = License.KeyContainer.OutputProtection.read(pbf, pbf.readVarint() + pbf.pos);
};
License.KeyContainer.VideoResolutionConstraint.write = function (obj, pbf) {
if (obj.min_resolution_pixels) pbf.writeVarintField(1, obj.min_resolution_pixels);
if (obj.max_resolution_pixels) pbf.writeVarintField(2, obj.max_resolution_pixels);
if (obj.required_protection) pbf.writeMessage(3, License.KeyContainer.OutputProtection.write, obj.required_protection);
};
// License.KeyContainer.OperatorSessionKeyPermissions ========================================
License.KeyContainer.OperatorSessionKeyPermissions = {};
License.KeyContainer.OperatorSessionKeyPermissions.read = function (pbf, end) {
return pbf.readFields(License.KeyContainer.OperatorSessionKeyPermissions._readField, {allow_encrypt: false, allow_decrypt: false, allow_sign: false, allow_signature_verify: false}, end);
};
License.KeyContainer.OperatorSessionKeyPermissions._readField = function (tag, obj, pbf) {
if (tag === 1) obj.allow_encrypt = pbf.readBoolean();
else if (tag === 2) obj.allow_decrypt = pbf.readBoolean();
else if (tag === 3) obj.allow_sign = pbf.readBoolean();
else if (tag === 4) obj.allow_signature_verify = pbf.readBoolean();
};
License.KeyContainer.OperatorSessionKeyPermissions.write = function (obj, pbf) {
if (obj.allow_encrypt) pbf.writeBooleanField(1, obj.allow_encrypt);
if (obj.allow_decrypt) pbf.writeBooleanField(2, obj.allow_decrypt);
if (obj.allow_sign) pbf.writeBooleanField(3, obj.allow_sign);
if (obj.allow_signature_verify) pbf.writeBooleanField(4, obj.allow_signature_verify);
};
// LicenseRequest ========================================
var LicenseRequest = self.LicenseRequest = {};
LicenseRequest.read = function (pbf, end) {
return pbf.readFields(LicenseRequest._readField, {client_id: null, content_id: null, type: 0, request_time: 0, key_control_nonce_deprecated: null, protocol_version: {"value":20,"options":{}}, key_control_nonce: 0, encrypted_client_id: null}, end);
};
LicenseRequest._readField = function (tag, obj, pbf) {
if (tag === 1) obj.client_id = ClientIdentification.read(pbf, pbf.readVarint() + pbf.pos);
else if (tag === 2) obj.content_id = LicenseRequest.ContentIdentification.read(pbf, pbf.readVarint() + pbf.pos);
else if (tag === 3) obj.type = pbf.readVarint();
else if (tag === 4) obj.request_time = pbf.readVarint(true);
else if (tag === 5) obj.key_control_nonce_deprecated = pbf.readBytes();
else if (tag === 6) obj.protocol_version = pbf.readVarint();
else if (tag === 7) obj.key_control_nonce = pbf.readVarint();
else if (tag === 8) obj.encrypted_client_id = EncryptedClientIdentification.read(pbf, pbf.readVarint() + pbf.pos);
};
LicenseRequest.write = function (obj, pbf) {
if (obj.client_id) pbf.writeMessage(1, ClientIdentification.write, obj.client_id);
if (obj.content_id) pbf.writeMessage(2, LicenseRequest.ContentIdentification.write, obj.content_id);
if (obj.type) pbf.writeVarintField(3, obj.type);
if (obj.request_time) pbf.writeVarintField(4, obj.request_time);
if (obj.key_control_nonce_deprecated) pbf.writeBytesField(5, obj.key_control_nonce_deprecated);
if (obj.protocol_version != undefined && obj.protocol_version !== {"value":20,"options":{}}) pbf.writeVarintField(6, obj.protocol_version);
if (obj.key_control_nonce) pbf.writeVarintField(7, obj.key_control_nonce);
if (obj.encrypted_client_id) pbf.writeMessage(8, EncryptedClientIdentification.write, obj.encrypted_client_id);
};
LicenseRequest.RequestType = {
"NEW": {
"value": 1,
"options": {}
},
"RENEWAL": {
"value": 2,
"options": {}
},
"RELEASE": {
"value": 3,
"options": {}
}
};
// LicenseRequest.ContentIdentification ========================================
LicenseRequest.ContentIdentification = {};
LicenseRequest.ContentIdentification.read = function (pbf, end) {
return pbf.readFields(LicenseRequest.ContentIdentification._readField, {cenc_id: null, webm_id: null, license: null}, end);
};
LicenseRequest.ContentIdentification._readField = function (tag, obj, pbf) {
if (tag === 1) obj.cenc_id = LicenseRequest.ContentIdentification.CENC.read(pbf, pbf.readVarint() + pbf.pos);
else if (tag === 2) obj.webm_id = LicenseRequest.ContentIdentification.WebM.read(pbf, pbf.readVarint() + pbf.pos);
else if (tag === 3) obj.license = LicenseRequest.ContentIdentification.ExistingLicense.read(pbf, pbf.readVarint() + pbf.pos);
};
LicenseRequest.ContentIdentification.write = function (obj, pbf) {
if (obj.cenc_id) pbf.writeMessage(1, LicenseRequest.ContentIdentification.CENC.write, obj.cenc_id);
if (obj.webm_id) pbf.writeMessage(2, LicenseRequest.ContentIdentification.WebM.write, obj.webm_id);
if (obj.license) pbf.writeMessage(3, LicenseRequest.ContentIdentification.ExistingLicense.write, obj.license);
};
// LicenseRequest.ContentIdentification.CENC ========================================
LicenseRequest.ContentIdentification.CENC = {};
LicenseRequest.ContentIdentification.CENC.read = function (pbf, end) {
return pbf.readFields(LicenseRequest.ContentIdentification.CENC._readField, {pssh: [], license_type: 0, request_id: null}, end);
};
LicenseRequest.ContentIdentification.CENC._readField = function (tag, obj, pbf) {
if (tag === 1) obj.pssh.push(pbf.readBytes());
else if (tag === 2) obj.license_type = pbf.readVarint();
else if (tag === 3) obj.request_id = pbf.readBytes();
};
LicenseRequest.ContentIdentification.CENC.write = function (obj, pbf) {
if (obj.pssh) for (var i = 0; i < obj.pssh.length; i++) pbf.writeBytesField(1, obj.pssh[i]);
if (obj.license_type) pbf.writeVarintField(2, obj.license_type);
if (obj.request_id) pbf.writeBytesField(3, obj.request_id);
};
// LicenseRequest.ContentIdentification.WebM ========================================
LicenseRequest.ContentIdentification.WebM = {};
LicenseRequest.ContentIdentification.WebM.read = function (pbf, end) {
return pbf.readFields(LicenseRequest.ContentIdentification.WebM._readField, {header: null, license_type: 0, request_id: null}, end);
};
LicenseRequest.ContentIdentification.WebM._readField = function (tag, obj, pbf) {
if (tag === 1) obj.header = pbf.readBytes();
else if (tag === 2) obj.license_type = pbf.readVarint();
else if (tag === 3) obj.request_id = pbf.readBytes();
};
LicenseRequest.ContentIdentification.WebM.write = function (obj, pbf) {
if (obj.header) pbf.writeBytesField(1, obj.header);
if (obj.license_type) pbf.writeVarintField(2, obj.license_type);
if (obj.request_id) pbf.writeBytesField(3, obj.request_id);
};
// LicenseRequest.ContentIdentification.ExistingLicense ========================================
LicenseRequest.ContentIdentification.ExistingLicense = {};
LicenseRequest.ContentIdentification.ExistingLicense.read = function (pbf, end) {
return pbf.readFields(LicenseRequest.ContentIdentification.ExistingLicense._readField, {license_id: null, seconds_since_started: 0, seconds_since_last_played: 0, session_usage_table_entry: null}, end);
};
LicenseRequest.ContentIdentification.ExistingLicense._readField = function (tag, obj, pbf) {
if (tag === 1) obj.license_id = LicenseIdentification.read(pbf, pbf.readVarint() + pbf.pos);
else if (tag === 2) obj.seconds_since_started = pbf.readVarint(true);
else if (tag === 3) obj.seconds_since_last_played = pbf.readVarint(true);
else if (tag === 4) obj.session_usage_table_entry = pbf.readBytes();
};
LicenseRequest.ContentIdentification.ExistingLicense.write = function (obj, pbf) {
if (obj.license_id) pbf.writeMessage(1, LicenseIdentification.write, obj.license_id);
if (obj.seconds_since_started) pbf.writeVarintField(2, obj.seconds_since_started);
if (obj.seconds_since_last_played) pbf.writeVarintField(3, obj.seconds_since_last_played);
if (obj.session_usage_table_entry) pbf.writeBytesField(4, obj.session_usage_table_entry);
};
// LicenseError ========================================
var LicenseError = self.LicenseError = {};
LicenseError.read = function (pbf, end) {
return pbf.readFields(LicenseError._readField, {error_code: 0}, end);
};
LicenseError._readField = function (tag, obj, pbf) {
if (tag === 1) obj.error_code = pbf.readVarint();
};
LicenseError.write = function (obj, pbf) {
if (obj.error_code) pbf.writeVarintField(1, obj.error_code);
};
LicenseError.Error = {
"INVALID_DEVICE_CERTIFICATE": {
"value": 1,
"options": {}
},
"REVOKED_DEVICE_CERTIFICATE": {
"value": 2,
"options": {}
},
"SERVICE_UNAVAILABLE": {
"value": 3,
"options": {}
}
};
// RemoteAttestation ========================================
var RemoteAttestation = self.RemoteAttestation = {};
RemoteAttestation.read = function (pbf, end) {
return pbf.readFields(RemoteAttestation._readField, {certificate: null, salt: null, signature: null}, end);
};
RemoteAttestation._readField = function (tag, obj, pbf) {
if (tag === 1) obj.certificate = EncryptedClientIdentification.read(pbf, pbf.readVarint() + pbf.pos);
else if (tag === 2) obj.salt = pbf.readBytes();
else if (tag === 3) obj.signature = pbf.readBytes();
};
RemoteAttestation.write = function (obj, pbf) {
if (obj.certificate) pbf.writeMessage(1, EncryptedClientIdentification.write, obj.certificate);
if (obj.salt) pbf.writeBytesField(2, obj.salt);
if (obj.signature) pbf.writeBytesField(3, obj.signature);
};
// SignedMessage ========================================
var SignedMessage = self.SignedMessage = {};
SignedMessage.read = function (pbf, end) {
return pbf.readFields(SignedMessage._readField, {type: 0, msg: null, signature: null, session_key: null, remote_attestation: null}, end);
};
SignedMessage._readField = function (tag, obj, pbf) {
if (tag === 1) obj.type = pbf.readVarint();
else if (tag === 2) obj.msg = pbf.readBytes();
else if (tag === 3) obj.signature = pbf.readBytes();
else if (tag === 4) obj.session_key = pbf.readBytes();
else if (tag === 5) obj.remote_attestation = RemoteAttestation.read(pbf, pbf.readVarint() + pbf.pos);
};
SignedMessage.write = function (obj, pbf) {
if (obj.type) pbf.writeVarintField(1, obj.type);
if (obj.msg) pbf.writeBytesField(2, obj.msg);
if (obj.signature) pbf.writeBytesField(3, obj.signature);
if (obj.session_key) pbf.writeBytesField(4, obj.session_key);
if (obj.remote_attestation) pbf.writeMessage(5, RemoteAttestation.write, obj.remote_attestation);
};
SignedMessage.MessageType = {
"LICENSE_REQUEST": {
"value": 1,
"options": {}
},
"LICENSE": {
"value": 2,
"options": {}
},
"ERROR_RESPONSE": {
"value": 3,
"options": {}
},
"SERVICE_CERTIFICATE_REQUEST": {
"value": 4,
"options": {}
},
"SERVICE_CERTIFICATE": {
"value": 5,
"options": {}
}
};
// ProvisioningOptions ========================================
var ProvisioningOptions = self.ProvisioningOptions = {};
ProvisioningOptions.read = function (pbf, end) {
return pbf.readFields(ProvisioningOptions._readField, {certificate_type: 0, certificate_authority: ""}, end);
};
ProvisioningOptions._readField = function (tag, obj, pbf) {
if (tag === 1) obj.certificate_type = pbf.readVarint();
else if (tag === 2) obj.certificate_authority = pbf.readString();
};
ProvisioningOptions.write = function (obj, pbf) {
if (obj.certificate_type) pbf.writeVarintField(1, obj.certificate_type);
if (obj.certificate_authority) pbf.writeStringField(2, obj.certificate_authority);
};
ProvisioningOptions.CertificateType = {
"WIDEVINE_DRM": {
"value": 0,
"options": {}
},
"X509": {
"value": 1,
"options": {}
}
};
// ProvisioningRequest ========================================
var ProvisioningRequest = self.ProvisioningRequest = {};
ProvisioningRequest.read = function (pbf, end) {
return pbf.readFields(ProvisioningRequest._readField, {client_id: null, nonce: null, options: null, stable_id: null}, end);
};
ProvisioningRequest._readField = function (tag, obj, pbf) {
if (tag === 1) obj.client_id = ClientIdentification.read(pbf, pbf.readVarint() + pbf.pos);
else if (tag === 2) obj.nonce = pbf.readBytes();
else if (tag === 3) obj.options = ProvisioningOptions.read(pbf, pbf.readVarint() + pbf.pos);
else if (tag === 4) obj.stable_id = pbf.readBytes();
};
ProvisioningRequest.write = function (obj, pbf) {
if (obj.client_id) pbf.writeMessage(1, ClientIdentification.write, obj.client_id);
if (obj.nonce) pbf.writeBytesField(2, obj.nonce);
if (obj.options) pbf.writeMessage(3, ProvisioningOptions.write, obj.options);
if (obj.stable_id) pbf.writeBytesField(4, obj.stable_id);
};
// ProvisioningResponse ========================================
var ProvisioningResponse = self.ProvisioningResponse = {};
ProvisioningResponse.read = function (pbf, end) {
return pbf.readFields(ProvisioningResponse._readField, {device_rsa_key: null, device_rsa_key_iv: null, device_certificate: null, nonce: null}, end);
};
ProvisioningResponse._readField = function (tag, obj, pbf) {
if (tag === 1) obj.device_rsa_key = pbf.readBytes();
else if (tag === 2) obj.device_rsa_key_iv = pbf.readBytes();
else if (tag === 3) obj.device_certificate = pbf.readBytes();
else if (tag === 4) obj.nonce = pbf.readBytes();
};
ProvisioningResponse.write = function (obj, pbf) {
if (obj.device_rsa_key) pbf.writeBytesField(1, obj.device_rsa_key);
if (obj.device_rsa_key_iv) pbf.writeBytesField(2, obj.device_rsa_key_iv);
if (obj.device_certificate) pbf.writeBytesField(3, obj.device_certificate);
if (obj.nonce) pbf.writeBytesField(4, obj.nonce);
};
// SignedProvisioningMessage ========================================
var SignedProvisioningMessage = self.SignedProvisioningMessage = {};
SignedProvisioningMessage.read = function (pbf, end) {
return pbf.readFields(SignedProvisioningMessage._readField, {message: null, signature: null}, end);
};
SignedProvisioningMessage._readField = function (tag, obj, pbf) {
if (tag === 1) obj.message = pbf.readBytes();
else if (tag === 2) obj.signature = pbf.readBytes();
};
SignedProvisioningMessage.write = function (obj, pbf) {
if (obj.message) pbf.writeBytesField(1, obj.message);
if (obj.signature) pbf.writeBytesField(2, obj.signature);
};
// ClientIdentification ========================================
var ClientIdentification = self.ClientIdentification = {};
ClientIdentification.read = function (pbf, end) {
return pbf.readFields(ClientIdentification._readField, {type: {"value":0,"options":{}}, token: null, client_info: [], provider_client_token: null, license_counter: 0, client_capabilities: null}, end);
};
ClientIdentification._readField = function (tag, obj, pbf) {
if (tag === 1) obj.type = pbf.readVarint();
else if (tag === 2) obj.token = pbf.readBytes();
else if (tag === 3) obj.client_info.push(ClientIdentification.NameValue.read(pbf, pbf.readVarint() + pbf.pos));
else if (tag === 4) obj.provider_client_token = pbf.readBytes();
else if (tag === 5) obj.license_counter = pbf.readVarint();
else if (tag === 6) obj.client_capabilities = ClientIdentification.ClientCapabilities.read(pbf, pbf.readVarint() + pbf.pos);
};
ClientIdentification.write = function (obj, pbf) {
if (obj.type != undefined && obj.type !== {"value":0,"options":{}}) pbf.writeVarintField(1, obj.type);
if (obj.token) pbf.writeBytesField(2, obj.token);
if (obj.client_info) for (var i = 0; i < obj.client_info.length; i++) pbf.writeMessage(3, ClientIdentification.NameValue.write, obj.client_info[i]);
if (obj.provider_client_token) pbf.writeBytesField(4, obj.provider_client_token);
if (obj.license_counter) pbf.writeVarintField(5, obj.license_counter);
if (obj.client_capabilities) pbf.writeMessage(6, ClientIdentification.ClientCapabilities.write, obj.client_capabilities);
};
ClientIdentification.TokenType = {
"KEYBOX": {
"value": 0,
"options": {}
},
"DEVICE_CERTIFICATE": {
"value": 1,
"options": {}
},
"REMOTE_ATTESTATION_CERTIFICATE": {
"value": 2,
"options": {}
}
};
// ClientIdentification.NameValue ========================================
ClientIdentification.NameValue = {};
ClientIdentification.NameValue.read = function (pbf, end) {
return pbf.readFields(ClientIdentification.NameValue._readField, {name: "", value: ""}, end);
};
ClientIdentification.NameValue._readField = function (tag, obj, pbf) {
if (tag === 1) obj.name = pbf.readString();
else if (tag === 2) obj.value = pbf.readString();
};
ClientIdentification.NameValue.write = function (obj, pbf) {
if (obj.name) pbf.writeStringField(1, obj.name);
if (obj.value) pbf.writeStringField(2, obj.value);
};
// ClientIdentification.ClientCapabilities ========================================
ClientIdentification.ClientCapabilities = {};
ClientIdentification.ClientCapabilities.read = function (pbf, end) {
return pbf.readFields(ClientIdentification.ClientCapabilities._readField, {client_token: false, session_token: false, video_resolution_constraints: false, max_hdcp_version: {"value":0,"options":{}}, oem_crypto_api_version: 0, anti_rollback_usage_table: false}, end);
};
ClientIdentification.ClientCapabilities._readField = function (tag, obj, pbf) {
if (tag === 1) obj.client_token = pbf.readBoolean();
else if (tag === 2) obj.session_token = pbf.readBoolean();
else if (tag === 3) obj.video_resolution_constraints = pbf.readBoolean();
else if (tag === 4) obj.max_hdcp_version = pbf.readVarint();
else if (tag === 5) obj.oem_crypto_api_version = pbf.readVarint();
else if (tag === 6) obj.anti_rollback_usage_table = pbf.readBoolean();
};
ClientIdentification.ClientCapabilities.write = function (obj, pbf) {
if (obj.client_token) pbf.writeBooleanField(1, obj.client_token);
if (obj.session_token) pbf.writeBooleanField(2, obj.session_token);
if (obj.video_resolution_constraints) pbf.writeBooleanField(3, obj.video_resolution_constraints);
if (obj.max_hdcp_version != undefined && obj.max_hdcp_version !== {"value":0,"options":{}}) pbf.writeVarintField(4, obj.max_hdcp_version);
if (obj.oem_crypto_api_version) pbf.writeVarintField(5, obj.oem_crypto_api_version);
if (obj.anti_rollback_usage_table) pbf.writeBooleanField(6, obj.anti_rollback_usage_table);
};
ClientIdentification.ClientCapabilities.HdcpVersion = {
"HDCP_NONE": {
"value": 0,
"options": {}
},
"HDCP_V1": {
"value": 1,
"options": {}
},
"HDCP_V2": {
"value": 2,
"options": {}
},
"HDCP_V2_1": {
"value": 3,
"options": {}
},
"HDCP_V2_2": {
"value": 4,
"options": {}
},
"HDCP_NO_DIGITAL_OUTPUT": {
"value": 255,
"options": {}
}
};
// EncryptedClientIdentification ========================================
var EncryptedClientIdentification = self.EncryptedClientIdentification = {};
EncryptedClientIdentification.read = function (pbf, end) {
return pbf.readFields(EncryptedClientIdentification._readField, {service_id: "", service_certificate_serial_number: null, encrypted_client_id: null, encrypted_client_id_iv: null, encrypted_privacy_key: null}, end);
};
EncryptedClientIdentification._readField = function (tag, obj, pbf) {
if (tag === 1) obj.service_id = pbf.readString();
else if (tag === 2) obj.service_certificate_serial_number = pbf.readBytes();
else if (tag === 3) obj.encrypted_client_id = pbf.readBytes();
else if (tag === 4) obj.encrypted_client_id_iv = pbf.readBytes();
else if (tag === 5) obj.encrypted_privacy_key = pbf.readBytes();
};
EncryptedClientIdentification.write = function (obj, pbf) {
if (obj.service_id) pbf.writeStringField(1, obj.service_id);
if (obj.service_certificate_serial_number) pbf.writeBytesField(2, obj.service_certificate_serial_number);
if (obj.encrypted_client_id) pbf.writeBytesField(3, obj.encrypted_client_id);
if (obj.encrypted_client_id_iv) pbf.writeBytesField(4, obj.encrypted_client_id_iv);
if (obj.encrypted_privacy_key) pbf.writeBytesField(5, obj.encrypted_privacy_key);
};
// DeviceCertificate ========================================
var DeviceCertificate = self.DeviceCertificate = {};
DeviceCertificate.read = function (pbf, end) {
return pbf.readFields(DeviceCertificate._readField, {type: 0, serial_number: null, creation_time_seconds: 0, public_key: null, system_id: 0, test_device_deprecated: false, service_id: ""}, end);
};
DeviceCertificate._readField = function (tag, obj, pbf) {
if (tag === 1) obj.type = pbf.readVarint();
else if (tag === 2) obj.serial_number = pbf.readBytes();
else if (tag === 3) obj.creation_time_seconds = pbf.readVarint();
else if (tag === 4) obj.public_key = pbf.readBytes();
else if (tag === 5) obj.system_id = pbf.readVarint();
else if (tag === 6) obj.test_device_deprecated = pbf.readBoolean();
else if (tag === 7) obj.service_id = pbf.readString();
};
DeviceCertificate.write = function (obj, pbf) {
if (obj.type) pbf.writeVarintField(1, obj.type);
if (obj.serial_number) pbf.writeBytesField(2, obj.serial_number);
if (obj.creation_time_seconds) pbf.writeVarintField(3, obj.creation_time_seconds);
if (obj.public_key) pbf.writeBytesField(4, obj.public_key);
if (obj.system_id) pbf.writeVarintField(5, obj.system_id);
if (obj.test_device_deprecated) pbf.writeBooleanField(6, obj.test_device_deprecated);
if (obj.service_id) pbf.writeStringField(7, obj.service_id);
};
DeviceCertificate.CertificateType = {
"ROOT": {
"value": 0,
"options": {}
},
"INTERMEDIATE": {
"value": 1,
"options": {}
},
"USER_DEVICE": {
"value": 2,
"options": {}
},
"SERVICE": {
"value": 3,
"options": {}
}
};
// SignedDeviceCertificate ========================================
var SignedDeviceCertificate = self.SignedDeviceCertificate = {};
SignedDeviceCertificate.read = function (pbf, end) {
return pbf.readFields(SignedDeviceCertificate._readField, {device_certificate: null, signature: null, signer: null}, end);
};
SignedDeviceCertificate._readField = function (tag, obj, pbf) {
if (tag === 1) obj.device_certificate = pbf.readBytes();
else if (tag === 2) obj.signature = pbf.readBytes();
else if (tag === 3) obj.signer = SignedDeviceCertificate.read(pbf, pbf.readVarint() + pbf.pos);
};
SignedDeviceCertificate.write = function (obj, pbf) {
if (obj.device_certificate) pbf.writeBytesField(1, obj.device_certificate);
if (obj.signature) pbf.writeBytesField(2, obj.signature);
if (obj.signer) pbf.writeMessage(3, SignedDeviceCertificate.write, obj.signer);
};
// ProvisionedDeviceInfo ========================================
var ProvisionedDeviceInfo = self.ProvisionedDeviceInfo = {};
ProvisionedDeviceInfo.read = function (pbf, end) {
return pbf.readFields(ProvisionedDeviceInfo._readField, {system_id: 0, soc: "", manufacturer: "", model: "", device_type: "", model_year: 0, security_level: {"value":0,"options":{}}, test_device: false}, end);
};
ProvisionedDeviceInfo._readField = function (tag, obj, pbf) {
if (tag === 1) obj.system_id = pbf.readVarint();
else if (tag === 2) obj.soc = pbf.readString();
else if (tag === 3) obj.manufacturer = pbf.readString();
else if (tag === 4) obj.model = pbf.readString();
else if (tag === 5) obj.device_type = pbf.readString();
else if (tag === 6) obj.model_year = pbf.readVarint();
else if (tag === 7) obj.security_level = pbf.readVarint();
else if (tag === 8) obj.test_device = pbf.readBoolean();
};
ProvisionedDeviceInfo.write = function (obj, pbf) {
if (obj.system_id) pbf.writeVarintField(1, obj.system_id);
if (obj.soc) pbf.writeStringField(2, obj.soc);
if (obj.manufacturer) pbf.writeStringField(3, obj.manufacturer);
if (obj.model) pbf.writeStringField(4, obj.model);
if (obj.device_type) pbf.writeStringField(5, obj.device_type);
if (obj.model_year) pbf.writeVarintField(6, obj.model_year);
if (obj.security_level != undefined && obj.security_level !== {"value":0,"options":{}}) pbf.writeVarintField(7, obj.security_level);
if (obj.test_device) pbf.writeBooleanField(8, obj.test_device);
};
ProvisionedDeviceInfo.WvSecurityLevel = {
"LEVEL_UNSPECIFIED": {
"value": 0,
"options": {}
},
"LEVEL_1": {
"value": 1,
"options": {}
},
"LEVEL_2": {
"value": 2,
"options": {}
},
"LEVEL_3": {
"value": 3,
"options": {}
}
};
// DeviceCertificateStatus ========================================
var DeviceCertificateStatus = self.DeviceCertificateStatus = {};
DeviceCertificateStatus.read = function (pbf, end) {
return pbf.readFields(DeviceCertificateStatus._readField, {serial_number: null, status: {"value":0,"options":{}}, device_info: null}, end);
};
DeviceCertificateStatus._readField = function (tag, obj, pbf) {
if (tag === 1) obj.serial_number = pbf.readBytes();
else if (tag === 2) obj.status = pbf.readVarint();
else if (tag === 4) obj.device_info = ProvisionedDeviceInfo.read(pbf, pbf.readVarint() + pbf.pos);
};
DeviceCertificateStatus.write = function (obj, pbf) {
if (obj.serial_number) pbf.writeBytesField(1, obj.serial_number);
if (obj.status != undefined && obj.status !== {"value":0,"options":{}}) pbf.writeVarintField(2, obj.status);
if (obj.device_info) pbf.writeMessage(4, ProvisionedDeviceInfo.write, obj.device_info);
};
DeviceCertificateStatus.CertificateStatus = {
"VALID": {
"value": 0,
"options": {}
},
"REVOKED": {
"value": 1,
"options": {}
}
};
// DeviceCertificateStatusList ========================================
var DeviceCertificateStatusList = self.DeviceCertificateStatusList = {};
DeviceCertificateStatusList.read = function (pbf, end) {
return pbf.readFields(DeviceCertificateStatusList._readField, {creation_time_seconds: 0, certificate_status: []}, end);
};
DeviceCertificateStatusList._readField = function (tag, obj, pbf) {
if (tag === 1) obj.creation_time_seconds = pbf.readVarint();
else if (tag === 2) obj.certificate_status.push(DeviceCertificateStatus.read(pbf, pbf.readVarint() + pbf.pos));
};
DeviceCertificateStatusList.write = function (obj, pbf) {
if (obj.creation_time_seconds) pbf.writeVarintField(1, obj.creation_time_seconds);
if (obj.certificate_status) for (var i = 0; i < obj.certificate_status.length; i++) pbf.writeMessage(2, DeviceCertificateStatus.write, obj.certificate_status[i]);
};
// SignedCertificateStatusList ========================================
var SignedCertificateStatusList = self.SignedCertificateStatusList = {};
SignedCertificateStatusList.read = function (pbf, end) {
return pbf.readFields(SignedCertificateStatusList._readField, {certificate_status_list: null, signature: null}, end);
};
SignedCertificateStatusList._readField = function (tag, obj, pbf) {
if (tag === 1) obj.certificate_status_list = pbf.readBytes();
else if (tag === 2) obj.signature = pbf.readBytes();
};
SignedCertificateStatusList.write = function (obj, pbf) {
if (obj.certificate_status_list) pbf.writeBytesField(1, obj.certificate_status_list);
if (obj.signature) pbf.writeBytesField(2, obj.signature);
};

21
wasm/wasm_gsr.js Normal file

File diff suppressed because one or more lines are too long

BIN
wasm/wasm_gsr.wasm Normal file

Binary file not shown.

345
wasm_src/algebra.cpp Normal file
View File

@ -0,0 +1,345 @@
// algebra.cpp - originally written and placed in the public domain by Wei Dai
#include "pch.h"
#ifndef CRYPTOPP_ALGEBRA_CPP // SunCC workaround: compiler could cause this file to be included twice
#define CRYPTOPP_ALGEBRA_CPP
#include "algebra.h"
#include "integer.h"
#include <vector>
NAMESPACE_BEGIN(CryptoPP)
template <class T> const T& AbstractGroup<T>::Double(const Element &a) const
{
return this->Add(a, a);
}
template <class T> const T& AbstractGroup<T>::Subtract(const Element &a, const Element &b) const
{
// make copy of a in case Inverse() overwrites it
Element a1(a);
return this->Add(a1, Inverse(b));
}
template <class T> T& AbstractGroup<T>::Accumulate(Element &a, const Element &b) const
{
return a = this->Add(a, b);
}
template <class T> T& AbstractGroup<T>::Reduce(Element &a, const Element &b) const
{
return a = this->Subtract(a, b);
}
template <class T> const T& AbstractRing<T>::Square(const Element &a) const
{
return this->Multiply(a, a);
}
template <class T> const T& AbstractRing<T>::Divide(const Element &a, const Element &b) const
{
// make copy of a in case MultiplicativeInverse() overwrites it
Element a1(a);
return this->Multiply(a1, this->MultiplicativeInverse(b));
}
template <class T> const T& AbstractEuclideanDomain<T>::Mod(const Element &a, const Element &b) const
{
Element q;
this->DivisionAlgorithm(result, q, a, b);
return result;
}
template <class T> const T& AbstractEuclideanDomain<T>::Gcd(const Element &a, const Element &b) const
{
Element g[3]={b, a};
unsigned int i0=0, i1=1, i2=2;
while (!this->Equal(g[i1], this->Identity()))
{
g[i2] = this->Mod(g[i0], g[i1]);
unsigned int t = i0; i0 = i1; i1 = i2; i2 = t;
}
return result = g[i0];
}
template <class T> const typename QuotientRing<T>::Element& QuotientRing<T>::MultiplicativeInverse(const Element &a) const
{
Element g[3]={m_modulus, a};
Element v[3]={m_domain.Identity(), m_domain.MultiplicativeIdentity()};
Element y;
unsigned int i0=0, i1=1, i2=2;
while (!this->Equal(g[i1], this->Identity()))
{
// y = g[i0] / g[i1];
// g[i2] = g[i0] % g[i1];
m_domain.DivisionAlgorithm(g[i2], y, g[i0], g[i1]);
// v[i2] = v[i0] - (v[i1] * y);
v[i2] = m_domain.Subtract(v[i0], m_domain.Multiply(v[i1], y));
unsigned int t = i0; i0 = i1; i1 = i2; i2 = t;
}
return m_domain.IsUnit(g[i0]) ? m_domain.Divide(v[i0], g[i0]) : m_domain.Identity();
}
template <class T> T AbstractGroup<T>::ScalarMultiply(const Element &base, const Integer &exponent) const
{
Element result;
this->SimultaneousMultiply(&result, base, &exponent, 1);
return result;
}
template <class T> T AbstractGroup<T>::CascadeScalarMultiply(const Element &x, const Integer &e1, const Element &y, const Integer &e2) const
{
const unsigned expLen = STDMAX(e1.BitCount(), e2.BitCount());
if (expLen==0)
return this->Identity();
const unsigned w = (expLen <= 46 ? 1 : (expLen <= 260 ? 2 : 3));
const unsigned tableSize = 1<<w;
std::vector<Element> powerTable(tableSize << w);
powerTable[1] = x;
powerTable[tableSize] = y;
if (w==1)
powerTable[3] = this->Add(x,y);
else
{
powerTable[2] = this->Double(x);
powerTable[2*tableSize] = this->Double(y);
unsigned i, j;
for (i=3; i<tableSize; i+=2)
powerTable[i] = Add(powerTable[i-2], powerTable[2]);
for (i=1; i<tableSize; i+=2)
for (j=i+tableSize; j<(tableSize<<w); j+=tableSize)
powerTable[j] = Add(powerTable[j-tableSize], y);
for (i=3*tableSize; i<(tableSize<<w); i+=2*tableSize)
powerTable[i] = Add(powerTable[i-2*tableSize], powerTable[2*tableSize]);
for (i=tableSize; i<(tableSize<<w); i+=2*tableSize)
for (j=i+2; j<i+tableSize; j+=2)
powerTable[j] = Add(powerTable[j-1], x);
}
Element result;
unsigned power1 = 0, power2 = 0, prevPosition = expLen-1;
bool firstTime = true;
for (int i = expLen-1; i>=0; i--)
{
power1 = 2*power1 + e1.GetBit(i);
power2 = 2*power2 + e2.GetBit(i);
if (i==0 || 2*power1 >= tableSize || 2*power2 >= tableSize)
{
unsigned squaresBefore = prevPosition-i;
unsigned squaresAfter = 0;
prevPosition = i;
while ((power1 || power2) && power1%2 == 0 && power2%2==0)
{
power1 /= 2;
power2 /= 2;
squaresBefore--;
squaresAfter++;
}
if (firstTime)
{
result = powerTable[(power2<<w) + power1];
firstTime = false;
}
else
{
while (squaresBefore--)
result = this->Double(result);
if (power1 || power2)
Accumulate(result, powerTable[(power2<<w) + power1]);
}
while (squaresAfter--)
result = this->Double(result);
power1 = power2 = 0;
}
}
return result;
}
template <class Element, class Iterator> Element GeneralCascadeMultiplication(const AbstractGroup<Element> &group, Iterator begin, Iterator end)
{
if (end-begin == 1)
return group.ScalarMultiply(begin->base, begin->exponent);
else if (end-begin == 2)
return group.CascadeScalarMultiply(begin->base, begin->exponent, (begin+1)->base, (begin+1)->exponent);
else
{
Integer q, t;
Iterator last = end;
--last;
std::make_heap(begin, end);
std::pop_heap(begin, end);
while (!!begin->exponent)
{
// last->exponent is largest exponent, begin->exponent is next largest
t = last->exponent;
Integer::Divide(last->exponent, q, t, begin->exponent);
if (q == Integer::One())
group.Accumulate(begin->base, last->base); // avoid overhead of ScalarMultiply()
else
group.Accumulate(begin->base, group.ScalarMultiply(last->base, q));
std::push_heap(begin, end);
std::pop_heap(begin, end);
}
return group.ScalarMultiply(last->base, last->exponent);
}
}
struct WindowSlider
{
WindowSlider(const Integer &expIn, bool fastNegate, unsigned int windowSizeIn=0)
: exp(expIn), windowModulus(Integer::One()), windowSize(windowSizeIn), windowBegin(0), expWindow(0)
, fastNegate(fastNegate), negateNext(false), firstTime(true), finished(false)
{
if (windowSize == 0)
{
unsigned int expLen = exp.BitCount();
windowSize = expLen <= 17 ? 1 : (expLen <= 24 ? 2 : (expLen <= 70 ? 3 : (expLen <= 197 ? 4 : (expLen <= 539 ? 5 : (expLen <= 1434 ? 6 : 7)))));
}
windowModulus <<= windowSize;
}
void FindNextWindow()
{
unsigned int expLen = exp.WordCount() * WORD_BITS;
unsigned int skipCount = firstTime ? 0 : windowSize;
firstTime = false;
while (!exp.GetBit(skipCount))
{
if (skipCount >= expLen)
{
finished = true;
return;
}
skipCount++;
}
exp >>= skipCount;
windowBegin += skipCount;
expWindow = word32(exp % (word(1) << windowSize));
if (fastNegate && exp.GetBit(windowSize))
{
negateNext = true;
expWindow = (word32(1) << windowSize) - expWindow;
exp += windowModulus;
}
else
negateNext = false;
}
Integer exp, windowModulus;
unsigned int windowSize, windowBegin;
word32 expWindow;
bool fastNegate, negateNext, firstTime, finished;
};
template <class T>
void AbstractGroup<T>::SimultaneousMultiply(T *results, const T &base, const Integer *expBegin, unsigned int expCount) const
{
std::vector<std::vector<Element> > buckets(expCount);
std::vector<WindowSlider> exponents;
exponents.reserve(expCount);
unsigned int i;
for (i=0; expBegin && i<expCount; i++)
{
CRYPTOPP_ASSERT(expBegin->NotNegative());
exponents.push_back(WindowSlider(*expBegin++, InversionIsFast(), 0));
exponents[i].FindNextWindow();
buckets[i].resize(((size_t) 1) << (exponents[i].windowSize-1), Identity());
}
unsigned int expBitPosition = 0;
Element g = base;
bool notDone = true;
while (notDone)
{
notDone = false;
for (i=0; i<expCount; i++)
{
if (!exponents[i].finished && expBitPosition == exponents[i].windowBegin)
{
Element &bucket = buckets[i][exponents[i].expWindow/2];
if (exponents[i].negateNext)
Accumulate(bucket, Inverse(g));
else
Accumulate(bucket, g);
exponents[i].FindNextWindow();
}
notDone = notDone || !exponents[i].finished;
}
if (notDone)
{
g = Double(g);
expBitPosition++;
}
}
for (i=0; i<expCount; i++)
{
Element &r = *results++;
r = buckets[i][buckets[i].size()-1];
if (buckets[i].size() > 1)
{
for (int j = (int)buckets[i].size()-2; j >= 1; j--)
{
Accumulate(buckets[i][j], buckets[i][j+1]);
Accumulate(r, buckets[i][j]);
}
Accumulate(buckets[i][0], buckets[i][1]);
r = Add(Double(r), buckets[i][0]);
}
}
}
template <class T> T AbstractRing<T>::Exponentiate(const Element &base, const Integer &exponent) const
{
Element result;
SimultaneousExponentiate(&result, base, &exponent, 1);
return result;
}
template <class T> T AbstractRing<T>::CascadeExponentiate(const Element &x, const Integer &e1, const Element &y, const Integer &e2) const
{
return MultiplicativeGroup().AbstractGroup<T>::CascadeScalarMultiply(x, e1, y, e2);
}
template <class Element, class Iterator> Element GeneralCascadeExponentiation(const AbstractRing<Element> &ring, Iterator begin, Iterator end)
{
return GeneralCascadeMultiplication<Element>(ring.MultiplicativeGroup(), begin, end);
}
template <class T>
void AbstractRing<T>::SimultaneousExponentiate(T *results, const T &base, const Integer *exponents, unsigned int expCount) const
{
MultiplicativeGroup().AbstractGroup<T>::SimultaneousMultiply(results, base, exponents, expCount);
}
template class AbstractGroup<Integer>;
template class AbstractRing<Integer>;
template class AbstractEuclideanDomain<Integer>;
NAMESPACE_END
#endif

453
wasm_src/algebra.h Normal file
View File

@ -0,0 +1,453 @@
// algebra.h - originally written and placed in the public domain by Wei Dai
/// \file algebra.h
/// \brief Classes for performing mathematics over different fields
#ifndef CRYPTOPP_ALGEBRA_H
#define CRYPTOPP_ALGEBRA_H
#include "config.h"
#include "integer.h"
#include "misc.h"
NAMESPACE_BEGIN(CryptoPP)
class Integer;
/// \brief Abstract group
/// \tparam T element class or type
/// \details <tt>const Element&</tt> returned by member functions are references
/// to internal data members. Since each object may have only
/// one such data member for holding results, the following code
/// will produce incorrect results:
/// <pre> abcd = group.Add(group.Add(a,b), group.Add(c,d));</pre>
/// But this should be fine:
/// <pre> abcd = group.Add(a, group.Add(b, group.Add(c,d));</pre>
template <class T> class CRYPTOPP_NO_VTABLE AbstractGroup
{
public:
typedef T Element;
virtual ~AbstractGroup() {}
/// \brief Compare two elements for equality
/// \param a first element
/// \param b second element
/// \return true if the elements are equal, false otherwise
/// \details Equal() tests the elements for equality using <tt>a==b</tt>
virtual bool Equal(const Element &a, const Element &b) const =0;
/// \brief Provides the Identity element
/// \return the Identity element
virtual const Element& Identity() const =0;
/// \brief Adds elements in the group
/// \param a first element
/// \param b second element
/// \return the sum of <tt>a</tt> and <tt>b</tt>
virtual const Element& Add(const Element &a, const Element &b) const =0;
/// \brief Inverts the element in the group
/// \param a first element
/// \return the inverse of the element
virtual const Element& Inverse(const Element &a) const =0;
/// \brief Determine if inversion is fast
/// \return true if inversion is fast, false otherwise
virtual bool InversionIsFast() const {return false;}
/// \brief Doubles an element in the group
/// \param a the element
/// \return the element doubled
virtual const Element& Double(const Element &a) const;
/// \brief Subtracts elements in the group
/// \param a first element
/// \param b second element
/// \return the difference of <tt>a</tt> and <tt>b</tt>. The element <tt>a</tt> must provide a Subtract member function.
virtual const Element& Subtract(const Element &a, const Element &b) const;
/// \brief TODO
/// \param a first element
/// \param b second element
/// \return TODO
virtual Element& Accumulate(Element &a, const Element &b) const;
/// \brief Reduces an element in the congruence class
/// \param a element to reduce
/// \param b the congruence class
/// \return the reduced element
virtual Element& Reduce(Element &a, const Element &b) const;
/// \brief Performs a scalar multiplication
/// \param a multiplicand
/// \param e multiplier
/// \return the product
virtual Element ScalarMultiply(const Element &a, const Integer &e) const;
/// \brief TODO
/// \param x first multiplicand
/// \param e1 the first multiplier
/// \param y second multiplicand
/// \param e2 the second multiplier
/// \return TODO
virtual Element CascadeScalarMultiply(const Element &x, const Integer &e1, const Element &y, const Integer &e2) const;
/// \brief Multiplies a base to multiple exponents in a group
/// \param results an array of Elements
/// \param base the base to raise to the exponents
/// \param exponents an array of exponents
/// \param exponentsCount the number of exponents in the array
/// \details SimultaneousMultiply() multiplies the base to each exponent in the exponents array and stores the
/// result at the respective position in the results array.
/// \details SimultaneousMultiply() must be implemented in a derived class.
/// \pre <tt>COUNTOF(results) == exponentsCount</tt>
/// \pre <tt>COUNTOF(exponents) == exponentsCount</tt>
virtual void SimultaneousMultiply(Element *results, const Element &base, const Integer *exponents, unsigned int exponentsCount) const;
};
/// \brief Abstract ring
/// \tparam T element class or type
/// \details <tt>const Element&</tt> returned by member functions are references
/// to internal data members. Since each object may have only
/// one such data member for holding results, the following code
/// will produce incorrect results:
/// <pre> abcd = group.Add(group.Add(a,b), group.Add(c,d));</pre>
/// But this should be fine:
/// <pre> abcd = group.Add(a, group.Add(b, group.Add(c,d));</pre>
template <class T> class CRYPTOPP_NO_VTABLE AbstractRing : public AbstractGroup<T>
{
public:
typedef T Element;
/// \brief Construct an AbstractRing
AbstractRing() {m_mg.m_pRing = this;}
/// \brief Copy construct an AbstractRing
/// \param source other AbstractRing
AbstractRing(const AbstractRing &source)
{CRYPTOPP_UNUSED(source); m_mg.m_pRing = this;}
/// \brief Assign an AbstractRing
/// \param source other AbstractRing
AbstractRing& operator=(const AbstractRing &source)
{CRYPTOPP_UNUSED(source); return *this;}
/// \brief Determines whether an element is a unit in the group
/// \param a the element
/// \return true if the element is a unit after reduction, false otherwise.
virtual bool IsUnit(const Element &a) const =0;
/// \brief Retrieves the multiplicative identity
/// \return the multiplicative identity
virtual const Element& MultiplicativeIdentity() const =0;
/// \brief Multiplies elements in the group
/// \param a the multiplicand
/// \param b the multiplier
/// \return the product of a and b
virtual const Element& Multiply(const Element &a, const Element &b) const =0;
/// \brief Calculate the multiplicative inverse of an element in the group
/// \param a the element
virtual const Element& MultiplicativeInverse(const Element &a) const =0;
/// \brief Square an element in the group
/// \param a the element
/// \return the element squared
virtual const Element& Square(const Element &a) const;
/// \brief Divides elements in the group
/// \param a the dividend
/// \param b the divisor
/// \return the quotient
virtual const Element& Divide(const Element &a, const Element &b) const;
/// \brief Raises a base to an exponent in the group
/// \param a the base
/// \param e the exponent
/// \return the exponentiation
virtual Element Exponentiate(const Element &a, const Integer &e) const;
/// \brief TODO
/// \param x first element
/// \param e1 first exponent
/// \param y second element
/// \param e2 second exponent
/// \return TODO
virtual Element CascadeExponentiate(const Element &x, const Integer &e1, const Element &y, const Integer &e2) const;
/// \brief Exponentiates a base to multiple exponents in the Ring
/// \param results an array of Elements
/// \param base the base to raise to the exponents
/// \param exponents an array of exponents
/// \param exponentsCount the number of exponents in the array
/// \details SimultaneousExponentiate() raises the base to each exponent in the exponents array and stores the
/// result at the respective position in the results array.
/// \details SimultaneousExponentiate() must be implemented in a derived class.
/// \pre <tt>COUNTOF(results) == exponentsCount</tt>
/// \pre <tt>COUNTOF(exponents) == exponentsCount</tt>
virtual void SimultaneousExponentiate(Element *results, const Element &base, const Integer *exponents, unsigned int exponentsCount) const;
/// \brief Retrieves the multiplicative group
/// \return the multiplicative group
virtual const AbstractGroup<T>& MultiplicativeGroup() const
{return m_mg;}
private:
class MultiplicativeGroupT : public AbstractGroup<T>
{
public:
const AbstractRing<T>& GetRing() const
{return *m_pRing;}
bool Equal(const Element &a, const Element &b) const
{return GetRing().Equal(a, b);}
const Element& Identity() const
{return GetRing().MultiplicativeIdentity();}
const Element& Add(const Element &a, const Element &b) const
{return GetRing().Multiply(a, b);}
Element& Accumulate(Element &a, const Element &b) const
{return a = GetRing().Multiply(a, b);}
const Element& Inverse(const Element &a) const
{return GetRing().MultiplicativeInverse(a);}
const Element& Subtract(const Element &a, const Element &b) const
{return GetRing().Divide(a, b);}
Element& Reduce(Element &a, const Element &b) const
{return a = GetRing().Divide(a, b);}
const Element& Double(const Element &a) const
{return GetRing().Square(a);}
Element ScalarMultiply(const Element &a, const Integer &e) const
{return GetRing().Exponentiate(a, e);}
Element CascadeScalarMultiply(const Element &x, const Integer &e1, const Element &y, const Integer &e2) const
{return GetRing().CascadeExponentiate(x, e1, y, e2);}
void SimultaneousMultiply(Element *results, const Element &base, const Integer *exponents, unsigned int exponentsCount) const
{GetRing().SimultaneousExponentiate(results, base, exponents, exponentsCount);}
const AbstractRing<T> *m_pRing;
};
MultiplicativeGroupT m_mg;
};
// ********************************************************
/// \brief Base and exponent
/// \tparam T base class or type
/// \tparam E exponent class or type
template <class T, class E = Integer>
struct BaseAndExponent
{
public:
BaseAndExponent() {}
BaseAndExponent(const T &base, const E &exponent) : base(base), exponent(exponent) {}
bool operator<(const BaseAndExponent<T, E> &rhs) const {return exponent < rhs.exponent;}
T base;
E exponent;
};
// VC60 workaround: incomplete member template support
template <class Element, class Iterator>
Element GeneralCascadeMultiplication(const AbstractGroup<Element> &group, Iterator begin, Iterator end);
template <class Element, class Iterator>
Element GeneralCascadeExponentiation(const AbstractRing<Element> &ring, Iterator begin, Iterator end);
// ********************************************************
/// \brief Abstract Euclidean domain
/// \tparam T element class or type
/// \details <tt>const Element&</tt> returned by member functions are references
/// to internal data members. Since each object may have only
/// one such data member for holding results, the following code
/// will produce incorrect results:
/// <pre> abcd = group.Add(group.Add(a,b), group.Add(c,d));</pre>
/// But this should be fine:
/// <pre> abcd = group.Add(a, group.Add(b, group.Add(c,d));</pre>
template <class T> class CRYPTOPP_NO_VTABLE AbstractEuclideanDomain : public AbstractRing<T>
{
public:
typedef T Element;
/// \brief Performs the division algorithm on two elements in the ring
/// \param r the remainder
/// \param q the quotient
/// \param a the dividend
/// \param d the divisor
virtual void DivisionAlgorithm(Element &r, Element &q, const Element &a, const Element &d) const =0;
/// \brief Performs a modular reduction in the ring
/// \param a the element
/// \param b the modulus
/// \return the result of <tt>a%b</tt>.
virtual const Element& Mod(const Element &a, const Element &b) const =0;
/// \brief Calculates the greatest common denominator in the ring
/// \param a the first element
/// \param b the second element
/// \return the greatest common denominator of a and b.
virtual const Element& Gcd(const Element &a, const Element &b) const;
protected:
mutable Element result;
};
// ********************************************************
/// \brief Euclidean domain
/// \tparam T element class or type
/// \details <tt>const Element&</tt> returned by member functions are references
/// to internal data members. Since each object may have only
/// one such data member for holding results, the following code
/// will produce incorrect results:
/// <pre> abcd = group.Add(group.Add(a,b), group.Add(c,d));</pre>
/// But this should be fine:
/// <pre> abcd = group.Add(a, group.Add(b, group.Add(c,d));</pre>
template <class T> class EuclideanDomainOf : public AbstractEuclideanDomain<T>
{
public:
typedef T Element;
EuclideanDomainOf() {}
bool Equal(const Element &a, const Element &b) const
{return a==b;}
const Element& Identity() const
{return Element::Zero();}
const Element& Add(const Element &a, const Element &b) const
{return result = a+b;}
Element& Accumulate(Element &a, const Element &b) const
{return a+=b;}
const Element& Inverse(const Element &a) const
{return result = -a;}
const Element& Subtract(const Element &a, const Element &b) const
{return result = a-b;}
Element& Reduce(Element &a, const Element &b) const
{return a-=b;}
const Element& Double(const Element &a) const
{return result = a.Doubled();}
const Element& MultiplicativeIdentity() const
{return Element::One();}
const Element& Multiply(const Element &a, const Element &b) const
{return result = a*b;}
const Element& Square(const Element &a) const
{return result = a.Squared();}
bool IsUnit(const Element &a) const
{return a.IsUnit();}
const Element& MultiplicativeInverse(const Element &a) const
{return result = a.MultiplicativeInverse();}
const Element& Divide(const Element &a, const Element &b) const
{return result = a/b;}
const Element& Mod(const Element &a, const Element &b) const
{return result = a%b;}
void DivisionAlgorithm(Element &r, Element &q, const Element &a, const Element &d) const
{Element::Divide(r, q, a, d);}
bool operator==(const EuclideanDomainOf<T> &rhs) const
{CRYPTOPP_UNUSED(rhs); return true;}
private:
mutable Element result;
};
/// \brief Quotient ring
/// \tparam T element class or type
/// \details <tt>const Element&</tt> returned by member functions are references
/// to internal data members. Since each object may have only
/// one such data member for holding results, the following code
/// will produce incorrect results:
/// <pre> abcd = group.Add(group.Add(a,b), group.Add(c,d));</pre>
/// But this should be fine:
/// <pre> abcd = group.Add(a, group.Add(b, group.Add(c,d));</pre>
template <class T> class QuotientRing : public AbstractRing<typename T::Element>
{
public:
typedef T EuclideanDomain;
typedef typename T::Element Element;
QuotientRing(const EuclideanDomain &domain, const Element &modulus)
: m_domain(domain), m_modulus(modulus) {}
const EuclideanDomain & GetDomain() const
{return m_domain;}
const Element& GetModulus() const
{return m_modulus;}
bool Equal(const Element &a, const Element &b) const
{return m_domain.Equal(m_domain.Mod(m_domain.Subtract(a, b), m_modulus), m_domain.Identity());}
const Element& Identity() const
{return m_domain.Identity();}
const Element& Add(const Element &a, const Element &b) const
{return m_domain.Add(a, b);}
Element& Accumulate(Element &a, const Element &b) const
{return m_domain.Accumulate(a, b);}
const Element& Inverse(const Element &a) const
{return m_domain.Inverse(a);}
const Element& Subtract(const Element &a, const Element &b) const
{return m_domain.Subtract(a, b);}
Element& Reduce(Element &a, const Element &b) const
{return m_domain.Reduce(a, b);}
const Element& Double(const Element &a) const
{return m_domain.Double(a);}
bool IsUnit(const Element &a) const
{return m_domain.IsUnit(m_domain.Gcd(a, m_modulus));}
const Element& MultiplicativeIdentity() const
{return m_domain.MultiplicativeIdentity();}
const Element& Multiply(const Element &a, const Element &b) const
{return m_domain.Mod(m_domain.Multiply(a, b), m_modulus);}
const Element& Square(const Element &a) const
{return m_domain.Mod(m_domain.Square(a), m_modulus);}
const Element& MultiplicativeInverse(const Element &a) const;
bool operator==(const QuotientRing<T> &rhs) const
{return m_domain == rhs.m_domain && m_modulus == rhs.m_modulus;}
protected:
EuclideanDomain m_domain;
Element m_modulus;
};
NAMESPACE_END
#ifdef CRYPTOPP_MANUALLY_INSTANTIATE_TEMPLATES
#include "algebra.cpp"
#endif
#endif

520
wasm_src/algparam.h Normal file
View File

@ -0,0 +1,520 @@
// algparam.h - originally written and placed in the public domain by Wei Dai
/// \file algparam.h
/// \brief Classes for working with NameValuePairs
#ifndef CRYPTOPP_ALGPARAM_H
#define CRYPTOPP_ALGPARAM_H
#include "config.h"
#include "cryptlib.h"
#include "smartptr.h"
#include "secblock.h"
#include "integer.h"
#include "misc.h"
#include <string>
#include <typeinfo>
#include <exception>
NAMESPACE_BEGIN(CryptoPP)
/// \brief Used to pass byte array input as part of a NameValuePairs object
class ConstByteArrayParameter
{
public:
/// \brief Construct a ConstByteArrayParameter
/// \param data a C-String
/// \param deepCopy flag indicating whether the data should be copied
/// \details The deepCopy option is used when the NameValuePairs object can't
/// keep a copy of the data available
ConstByteArrayParameter(const char *data = NULLPTR, bool deepCopy = false)
: m_deepCopy(false), m_data(NULLPTR), m_size(0)
{
Assign(reinterpret_cast<const byte *>(data), data ? strlen(data) : 0, deepCopy);
}
/// \brief Construct a ConstByteArrayParameter
/// \param data a memory buffer
/// \param size the length of the memory buffer
/// \param deepCopy flag indicating whether the data should be copied
/// \details The deepCopy option is used when the NameValuePairs object can't
/// keep a copy of the data available
ConstByteArrayParameter(const byte *data, size_t size, bool deepCopy = false)
: m_deepCopy(false), m_data(NULLPTR), m_size(0)
{
Assign(data, size, deepCopy);
}
/// \brief Construct a ConstByteArrayParameter
/// \tparam T a std::basic_string<char> or std::vector<byte> class
/// \param string a std::basic_string<char> or std::vector<byte> object
/// \param deepCopy flag indicating whether the data should be copied
/// \details The deepCopy option is used when the NameValuePairs object can't
/// keep a copy of the data available
template <class T> ConstByteArrayParameter(const T &string, bool deepCopy = false)
: m_deepCopy(false), m_data(NULLPTR), m_size(0)
{
CRYPTOPP_COMPILE_ASSERT(sizeof(typename T::value_type) == 1);
Assign(reinterpret_cast<const byte *>(&string[0]), string.size(), deepCopy);
}
/// \brief Assign contents from a memory buffer
/// \param data a memory buffer
/// \param size the length of the memory buffer
/// \param deepCopy flag indicating whether the data should be copied
/// \details The deepCopy option is used when the NameValuePairs object can't
/// keep a copy of the data available
void Assign(const byte *data, size_t size, bool deepCopy)
{
// This fires, which means: no data with a size, or data with no size.
// CRYPTOPP_ASSERT((data && size) || !(data || size));
if (deepCopy)
m_block.Assign(data, size);
else
{
m_data = data;
m_size = size;
}
m_deepCopy = deepCopy;
}
/// \brief Pointer to the first byte in the memory block
const byte *begin() const {return m_deepCopy ? m_block.begin() : m_data;}
/// \brief Pointer beyond the last byte in the memory block
const byte *end() const {return m_deepCopy ? m_block.end() : m_data + m_size;}
/// \brief Length of the memory block
size_t size() const {return m_deepCopy ? m_block.size() : m_size;}
private:
bool m_deepCopy;
const byte *m_data;
size_t m_size;
SecByteBlock m_block;
};
/// \brief Used to pass byte array input as part of a NameValuePairs object
class ByteArrayParameter
{
public:
/// \brief Construct a ByteArrayParameter
/// \param data a memory buffer
/// \param size the length of the memory buffer
ByteArrayParameter(byte *data = NULLPTR, unsigned int size = 0)
: m_data(data), m_size(size) {}
/// \brief Construct a ByteArrayParameter
/// \param block a SecByteBlock
ByteArrayParameter(SecByteBlock &block)
: m_data(block.begin()), m_size(block.size()) {}
/// \brief Pointer to the first byte in the memory block
byte *begin() const {return m_data;}
/// \brief Pointer beyond the last byte in the memory block
byte *end() const {return m_data + m_size;}
/// \brief Length of the memory block
size_t size() const {return m_size;}
private:
byte *m_data;
size_t m_size;
};
/// \brief Combines two sets of NameValuePairs
/// \details CombinedNameValuePairs allows you to provide two sets of of NameValuePairs.
/// If a name is not found in the first set, then the second set is searched for the
/// name and value pair. The second set of NameValuePairs often provides default values.
class CRYPTOPP_DLL CombinedNameValuePairs : public NameValuePairs
{
public:
/// \brief Construct a CombinedNameValuePairs
/// \param pairs1 reference to the first set of NameValuePairs
/// \param pairs2 reference to the second set of NameValuePairs
CombinedNameValuePairs(const NameValuePairs &pairs1, const NameValuePairs &pairs2)
: m_pairs1(pairs1), m_pairs2(pairs2) {}
bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const;
private:
const NameValuePairs &m_pairs1, &m_pairs2;
};
#ifndef CRYPTOPP_DOXYGEN_PROCESSING
template <class T, class BASE>
class GetValueHelperClass
{
public:
GetValueHelperClass(const T *pObject, const char *name, const std::type_info &valueType, void *pValue, const NameValuePairs *searchFirst)
: m_pObject(pObject), m_name(name), m_valueType(&valueType), m_pValue(pValue), m_found(false), m_getValueNames(false)
{
if (strcmp(m_name, "ValueNames") == 0)
{
m_found = m_getValueNames = true;
NameValuePairs::ThrowIfTypeMismatch(m_name, typeid(std::string), *m_valueType);
if (searchFirst)
searchFirst->GetVoidValue(m_name, valueType, pValue);
if (typeid(T) != typeid(BASE))
pObject->BASE::GetVoidValue(m_name, valueType, pValue);
((*reinterpret_cast<std::string *>(m_pValue) += "ThisPointer:") += typeid(T).name()) += ';';
}
if (!m_found && strncmp(m_name, "ThisPointer:", 12) == 0 && strcmp(m_name+12, typeid(T).name()) == 0)
{
NameValuePairs::ThrowIfTypeMismatch(m_name, typeid(T *), *m_valueType);
*reinterpret_cast<const T **>(pValue) = pObject;
m_found = true;
return;
}
if (!m_found && searchFirst)
m_found = searchFirst->GetVoidValue(m_name, valueType, pValue);
if (!m_found && typeid(T) != typeid(BASE))
m_found = pObject->BASE::GetVoidValue(m_name, valueType, pValue);
}
operator bool() const {return m_found;}
template <class R>
GetValueHelperClass<T,BASE> & operator()(const char *name, const R & (T::*pm)() const)
{
if (m_getValueNames)
(*reinterpret_cast<std::string *>(m_pValue) += name) += ";";
if (!m_found && strcmp(name, m_name) == 0)
{
NameValuePairs::ThrowIfTypeMismatch(name, typeid(R), *m_valueType);
*reinterpret_cast<R *>(m_pValue) = (m_pObject->*pm)();
m_found = true;
}
return *this;
}
GetValueHelperClass<T,BASE> &Assignable()
{
#ifndef __INTEL_COMPILER // ICL 9.1 workaround: Intel compiler copies the vTable pointer for some reason
if (m_getValueNames)
((*reinterpret_cast<std::string *>(m_pValue) += "ThisObject:") += typeid(T).name()) += ';';
if (!m_found && strncmp(m_name, "ThisObject:", 11) == 0 && strcmp(m_name+11, typeid(T).name()) == 0)
{
NameValuePairs::ThrowIfTypeMismatch(m_name, typeid(T), *m_valueType);
*reinterpret_cast<T *>(m_pValue) = *m_pObject;
m_found = true;
}
#endif
return *this;
}
private:
const T *m_pObject;
const char *m_name;
const std::type_info *m_valueType;
void *m_pValue;
bool m_found, m_getValueNames;
};
template <class BASE, class T>
GetValueHelperClass<T, BASE> GetValueHelper(const T *pObject, const char *name, const std::type_info &valueType, void *pValue, const NameValuePairs *searchFirst=NULLPTR)
{
return GetValueHelperClass<T, BASE>(pObject, name, valueType, pValue, searchFirst);
}
template <class T>
GetValueHelperClass<T, T> GetValueHelper(const T *pObject, const char *name, const std::type_info &valueType, void *pValue, const NameValuePairs *searchFirst=NULLPTR)
{
return GetValueHelperClass<T, T>(pObject, name, valueType, pValue, searchFirst);
}
// ********************************************************
template <class T, class BASE>
class AssignFromHelperClass
{
public:
AssignFromHelperClass(T *pObject, const NameValuePairs &source)
: m_pObject(pObject), m_source(source), m_done(false)
{
if (source.GetThisObject(*pObject))
m_done = true;
else if (typeid(BASE) != typeid(T))
pObject->BASE::AssignFrom(source);
}
template <class R>
AssignFromHelperClass & operator()(const char *name, void (T::*pm)(const R&))
{
if (!m_done)
{
R value;
if (!m_source.GetValue(name, value))
throw InvalidArgument(std::string(typeid(T).name()) + ": Missing required parameter '" + name + "'");
(m_pObject->*pm)(value);
}
return *this;
}
template <class R, class S>
AssignFromHelperClass & operator()(const char *name1, const char *name2, void (T::*pm)(const R&, const S&))
{
if (!m_done)
{
R value1;
if (!m_source.GetValue(name1, value1))
throw InvalidArgument(std::string(typeid(T).name()) + ": Missing required parameter '" + name1 + "'");
S value2;
if (!m_source.GetValue(name2, value2))
throw InvalidArgument(std::string(typeid(T).name()) + ": Missing required parameter '" + name2 + "'");
(m_pObject->*pm)(value1, value2);
}
return *this;
}
private:
T *m_pObject;
const NameValuePairs &m_source;
bool m_done;
};
template <class BASE, class T>
AssignFromHelperClass<T, BASE> AssignFromHelper(T *pObject, const NameValuePairs &source)
{
return AssignFromHelperClass<T, BASE>(pObject, source);
}
template <class T>
AssignFromHelperClass<T, T> AssignFromHelper(T *pObject, const NameValuePairs &source)
{
return AssignFromHelperClass<T, T>(pObject, source);
}
#endif // CRYPTOPP_DOXYGEN_PROCESSING
// ********************************************************
#ifndef CRYPTOPP_NO_ASSIGN_TO_INTEGER
// Allow the linker to discard Integer code if not needed.
// Also see http://github.com/weidai11/cryptopp/issues/389.
CRYPTOPP_DLL bool AssignIntToInteger(const std::type_info &valueType, void *pInteger, const void *pInt);
#endif
CRYPTOPP_DLL const std::type_info & CRYPTOPP_API IntegerTypeId();
/// \brief Base class for AlgorithmParameters
class CRYPTOPP_DLL AlgorithmParametersBase
{
public:
/// \brief Exception thrown when an AlgorithmParameter is unused
class ParameterNotUsed : public Exception
{
public:
ParameterNotUsed(const char *name) : Exception(OTHER_ERROR, std::string("AlgorithmParametersBase: parameter \"") + name + "\" not used") {}
};
virtual ~AlgorithmParametersBase() CRYPTOPP_THROW
{
#if defined(CRYPTOPP_CXX17_UNCAUGHT_EXCEPTIONS)
if (std::uncaught_exceptions() == 0)
#elif defined(CRYPTOPP_CXX98_UNCAUGHT_EXCEPTION)
if (std::uncaught_exception() == false)
#else
try
#endif
{
if (m_throwIfNotUsed && !m_used)
throw ParameterNotUsed(m_name);
}
#if !defined(CRYPTOPP_CXX98_UNCAUGHT_EXCEPTION)
# if !defined(CRYPTOPP_CXX17_UNCAUGHT_EXCEPTIONS)
catch(const Exception&)
{
}
# endif
#endif
}
// this is actually a move, not a copy
AlgorithmParametersBase(const AlgorithmParametersBase &x)
: m_name(x.m_name), m_throwIfNotUsed(x.m_throwIfNotUsed), m_used(x.m_used)
{
m_next.reset(const_cast<AlgorithmParametersBase &>(x).m_next.release());
x.m_used = true;
}
/// \brief Construct a AlgorithmParametersBase
/// \param name the parameter name
/// \param throwIfNotUsed flags indicating whether an exception should be thrown
/// \details If throwIfNotUsed is true, then a ParameterNotUsed exception
/// will be thrown in the destructor if the parameter is not not retrieved.
AlgorithmParametersBase(const char *name, bool throwIfNotUsed)
: m_name(name), m_throwIfNotUsed(throwIfNotUsed), m_used(false) {}
bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const;
protected:
friend class AlgorithmParameters;
void operator=(const AlgorithmParametersBase& rhs); // assignment not allowed, declare this for VC60
virtual void AssignValue(const char *name, const std::type_info &valueType, void *pValue) const =0;
virtual void MoveInto(void *p) const =0; // not really const
const char *m_name;
bool m_throwIfNotUsed;
mutable bool m_used;
member_ptr<AlgorithmParametersBase> m_next;
};
/// \brief Template base class for AlgorithmParameters
/// \tparam T the class or type
template <class T>
class AlgorithmParametersTemplate : public AlgorithmParametersBase
{
public:
/// \brief Construct an AlgorithmParametersTemplate
/// \param name the name of the value
/// \param value a reference to the value
/// \param throwIfNotUsed flags indicating whether an exception should be thrown
/// \details If throwIfNotUsed is true, then a ParameterNotUsed exception
/// will be thrown in the destructor if the parameter is not not retrieved.
AlgorithmParametersTemplate(const char *name, const T &value, bool throwIfNotUsed)
: AlgorithmParametersBase(name, throwIfNotUsed), m_value(value)
{
}
void AssignValue(const char *name, const std::type_info &valueType, void *pValue) const
{
#ifndef CRYPTOPP_NO_ASSIGN_TO_INTEGER
// Special case for retrieving an Integer parameter when an int was passed in
if (!(typeid(T) == typeid(int) && AssignIntToInteger(valueType, pValue, &m_value)))
#endif
{
NameValuePairs::ThrowIfTypeMismatch(name, typeid(T), valueType);
*reinterpret_cast<T *>(pValue) = m_value;
}
}
#if defined(DEBUG_NEW) && (_MSC_VER >= 1300)
# pragma push_macro("new")
# undef new
#endif
void MoveInto(void *buffer) const
{
AlgorithmParametersTemplate<T>* p = new(buffer) AlgorithmParametersTemplate<T>(*this);
CRYPTOPP_UNUSED(p); // silence warning
}
#if defined(DEBUG_NEW) && (_MSC_VER >= 1300)
# pragma pop_macro("new")
#endif
protected:
T m_value;
};
CRYPTOPP_DLL_TEMPLATE_CLASS AlgorithmParametersTemplate<bool>;
CRYPTOPP_DLL_TEMPLATE_CLASS AlgorithmParametersTemplate<int>;
CRYPTOPP_DLL_TEMPLATE_CLASS AlgorithmParametersTemplate<ConstByteArrayParameter>;
/// \brief An object that implements NameValuePairs
/// \note A NameValuePairs object containing an arbitrary number of name value pairs may be constructed by
/// repeatedly using operator() on the object returned by MakeParameters, for example:
/// <pre>
/// AlgorithmParameters parameters = MakeParameters(name1, value1)(name2, value2)(name3, value3);
/// </pre>
class CRYPTOPP_DLL AlgorithmParameters : public NameValuePairs
{
public:
/// \brief Construct a AlgorithmParameters
/// \note A NameValuePairs object containing an arbitrary number of name value pairs may be constructed by
/// repeatedly using operator() on the object returned by MakeParameters, for example:
/// <pre>
/// AlgorithmParameters parameters = MakeParameters(name1, value1)(name2, value2)(name3, value3);
/// </pre>
AlgorithmParameters();
#ifdef __BORLANDC__
/// \brief Construct a AlgorithmParameters
/// \tparam T the class or type
/// \param name the name of the object or value to retrieve
/// \param value reference to a variable that receives the value
/// \param throwIfNotUsed if true, the object will throw an exception if the value is not accessed
/// \note throwIfNotUsed is ignored if using a compiler that does not support std::uncaught_exception(),
/// such as MSVC 7.0 and earlier.
/// \note A NameValuePairs object containing an arbitrary number of name value pairs may be constructed by
/// repeatedly using operator() on the object returned by MakeParameters, for example:
/// <pre>
/// AlgorithmParameters parameters = MakeParameters(name1, value1)(name2, value2)(name3, value3);
/// </pre>
template <class T>
AlgorithmParameters(const char *name, const T &value, bool throwIfNotUsed=true)
: m_next(new AlgorithmParametersTemplate<T>(name, value, throwIfNotUsed))
, m_defaultThrowIfNotUsed(throwIfNotUsed)
{
}
#endif
AlgorithmParameters(const AlgorithmParameters &x);
AlgorithmParameters & operator=(const AlgorithmParameters &x);
/// \tparam T the class or type
/// \param name the name of the object or value to retrieve
/// \param value reference to a variable that receives the value
/// \param throwIfNotUsed if true, the object will throw an exception if the value is not accessed
template <class T>
AlgorithmParameters & operator()(const char *name, const T &value, bool throwIfNotUsed)
{
member_ptr<AlgorithmParametersBase> p(new AlgorithmParametersTemplate<T>(name, value, throwIfNotUsed));
p->m_next.reset(m_next.release());
m_next.reset(p.release());
m_defaultThrowIfNotUsed = throwIfNotUsed;
return *this;
}
/// \brief Appends a NameValuePair to a collection of NameValuePairs
/// \tparam T the class or type
/// \param name the name of the object or value to retrieve
/// \param value reference to a variable that receives the value
template <class T>
AlgorithmParameters & operator()(const char *name, const T &value)
{
return operator()(name, value, m_defaultThrowIfNotUsed);
}
bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const;
protected:
member_ptr<AlgorithmParametersBase> m_next;
bool m_defaultThrowIfNotUsed;
};
/// \brief Create an object that implements NameValuePairs
/// \tparam T the class or type
/// \param name the name of the object or value to retrieve
/// \param value reference to a variable that receives the value
/// \param throwIfNotUsed if true, the object will throw an exception if the value is not accessed
/// \note throwIfNotUsed is ignored if using a compiler that does not support std::uncaught_exception(),
/// such as MSVC 7.0 and earlier.
/// \note A NameValuePairs object containing an arbitrary number of name value pairs may be constructed by
/// repeatedly using \p operator() on the object returned by \p MakeParameters, for example:
/// <pre>
/// AlgorithmParameters parameters = MakeParameters(name1, value1)(name2, value2)(name3, value3);
/// </pre>
#ifdef __BORLANDC__
typedef AlgorithmParameters MakeParameters;
#else
template <class T>
AlgorithmParameters MakeParameters(const char *name, const T &value, bool throwIfNotUsed = true)
{
return AlgorithmParameters()(name, value, throwIfNotUsed);
}
#endif
#define CRYPTOPP_GET_FUNCTION_ENTRY(name) (Name::name(), &ThisClass::Get##name)
#define CRYPTOPP_SET_FUNCTION_ENTRY(name) (Name::name(), &ThisClass::Set##name)
#define CRYPTOPP_SET_FUNCTION_ENTRY2(name1, name2) (Name::name1(), Name::name2(), &ThisClass::Set##name1##And##name2)
NAMESPACE_END
#endif

107
wasm_src/allocate.cpp Normal file
View File

@ -0,0 +1,107 @@
// allocate.cpp - written and placed in the public domain by Jeffrey Walton
// The functions in allocate.h and allocate.cpp were originally in misc.h
// and misc.cpp. They were extracted in September 2019 to sidestep a circular
// dependency with misc.h and secblock.h.
#include "pch.h"
#include "config.h"
#ifndef CRYPTOPP_IMPORTS
#include "allocate.h"
#include "stdcpp.h"
#include "misc.h"
// for memalign
#if defined(CRYPTOPP_MEMALIGN_AVAILABLE) || defined(CRYPTOPP_MM_MALLOC_AVAILABLE) || defined(QNX)
# include <malloc.h>
#endif
// for posix_memalign
#if defined(CRYPTOPP_POSIX_MEMALIGN_AVAILABLE)
# include <stdlib.h>
#endif
NAMESPACE_BEGIN(CryptoPP)
void CallNewHandler()
{
using std::new_handler;
using std::set_new_handler;
new_handler newHandler = set_new_handler(NULLPTR);
if (newHandler)
set_new_handler(newHandler);
if (newHandler)
newHandler();
else
throw std::bad_alloc();
}
void * AlignedAllocate(size_t size)
{
byte *p;
#if defined(CRYPTOPP_MM_MALLOC_AVAILABLE)
while ((p = (byte *)_mm_malloc(size, 16)) == NULLPTR)
#elif defined(CRYPTOPP_MEMALIGN_AVAILABLE)
while ((p = (byte *)memalign(16, size)) == NULLPTR)
#elif defined(CRYPTOPP_MALLOC_ALIGNMENT_IS_16)
while ((p = (byte *)malloc(size)) == NULLPTR)
#elif defined(CRYPTOPP_POSIX_MEMALIGN_AVAILABLE)
while (posix_memalign(reinterpret_cast<void**>(&p), 16, size) != 0)
#else
while ((p = (byte *)malloc(size + 16)) == NULLPTR)
#endif
CallNewHandler();
#ifdef CRYPTOPP_NO_ALIGNED_ALLOC
size_t adjustment = 16-((size_t)p%16);
CRYPTOPP_ASSERT(adjustment > 0);
p += adjustment;
p[-1] = (byte)adjustment;
#endif
// If this assert fires then there are problems that need
// to be fixed. Please open a bug report.
CRYPTOPP_ASSERT(IsAlignedOn(p, 16));
return p;
}
void AlignedDeallocate(void *p)
{
// Guard pointer due to crash on AIX when CRYPTOPP_NO_ALIGNED_ALLOC
// is in effect. The guard was previously in place in SecBlock,
// but it was removed at f4d68353ca7c as part of GH #875.
CRYPTOPP_ASSERT(p);
if (p != NULLPTR)
{
#ifdef CRYPTOPP_MM_MALLOC_AVAILABLE
_mm_free(p);
#elif defined(CRYPTOPP_NO_ALIGNED_ALLOC)
p = (byte *)p - ((byte *)p)[-1];
free(p);
#else
free(p);
#endif
}
}
void * UnalignedAllocate(size_t size)
{
void *p;
while ((p = malloc(size)) == NULLPTR)
CallNewHandler();
return p;
}
void UnalignedDeallocate(void *p)
{
free(p);
}
NAMESPACE_END
#endif // CRYPTOPP_IMPORTS

74
wasm_src/allocate.h Normal file
View File

@ -0,0 +1,74 @@
// allocate.h - written and placed in the public domain by Jeffrey Walton
// The functions in allocate.h and allocate.cpp were originally in misc.h
// and misc.cpp. They were extracted in September 2019 to sidestep a circular
// dependency with misc.h and secblock.h.
/// \file allocate.h
/// \brief Functions for allocating aligned buffers
#ifndef CRYPTOPP_ALLOCATE_H
#define CRYPTOPP_ALLOCATE_H
#include "config.h"
#include "cryptlib.h"
NAMESPACE_BEGIN(CryptoPP)
/// \brief Attempts to reclaim unused memory
/// \throw bad_alloc
/// \details In the normal course of running a program, a request for memory
/// normally succeeds. If a call to AlignedAllocate or UnalignedAllocate fails,
/// then CallNewHandler is called in n effort to recover. Internally,
/// CallNewHandler calls set_new_handler(nullptr) in an effort to free memory.
/// There is no guarantee CallNewHandler will be able to obtain more memory so
/// an allocation succeeds. If the call to set_new_handler fails, then CallNewHandler
/// throws a bad_alloc exception.
/// \throw bad_alloc on failure
/// \since Crypto++ 5.0
/// \sa AlignedAllocate, AlignedDeallocate, UnalignedAllocate, UnalignedDeallocate
CRYPTOPP_DLL void CRYPTOPP_API CallNewHandler();
/// \brief Allocates a buffer on 16-byte boundary
/// \param size the size of the buffer
/// \details AlignedAllocate is primarily used when the data will be
/// processed by SSE, NEON, ARMv8 or PowerPC instructions. The assembly
/// language routines rely on the alignment. If the alignment is not
/// respected, then a SIGBUS could be generated on Unix and Linux, and an
/// EXCEPTION_DATATYPE_MISALIGNMENT could be generated on Windows.
/// \details Formerly, AlignedAllocate and AlignedDeallocate were only
/// available on certain platforms when CRYTPOPP_DISABLE_ASM was not in
/// effect. However, Android and iOS debug simulator builds got into a
/// state where the aligned allocator was not available and caused link
/// failures.
/// \since AlignedAllocate for SIMD since Crypto++ 1.0, AlignedAllocate
/// for all builds since Crypto++ 8.1
/// \sa AlignedDeallocate, UnalignedAllocate, UnalignedDeallocate, CallNewHandler,
/// <A HREF="http://github.com/weidai11/cryptopp/issues/779">Issue 779</A>
CRYPTOPP_DLL void* CRYPTOPP_API AlignedAllocate(size_t size);
/// \brief Frees a buffer allocated with AlignedAllocate
/// \param ptr the buffer to free
/// \since AlignedDeallocate for SIMD since Crypto++ 1.0, AlignedAllocate
/// for all builds since Crypto++ 8.1
/// \sa AlignedAllocate, UnalignedAllocate, UnalignedDeallocate, CallNewHandler,
/// <A HREF="http://github.com/weidai11/cryptopp/issues/779">Issue 779</A>
CRYPTOPP_DLL void CRYPTOPP_API AlignedDeallocate(void *ptr);
/// \brief Allocates a buffer
/// \param size the size of the buffer
/// \since Crypto++ 1.0
/// \sa AlignedAllocate, AlignedDeallocate, UnalignedDeallocate, CallNewHandler,
/// <A HREF="http://github.com/weidai11/cryptopp/issues/779">Issue 779</A>
CRYPTOPP_DLL void * CRYPTOPP_API UnalignedAllocate(size_t size);
/// \brief Frees a buffer allocated with UnalignedAllocate
/// \param ptr the buffer to free
/// \since Crypto++ 1.0
/// \sa AlignedAllocate, AlignedDeallocate, UnalignedAllocate, CallNewHandler,
/// <A HREF="http://github.com/weidai11/cryptopp/issues/779">Issue 779</A>
CRYPTOPP_DLL void CRYPTOPP_API UnalignedDeallocate(void *ptr);
NAMESPACE_END
#endif // CRYPTOPP_ALLOCATE_H

10333
wasm_src/codelift.cpp Normal file

File diff suppressed because it is too large Load Diff

8
wasm_src/codelift.h Normal file
View File

@ -0,0 +1,8 @@
#include <stdint.h>
#include <emscripten/emscripten.h>
extern "C" {
EMSCRIPTEN_KEEPALIVE const char* guessInput(const char* input);
EMSCRIPTEN_KEEPALIVE const char* getOutput(const char* input);
EMSCRIPTEN_KEEPALIVE const char* getDeoaep(const char* input);
EMSCRIPTEN_KEEPALIVE void freeStr(void* str);
}

1253
wasm_src/config.h Normal file

File diff suppressed because it is too large Load Diff

1085
wasm_src/cpu.h Normal file

File diff suppressed because it is too large Load Diff

3349
wasm_src/cryptlib.h Normal file

File diff suppressed because it is too large Load Diff

1529
wasm_src/filters.h Normal file

File diff suppressed because it is too large Load Diff

4648
wasm_src/integer.cpp Normal file

File diff suppressed because it is too large Load Diff

670
wasm_src/integer.h Normal file
View File

@ -0,0 +1,670 @@
// integer.h - originally written and placed in the public domain by Wei Dai
/// \file integer.h
/// \brief Multiple precision integer with arithmetic operations
/// \details The Integer class can represent positive and negative integers
/// with absolute value less than (256**sizeof(word))<sup>(256**sizeof(int))</sup>.
/// \details Internally, the library uses a sign magnitude representation, and the class
/// has two data members. The first is a IntegerSecBlock (a SecBlock<word>) and it is
/// used to hold the representation. The second is a Sign (an enumeration), and it is
/// used to track the sign of the Integer.
/// \details For details on how the Integer class initializes its function pointers using
/// InitializeInteger and how it creates Integer::Zero(), Integer::One(), and
/// Integer::Two(), then see the comments at the top of <tt>integer.cpp</tt>.
/// \since Crypto++ 1.0
#ifndef CRYPTOPP_INTEGER_H
#define CRYPTOPP_INTEGER_H
#include "cryptlib.h"
#include "secblock.h"
#include "stdcpp.h"
#include <iosfwd>
NAMESPACE_BEGIN(CryptoPP)
/// \struct InitializeInteger
/// \brief Performs static initialization of the Integer class
struct InitializeInteger
{
InitializeInteger();
};
// Always align, http://github.com/weidai11/cryptopp/issues/256
typedef SecBlock<word, AllocatorWithCleanup<word, true> > IntegerSecBlock;
template class SecBlock<word, AllocatorWithCleanup<word, true> > ;
/// \brief Multiple precision integer with arithmetic operations
/// \details The Integer class can represent positive and negative integers
/// with absolute value less than (256**sizeof(word))<sup>(256**sizeof(int))</sup>.
/// \details Internally, the library uses a sign magnitude representation, and the class
/// has two data members. The first is a IntegerSecBlock (a SecBlock<word>) and it is
/// used to hold the representation. The second is a Sign (an enumeration), and it is
/// used to track the sign of the Integer.
/// \details For details on how the Integer class initializes its function pointers using
/// InitializeInteger and how it creates Integer::Zero(), Integer::One(), and
/// Integer::Two(), then see the comments at the top of <tt>integer.cpp</tt>.
/// \since Crypto++ 1.0
/// \nosubgrouping
class CRYPTOPP_DLL Integer : private InitializeInteger
{
public:
/// \name ENUMS, EXCEPTIONS, and TYPEDEFS
//@{
/// \brief Exception thrown when division by 0 is encountered
class DivideByZero : public Exception
{
public:
DivideByZero() : Exception(OTHER_ERROR, "Integer: division by zero") {}
};
/// \enum Sign
/// \brief Used internally to represent the integer
/// \details Sign is used internally to represent the integer. It is also used in a few API functions.
/// \sa SetPositive(), SetNegative(), Signedness
enum Sign {
/// \brief the value is positive or 0
POSITIVE=0,
/// \brief the value is negative
NEGATIVE=1};
/// \enum Signedness
/// \brief Used when importing and exporting integers
/// \details Signedness is usually used in API functions.
/// \sa Sign
enum Signedness {
/// \brief an unsigned value
UNSIGNED,
/// \brief a signed value
SIGNED};
//@}
/// \name CREATORS
//@{
/// \brief Creates the zero integer
Integer();
/// copy constructor
Integer(const Integer& t);
/// \brief Convert from signed long
Integer(signed long value);
/// \brief Convert from lword
/// \param sign enumeration indicating Sign
/// \param value the long word
Integer(Sign sign, lword value);
/// \brief Convert from two words
/// \param sign enumeration indicating Sign
/// \param highWord the high word
/// \param lowWord the low word
Integer(Sign sign, word highWord, word lowWord);
/// \brief Convert from a C-string
/// \param str C-string value
/// \param order the ByteOrder of the string to be processed
/// \details \p str can be in base 2, 8, 10, or 16. Base is determined by a case
/// insensitive suffix of 'h', 'o', or 'b'. No suffix means base 10.
/// \details Byte order was added at Crypto++ 5.7 to allow use of little-endian
/// integers with curve25519, Poly1305 and Microsoft CAPI.
explicit Integer(const char *str, ByteOrder order = BIG_ENDIAN_ORDER);
/// \brief Convert from a wide C-string
/// \param str wide C-string value
/// \param order the ByteOrder of the string to be processed
/// \details \p str can be in base 2, 8, 10, or 16. Base is determined by a case
/// insensitive suffix of 'h', 'o', or 'b'. No suffix means base 10.
/// \details Byte order was added at Crypto++ 5.7 to allow use of little-endian
/// integers with curve25519, Poly1305 and Microsoft CAPI.
explicit Integer(const wchar_t *str, ByteOrder order = BIG_ENDIAN_ORDER);
/// \brief Convert from a big-endian byte array
/// \param encodedInteger big-endian byte array
/// \param byteCount length of the byte array
/// \param sign enumeration indicating Signedness
/// \param order the ByteOrder of the array to be processed
/// \details Byte order was added at Crypto++ 5.7 to allow use of little-endian
/// integers with curve25519, Poly1305 and Microsoft CAPI.
Integer(const byte *encodedInteger, size_t byteCount, Signedness sign=UNSIGNED, ByteOrder order = BIG_ENDIAN_ORDER);
/// \brief Convert from a big-endian array
/// \param bt BufferedTransformation object with big-endian byte array
/// \param byteCount length of the byte array
/// \param sign enumeration indicating Signedness
/// \param order the ByteOrder of the data to be processed
/// \details Byte order was added at Crypto++ 5.7 to allow use of little-endian
/// integers with curve25519, Poly1305 and Microsoft CAPI.
Integer(BufferedTransformation &bt, size_t byteCount, Signedness sign=UNSIGNED, ByteOrder order = BIG_ENDIAN_ORDER);
/// \brief Integer representing 0
/// \return an Integer representing 0
/// \details Zero() avoids calling constructors for frequently used integers
static const Integer & CRYPTOPP_API Zero();
/// \brief Integer representing 1
/// \return an Integer representing 1
/// \details One() avoids calling constructors for frequently used integers
static const Integer & CRYPTOPP_API One();
/// \brief Integer representing 2
/// \return an Integer representing 2
/// \details Two() avoids calling constructors for frequently used integers
static const Integer & CRYPTOPP_API Two();
/// \brief Exponentiates to a power of 2
/// \return the Integer 2<sup>e</sup>
/// \sa a_times_b_mod_c() and a_exp_b_mod_c()
static Integer CRYPTOPP_API Power2(size_t e);
//@}
/// \name ENCODE/DECODE
//@{
/// \brief Minimum number of bytes to encode this integer
/// \param sign enumeration indicating Signedness
/// \note The MinEncodedSize() of 0 is 1.
size_t MinEncodedSize(Signedness sign=UNSIGNED) const;
/// \brief Encode in big-endian format
/// \param output big-endian byte array
/// \param outputLen length of the byte array
/// \param sign enumeration indicating Signedness
/// \details Unsigned means encode absolute value, signed means encode two's complement if negative.
/// \details outputLen can be used to ensure an Integer is encoded to an exact size (rather than a
/// minimum size). An exact size is useful, for example, when encoding to a field element size.
void Encode(byte *output, size_t outputLen, Signedness sign=UNSIGNED) const;
/// \brief Decode from big-endian byte array
/// \param input big-endian byte array
/// \param inputLen length of the byte array
/// \param sign enumeration indicating Signedness
void Decode(const byte *input, size_t inputLen, Signedness sign=UNSIGNED);
/// \brief Decode nonnegative value from big-endian byte array
/// \param bt BufferedTransformation object
/// \param inputLen length of the byte array
/// \param sign enumeration indicating Signedness
/// \note <tt>bt.MaxRetrievable() \>= inputLen</tt>.
void Decode(BufferedTransformation &bt, size_t inputLen, Signedness sign=UNSIGNED);
//@}
/// \name ACCESSORS
//@{
/// \brief Determines if the Integer is convertable to Long
/// \return true if *this can be represented as a signed long
/// \sa ConvertToLong()
bool IsConvertableToLong() const;
/// \brief Convert the Integer to Long
/// \return equivalent signed long if possible, otherwise undefined
/// \sa IsConvertableToLong()
signed long ConvertToLong() const;
/// \brief Determines the number of bits required to represent the Integer
/// \return number of significant bits
/// \details BitCount is calculated as <tt>floor(log2(abs(*this))) + 1</tt>.
unsigned int BitCount() const;
/// \brief Determines the number of bytes required to represent the Integer
/// \return number of significant bytes
/// \details ByteCount is calculated as <tt>ceiling(BitCount()/8)</tt>.
unsigned int ByteCount() const;
/// \brief Determines the number of words required to represent the Integer
/// \return number of significant words
/// \details WordCount is calculated as <tt>ceiling(ByteCount()/sizeof(word))</tt>.
unsigned int WordCount() const;
/// \brief Provides the i-th bit of the Integer
/// \return the i-th bit, i=0 being the least significant bit
bool GetBit(size_t i) const;
/// \brief Provides the i-th byte of the Integer
/// \return the i-th byte
byte GetByte(size_t i) const;
/// \brief Provides the low order bits of the Integer
/// \return n lowest bits of *this >> i
lword GetBits(size_t i, size_t n) const;
/// \brief Determines if the Integer is 0
/// \return true if the Integer is 0, false otherwise
bool IsZero() const {return !*this;}
/// \brief Determines if the Integer is non-0
/// \return true if the Integer is non-0, false otherwise
bool NotZero() const {return !IsZero();}
/// \brief Determines if the Integer is negative
/// \return true if the Integer is negative, false otherwise
bool IsNegative() const {return sign == NEGATIVE;}
/// \brief Determines if the Integer is non-negative
/// \return true if the Integer is non-negative, false otherwise
bool NotNegative() const {return !IsNegative();}
/// \brief Determines if the Integer is positive
/// \return true if the Integer is positive, false otherwise
bool IsPositive() const {return NotNegative() && NotZero();}
/// \brief Determines if the Integer is non-positive
/// \return true if the Integer is non-positive, false otherwise
bool NotPositive() const {return !IsPositive();}
/// \brief Determines if the Integer is even parity
/// \return true if the Integer is even, false otherwise
bool IsEven() const {return GetBit(0) == 0;}
/// \brief Determines if the Integer is odd parity
/// \return true if the Integer is odd, false otherwise
bool IsOdd() const {return GetBit(0) == 1;}
//@}
/// \name MANIPULATORS
//@{
/// \brief Assignment
/// \param t the other Integer
/// \return the result of assignment
Integer& operator=(const Integer& t);
/// \brief Addition Assignment
/// \param t the other Integer
/// \return the result of <tt>*this + t</tt>
Integer& operator+=(const Integer& t);
/// \brief Subtraction Assignment
/// \param t the other Integer
/// \return the result of <tt>*this - t</tt>
Integer& operator-=(const Integer& t);
/// \brief Multiplication Assignment
/// \param t the other Integer
/// \return the result of <tt>*this * t</tt>
/// \sa a_times_b_mod_c() and a_exp_b_mod_c()
Integer& operator*=(const Integer& t) {return *this = Times(t);}
/// \brief Division Assignment
/// \param t the other Integer
/// \return the result of <tt>*this / t</tt>
Integer& operator/=(const Integer& t) {return *this = DividedBy(t);}
/// \brief Remainder Assignment
/// \param t the other Integer
/// \return the result of <tt>*this % t</tt>
/// \sa a_times_b_mod_c() and a_exp_b_mod_c()
Integer& operator%=(const Integer& t) {return *this = Modulo(t);}
/// \brief Division Assignment
/// \param t the other word
/// \return the result of <tt>*this / t</tt>
Integer& operator/=(word t) {return *this = DividedBy(t);}
/// \brief Remainder Assignment
/// \param t the other word
/// \return the result of <tt>*this % t</tt>
/// \sa a_times_b_mod_c() and a_exp_b_mod_c()
Integer& operator%=(word t) {return *this = Integer(POSITIVE, 0, Modulo(t));}
/// \brief Left-shift Assignment
/// \param n number of bits to shift
/// \return reference to this Integer
Integer& operator<<=(size_t n);
/// \brief Right-shift Assignment
/// \param n number of bits to shift
/// \return reference to this Integer
Integer& operator>>=(size_t n);
/// \brief Bitwise AND Assignment
/// \param t the other Integer
/// \return the result of *this & t
/// \details operator&=() performs a bitwise AND on *this. Missing bits are truncated
/// at the most significant bit positions, so the result is as small as the
/// smaller of the operands.
/// \details Internally, Crypto++ uses a sign-magnitude representation. The library
/// does not attempt to interpret bits, and the result is always POSITIVE. If needed,
/// the integer should be converted to a 2's compliment representation before performing
/// the operation.
/// \since Crypto++ 6.0
Integer& operator&=(const Integer& t);
/// \brief Bitwise OR Assignment
/// \param t the second Integer
/// \return the result of *this | t
/// \details operator|=() performs a bitwise OR on *this. Missing bits are shifted in
/// at the most significant bit positions, so the result is as large as the
/// larger of the operands.
/// \details Internally, Crypto++ uses a sign-magnitude representation. The library
/// does not attempt to interpret bits, and the result is always POSITIVE. If needed,
/// the integer should be converted to a 2's compliment representation before performing
/// the operation.
/// \since Crypto++ 6.0
Integer& operator|=(const Integer& t);
/// \brief Bitwise XOR Assignment
/// \param t the other Integer
/// \return the result of *this ^ t
/// \details operator^=() performs a bitwise XOR on *this. Missing bits are shifted
/// in at the most significant bit positions, so the result is as large as the
/// larger of the operands.
/// \details Internally, Crypto++ uses a sign-magnitude representation. The library
/// does not attempt to interpret bits, and the result is always POSITIVE. If needed,
/// the integer should be converted to a 2's compliment representation before performing
/// the operation.
/// \since Crypto++ 6.0
Integer& operator^=(const Integer& t);
/// \brief Set the n-th bit to value
/// \details 0-based numbering.
void SetBit(size_t n, bool value=1);
/// \brief Set the n-th byte to value
/// \details 0-based numbering.
void SetByte(size_t n, byte value);
/// \brief Reverse the Sign of the Integer
void Negate();
/// \brief Sets the Integer to positive
void SetPositive() {sign = POSITIVE;}
/// \brief Sets the Integer to negative
void SetNegative() {if (!!(*this)) sign = NEGATIVE;}
/// \brief Swaps this Integer with another Integer
void swap(Integer &a);
//@}
/// \name UNARY OPERATORS
//@{
/// \brief Negation
bool operator!() const;
/// \brief Addition
Integer operator+() const {return *this;}
/// \brief Subtraction
Integer operator-() const;
/// \brief Pre-increment
Integer& operator++();
/// \brief Pre-decrement
Integer& operator--();
/// \brief Post-increment
Integer operator++(int) {Integer temp = *this; ++*this; return temp;}
/// \brief Post-decrement
Integer operator--(int) {Integer temp = *this; --*this; return temp;}
//@}
/// \name BINARY OPERATORS
//@{
/// \brief Perform signed comparison
/// \param a the Integer to comapre
/// \retval -1 if <tt>*this < a</tt>
/// \retval 0 if <tt>*this = a</tt>
/// \retval 1 if <tt>*this > a</tt>
int Compare(const Integer& a) const;
/// \brief Addition
Integer Plus(const Integer &b) const;
/// \brief Subtraction
Integer Minus(const Integer &b) const;
/// \brief Multiplication
/// \sa a_times_b_mod_c() and a_exp_b_mod_c()
Integer Times(const Integer &b) const;
/// \brief Division
Integer DividedBy(const Integer &b) const;
/// \brief Remainder
/// \sa a_times_b_mod_c() and a_exp_b_mod_c()
Integer Modulo(const Integer &b) const;
/// \brief Division
Integer DividedBy(word b) const;
/// \brief Remainder
/// \sa a_times_b_mod_c() and a_exp_b_mod_c()
word Modulo(word b) const;
/// \brief Bitwise AND
/// \param t the other Integer
/// \return the result of <tt>*this & t</tt>
/// \details And() performs a bitwise AND on the operands. Missing bits are truncated
/// at the most significant bit positions, so the result is as small as the
/// smaller of the operands.
/// \details Internally, Crypto++ uses a sign-magnitude representation. The library
/// does not attempt to interpret bits, and the result is always POSITIVE. If needed,
/// the integer should be converted to a 2's compliment representation before performing
/// the operation.
/// \since Crypto++ 6.0
Integer And(const Integer& t) const;
/// \brief Bitwise OR
/// \param t the other Integer
/// \return the result of <tt>*this | t</tt>
/// \details Or() performs a bitwise OR on the operands. Missing bits are shifted in
/// at the most significant bit positions, so the result is as large as the
/// larger of the operands.
/// \details Internally, Crypto++ uses a sign-magnitude representation. The library
/// does not attempt to interpret bits, and the result is always POSITIVE. If needed,
/// the integer should be converted to a 2's compliment representation before performing
/// the operation.
/// \since Crypto++ 6.0
Integer Or(const Integer& t) const;
/// \brief Bitwise XOR
/// \param t the other Integer
/// \return the result of <tt>*this ^ t</tt>
/// \details Xor() performs a bitwise XOR on the operands. Missing bits are shifted in
/// at the most significant bit positions, so the result is as large as the
/// larger of the operands.
/// \details Internally, Crypto++ uses a sign-magnitude representation. The library
/// does not attempt to interpret bits, and the result is always POSITIVE. If needed,
/// the integer should be converted to a 2's compliment representation before performing
/// the operation.
/// \since Crypto++ 6.0
Integer Xor(const Integer& t) const;
/// \brief Right-shift
Integer operator>>(size_t n) const {return Integer(*this)>>=n;}
/// \brief Left-shift
Integer operator<<(size_t n) const {return Integer(*this)<<=n;}
//@}
/// \name OTHER ARITHMETIC FUNCTIONS
//@{
/// \brief Retrieve the absolute value of this integer
Integer AbsoluteValue() const;
/// \brief Add this integer to itself
Integer Doubled() const {return Plus(*this);}
/// \brief Multiply this integer by itself
/// \sa a_times_b_mod_c() and a_exp_b_mod_c()
Integer Squared() const {return Times(*this);}
/// \brief Extract square root
/// \details if negative return 0, else return floor of square root
Integer SquareRoot() const;
/// \brief Determine whether this integer is a perfect square
bool IsSquare() const;
/// \brief Determine if 1 or -1
/// \return true if this integer is 1 or -1, false otherwise
bool IsUnit() const;
/// \brief Calculate multiplicative inverse
/// \return MultiplicativeInverse inverse if 1 or -1, otherwise return 0.
Integer MultiplicativeInverse() const;
/// \brief Extended Division
/// \param r a reference for the remainder
/// \param q a reference for the quotient
/// \param a a reference to the dividend
/// \param d a reference to the divisor
/// \details Divide calculates r and q such that (a == d*q + r) && (0 <= r < abs(d)).
static void CRYPTOPP_API Divide(Integer &r, Integer &q, const Integer &a, const Integer &d);
/// \brief Extended Division
/// \param r a reference for the remainder
/// \param q a reference for the quotient
/// \param a a reference to the dividend
/// \param d a reference to the divisor
/// \details Divide calculates r and q such that (a == d*q + r) && (0 <= r < abs(d)).
/// This overload uses a faster division algorithm because the divisor is short.
static void CRYPTOPP_API Divide(word &r, Integer &q, const Integer &a, word d);
/// \brief Extended Division
/// \param r a reference for the remainder
/// \param q a reference for the quotient
/// \param a a reference to the dividend
/// \param n a reference to the divisor
/// \details DivideByPowerOf2 calculates r and q such that (a == d*q + r) && (0 <= r < abs(d)).
/// It returns same result as Divide(r, q, a, Power2(n)), but faster.
/// This overload uses a faster division algorithm because the divisor is a power of 2.
static void CRYPTOPP_API DivideByPowerOf2(Integer &r, Integer &q, const Integer &a, unsigned int n);
/// \brief Calculate greatest common divisor
/// \param a a reference to the first number
/// \param n a reference to the secind number
/// \return the greatest common divisor <tt>a</tt> and <tt>n</tt>.
static Integer CRYPTOPP_API Gcd(const Integer &a, const Integer &n);
/// \brief Calculate multiplicative inverse
/// \param n a reference to the modulus
/// \return an Integer <tt>*this % n</tt>.
/// \details InverseMod returns the multiplicative inverse of the Integer <tt>*this</tt>
/// modulo the Integer <tt>n</tt>. If no Integer exists then Integer 0 is returned.
/// \sa a_times_b_mod_c() and a_exp_b_mod_c()
Integer InverseMod(const Integer &n) const;
/// \brief Calculate multiplicative inverse
/// \param n the modulus
/// \return a word <tt>*this % n</tt>.
/// \details InverseMod returns the multiplicative inverse of the Integer <tt>*this</tt>
/// modulo the word <tt>n</tt>. If no Integer exists then word 0 is returned.
/// \sa a_times_b_mod_c() and a_exp_b_mod_c()
word InverseMod(word n) const;
//@}
/// \name INPUT/OUTPUT
//@{
/// \brief Extraction operator
/// \param in a reference to a std::istream
/// \param a a reference to an Integer
/// \return a reference to a std::istream reference
friend CRYPTOPP_DLL std::istream& CRYPTOPP_API operator>>(std::istream& in, Integer &a);
/// \brief Insertion operator
/// \param out a reference to a std::ostream
/// \param a a constant reference to an Integer
/// \return a reference to a std::ostream reference
/// \details The output integer responds to std::hex, std::oct, std::hex, std::upper and
/// std::lower. The output includes the suffix \a h (for hex), \a . (\a dot, for dec)
/// and \a o (for octal). There is currently no way to suppress the suffix.
/// \details If you want to print an Integer without the suffix or using an arbitrary base, then
/// use IntToString<Integer>().
/// \sa IntToString<Integer>
friend CRYPTOPP_DLL std::ostream& CRYPTOPP_API operator<<(std::ostream& out, const Integer &a);
//@}
/// \brief Modular multiplication
/// \param x a reference to the first term
/// \param y a reference to the second term
/// \param m a reference to the modulus
/// \return an Integer <tt>(a * b) % m</tt>.
CRYPTOPP_DLL friend Integer CRYPTOPP_API a_times_b_mod_c(const Integer &x, const Integer& y, const Integer& m);
/// \brief Modular exponentiation
/// \param x a reference to the base
/// \param e a reference to the exponent
/// \param m a reference to the modulus
/// \return an Integer <tt>(a ^ b) % m</tt>.
CRYPTOPP_DLL friend Integer CRYPTOPP_API a_exp_b_mod_c(const Integer &x, const Integer& e, const Integer& m);
protected:
// http://github.com/weidai11/cryptopp/issues/602
Integer InverseModNext(const Integer &n) const;
private:
Integer(word value, size_t length);
int PositiveCompare(const Integer &t) const;
IntegerSecBlock reg;
Sign sign;
#ifndef CRYPTOPP_DOXYGEN_PROCESSING
friend class ModularArithmetic;
friend class MontgomeryRepresentation;
friend class HalfMontgomeryRepresentation;
friend void PositiveAdd(Integer &sum, const Integer &a, const Integer &b);
friend void PositiveSubtract(Integer &diff, const Integer &a, const Integer &b);
friend void PositiveMultiply(Integer &product, const Integer &a, const Integer &b);
friend void PositiveDivide(Integer &remainder, Integer &quotient, const Integer &dividend, const Integer &divisor);
#endif
};
/// \brief Comparison
inline bool operator==(const CryptoPP::Integer& a, const CryptoPP::Integer& b) {return a.Compare(b)==0;}
/// \brief Comparison
inline bool operator!=(const CryptoPP::Integer& a, const CryptoPP::Integer& b) {return a.Compare(b)!=0;}
/// \brief Comparison
inline bool operator> (const CryptoPP::Integer& a, const CryptoPP::Integer& b) {return a.Compare(b)> 0;}
/// \brief Comparison
inline bool operator>=(const CryptoPP::Integer& a, const CryptoPP::Integer& b) {return a.Compare(b)>=0;}
/// \brief Comparison
inline bool operator< (const CryptoPP::Integer& a, const CryptoPP::Integer& b) {return a.Compare(b)< 0;}
/// \brief Comparison
inline bool operator<=(const CryptoPP::Integer& a, const CryptoPP::Integer& b) {return a.Compare(b)<=0;}
/// \brief Addition
inline CryptoPP::Integer operator+(const CryptoPP::Integer &a, const CryptoPP::Integer &b) {return a.Plus(b);}
/// \brief Subtraction
inline CryptoPP::Integer operator-(const CryptoPP::Integer &a, const CryptoPP::Integer &b) {return a.Minus(b);}
/// \brief Multiplication
/// \sa a_times_b_mod_c() and a_exp_b_mod_c()
inline CryptoPP::Integer operator*(const CryptoPP::Integer &a, const CryptoPP::Integer &b) {return a.Times(b);}
/// \brief Division
inline CryptoPP::Integer operator/(const CryptoPP::Integer &a, const CryptoPP::Integer &b) {return a.DividedBy(b);}
/// \brief Remainder
/// \sa a_times_b_mod_c() and a_exp_b_mod_c()
inline CryptoPP::Integer operator%(const CryptoPP::Integer &a, const CryptoPP::Integer &b) {return a.Modulo(b);}
/// \brief Division
inline CryptoPP::Integer operator/(const CryptoPP::Integer &a, CryptoPP::word b) {return a.DividedBy(b);}
/// \brief Remainder
/// \sa a_times_b_mod_c() and a_exp_b_mod_c()
inline CryptoPP::word operator%(const CryptoPP::Integer &a, CryptoPP::word b) {return a.Modulo(b);}
/// \brief Bitwise AND
/// \param a the first Integer
/// \param b the second Integer
/// \return the result of a & b
/// \details operator&() performs a bitwise AND on the operands. Missing bits are truncated
/// at the most significant bit positions, so the result is as small as the
/// smaller of the operands.
/// \details Internally, Crypto++ uses a sign-magnitude representation. The library
/// does not attempt to interpret bits, and the result is always POSITIVE. If needed,
/// the integer should be converted to a 2's compliment representation before performing
/// the operation.
/// \since Crypto++ 6.0
inline CryptoPP::Integer operator&(const CryptoPP::Integer &a, const CryptoPP::Integer &b) {return a.And(b);}
/// \brief Bitwise OR
/// \param a the first Integer
/// \param b the second Integer
/// \return the result of a | b
/// \details operator|() performs a bitwise OR on the operands. Missing bits are shifted in
/// at the most significant bit positions, so the result is as large as the
/// larger of the operands.
/// \details Internally, Crypto++ uses a sign-magnitude representation. The library
/// does not attempt to interpret bits, and the result is always POSITIVE. If needed,
/// the integer should be converted to a 2's compliment representation before performing
/// the operation.
/// \since Crypto++ 6.0
inline CryptoPP::Integer operator|(const CryptoPP::Integer &a, const CryptoPP::Integer &b) {return a.Or(b);}
/// \brief Bitwise XOR
/// \param a the first Integer
/// \param b the second Integer
/// \return the result of a ^ b
/// \details operator^() performs a bitwise XOR on the operands. Missing bits are shifted
/// in at the most significant bit positions, so the result is as large as the
/// larger of the operands.
/// \details Internally, Crypto++ uses a sign-magnitude representation. The library
/// does not attempt to interpret bits, and the result is always POSITIVE. If needed,
/// the integer should be converted to a 2's compliment representation before performing
/// the operation.
/// \since Crypto++ 6.0
inline CryptoPP::Integer operator^(const CryptoPP::Integer &a, const CryptoPP::Integer &b) {return a.Xor(b);}
NAMESPACE_END
#ifndef __BORLANDC__
NAMESPACE_BEGIN(std)
inline void swap(CryptoPP::Integer &a, CryptoPP::Integer &b)
{
a.swap(b);
}
NAMESPACE_END
#endif
#endif

669
wasm_src/longconsts.h Normal file

File diff suppressed because one or more lines are too long

393
wasm_src/misc.cpp Normal file
View File

@ -0,0 +1,393 @@
// misc.cpp - originally written and placed in the public domain by Wei Dai
#include "pch.h"
#include "config.h"
#if CRYPTOPP_MSC_VERSION
# pragma warning(disable: 4189)
# if (CRYPTOPP_MSC_VERSION >= 1400)
# pragma warning(disable: 6237)
# endif
#endif
#ifndef CRYPTOPP_IMPORTS
#include "misc.h"
#include "words.h"
#include "stdcpp.h"
#include "integer.h"
#include "secblock.h"
// Hack for OpenBSD and GCC 4.2.1. I believe they are stuck at 4.2.1 due to GPLv3.
#if defined(__OpenBSD__)
# if defined (CRYPTOPP_GCC_VERSION) && (CRYPTOPP_GCC_VERSION < 43000)
# undef CRYPTOPP_DISABLE_ASM
# define CRYPTOPP_DISABLE_ASM 1
# endif
#endif
#ifndef CRYPTOPP_DISABLE_ASM
# if defined(__SSE2__)
# include <emmintrin.h>
# endif
# if defined(__AVX__)
# include <immintrin.h>
# endif
# if defined(__aarch64__) || defined(__aarch32__) || defined(_M_ARM64)
# if defined(CRYPTOPP_ARM_NEON_HEADER)
# include <arm_neon.h>
# endif
# endif
#endif // CRYPTOPP_DISABLE_ASM
NAMESPACE_BEGIN(CryptoPP)
byte* BytePtr(SecByteBlock& str)
{
// Caller wants a writeable pointer
CRYPTOPP_ASSERT(str.empty() == false);
if (str.empty())
return NULLPTR;
return reinterpret_cast<byte*>(str.data());
}
const byte* ConstBytePtr(const SecByteBlock& str)
{
if (str.empty())
return NULLPTR;
return reinterpret_cast<const byte*>(str.data());
}
size_t BytePtrSize(const SecByteBlock& str)
{
return str.size();
}
// xorbuf simplified at https://github.com/weidai11/cryptopp/issues/1020
void xorbuf(byte *buf, const byte *mask, size_t count)
{
CRYPTOPP_ASSERT(buf != NULLPTR);
CRYPTOPP_ASSERT(mask != NULLPTR);
CRYPTOPP_ASSERT(count > 0);
#ifndef CRYPTOPP_DISABLE_ASM
# if defined(__AVX__)
while (count >= 32)
{
__m256i b = _mm256_loadu_si256(reinterpret_cast<const __m256i*>(buf));
__m256i m = _mm256_loadu_si256(reinterpret_cast<const __m256i*>(mask));
_mm256_storeu_si256(reinterpret_cast<__m256i*>(buf), _mm256_castps_si256(
_mm256_xor_ps(_mm256_castsi256_ps(b), _mm256_castsi256_ps(m))));
buf += 32; mask += 32; count -= 32;
}
// https://software.intel.com/en-us/articles/avoiding-avx-sse-transition-penalties
_mm256_zeroupper();
# endif
# if defined(__SSE2__)
while (count >= 16)
{
__m128i b = _mm_loadu_si128(reinterpret_cast<const __m128i*>(buf));
__m128i m = _mm_loadu_si128(reinterpret_cast<const __m128i*>(mask));
_mm_storeu_si128(reinterpret_cast<__m128i*>(buf), _mm_castps_si128(
_mm_xor_ps(_mm_castsi128_ps(b), _mm_castsi128_ps(m))));
buf += 16; mask += 16; count -= 16;
}
# endif
# if defined(__aarch64__) || defined(__aarch32__) || defined(_M_ARM64)
while (count >= 16)
{
vst1q_u8(buf, veorq_u8(vld1q_u8(buf), vld1q_u8(mask)));
buf += 16; mask += 16; count -= 16;
}
# endif
#endif // CRYPTOPP_DISABLE_ASM
#if CRYPTOPP_BOOL_PPC32 || CRYPTOPP_BOOL_PPC64
// word64 and stride of 8 slows things down on x86_64.
// word64 and stride of 8 makes no difference on ARM.
// word64 and stride of 16 benefits PowerPC.
while (count >= 16)
{
word64 r[2], b[2], m[2];
memcpy(&b, buf, 16); memcpy(&m, mask, 16);
r[0] = b[0] ^ m[0];
r[1] = b[1] ^ m[1];
memcpy(buf, &r, 16);
buf += 16; mask += 16; count -= 16;
}
#endif
// One of the arch specific xor's may have cleared the request
if (count == 0) return;
while (count >= 4)
{
word32 r, b, m;
memcpy(&b, buf, 4); memcpy(&m, mask, 4);
r = b ^ m;
memcpy(buf, &r, 4);
buf += 4; mask += 4; count -= 4;
}
for (size_t i=0; i<count; i++)
buf[i] ^= mask[i];
}
// xorbuf simplified at https://github.com/weidai11/cryptopp/issues/1020
void xorbuf(byte *output, const byte *input, const byte *mask, size_t count)
{
CRYPTOPP_ASSERT(output != NULLPTR);
CRYPTOPP_ASSERT(input != NULLPTR);
CRYPTOPP_ASSERT(count > 0);
#ifndef CRYPTOPP_DISABLE_ASM
# if defined(__AVX__)
while (count >= 32)
{
__m256i b = _mm256_loadu_si256(reinterpret_cast<const __m256i*>(input));
__m256i m = _mm256_loadu_si256(reinterpret_cast<const __m256i*>(mask));
_mm256_storeu_si256(reinterpret_cast<__m256i*>(output), _mm256_castps_si256(
_mm256_xor_ps(_mm256_castsi256_ps(b), _mm256_castsi256_ps(m))));
output += 32; input += 32; mask += 32; count -= 32;
}
// https://software.intel.com/en-us/articles/avoiding-avx-sse-transition-penalties
_mm256_zeroupper();
# endif
# if defined(__SSE2__)
while (count >= 16)
{
__m128i b = _mm_loadu_si128(reinterpret_cast<const __m128i*>(input));
__m128i m = _mm_loadu_si128(reinterpret_cast<const __m128i*>(mask));
_mm_storeu_si128(reinterpret_cast<__m128i*>(output), _mm_castps_si128(
_mm_xor_ps(_mm_castsi128_ps(b), _mm_castsi128_ps(m))));
output += 16; input += 16; mask += 16; count -= 16;
}
# endif
# if defined(__aarch64__) || defined(__aarch32__) || defined(_M_ARM64)
while (count >= 16)
{
vst1q_u8(output, veorq_u8(vld1q_u8(input), vld1q_u8(mask)));
output += 16; input += 16; mask += 16; count -= 16;
}
# endif
#endif // CRYPTOPP_DISABLE_ASM
#if CRYPTOPP_BOOL_PPC32 || CRYPTOPP_BOOL_PPC64
// word64 and stride of 8 slows things down on x86_64.
// word64 and stride of 8 makes no difference on ARM.
// word64 and stride of 16 benefits PowerPC.
while (count >= 16)
{
word64 b[2], m[2], r[2];
memcpy(&b, input, 16); memcpy(&m, mask, 16);
r[0] = b[0] ^ m[0];
r[1] = b[1] ^ m[1];
memcpy(output, &r, 16);
output += 16; input += 16; mask += 16; count -= 16;
}
#endif
// One of the arch specific xor's may have cleared the request
if (count == 0) return;
while (count >= 4)
{
word32 b, m, r;
memcpy(&b, input, 4); memcpy(&m, mask, 4);
r = b ^ m;
memcpy(output, &r, 4);
output += 4; input += 4; mask += 4; count -= 4;
}
for (size_t i=0; i<count; i++)
output[i] = input[i] ^ mask[i];
}
// VerifyBufsEqual simplified at https://github.com/weidai11/cryptopp/issues/1020
bool VerifyBufsEqual(const byte *buf, const byte *mask, size_t count)
{
CRYPTOPP_ASSERT(buf != NULLPTR);
CRYPTOPP_ASSERT(mask != NULLPTR);
// CRYPTOPP_ASSERT(count > 0);
#if CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_ARM64 || CRYPTOPP_BOOL_PPC64 || CRYPTOPP_BOOL_MIPS64 || CRYPTOPP_BOOL_SPARC64
word64 acc64 = 0;
while (count >= 8)
{
word64 b, m;
memcpy(&b, buf, 8); memcpy(&m, mask, 8);
acc64 |= b ^ m;
buf += 8; mask += 8; count -= 8;
}
word32 acc8 = (acc64 >> 32) | (acc64 & 0xffffffff);
acc8 = static_cast<byte>(acc8) | static_cast<byte>(acc8 >> 8) |
static_cast<byte>(acc8 >> 16) | static_cast<byte>(acc8 >> 24);
#else
word32 acc32 = 0;
while (count >= 4)
{
word32 b, m;
memcpy(&b, buf, 4); memcpy(&m, mask, 4);
acc32 |= b ^ m;
buf += 4; mask += 4; count -= 4;
}
word32 acc8 = acc32;
acc8 = static_cast<byte>(acc8) | static_cast<byte>(acc8 >> 8) |
static_cast<byte>(acc8 >> 16) | static_cast<byte>(acc8 >> 24);
#endif
for (size_t i=0; i<count; i++)
acc8 |= buf[i] ^ mask[i];
// word32 resuts in this tail code on x86:
// 33a: 85 c0 test %eax, %eax
// 33c: 0f 94 c0 sete %al
// 33f: c3 ret
return acc8 == 0;
}
std::string StringNarrow(const wchar_t *str, bool throwOnError)
{
CRYPTOPP_ASSERT(str);
std::string result;
// Safer functions on Windows for C&A, https://github.com/weidai11/cryptopp/issues/55
#if (CRYPTOPP_MSC_VERSION >= 1400)
size_t len=0, size=0;
errno_t err = 0;
//const wchar_t* ptr = str;
//while (*ptr++) len++;
len = wcslen(str)+1;
err = wcstombs_s(&size, NULLPTR, 0, str, len*sizeof(wchar_t));
CRYPTOPP_ASSERT(err == 0);
if (err != 0)
{
if (throwOnError)
throw InvalidArgument("StringNarrow: wcstombs_s() failed with error " + IntToString(err));
else
return std::string();
}
result.resize(size);
err = wcstombs_s(&size, &result[0], size, str, len*sizeof(wchar_t));
CRYPTOPP_ASSERT(err == 0);
if (err != 0)
{
if (throwOnError)
throw InvalidArgument("StringNarrow: wcstombs_s() failed with error " + IntToString(err));
else
return std::string();
}
// The safe routine's size includes the NULL.
if (!result.empty() && result[size - 1] == '\0')
result.erase(size - 1);
#else
size_t size = wcstombs(NULLPTR, str, 0);
CRYPTOPP_ASSERT(size != (size_t)-1);
if (size == (size_t)-1)
{
if (throwOnError)
throw InvalidArgument("StringNarrow: wcstombs() failed");
else
return std::string();
}
result.resize(size);
size = wcstombs(&result[0], str, size);
CRYPTOPP_ASSERT(size != (size_t)-1);
if (size == (size_t)-1)
{
if (throwOnError)
throw InvalidArgument("StringNarrow: wcstombs() failed");
else
return std::string();
}
#endif
return result;
}
std::wstring StringWiden(const char *str, bool throwOnError)
{
CRYPTOPP_ASSERT(str);
std::wstring result;
// Safer functions on Windows for C&A, https://github.com/weidai11/cryptopp/issues/55
#if (CRYPTOPP_MSC_VERSION >= 1400)
size_t len=0, size=0;
errno_t err = 0;
//const char* ptr = str;
//while (*ptr++) len++;
len = std::strlen(str)+1;
err = mbstowcs_s(&size, NULLPTR, 0, str, len);
CRYPTOPP_ASSERT(err == 0);
if (err != 0)
{
if (throwOnError)
throw InvalidArgument("StringWiden: wcstombs_s() failed with error " + IntToString(err));
else
return std::wstring();
}
result.resize(size);
err = mbstowcs_s(&size, &result[0], size, str, len);
CRYPTOPP_ASSERT(err == 0);
if (err != 0)
{
if (throwOnError)
throw InvalidArgument("StringWiden: wcstombs_s() failed with error " + IntToString(err));
else
return std::wstring();
}
// The safe routine's size includes the NULL.
if (!result.empty() && result[size - 1] == '\0')
result.erase(size - 1);
#else
size_t size = mbstowcs(NULLPTR, str, 0);
CRYPTOPP_ASSERT(size != (size_t)-1);
if (size == (size_t)-1)
{
if (throwOnError)
throw InvalidArgument("StringWiden: mbstowcs() failed");
else
return std::wstring();
}
result.resize(size);
size = mbstowcs(&result[0], str, size);
CRYPTOPP_ASSERT(size != (size_t)-1);
if (size == (size_t)-1)
{
if (throwOnError)
throw InvalidArgument("StringWiden: mbstowcs() failed");
else
return std::wstring();
}
#endif
return result;
}
NAMESPACE_END
#endif

2723
wasm_src/misc.h Normal file

File diff suppressed because it is too large Load Diff

315
wasm_src/modarith.h Normal file
View File

@ -0,0 +1,315 @@
// modarith.h - originally written and placed in the public domain by Wei Dai
/// \file modarith.h
/// \brief Class file for performing modular arithmetic.
#ifndef CRYPTOPP_MODARITH_H
#define CRYPTOPP_MODARITH_H
// implementations are in integer.cpp
#include "cryptlib.h"
#include "integer.h"
#include "algebra.h"
#include "secblock.h"
#include "misc.h"
#if CRYPTOPP_MSC_VERSION
# pragma warning(push)
# pragma warning(disable: 4231 4275)
#endif
NAMESPACE_BEGIN(CryptoPP)
template class AbstractGroup<Integer>;
template class AbstractRing<Integer>;
template class AbstractEuclideanDomain<Integer>;
/// \brief Ring of congruence classes modulo n
/// \details This implementation represents each congruence class as
/// the smallest non-negative integer in that class.
/// \details <tt>const Element&</tt> returned by member functions are
/// references to internal data members. Since each object may have
/// only one such data member for holding results, you should use the
/// class like this:
/// <pre> abcd = group.Add(a, group.Add(b, group.Add(c,d));</pre>
/// The following code will produce <i>incorrect</i> results:
/// <pre> abcd = group.Add(group.Add(a,b), group.Add(c,d));</pre>
/// \details If a ModularArithmetic() is copied or assigned the modulus
/// is copied, but not the internal data members. The internal data
/// members are undefined after copy or assignment.
/// \sa <A HREF="https://cryptopp.com/wiki/Integer">Integer</A> on the
/// Crypto++ wiki.
class CRYPTOPP_DLL ModularArithmetic : public AbstractRing<Integer>
{
public:
typedef int RandomizationParameter;
typedef Integer Element;
virtual ~ModularArithmetic() {}
/// \brief Construct a ModularArithmetic
/// \param modulus congruence class modulus
ModularArithmetic(const Integer &modulus = Integer::One())
: m_modulus(modulus), m_result(static_cast<word>(0), modulus.reg.size()) {}
/// \brief Copy construct a ModularArithmetic
/// \param ma other ModularArithmetic
ModularArithmetic(const ModularArithmetic &ma)
: AbstractRing<Integer>(ma), m_modulus(ma.m_modulus), m_result(static_cast<word>(0), m_modulus.reg.size()) {}
/// \brief Assign a ModularArithmetic
/// \param ma other ModularArithmetic
ModularArithmetic& operator=(const ModularArithmetic &ma) {
if (this != &ma)
{
m_modulus = ma.m_modulus;
m_result = Integer(static_cast<word>(0), m_modulus.reg.size());
}
return *this;
}
/// \brief Clone a ModularArithmetic
/// \return pointer to a new ModularArithmetic
/// \details Clone effectively copy constructs a new ModularArithmetic. The caller is
/// responsible for deleting the pointer returned from this method.
virtual ModularArithmetic * Clone() const {return new ModularArithmetic(*this);}
/// \brief Retrieves the modulus
/// \return the modulus
const Integer& GetModulus() const {return m_modulus;}
/// \brief Sets the modulus
/// \param newModulus the new modulus
void SetModulus(const Integer &newModulus)
{m_modulus = newModulus; m_result.reg.resize(m_modulus.reg.size());}
/// \brief Retrieves the representation
/// \return true if the if the modulus is in Montgomery form for multiplication, false otherwise
virtual bool IsMontgomeryRepresentation() const {return false;}
/// \brief Reduces an element in the congruence class
/// \param a element to convert
/// \return the reduced element
/// \details ConvertIn is useful for derived classes, like MontgomeryRepresentation, which
/// must convert between representations.
virtual Integer ConvertIn(const Integer &a) const
{return a%m_modulus;}
/// \brief Reduces an element in the congruence class
/// \param a element to convert
/// \return the reduced element
/// \details ConvertOut is useful for derived classes, like MontgomeryRepresentation, which
/// must convert between representations.
virtual Integer ConvertOut(const Integer &a) const
{return a;}
/// \brief Divides an element by 2
/// \param a element to convert
const Integer& Half(const Integer &a) const;
/// \brief Compare two elements for equality
/// \param a first element
/// \param b second element
/// \return true if the elements are equal, false otherwise
/// \details Equal() tests the elements for equality using <tt>a==b</tt>
bool Equal(const Integer &a, const Integer &b) const
{return a==b;}
/// \brief Provides the Identity element
/// \return the Identity element
const Integer& Identity() const
{return Integer::Zero();}
/// \brief Adds elements in the ring
/// \param a first element
/// \param b second element
/// \return the sum of <tt>a</tt> and <tt>b</tt>
const Integer& Add(const Integer &a, const Integer &b) const;
/// \brief TODO
/// \param a first element
/// \param b second element
/// \return TODO
Integer& Accumulate(Integer &a, const Integer &b) const;
/// \brief Inverts the element in the ring
/// \param a first element
/// \return the inverse of the element
const Integer& Inverse(const Integer &a) const;
/// \brief Subtracts elements in the ring
/// \param a first element
/// \param b second element
/// \return the difference of <tt>a</tt> and <tt>b</tt>. The element <tt>a</tt> must provide a Subtract member function.
const Integer& Subtract(const Integer &a, const Integer &b) const;
/// \brief TODO
/// \param a first element
/// \param b second element
/// \return TODO
Integer& Reduce(Integer &a, const Integer &b) const;
/// \brief Doubles an element in the ring
/// \param a the element
/// \return the element doubled
/// \details Double returns <tt>Add(a, a)</tt>. The element <tt>a</tt> must provide an Add member function.
const Integer& Double(const Integer &a) const
{return Add(a, a);}
/// \brief Retrieves the multiplicative identity
/// \return the multiplicative identity
/// \details the base class implementations returns 1.
const Integer& MultiplicativeIdentity() const
{return Integer::One();}
/// \brief Multiplies elements in the ring
/// \param a the multiplicand
/// \param b the multiplier
/// \return the product of a and b
/// \details Multiply returns <tt>a*b\%n</tt>.
const Integer& Multiply(const Integer &a, const Integer &b) const
{return m_result1 = a*b%m_modulus;}
/// \brief Square an element in the ring
/// \param a the element
/// \return the element squared
/// \details Square returns <tt>a*a\%n</tt>. The element <tt>a</tt> must provide a Square member function.
const Integer& Square(const Integer &a) const
{return m_result1 = a.Squared()%m_modulus;}
/// \brief Determines whether an element is a unit in the ring
/// \param a the element
/// \return true if the element is a unit after reduction, false otherwise.
bool IsUnit(const Integer &a) const
{return Integer::Gcd(a, m_modulus).IsUnit();}
/// \brief Calculate the multiplicative inverse of an element in the ring
/// \param a the element
/// \details MultiplicativeInverse returns <tt>a<sup>-1</sup>\%n</tt>. The element <tt>a</tt> must
/// provide a InverseMod member function.
const Integer& MultiplicativeInverse(const Integer &a) const
{return m_result1 = a.InverseMod(m_modulus);}
/// \brief Divides elements in the ring
/// \param a the dividend
/// \param b the divisor
/// \return the quotient
/// \details Divide returns <tt>a*b<sup>-1</sup>\%n</tt>.
const Integer& Divide(const Integer &a, const Integer &b) const
{return Multiply(a, MultiplicativeInverse(b));}
/// \brief TODO
/// \param x first element
/// \param e1 first exponent
/// \param y second element
/// \param e2 second exponent
/// \return TODO
Integer CascadeExponentiate(const Integer &x, const Integer &e1, const Integer &y, const Integer &e2) const;
/// \brief Exponentiates a base to multiple exponents in the ring
/// \param results an array of Elements
/// \param base the base to raise to the exponents
/// \param exponents an array of exponents
/// \param exponentsCount the number of exponents in the array
/// \details SimultaneousExponentiate() raises the base to each exponent in the exponents array and stores the
/// result at the respective position in the results array.
/// \details SimultaneousExponentiate() must be implemented in a derived class.
/// \pre <tt>COUNTOF(results) == exponentsCount</tt>
/// \pre <tt>COUNTOF(exponents) == exponentsCount</tt>
void SimultaneousExponentiate(Element *results, const Element &base, const Integer *exponents, unsigned int exponentsCount) const;
/// \brief Provides the maximum bit size of an element in the ring
/// \return maximum bit size of an element
unsigned int MaxElementBitLength() const
{return (m_modulus-1).BitCount();}
/// \brief Provides the maximum byte size of an element in the ring
/// \return maximum byte size of an element
unsigned int MaxElementByteLength() const
{return (m_modulus-1).ByteCount();}
/// \brief Compares two ModularArithmetic for equality
/// \param rhs other ModularArithmetic
/// \return true if this is equal to the other, false otherwise
/// \details The operator tests for equality using <tt>this.m_modulus == rhs.m_modulus</tt>.
bool operator==(const ModularArithmetic &rhs) const
{return m_modulus == rhs.m_modulus;}
static const RandomizationParameter DefaultRandomizationParameter;
private:
// TODO: Clang on OS X needs a real operator=.
// Squash warning on missing assignment operator.
// ModularArithmetic& operator=(const ModularArithmetic &ma);
protected:
Integer m_modulus;
mutable Integer m_result, m_result1;
};
// const ModularArithmetic::RandomizationParameter ModularArithmetic::DefaultRandomizationParameter = 0 ;
/// \brief Performs modular arithmetic in Montgomery representation for increased speed
/// \details The Montgomery representation represents each congruence class <tt>[a]</tt> as
/// <tt>a*r\%n</tt>, where <tt>r</tt> is a convenient power of 2.
/// \details <tt>const Element&</tt> returned by member functions are references to
/// internal data members. Since each object may have only one such data member for holding
/// results, the following code will produce incorrect results:
/// <pre> abcd = group.Add(group.Add(a,b), group.Add(c,d));</pre>
/// But this should be fine:
/// <pre> abcd = group.Add(a, group.Add(b, group.Add(c,d));</pre>
class CRYPTOPP_DLL MontgomeryRepresentation : public ModularArithmetic
{
public:
virtual ~MontgomeryRepresentation() {}
/// \brief Construct a MontgomeryRepresentation
/// \param modulus congruence class modulus
/// \note The modulus must be odd.
MontgomeryRepresentation(const Integer &modulus);
/// \brief Clone a MontgomeryRepresentation
/// \return pointer to a new MontgomeryRepresentation
/// \details Clone effectively copy constructs a new MontgomeryRepresentation. The caller is
/// responsible for deleting the pointer returned from this method.
virtual ModularArithmetic * Clone() const {return new MontgomeryRepresentation(*this);}
bool IsMontgomeryRepresentation() const {return true;}
Integer ConvertIn(const Integer &a) const
{return (a<<(WORD_BITS*m_modulus.reg.size()))%m_modulus;}
Integer ConvertOut(const Integer &a) const;
const Integer& MultiplicativeIdentity() const
{return m_result1 = Integer::Power2(WORD_BITS*m_modulus.reg.size())%m_modulus;}
const Integer& Multiply(const Integer &a, const Integer &b) const;
const Integer& Square(const Integer &a) const;
const Integer& MultiplicativeInverse(const Integer &a) const;
Integer CascadeExponentiate(const Integer &x, const Integer &e1, const Integer &y, const Integer &e2) const
{return AbstractRing<Integer>::CascadeExponentiate(x, e1, y, e2);}
void SimultaneousExponentiate(Element *results, const Element &base, const Integer *exponents, unsigned int exponentsCount) const
{AbstractRing<Integer>::SimultaneousExponentiate(results, base, exponents, exponentsCount);}
private:
Integer m_u;
mutable IntegerSecBlock m_workspace;
};
NAMESPACE_END
#if CRYPTOPP_MSC_VERSION
# pragma warning(pop)
#endif
#endif

317
wasm_src/nbtheory.h Normal file
View File

@ -0,0 +1,317 @@
// nbtheory.h - originally written and placed in the public domain by Wei Dai
/// \file nbtheory.h
/// \brief Classes and functions for number theoretic operations
#ifndef CRYPTOPP_NBTHEORY_H
#define CRYPTOPP_NBTHEORY_H
#include "cryptlib.h"
#include "integer.h"
#include "algparam.h"
NAMESPACE_BEGIN(CryptoPP)
/// \brief The Small Prime table
/// \details GetPrimeTable obtains pointer to small prime table and provides the size of the table.
CRYPTOPP_DLL const word16 * CRYPTOPP_API GetPrimeTable(unsigned int &size);
// ************ primality testing ****************
/// \brief Generates a provable prime
/// \param rng a RandomNumberGenerator to produce random material
/// \param bits the number of bits in the prime number
/// \return Integer() meeting Maurer's tests for primality
CRYPTOPP_DLL Integer CRYPTOPP_API MaurerProvablePrime(RandomNumberGenerator &rng, unsigned int bits);
/// \brief Generates a provable prime
/// \param rng a RandomNumberGenerator to produce random material
/// \param bits the number of bits in the prime number
/// \return Integer() meeting Mihailescu's tests for primality
/// \details Mihailescu's methods performs a search using algorithmic progressions.
CRYPTOPP_DLL Integer CRYPTOPP_API MihailescuProvablePrime(RandomNumberGenerator &rng, unsigned int bits);
/// \brief Tests whether a number is a small prime
/// \param p a candidate prime to test
/// \return true if p is a small prime, false otherwise
/// \details Internally, the library maintains a table of the first 32719 prime numbers
/// in sorted order. IsSmallPrime searches the table and returns true if p is
/// in the table.
CRYPTOPP_DLL bool CRYPTOPP_API IsSmallPrime(const Integer &p);
/// \brief Tests whether a number is divisible by a small prime
/// \return true if p is divisible by some prime less than bound.
/// \details TrialDivision() returns <tt>true</tt> if <tt>p</tt> is divisible by some prime less
/// than <tt>bound</tt>. <tt>bound</tt> should not be greater than the largest entry in the
/// prime table, which is 32719.
CRYPTOPP_DLL bool CRYPTOPP_API TrialDivision(const Integer &p, unsigned bound);
/// \brief Tests whether a number is divisible by a small prime
/// \return true if p is NOT divisible by small primes.
/// \details SmallDivisorsTest() returns <tt>true</tt> if <tt>p</tt> is NOT divisible by some
/// prime less than 32719.
CRYPTOPP_DLL bool CRYPTOPP_API SmallDivisorsTest(const Integer &p);
/// \brief Determine if a number is probably prime
/// \param n the number to test
/// \param b the base to exponentiate
/// \return true if the number n is probably prime, false otherwise.
/// \details IsFermatProbablePrime raises <tt>b</tt> to the <tt>n-1</tt> power and checks if
/// the result is congruent to 1 modulo <tt>n</tt>.
/// \details These is no reason to use IsFermatProbablePrime, use IsStrongProbablePrime or
/// IsStrongLucasProbablePrime instead.
/// \sa IsStrongProbablePrime, IsStrongLucasProbablePrime
CRYPTOPP_DLL bool CRYPTOPP_API IsFermatProbablePrime(const Integer &n, const Integer &b);
/// \brief Determine if a number is probably prime
/// \param n the number to test
/// \return true if the number n is probably prime, false otherwise.
/// \details These is no reason to use IsLucasProbablePrime, use IsStrongProbablePrime or
/// IsStrongLucasProbablePrime instead.
/// \sa IsStrongProbablePrime, IsStrongLucasProbablePrime
CRYPTOPP_DLL bool CRYPTOPP_API IsLucasProbablePrime(const Integer &n);
/// \brief Determine if a number is probably prime
/// \param n the number to test
/// \param b the base to exponentiate
/// \return true if the number n is probably prime, false otherwise.
CRYPTOPP_DLL bool CRYPTOPP_API IsStrongProbablePrime(const Integer &n, const Integer &b);
/// \brief Determine if a number is probably prime
/// \param n the number to test
/// \return true if the number n is probably prime, false otherwise.
CRYPTOPP_DLL bool CRYPTOPP_API IsStrongLucasProbablePrime(const Integer &n);
/// \brief Determine if a number is probably prime
/// \param rng a RandomNumberGenerator to produce random material
/// \param n the number to test
/// \param rounds the number of tests to perform
/// \details This is the Rabin-Miller primality test, i.e. repeating the strong probable prime
/// test for several rounds with random bases
/// \sa <A HREF="https://crypto.stackexchange.com/q/17707/10496">Trial divisions before
/// Miller-Rabin checks?</A> on Crypto Stack Exchange
CRYPTOPP_DLL bool CRYPTOPP_API RabinMillerTest(RandomNumberGenerator &rng, const Integer &n, unsigned int rounds);
/// \brief Verifies a number is probably prime
/// \param p a candidate prime to test
/// \return true if p is a probable prime, false otherwise
/// \details IsPrime() is suitable for testing candidate primes when creating them. Internally,
/// IsPrime() utilizes SmallDivisorsTest(), IsStrongProbablePrime() and IsStrongLucasProbablePrime().
CRYPTOPP_DLL bool CRYPTOPP_API IsPrime(const Integer &p);
/// \brief Verifies a number is probably prime
/// \param rng a RandomNumberGenerator for randomized testing
/// \param p a candidate prime to test
/// \param level the level of thoroughness of testing
/// \return true if p is a strong probable prime, false otherwise
/// \details VerifyPrime() is suitable for testing candidate primes created by others. Internally,
/// VerifyPrime() utilizes IsPrime() and one-round RabinMillerTest(). If the candidate passes and
/// level is greater than 1, then 10 round RabinMillerTest() primality testing is performed.
CRYPTOPP_DLL bool CRYPTOPP_API VerifyPrime(RandomNumberGenerator &rng, const Integer &p, unsigned int level = 1);
/// \brief Application callback to signal suitability of a cabdidate prime
class CRYPTOPP_DLL PrimeSelector
{
public:
virtual ~PrimeSelector() {}
const PrimeSelector *GetSelectorPointer() const {return this;}
virtual bool IsAcceptable(const Integer &candidate) const =0;
};
/// \brief Finds a random prime of special form
/// \param p an Integer reference to receive the prime
/// \param max the maximum value
/// \param equiv the equivalence class based on the parameter mod
/// \param mod the modulus used to reduce the equivalence class
/// \param pSelector pointer to a PrimeSelector function for the application to signal suitability
/// \return true if and only if FirstPrime() finds a prime and returns the prime through p. If FirstPrime()
/// returns false, then no such prime exists and the value of p is undefined
/// \details FirstPrime() uses a fast sieve to find the first probable prime
/// in <tt>{x | p<=x<=max and x%mod==equiv}</tt>
CRYPTOPP_DLL bool CRYPTOPP_API FirstPrime(Integer &p, const Integer &max, const Integer &equiv, const Integer &mod, const PrimeSelector *pSelector);
CRYPTOPP_DLL unsigned int CRYPTOPP_API PrimeSearchInterval(const Integer &max);
CRYPTOPP_DLL AlgorithmParameters CRYPTOPP_API MakeParametersForTwoPrimesOfEqualSize(unsigned int productBitLength);
// ********** other number theoretic functions ************
/// \brief Calculate the greatest common divisor
/// \param a the first term
/// \param b the second term
/// \return the greatest common divisor if one exists, 0 otherwise.
inline Integer GCD(const Integer &a, const Integer &b)
{return Integer::Gcd(a,b);}
/// \brief Determine relative primality
/// \param a the first term
/// \param b the second term
/// \return true if <tt>a</tt> and <tt>b</tt> are relatively prime, false otherwise.
inline bool RelativelyPrime(const Integer &a, const Integer &b)
{return Integer::Gcd(a,b) == Integer::One();}
/// \brief Calculate the least common multiple
/// \param a the first term
/// \param b the second term
/// \return the least common multiple of <tt>a</tt> and <tt>b</tt>.
inline Integer LCM(const Integer &a, const Integer &b)
{return a/Integer::Gcd(a,b)*b;}
/// \brief Calculate multiplicative inverse
/// \param a the number to test
/// \param b the modulus
/// \return an Integer <tt>(a ^ -1) % n</tt> or 0 if none exists.
/// \details EuclideanMultiplicativeInverse returns the multiplicative inverse of the Integer
/// <tt>*a</tt> modulo the Integer <tt>b</tt>. If no Integer exists then Integer 0 is returned.
inline Integer EuclideanMultiplicativeInverse(const Integer &a, const Integer &b)
{return a.InverseMod(b);}
/// \brief Chinese Remainder Theorem
/// \param xp the first number, mod p
/// \param p the first prime modulus
/// \param xq the second number, mod q
/// \param q the second prime modulus
/// \param u inverse of p mod q
/// \return the CRT value of the parameters
/// \details CRT uses the Chinese Remainder Theorem to calculate <tt>x</tt> given
/// <tt>x mod p</tt> and <tt>x mod q</tt>, and <tt>u</tt> the inverse of <tt>p mod q</tt>.
CRYPTOPP_DLL Integer CRYPTOPP_API CRT(const Integer &xp, const Integer &p, const Integer &xq, const Integer &q, const Integer &u);
/// \brief Calculate the Jacobi symbol
/// \param a the first term
/// \param b the second term
/// \return the Jacobi symbol.
/// \details Jacobi symbols are calculated using the following rules:
/// -# if <tt>b</tt> is prime, then <tt>Jacobi(a, b)</tt>, then return 0
/// -# if <tt>a%b</tt>==0 AND <tt>a</tt> is quadratic residue <tt>mod b</tt>, then return 1
/// -# return -1 otherwise
/// \details Refer to a number theory book for what Jacobi symbol means when <tt>b</tt> is not prime.
CRYPTOPP_DLL int CRYPTOPP_API Jacobi(const Integer &a, const Integer &b);
/// \brief Calculate the Lucas value
/// \return the Lucas value
/// \details Lucas() calculates the Lucas function <tt>V_e(p, 1) mod n</tt>.
CRYPTOPP_DLL Integer CRYPTOPP_API Lucas(const Integer &e, const Integer &p, const Integer &n);
/// \brief Calculate the inverse Lucas value
/// \return the inverse Lucas value
/// \details InverseLucas() calculates <tt>x</tt> such that <tt>m==Lucas(e, x, p*q)</tt>,
/// <tt>p q</tt> primes, <tt>u</tt> is inverse of <tt>p mod q</tt>.
CRYPTOPP_DLL Integer CRYPTOPP_API InverseLucas(const Integer &e, const Integer &m, const Integer &p, const Integer &q, const Integer &u);
/// \brief Modular multiplication
/// \param x the first term
/// \param y the second term
/// \param m the modulus
/// \return an Integer <tt>(x * y) % m</tt>.
inline Integer ModularMultiplication(const Integer &x, const Integer &y, const Integer &m)
{return a_times_b_mod_c(x, y, m);}
/// \brief Modular exponentiation
/// \param x the base
/// \param e the exponent
/// \param m the modulus
/// \return an Integer <tt>(a ^ b) % m</tt>.
inline Integer ModularExponentiation(const Integer &x, const Integer &e, const Integer &m)
{return a_exp_b_mod_c(x, e, m);}
/// \brief Extract a modular square root
/// \param a the number to extract square root
/// \param p the prime modulus
/// \return the modular square root if it exists
/// \details ModularSquareRoot returns <tt>x</tt> such that <tt>x*x%p == a</tt>, <tt>p</tt> prime
CRYPTOPP_DLL Integer CRYPTOPP_API ModularSquareRoot(const Integer &a, const Integer &p);
/// \brief Extract a modular root
/// \return a modular root if it exists
/// \details ModularRoot returns <tt>x</tt> such that <tt>a==ModularExponentiation(x, e, p*q)</tt>,
/// <tt>p</tt> <tt>q</tt> primes, and <tt>e</tt> relatively prime to <tt>(p-1)*(q-1)</tt>,
/// <tt>dp=d%(p-1)</tt>, <tt>dq=d%(q-1)</tt>, (d is inverse of <tt>e mod (p-1)*(q-1)</tt>)
/// and <tt>u=inverse of p mod q</tt>.
CRYPTOPP_DLL Integer CRYPTOPP_API ModularRoot(const Integer &a, const Integer &dp, const Integer &dq, const Integer &p, const Integer &q, const Integer &u);
/// \brief Solve a Modular Quadratic Equation
/// \param r1 the first residue
/// \param r2 the second residue
/// \param a the first coefficient
/// \param b the second coefficient
/// \param c the third constant
/// \param p the prime modulus
/// \return true if solutions exist
/// \details SolveModularQuadraticEquation() finds <tt>r1</tt> and <tt>r2</tt> such that <tt>ax^2 +
/// bx + c == 0 (mod p)</tt> for x in <tt>{r1, r2}</tt>, <tt>p</tt> prime.
CRYPTOPP_DLL bool CRYPTOPP_API SolveModularQuadraticEquation(Integer &r1, Integer &r2, const Integer &a, const Integer &b, const Integer &c, const Integer &p);
/// \brief Estimate work factor
/// \param bitlength the size of the number, in bits
/// \return the estimated work factor, in operations
/// \details DiscreteLogWorkFactor returns log base 2 of estimated number of operations to
/// calculate discrete log or factor a number.
CRYPTOPP_DLL unsigned int CRYPTOPP_API DiscreteLogWorkFactor(unsigned int bitlength);
/// \brief Estimate work factor
/// \param bitlength the size of the number, in bits
/// \return the estimated work factor, in operations
/// \details FactoringWorkFactor returns log base 2 of estimated number of operations to
/// calculate discrete log or factor a number.
CRYPTOPP_DLL unsigned int CRYPTOPP_API FactoringWorkFactor(unsigned int bitlength);
// ********************************************************
/// \brief Generator of prime numbers of special forms
class CRYPTOPP_DLL PrimeAndGenerator
{
public:
/// \brief Construct a PrimeAndGenerator
PrimeAndGenerator() {}
/// \brief Construct a PrimeAndGenerator
/// \param delta +1 or -1
/// \param rng a RandomNumberGenerator derived class
/// \param pbits the number of bits in the prime p
/// \details PrimeAndGenerator() generates a random prime p of the form <tt>2*q+delta</tt>, where delta is 1 or -1 and q is
/// also prime. Internally the constructor calls <tt>Generate(delta, rng, pbits, pbits-1)</tt>.
/// \pre <tt>pbits > 5</tt>
/// \warning This PrimeAndGenerator() is slow because primes of this form are harder to find.
PrimeAndGenerator(signed int delta, RandomNumberGenerator &rng, unsigned int pbits)
{Generate(delta, rng, pbits, pbits-1);}
/// \brief Construct a PrimeAndGenerator
/// \param delta +1 or -1
/// \param rng a RandomNumberGenerator derived class
/// \param pbits the number of bits in the prime p
/// \param qbits the number of bits in the prime q
/// \details PrimeAndGenerator() generates a random prime p of the form <tt>2*r*q+delta</tt>, where q is also prime.
/// Internally the constructor calls <tt>Generate(delta, rng, pbits, qbits)</tt>.
/// \pre <tt>qbits > 4 && pbits > qbits</tt>
PrimeAndGenerator(signed int delta, RandomNumberGenerator &rng, unsigned int pbits, unsigned qbits)
{Generate(delta, rng, pbits, qbits);}
/// \brief Generate a Prime and Generator
/// \param delta +1 or -1
/// \param rng a RandomNumberGenerator derived class
/// \param pbits the number of bits in the prime p
/// \param qbits the number of bits in the prime q
/// \details Generate() generates a random prime p of the form <tt>2*r*q+delta</tt>, where q is also prime.
void Generate(signed int delta, RandomNumberGenerator &rng, unsigned int pbits, unsigned qbits);
/// \brief Retrieve first prime
/// \return Prime() returns the prime p.
const Integer& Prime() const {return p;}
/// \brief Retrieve second prime
/// \return SubPrime() returns the prime q.
const Integer& SubPrime() const {return q;}
/// \brief Retrieve the generator
/// \return Generator() returns the generator g.
const Integer& Generator() const {return g;}
private:
Integer p, q, g;
};
NAMESPACE_END
#endif

31
wasm_src/pch.h Normal file
View File

@ -0,0 +1,31 @@
// pch.h - originally written and placed in the public domain by Wei Dai
/// \file pch.h
/// \brief Precompiled header file
/// \details The precompiled header files are used Windows.
#ifndef CRYPTOPP_PCH_H
#define CRYPTOPP_PCH_H
# ifdef CRYPTOPP_GENERATE_X64_MASM
#include "cpu.h"
# else
#include "config.h"
#ifdef USE_PRECOMPILED_HEADERS
#include "simple.h"
#include "secblock.h"
#include "misc.h"
#include "smartptr.h"
#include "stdcpp.h"
#endif
# endif
// Enable file and line numbers, if available.
// #if defined(_MSC_VER) && defined(_DEBUG) && defined(USE_PRECOMPILED_HEADERS)
// # define DEBUG_NEW new(_NORMAL_BLOCK, __FILE__, __LINE__)
// # define new DEBUG_NEW
// #endif
#endif // CRYPTOPP_PCH_H

272
wasm_src/queue.h Normal file
View File

@ -0,0 +1,272 @@
// queue.h - originally written and placed in the public domain by Wei Dai
/// \file
/// \brief Classes for an unlimited queue to store bytes
#ifndef CRYPTOPP_QUEUE_H
#define CRYPTOPP_QUEUE_H
#include "cryptlib.h"
#include "simple.h"
NAMESPACE_BEGIN(CryptoPP)
class ByteQueueNode;
/// \brief Data structure used to store byte strings
/// \details The queue is implemented as a linked list of byte arrays.
/// Each byte array is stored in a ByteQueueNode.
/// \sa <A HREF="https://www.cryptopp.com/wiki/ByteQueue">ByteQueue</A>
/// on the Crypto++ wiki.
/// \since Crypto++ 2.0
class CRYPTOPP_DLL ByteQueue : public Bufferless<BufferedTransformation>
{
public:
virtual ~ByteQueue();
/// \brief Construct a ByteQueue
/// \param nodeSize the initial node size
/// \details Internally, ByteQueue uses a ByteQueueNode to store bytes,
/// and <tt>nodeSize</tt> determines the size of the ByteQueueNode. A value
/// of 0 indicates the ByteQueueNode should be automatically sized,
/// which means a value of 256 is used.
ByteQueue(size_t nodeSize=0);
/// \brief Copy construct a ByteQueue
/// \param copy the other ByteQueue
ByteQueue(const ByteQueue &copy);
// BufferedTransformation
lword MaxRetrievable() const
{return CurrentSize();}
bool AnyRetrievable() const
{return !IsEmpty();}
void IsolatedInitialize(const NameValuePairs &parameters);
byte * CreatePutSpace(size_t &size);
size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking);
size_t Get(byte &outByte);
size_t Get(byte *outString, size_t getMax);
size_t Peek(byte &outByte) const;
size_t Peek(byte *outString, size_t peekMax) const;
size_t TransferTo2(BufferedTransformation &target, lword &transferBytes, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true);
size_t CopyRangeTo2(BufferedTransformation &target, lword &begin, lword end=LWORD_MAX, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true) const;
/// \brief Set node size
/// \param nodeSize the new node size, in bytes
/// \details The default node size is 256.
void SetNodeSize(size_t nodeSize);
/// \brief Determine data size
/// \return the data size, in bytes
lword CurrentSize() const;
/// \brief Determine data availability
/// \return true if the ByteQueue has data, false otherwise
bool IsEmpty() const;
/// \brief Empty the queue
void Clear();
/// \brief Insert data in the queue
/// \param inByte a byte to insert
/// \details Unget() inserts a byte at the head of the queue
void Unget(byte inByte);
/// \brief Insert data in the queue
/// \param inString a byte array to insert
/// \param length the size of the byte array
/// \details Unget() inserts a byte array at the head of the queue
void Unget(const byte *inString, size_t length);
/// \brief Peek data in the queue
/// \param contiguousSize the size of the data
/// \details Spy() peeks at data at the head of the queue. Spy() does
/// not remove data from the queue.
/// \details The data's size is returned in <tt>contiguousSize</tt>.
/// Spy() returns the size of the first byte array in the list. The
/// entire data may be larger since the queue is a linked list of
/// byte arrays.
const byte * Spy(size_t &contiguousSize) const;
/// \brief Insert data in the queue
/// \param inString a byte array to insert
/// \param size the length of the byte array
/// \details LazyPut() inserts a byte array at the tail of the queue.
/// The data may not be copied at this point. Rather, the pointer
/// and size to external data are recorded.
/// \details Another call to Put() or LazyPut() will force the data to
/// be copied. When lazy puts are used, the data is copied when
/// FinalizeLazyPut() is called.
/// \sa LazyPutter
void LazyPut(const byte *inString, size_t size);
/// \brief Insert data in the queue
/// \param inString a byte array to insert
/// \param size the length of the byte array
/// \details LazyPut() inserts a byte array at the tail of the queue.
/// The data may not be copied at this point. Rather, the pointer
/// and size to external data are recorded.
/// \details Another call to Put() or LazyPut() will force the data to
/// be copied. When lazy puts are used, the data is copied when
/// FinalizeLazyPut() is called.
/// \sa LazyPutter
void LazyPutModifiable(byte *inString, size_t size);
/// \brief Remove data from the queue
/// \param size the length of the data
/// \throw InvalidArgument if there is no lazy data in the queue or if
/// size is larger than the lazy string
/// \details UndoLazyPut() truncates data inserted using LazyPut() by
/// modifying size.
/// \sa LazyPutter
void UndoLazyPut(size_t size);
/// \brief Insert data in the queue
/// \details FinalizeLazyPut() copies external data inserted using
/// LazyPut() or LazyPutModifiable() into the tail of the queue.
/// \sa LazyPutter
void FinalizeLazyPut();
/// \brief Assign contents from another ByteQueue
/// \param rhs the other ByteQueue
/// \return reference to this ByteQueue
ByteQueue & operator=(const ByteQueue &rhs);
/// \brief Bitwise compare two ByteQueue
/// \param rhs the other ByteQueue
/// \return true if the size and bits are equal, false otherwise
/// \details operator==() walks each ByteQueue comparing bytes in
/// each queue. operator==() is not constant time.
bool operator==(const ByteQueue &rhs) const;
/// \brief Bitwise compare two ByteQueue
/// \param rhs the other ByteQueue
/// \return true if the size and bits are not equal, false otherwise
/// \details operator!=() is implemented in terms of operator==().
/// operator==() is not constant time.
bool operator!=(const ByteQueue &rhs) const {return !operator==(rhs);}
/// \brief Retrieve data from the queue
/// \param index of byte to retrieve
/// \return byte at the specified index
/// \details operator[]() does not perform bounds checking.
byte operator[](lword index) const;
/// \brief Swap contents with another ByteQueue
/// \param rhs the other ByteQueue
void swap(ByteQueue &rhs);
/// \brief A ByteQueue iterator
class Walker : public InputRejecting<BufferedTransformation>
{
public:
/// \brief Construct a ByteQueue Walker
/// \param queue a ByteQueue
Walker(const ByteQueue &queue)
: m_queue(queue), m_node(NULLPTR), m_position(0), m_offset(0), m_lazyString(NULLPTR), m_lazyLength(0)
{Initialize();}
lword GetCurrentPosition() {return m_position;}
lword MaxRetrievable() const
{return m_queue.CurrentSize() - m_position;}
void IsolatedInitialize(const NameValuePairs &parameters);
size_t Get(byte &outByte);
size_t Get(byte *outString, size_t getMax);
size_t Peek(byte &outByte) const;
size_t Peek(byte *outString, size_t peekMax) const;
size_t TransferTo2(BufferedTransformation &target, lword &transferBytes, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true);
size_t CopyRangeTo2(BufferedTransformation &target, lword &begin, lword end=LWORD_MAX, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true) const;
private:
const ByteQueue &m_queue;
const ByteQueueNode *m_node;
lword m_position;
size_t m_offset;
const byte *m_lazyString;
size_t m_lazyLength;
};
friend class Walker;
protected:
void CleanupUsedNodes();
void CopyFrom(const ByteQueue &copy);
void Destroy();
private:
ByteQueueNode *m_head, *m_tail;
byte *m_lazyString;
size_t m_lazyLength;
size_t m_nodeSize;
bool m_lazyStringModifiable;
bool m_autoNodeSize;
};
/// \brief Helper class to finalize Puts on ByteQueue
/// \details LazyPutter ensures LazyPut is committed to the ByteQueue
/// in event of exception. During destruction, the LazyPutter class
/// calls FinalizeLazyPut.
class CRYPTOPP_DLL LazyPutter
{
public:
virtual ~LazyPutter() {
try {m_bq.FinalizeLazyPut();}
catch(const Exception&) {CRYPTOPP_ASSERT(0);}
}
/// \brief Construct a LazyPutter
/// \param bq the ByteQueue
/// \param inString a byte array to insert
/// \param size the length of the byte array
/// \details LazyPutter ensures LazyPut is committed to the ByteQueue
/// in event of exception. During destruction, the LazyPutter class
/// calls FinalizeLazyPut.
LazyPutter(ByteQueue &bq, const byte *inString, size_t size)
: m_bq(bq) {bq.LazyPut(inString, size);}
protected:
LazyPutter(ByteQueue &bq) : m_bq(bq) {}
private:
ByteQueue &m_bq;
};
/// \brief Helper class to finalize Puts on ByteQueue
/// \details LazyPutterModifiable ensures LazyPut is committed to the
/// ByteQueue in event of exception. During destruction, the
/// LazyPutterModifiable class calls FinalizeLazyPut.
class LazyPutterModifiable : public LazyPutter
{
public:
/// \brief Construct a LazyPutterModifiable
/// \param bq the ByteQueue
/// \param inString a byte array to insert
/// \param size the length of the byte array
/// \details LazyPutterModifiable ensures LazyPut is committed to the
/// ByteQueue in event of exception. During destruction, the
/// LazyPutterModifiable class calls FinalizeLazyPut.
LazyPutterModifiable(ByteQueue &bq, byte *inString, size_t size)
: LazyPutter(bq) {bq.LazyPutModifiable(inString, size);}
};
NAMESPACE_END
#ifndef __BORLANDC__
NAMESPACE_BEGIN(std)
template<> inline void swap(CryptoPP::ByteQueue &a, CryptoPP::ByteQueue &b)
{
a.swap(b);
}
NAMESPACE_END
#endif
#endif

1299
wasm_src/secblock.h Normal file

File diff suppressed because it is too large Load Diff

29
wasm_src/secblockfwd.h Normal file
View File

@ -0,0 +1,29 @@
// secblockfwd.h - written and placed in the public domain by Jeffrey Walton
/// \file secblockfwd.h
/// \brief Forward declarations for SecBlock
/// \details secblock.h and misc.h have a circular dependency. secblockfwd.h
/// allows the library to sidestep the circular dependency, and reference
/// SecBlock classes without the full implementation.
/// \since Crypto++ 8.3
#ifndef CRYPTOPP_SECBLOCKFWD_H
#define CRYPTOPP_SECBLOCKFWD_H
#include "config.h"
NAMESPACE_BEGIN(CryptoPP)
template <class T, class A>
class SecBlock;
template <class T, bool A>
class AllocatorWithCleanup;
typedef SecBlock<byte, AllocatorWithCleanup<byte, false> > SecByteBlock;
typedef SecBlock<word, AllocatorWithCleanup<word, false> > SecWordBlock;
typedef SecBlock<byte, AllocatorWithCleanup<byte, true> > AlignedSecByteBlock;
NAMESPACE_END
#endif // CRYPTOPP_SECBLOCKFWD_H

506
wasm_src/simple.h Normal file
View File

@ -0,0 +1,506 @@
// simple.h - originally written and placed in the public domain by Wei Dai
/// \file simple.h
/// \brief Classes providing basic library services.
#ifndef CRYPTOPP_SIMPLE_H
#define CRYPTOPP_SIMPLE_H
#include "config.h"
#if CRYPTOPP_MSC_VERSION
# pragma warning(push)
# pragma warning(disable: 4127 4189)
#endif
#include "cryptlib.h"
#include "misc.h"
NAMESPACE_BEGIN(CryptoPP)
/// \brief Base class for identifying alogorithm
/// \tparam BASE base class from which to derive
/// \tparam DERIVED class which to clone
template <class DERIVED, class BASE>
class CRYPTOPP_NO_VTABLE ClonableImpl : public BASE
{
public:
/// \brief Create a copy of this object
/// \return a copy of this object
/// \details The caller is responsible for freeing the object.
Clonable * Clone() const {return new DERIVED(*static_cast<const DERIVED *>(this));}
};
/// \brief Base class information
/// \tparam BASE an Algorithm derived class
/// \tparam ALGORITHM_INFO an Algorithm derived class
/// \details AlgorithmImpl provides StaticAlgorithmName from the template parameter BASE
template <class BASE, class ALGORITHM_INFO=BASE>
class CRYPTOPP_NO_VTABLE AlgorithmImpl : public BASE
{
public:
/// \brief The algorithm name
/// \return the algorithm name
/// \details StaticAlgorithmName returns the algorithm's name as a static member function.
/// The name is taken from information provided by BASE.
static std::string CRYPTOPP_API StaticAlgorithmName() {return ALGORITHM_INFO::StaticAlgorithmName();}
/// \brief The algorithm name
/// \return the algorithm name
/// \details AlgorithmName returns the algorithm's name as a member function.
/// The name is acquired by calling StaticAlgorithmName.
std::string AlgorithmName() const {return ALGORITHM_INFO::StaticAlgorithmName();}
};
/// \brief Exception thrown when an invalid key length is encountered
class CRYPTOPP_DLL InvalidKeyLength : public InvalidArgument
{
public:
/// \brief Construct an InvalidKeyLength
/// \param algorithm the Algorithm associated with the exception
/// \param length the key size associated with the exception
explicit InvalidKeyLength(const std::string &algorithm, size_t length) : InvalidArgument(algorithm + ": " + IntToString(length) + " is not a valid key length") {}
};
/// \brief Exception thrown when an invalid number of rounds is encountered
class CRYPTOPP_DLL InvalidRounds : public InvalidArgument
{
public:
/// \brief Construct an InvalidRounds
/// \param algorithm the Algorithm associated with the exception
/// \param rounds the number of rounds associated with the exception
explicit InvalidRounds(const std::string &algorithm, unsigned int rounds) : InvalidArgument(algorithm + ": " + IntToString(rounds) + " is not a valid number of rounds") {}
};
/// \brief Exception thrown when an invalid block size is encountered
class CRYPTOPP_DLL InvalidBlockSize : public InvalidArgument
{
public:
/// \brief Construct an InvalidBlockSize
/// \param algorithm the Algorithm associated with the exception
/// \param length the block size associated with the exception
explicit InvalidBlockSize(const std::string &algorithm, size_t length) : InvalidArgument(algorithm + ": " + IntToString(length) + " is not a valid block size") {}
};
/// \brief Exception thrown when an invalid derived key length is encountered
class CRYPTOPP_DLL InvalidDerivedKeyLength : public InvalidArgument
{
public:
/// \brief Construct an InvalidDerivedKeyLength
/// \param algorithm the Algorithm associated with the exception
/// \param length the size associated with the exception
explicit InvalidDerivedKeyLength(const std::string &algorithm, size_t length) : InvalidArgument(algorithm + ": " + IntToString(length) + " is not a valid derived key length") {}
};
/// \brief Exception thrown when an invalid personalization string length is encountered
class CRYPTOPP_DLL InvalidPersonalizationLength : public InvalidArgument
{
public:
/// \brief Construct an InvalidPersonalizationLength
/// \param algorithm the Algorithm associated with the exception
/// \param length the personalization size associated with the exception
explicit InvalidPersonalizationLength(const std::string &algorithm, size_t length) : InvalidArgument(algorithm + ": " + IntToString(length) + " is not a valid salt length") {}
};
/// \brief Exception thrown when an invalid salt length is encountered
class CRYPTOPP_DLL InvalidSaltLength : public InvalidArgument
{
public:
/// \brief Construct an InvalidSaltLength
/// \param algorithm the Algorithm associated with the exception
/// \param length the salt size associated with the exception
explicit InvalidSaltLength(const std::string &algorithm, size_t length) : InvalidArgument(algorithm + ": " + IntToString(length) + " is not a valid salt length") {}
};
// *****************************
/// \brief Base class for bufferless filters
/// \tparam T the class or type
template <class T>
class CRYPTOPP_NO_VTABLE Bufferless : public T
{
public:
/// \brief Flushes data buffered by this object, without signal propagation
/// \param hardFlush indicates whether all data should be flushed
/// \param blocking specifies whether the object should block when processing input
/// \note hardFlush must be used with care
bool IsolatedFlush(bool hardFlush, bool blocking)
{CRYPTOPP_UNUSED(hardFlush); CRYPTOPP_UNUSED(blocking); return false;}
};
/// \brief Base class for unflushable filters
/// \tparam T the class or type
template <class T>
class CRYPTOPP_NO_VTABLE Unflushable : public T
{
public:
/// \brief Flush buffered input and/or output, with signal propagation
/// \param completeFlush is used to indicate whether all data should be flushed
/// \param propagation the number of attached transformations the Flush()
/// signal should be passed
/// \param blocking specifies whether the object should block when processing
/// input
/// \details propagation count includes this object. Setting propagation to
/// <tt>1</tt> means this object only. Setting propagation to <tt>-1</tt>
/// means unlimited propagation.
/// \note Hard flushes must be used with care. It means try to process and
/// output everything, even if there may not be enough data to complete the
/// action. For example, hard flushing a HexDecoder would cause an error if
/// you do it after inputing an odd number of hex encoded characters.
/// \note For some types of filters, like ZlibDecompressor, hard flushes can
/// only be done at "synchronization points". These synchronization points
/// are positions in the data stream that are created by hard flushes on the
/// corresponding reverse filters, in this example ZlibCompressor. This is
/// useful when zlib compressed data is moved across a network in packets
/// and compression state is preserved across packets, as in the SSH2 protocol.
bool Flush(bool completeFlush, int propagation=-1, bool blocking=true)
{return ChannelFlush(DEFAULT_CHANNEL, completeFlush, propagation, blocking);}
/// \brief Flushes data buffered by this object, without signal propagation
/// \param hardFlush indicates whether all data should be flushed
/// \param blocking specifies whether the object should block when processing input
/// \note hardFlush must be used with care
bool IsolatedFlush(bool hardFlush, bool blocking)
{CRYPTOPP_UNUSED(hardFlush); CRYPTOPP_UNUSED(blocking); CRYPTOPP_ASSERT(false); return false;}
/// \brief Flush buffered input and/or output on a channel
/// \param channel the channel to flush the data
/// \param hardFlush is used to indicate whether all data should be flushed
/// \param propagation the number of attached transformations the ChannelFlush()
/// signal should be passed
/// \param blocking specifies whether the object should block when processing input
/// \return true of the Flush was successful
/// \details propagation count includes this object. Setting propagation to
/// <tt>1</tt> means this object only. Setting propagation to <tt>-1</tt> means
/// unlimited propagation.
bool ChannelFlush(const std::string &channel, bool hardFlush, int propagation=-1, bool blocking=true)
{
if (hardFlush && !InputBufferIsEmpty())
throw CannotFlush("Unflushable<T>: this object has buffered input that cannot be flushed");
else
{
BufferedTransformation *attached = this->AttachedTransformation();
return attached && propagation ? attached->ChannelFlush(channel, hardFlush, propagation-1, blocking) : false;
}
}
protected:
virtual bool InputBufferIsEmpty() const {return false;}
};
/// \brief Base class for input rejecting filters
/// \tparam T the class or type
/// \details T should be a BufferedTransformation derived class
template <class T>
class CRYPTOPP_NO_VTABLE InputRejecting : public T
{
public:
struct InputRejected : public NotImplemented
{InputRejected() : NotImplemented("BufferedTransformation: this object doesn't allow input") {}};
/// \name INPUT
//@{
/// \brief Input a byte array for processing
/// \param inString the byte array to process
/// \param length the size of the string, in bytes
/// \param messageEnd means how many filters to signal MessageEnd() to, including this one
/// \param blocking specifies whether the object should block when processing input
/// \throw InputRejected
/// \return the number of bytes that remain to be processed (i.e., bytes not processed)
/// \details Internally, the default implementation throws InputRejected.
size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking)
{CRYPTOPP_UNUSED(inString); CRYPTOPP_UNUSED(length); CRYPTOPP_UNUSED(messageEnd); CRYPTOPP_UNUSED(blocking); throw InputRejected();}
//@}
/// \name SIGNALS
//@{
/// \brief Flushes data buffered by this object, without signal propagation
/// \param hardFlush indicates whether all data should be flushed
/// \param blocking specifies whether the object should block when processing input
/// \note hardFlush must be used with care
bool IsolatedFlush(bool hardFlush, bool blocking)
{CRYPTOPP_UNUSED(hardFlush); CRYPTOPP_UNUSED(blocking); return false;}
/// \brief Marks the end of a series of messages, without signal propagation
/// \param blocking specifies whether the object should block when completing the processing on
/// the current series of messages
/// \return true if the message was successful, false otherwise
bool IsolatedMessageSeriesEnd(bool blocking)
{CRYPTOPP_UNUSED(blocking); throw InputRejected();}
/// \brief Input multiple bytes for processing on a channel.
/// \param channel the channel to process the data.
/// \param inString the byte buffer to process.
/// \param length the size of the string, in bytes.
/// \param messageEnd means how many filters to signal MessageEnd() to, including this one.
/// \param blocking specifies whether the object should block when processing input.
/// \return the number of bytes that remain to be processed (i.e., bytes not processed)
size_t ChannelPut2(const std::string &channel, const byte *inString, size_t length, int messageEnd, bool blocking)
{CRYPTOPP_UNUSED(channel); CRYPTOPP_UNUSED(inString); CRYPTOPP_UNUSED(length);
CRYPTOPP_UNUSED(messageEnd); CRYPTOPP_UNUSED(blocking); throw InputRejected();}
/// \brief Marks the end of a series of messages on a channel
/// \param channel the channel to signal the end of a series of messages
/// \param messageEnd the number of attached transformations the ChannelMessageSeriesEnd() signal should be passed
/// \param blocking specifies whether the object should block when processing input
/// \return true if the message was successful, false otherwise
/// \details Each object that receives the signal will perform its processing, decrement
/// propagation, and then pass the signal on to attached transformations if the value is not 0.
/// \details propagation count includes this object. Setting propagation to <tt>1</tt> means this
/// object only. Setting propagation to <tt>-1</tt> means unlimited propagation.
/// \note There should be a MessageEnd() immediately before MessageSeriesEnd().
bool ChannelMessageSeriesEnd(const std::string& channel, int messageEnd, bool blocking)
{CRYPTOPP_UNUSED(channel); CRYPTOPP_UNUSED(messageEnd); CRYPTOPP_UNUSED(blocking); throw InputRejected();}
//@}
};
/// \brief Interface for custom flush signals propagation
/// \tparam T BufferedTransformation derived class
template <class T>
class CRYPTOPP_NO_VTABLE CustomFlushPropagation : public T
{
public:
/// \name SIGNALS
//@{
/// \brief Flush buffered input and/or output, with signal propagation
/// \param hardFlush is used to indicate whether all data should be flushed
/// \param propagation the number of attached transformations the Flush() signal should be passed
/// \param blocking specifies whether the object should block when processing input
/// \details propagation count includes this object. Setting propagation to <tt>1</tt> means this
/// object only. Setting propagation to <tt>-1</tt> means unlimited propagation.
/// \note Hard flushes must be used with care. It means try to process and output everything, even if
/// there may not be enough data to complete the action. For example, hard flushing a HexDecoder
/// would cause an error if you do it after inputing an odd number of hex encoded characters.
/// \note For some types of filters, like ZlibDecompressor, hard flushes can only
/// be done at "synchronization points". These synchronization points are positions in the data
/// stream that are created by hard flushes on the corresponding reverse filters, in this
/// example ZlibCompressor. This is useful when zlib compressed data is moved across a
/// network in packets and compression state is preserved across packets, as in the SSH2 protocol.
virtual bool Flush(bool hardFlush, int propagation=-1, bool blocking=true) =0;
//@}
private:
bool IsolatedFlush(bool hardFlush, bool blocking)
{CRYPTOPP_UNUSED(hardFlush); CRYPTOPP_UNUSED(blocking); CRYPTOPP_ASSERT(false); return false;}
};
/// \brief Interface for custom flush signals
/// \tparam T BufferedTransformation derived class
template <class T>
class CRYPTOPP_NO_VTABLE CustomSignalPropagation : public CustomFlushPropagation<T>
{
public:
/// \brief Initialize or reinitialize this object, with signal propagation
/// \param parameters a set of NameValuePairs to initialize or reinitialize this object
/// \param propagation the number of attached transformations the Initialize() signal should be passed
/// \details Initialize() is used to initialize or reinitialize an object using a variable number of
/// arbitrarily typed arguments. The function avoids the need for multiple constructors providing
/// all possible combintations of configurable parameters.
/// \details propagation count includes this object. Setting propagation to <tt>1</tt> means this
/// object only. Setting propagation to <tt>-1</tt> means unlimited propagation.
virtual void Initialize(const NameValuePairs &parameters=g_nullNameValuePairs, int propagation=-1) =0;
private:
void IsolatedInitialize(const NameValuePairs &parameters)
{CRYPTOPP_UNUSED(parameters); CRYPTOPP_ASSERT(false);}
};
/// \brief Multiple channels support for custom signal processing
/// \tparam T the class or type
/// \details T should be a BufferedTransformation derived class
template <class T>
class CRYPTOPP_NO_VTABLE Multichannel : public CustomFlushPropagation<T>
{
public:
bool Flush(bool hardFlush, int propagation=-1, bool blocking=true)
{return this->ChannelFlush(DEFAULT_CHANNEL, hardFlush, propagation, blocking);}
/// \brief Marks the end of a series of messages, with signal propagation
/// \param propagation the number of attached transformations the MessageSeriesEnd() signal should be passed
/// \param blocking specifies whether the object should block when processing input
/// \details Each object that receives the signal will perform its processing, decrement
/// propagation, and then pass the signal on to attached transformations if the value is not 0.
/// \details propagation count includes this object. Setting propagation to <tt>1</tt> means this
/// object only. Setting propagation to <tt>-1</tt> means unlimited propagation.
/// \note There should be a MessageEnd() immediately before MessageSeriesEnd().
bool MessageSeriesEnd(int propagation=-1, bool blocking=true)
{return this->ChannelMessageSeriesEnd(DEFAULT_CHANNEL, propagation, blocking);}
/// \brief Request space which can be written into by the caller
/// \param size the requested size of the buffer
/// \details The purpose of this method is to help avoid extra memory allocations.
/// \details size is an \a IN and \a OUT parameter and used as a hint. When the call is made,
/// size is the requested size of the buffer. When the call returns, size is the size of
/// the array returned to the caller.
/// \details The base class implementation sets size to 0 and returns NULL.
/// \note Some objects, like ArraySink, cannot create a space because its fixed. In the case of
/// an ArraySink, the pointer to the array is returned and the size is remaining size.
byte * CreatePutSpace(size_t &size)
{return this->ChannelCreatePutSpace(DEFAULT_CHANNEL, size);}
/// \brief Input multiple bytes for processing
/// \param inString the byte buffer to process
/// \param length the size of the string, in bytes
/// \param messageEnd means how many filters to signal MessageEnd() to, including this one
/// \param blocking specifies whether the object should block when processing input
/// \return the number of bytes that remain to be processed (i.e., bytes not processed)
/// \details Derived classes must implement Put2().
size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking)
{return this->ChannelPut2(DEFAULT_CHANNEL, inString, length, messageEnd, blocking);}
/// \brief Input multiple bytes that may be modified by callee.
/// \param inString the byte buffer to process.
/// \param length the size of the string, in bytes.
/// \param messageEnd means how many filters to signal MessageEnd() to, including this one.
/// \param blocking specifies whether the object should block when processing input.
/// \return the number of bytes that remain to be processed (i.e., bytes not processed)
/// \details Internally, PutModifiable2() calls Put2().
size_t PutModifiable2(byte *inString, size_t length, int messageEnd, bool blocking)
{return this->ChannelPutModifiable2(DEFAULT_CHANNEL, inString, length, messageEnd, blocking);}
// void ChannelMessageSeriesEnd(const std::string &channel, int propagation=-1)
// {PropagateMessageSeriesEnd(propagation, channel);}
/// \brief Request space which can be written into by the caller
/// \param channel the channel to process the data
/// \param size the requested size of the buffer
/// \return a pointer to a memory block with length size
/// \details The purpose of this method is to help avoid extra memory allocations.
/// \details size is an \a IN and \a OUT parameter and used as a hint. When the call is made,
/// size is the requested size of the buffer. When the call returns, size is the size of
/// the array returned to the caller.
/// \details The base class implementation sets size to 0 and returns NULL.
/// \note Some objects, like ArraySink(), cannot create a space because its fixed. In the case of
/// an ArraySink(), the pointer to the array is returned and the size is remaining size.
byte * ChannelCreatePutSpace(const std::string &channel, size_t &size)
{CRYPTOPP_UNUSED(channel); size = 0; return NULLPTR;}
/// \brief Input multiple bytes that may be modified by callee on a channel
/// \param channel the channel to process the data.
/// \param inString the byte buffer to process
/// \param length the size of the string, in bytes
/// \return true if all bytes were processed, false otherwise.
bool ChannelPutModifiable(const std::string &channel, byte *inString, size_t length)
{this->ChannelPut(channel, inString, length); return false;}
/// \brief Input multiple bytes for processing on a channel.
/// \param channel the channel to process the data.
/// \param begin the byte buffer to process.
/// \param length the size of the string, in bytes.
/// \param messageEnd means how many filters to signal MessageEnd() to, including this one.
/// \param blocking specifies whether the object should block when processing input.
/// \return the number of bytes that remain to be processed (i.e., bytes not processed)
virtual size_t ChannelPut2(const std::string &channel, const byte *begin, size_t length, int messageEnd, bool blocking) =0;
/// \brief Input multiple bytes that may be modified by callee on a channel
/// \param channel the channel to process the data
/// \param begin the byte buffer to process
/// \param length the size of the string, in bytes
/// \param messageEnd means how many filters to signal MessageEnd() to, including this one
/// \param blocking specifies whether the object should block when processing input
/// \return the number of bytes that remain to be processed (i.e., bytes not processed)
size_t ChannelPutModifiable2(const std::string &channel, byte *begin, size_t length, int messageEnd, bool blocking)
{return ChannelPut2(channel, begin, length, messageEnd, blocking);}
/// \brief Flush buffered input and/or output on a channel
/// \param channel the channel to flush the data
/// \param hardFlush is used to indicate whether all data should be flushed
/// \param propagation the number of attached transformations the ChannelFlush() signal should be passed
/// \param blocking specifies whether the object should block when processing input
/// \return true of the Flush was successful
/// \details propagation count includes this object. Setting propagation to <tt>1</tt> means this
/// object only. Setting propagation to <tt>-1</tt> means unlimited propagation.
virtual bool ChannelFlush(const std::string &channel, bool hardFlush, int propagation=-1, bool blocking=true) =0;
};
/// \brief Provides auto signaling support
/// \tparam T BufferedTransformation derived class
template <class T>
class CRYPTOPP_NO_VTABLE AutoSignaling : public T
{
public:
/// \brief Construct an AutoSignaling
/// \param propagation the propagation count
AutoSignaling(int propagation=-1) : m_autoSignalPropagation(propagation) {}
/// \brief Set propagation of automatically generated and transferred signals
/// \param propagation then new value
/// \details Setting propagation to <tt>0</tt> means do not automatically generate signals. Setting
/// propagation to <tt>-1</tt> means unlimited propagation.
void SetAutoSignalPropagation(int propagation)
{m_autoSignalPropagation = propagation;}
/// \brief Retrieve automatic signal propagation value
/// \return the number of attached transformations the signal is propagated to. 0 indicates
/// the signal is only witnessed by this object
int GetAutoSignalPropagation() const
{return m_autoSignalPropagation;}
private:
int m_autoSignalPropagation;
};
/// \brief Acts as a Source for pre-existing, static data
class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE Store : public AutoSignaling<InputRejecting<BufferedTransformation> >
{
public:
/// \brief Construct a Store
Store() : m_messageEnd(false) {}
void IsolatedInitialize(const NameValuePairs &parameters)
{
m_messageEnd = false;
StoreInitialize(parameters);
}
unsigned int NumberOfMessages() const {return m_messageEnd ? 0 : 1;}
bool GetNextMessage();
unsigned int CopyMessagesTo(BufferedTransformation &target, unsigned int count=UINT_MAX, const std::string &channel=DEFAULT_CHANNEL) const;
protected:
virtual void StoreInitialize(const NameValuePairs &parameters) =0;
bool m_messageEnd;
};
/// \brief Implementation of BufferedTransformation's attachment interface
/// \details Sink is a cornerstone of the Pipeline trinitiy. Data flows from
/// Sources, through Filters, and then terminates in Sinks. The difference
/// between a Source and Filter is a Source \a pumps data, while a Filter does
/// not. The difference between a Filter and a Sink is a Filter allows an
/// attached transformation, while a Sink does not.
/// \details A Sink doesnot produce any retrievable output.
/// \details See the discussion of BufferedTransformation in cryptlib.h for
/// more details.
class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE Sink : public BufferedTransformation
{
public:
size_t TransferTo2(BufferedTransformation &target, lword &transferBytes, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true)
{CRYPTOPP_UNUSED(target); CRYPTOPP_UNUSED(transferBytes); CRYPTOPP_UNUSED(channel); CRYPTOPP_UNUSED(blocking); transferBytes = 0; return 0;}
size_t CopyRangeTo2(BufferedTransformation &target, lword &begin, lword end=LWORD_MAX, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true) const
{CRYPTOPP_UNUSED(target); CRYPTOPP_UNUSED(begin); CRYPTOPP_UNUSED(end); CRYPTOPP_UNUSED(channel); CRYPTOPP_UNUSED(blocking); return 0;}
};
/// \brief Acts as an input discarding Filter or Sink
/// \details The BitBucket discards all input and returns 0 to the caller
/// to indicate all data was processed.
class CRYPTOPP_DLL BitBucket : public Bufferless<Sink>
{
public:
std::string AlgorithmName() const {return "BitBucket";}
void IsolatedInitialize(const NameValuePairs &params)
{CRYPTOPP_UNUSED(params);}
size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking)
{CRYPTOPP_UNUSED(inString); CRYPTOPP_UNUSED(length); CRYPTOPP_UNUSED(messageEnd); CRYPTOPP_UNUSED(blocking); return 0;}
};
NAMESPACE_END
#if CRYPTOPP_MSC_VERSION
# pragma warning(pop)
#endif
#endif

257
wasm_src/smartptr.h Normal file
View File

@ -0,0 +1,257 @@
// smartptr.h - originally written and placed in the public domain by Wei Dai
/// \file smartptr.h
/// \brief Classes for automatic resource management
#ifndef CRYPTOPP_SMARTPTR_H
#define CRYPTOPP_SMARTPTR_H
#include "config.h"
#include "stdcpp.h"
NAMESPACE_BEGIN(CryptoPP)
/// \brief Manages resources for a single object
/// \tparam T class or type
/// \details \p simple_ptr is used frequently in the library to manage resources and
/// ensure cleanup under the RAII pattern (Resource Acquisition Is Initialization).
template <class T> class simple_ptr
{
public:
simple_ptr(T *p = NULLPTR) : m_p(p) {}
~simple_ptr()
{
delete m_p;
m_p = NULLPTR;
}
T *m_p;
};
/// \brief Pointer that overloads operator ->
/// \tparam T class or type
/// \details member_ptr is used frequently in the library to avoid the issues related to
/// std::auto_ptr in C++11 (deprecated) and std::unique_ptr in C++03 (non-existent).
/// \bug <a href="http://github.com/weidai11/cryptopp/issues/48">Issue 48: "Use of auto_ptr
/// causes dirty compile under C++11"</a>
template <class T> class member_ptr
{
public:
explicit member_ptr(T *p = NULLPTR) : m_p(p) {}
~member_ptr();
const T& operator*() const { return *m_p; }
T& operator*() { return *m_p; }
const T* operator->() const { return m_p; }
T* operator->() { return m_p; }
const T* get() const { return m_p; }
T* get() { return m_p; }
T* release()
{
T *old_p = m_p;
m_p = NULLPTR;
return old_p;
}
void reset(T *p = NULLPTR);
protected:
member_ptr(const member_ptr<T>& rhs); // copy not allowed
void operator=(const member_ptr<T>& rhs); // assignment not allowed
T *m_p;
};
template <class T> member_ptr<T>::~member_ptr() {delete m_p;}
template <class T> void member_ptr<T>::reset(T *p) {delete m_p; m_p = p;}
// ********************************************************
/// \brief Value pointer
/// \tparam T class or type
template<class T> class value_ptr : public member_ptr<T>
{
public:
value_ptr(const T &obj) : member_ptr<T>(new T(obj)) {}
value_ptr(T *p = NULLPTR) : member_ptr<T>(p) {}
value_ptr(const value_ptr<T>& rhs)
: member_ptr<T>(rhs.m_p ? new T(*rhs.m_p) : NULLPTR) {}
value_ptr<T>& operator=(const value_ptr<T>& rhs);
bool operator==(const value_ptr<T>& rhs)
{
return (!this->m_p && !rhs.m_p) || (this->m_p && rhs.m_p && *this->m_p == *rhs.m_p);
}
};
template <class T> value_ptr<T>& value_ptr<T>::operator=(const value_ptr<T>& rhs)
{
T *old_p = this->m_p;
this->m_p = rhs.m_p ? new T(*rhs.m_p) : NULLPTR;
delete old_p;
return *this;
}
// ********************************************************
/// \brief A pointer which can be copied and cloned
/// \tparam T class or type
/// \details \p T should adhere to the \p Clonable interface
template<class T> class clonable_ptr : public member_ptr<T>
{
public:
clonable_ptr(const T &obj) : member_ptr<T>(obj.Clone()) {}
clonable_ptr(T *p = NULLPTR) : member_ptr<T>(p) {}
clonable_ptr(const clonable_ptr<T>& rhs)
: member_ptr<T>(rhs.m_p ? rhs.m_p->Clone() : NULLPTR) {}
clonable_ptr<T>& operator=(const clonable_ptr<T>& rhs);
};
template <class T> clonable_ptr<T>& clonable_ptr<T>::operator=(const clonable_ptr<T>& rhs)
{
T *old_p = this->m_p;
this->m_p = rhs.m_p ? rhs.m_p->Clone() : NULLPTR;
delete old_p;
return *this;
}
// ********************************************************
/// \brief Reference counted pointer
/// \tparam T class or type
/// \details users should declare \p m_referenceCount as <tt>std::atomic<unsigned></tt>
/// (or similar) under C++ 11
template<class T> class counted_ptr
{
public:
explicit counted_ptr(T *p = NULLPTR);
counted_ptr(const T &r) : m_p(0) {attach(r);}
counted_ptr(const counted_ptr<T>& rhs);
~counted_ptr();
const T& operator*() const { return *m_p; }
T& operator*() { return *m_p; }
const T* operator->() const { return m_p; }
T* operator->() { return get(); }
const T* get() const { return m_p; }
T* get();
void attach(const T &p);
counted_ptr<T> & operator=(const counted_ptr<T>& rhs);
private:
T *m_p;
};
template <class T> counted_ptr<T>::counted_ptr(T *p)
: m_p(p)
{
if (m_p)
m_p->m_referenceCount = 1;
}
template <class T> counted_ptr<T>::counted_ptr(const counted_ptr<T>& rhs)
: m_p(rhs.m_p)
{
if (m_p)
m_p->m_referenceCount++;
}
template <class T> counted_ptr<T>::~counted_ptr()
{
if (m_p && --m_p->m_referenceCount == 0)
delete m_p;
}
template <class T> void counted_ptr<T>::attach(const T &r)
{
if (m_p && --m_p->m_referenceCount == 0)
delete m_p;
if (r.m_referenceCount == 0)
{
m_p = r.clone();
m_p->m_referenceCount = 1;
}
else
{
m_p = const_cast<T *>(&r);
m_p->m_referenceCount++;
}
}
template <class T> T* counted_ptr<T>::get()
{
if (m_p && m_p->m_referenceCount > 1)
{
T *temp = m_p->clone();
m_p->m_referenceCount--;
m_p = temp;
m_p->m_referenceCount = 1;
}
return m_p;
}
template <class T> counted_ptr<T> & counted_ptr<T>::operator=(const counted_ptr<T>& rhs)
{
if (m_p != rhs.m_p)
{
if (m_p && --m_p->m_referenceCount == 0)
delete m_p;
m_p = rhs.m_p;
if (m_p)
m_p->m_referenceCount++;
}
return *this;
}
// ********************************************************
/// \brief Manages resources for an array of objects
/// \tparam T class or type
template <class T> class vector_member_ptrs
{
public:
/// Construct an arry of \p T
/// \param size the size of the array, in elements
/// \details If \p T is a Plain Old Dataype (POD), then the array is uninitialized.
vector_member_ptrs(size_t size=0)
: m_size(size), m_ptr(new member_ptr<T>[size]) {}
~vector_member_ptrs()
{delete [] this->m_ptr;}
member_ptr<T>& operator[](size_t index)
{CRYPTOPP_ASSERT(index<this->m_size); return this->m_ptr[index];}
const member_ptr<T>& operator[](size_t index) const
{CRYPTOPP_ASSERT(index<this->m_size); return this->m_ptr[index];}
size_t size() const {return this->m_size;}
void resize(size_t newSize)
{
member_ptr<T> *newPtr = new member_ptr<T>[newSize];
for (size_t i=0; i<this->m_size && i<newSize; i++)
newPtr[i].reset(this->m_ptr[i].release());
delete [] this->m_ptr;
this->m_size = newSize;
this->m_ptr = newPtr;
}
private:
vector_member_ptrs(const vector_member_ptrs<T> &c); // copy not allowed
void operator=(const vector_member_ptrs<T> &x); // assignment not allowed
size_t m_size;
member_ptr<T> *m_ptr;
};
NAMESPACE_END
#endif

101
wasm_src/stdcpp.h Normal file
View File

@ -0,0 +1,101 @@
// stdcpp.h - originally written and placed in the public domain by Wei Dai
/// \file stdcpp.h
/// \brief Common C++ header files
#ifndef CRYPTOPP_STDCPP_H
#define CRYPTOPP_STDCPP_H
#if _MSC_VER >= 1500
#define _DO_NOT_DECLARE_INTERLOCKED_INTRINSICS_IN_MEMORY
#include <intrin.h>
#endif
#include <string>
#include <memory>
#include <exception>
#include <typeinfo>
#include <algorithm>
#include <functional>
#include <utility>
#include <vector>
#include <limits>
#include <deque>
#include <list>
#include <map>
#include <new>
// http://connect.microsoft.com/VisualStudio/feedback/details/1600701/type-info-does-not-compile-with-has-exceptions-0
#if defined(_MSC_VER) && (_MSC_VER < 1900) && defined(_HAS_EXCEPTIONS) && (_HAS_EXCEPTIONS == 0)
namespace std {
using ::type_info;
}
#endif
// workaround needed for IBM XLC and debug heaps on AIX
#if defined(_AIX) && (defined(__xlc__) || defined(__xlC__) || defined(__ibmxl__))
# if defined(__DEBUG_ALLOC__)
namespace std {
using ::_debug_memset;
using ::_debug_memcpy;
}
# endif
#endif
// make_unchecked_array_iterator
#if _MSC_VER >= 1600
#include <iterator>
#endif
#if defined(CRYPTOPP_CXX11_ATOMIC)
#include <atomic>
#endif
#if defined(CRYPTOPP_CXX11_SYNCHRONIZATION)
#include <mutex>
#endif
#if defined(CRYPTOPP_CXX11_RVALUES)
# include <utility>
#endif
#include <cstdlib>
#include <cstring>
#include <climits>
#include <cmath>
// It is 2019 and VS2017/Win10 still can't compile a
// program that includes <cstddef> without making users
// do something special. "Epic fail" comes to mind.
// Also see https://github.com/weidai11/cryptopp/issues/781
#ifndef _MSC_VER
# include <cstddef>
#endif
// uintptr_t and ptrdiff_t
#if defined(__SUNPRO_CC)
# if (__SUNPRO_CC >= 0x5100)
# include <stdint.h>
# endif
#elif defined(_MSC_VER)
# if (_MSC_VER >= 1700)
# include <stdint.h>
# else
# include <stddef.h>
# endif
#elif (__cplusplus < 201103L)
# include <stdint.h>
#endif
// workaround needed on Sun Studio 12u1 Sun C++ 5.10 SunOS_i386 128229-02 2009/09/21
#ifdef CRYPTOPP_INCLUDE_VECTOR_CC
# include <vector.cc>
#endif
// C++Builder's standard library (Dinkumware) do not have C's global log() function
// https://github.com/weidai11/cryptopp/issues/520
#ifdef __BORLANDC__
using std::log;
#endif
#endif // CRYPTOPP_STDCPP_H

225
wasm_src/words.h Normal file
View File

@ -0,0 +1,225 @@
// words.h - originally written and placed in the public domain by Wei Dai
/// \file words.h
/// \brief Support functions for word operations
#ifndef CRYPTOPP_WORDS_H
#define CRYPTOPP_WORDS_H
#include "config.h"
#include "misc.h"
NAMESPACE_BEGIN(CryptoPP)
/// \brief Count the number of words
/// \param x word array
/// \param n size of the word array, in elements
/// \return number of words used in the array.
/// \details CountWords counts the number of words in a word array.
/// Leading 0-words are not included in the count.
/// \since Crypto++ 1.0
inline size_t CountWords(const word *x, size_t n)
{
while (n && x[n-1]==0)
n--;
return n;
}
/// \brief Set the value of words
/// \param r word array
/// \param a value
/// \param n size of the word array, in elements
/// \details SetWords sets all elements in the word array to the
/// specified value.
/// \since Crypto++ 1.0
inline void SetWords(word *r, word a, size_t n)
{
for (size_t i=0; i<n; i++)
r[i] = a;
}
/// \brief Copy word array
/// \param r destination word array
/// \param a source word array
/// \param n size of the word array, in elements
/// \details CopyWords copies the source word array to the destination
/// word array.
/// \since Crypto++ 1.0
inline void CopyWords(word *r, const word *a, size_t n)
{
if (r != a)
#if CRYPTOPP_MSC_VERSION
memcpy_s(r, n*WORD_SIZE, a, n*WORD_SIZE);
#else
memcpy(r, a, n*WORD_SIZE);
#endif
}
/// \brief XOR word arrays
/// \param r destination word array
/// \param a first source word array
/// \param b second source word array
/// \param n size of the word array, in elements
/// \details XorWords XORs the two source word arrays and copies the
/// result to the destination word array.
/// \since Crypto++ 1.0
inline void XorWords(word *r, const word *a, const word *b, size_t n)
{
for (size_t i=0; i<n; i++)
r[i] = a[i] ^ b[i];
}
/// \brief XOR word arrays
/// \param r destination word array
/// \param a source word array
/// \param n size of the word array, in elements
/// \details XorWords XORs the source word array with the
/// destination word array.
/// \since Crypto++ 1.0
inline void XorWords(word *r, const word *a, size_t n)
{
for (size_t i=0; i<n; i++)
r[i] ^= a[i];
}
/// \brief AND word arrays
/// \param r destination word array
/// \param a first source word array
/// \param b second source word array
/// \param n size of the word array, in elements
/// \details AndWords ANDs the two source word arrays and copies the
/// result to the destination word array.
/// \since Crypto++ 1.0
inline void AndWords(word *r, const word *a, const word *b, size_t n)
{
for (size_t i=0; i<n; i++)
r[i] = a[i] & b[i];
}
/// \brief AND word arrays
/// \param r destination word array
/// \param a source word array
/// \param n size of the word array, in elements
/// \details AndWords ANDs the source word array with the
/// destination word array.
/// \since Crypto++ 1.0
inline void AndWords(word *r, const word *a, size_t n)
{
for (size_t i=0; i<n; i++)
r[i] &= a[i];
}
/// \brief OR word arrays
/// \param r destination word array
/// \param a first source word array
/// \param b second source word array
/// \param n size of the word array, in elements
/// \details OrWords ORs the two source word arrays and copies the
/// result to the destination word array.
/// \since Crypto++ 1.0
inline void OrWords(word *r, const word *a, const word *b, size_t n)
{
for (size_t i=0; i<n; i++)
r[i] = a[i] | b[i];
}
/// \brief OR word arrays
/// \param r destination word array
/// \param a source word array
/// \param n size of the word array, in elements
/// \details OrWords ORs the source word array with the
/// destination word array.
/// \since Crypto++ 1.0
inline void OrWords(word *r, const word *a, size_t n)
{
for (size_t i=0; i<n; i++)
r[i] |= a[i];
}
/// \brief Left shift word array
/// \param r word array
/// \param n size of the word array, in elements
/// \param shiftBits number of bits to shift
/// \return word shifted out
/// \details ShiftWordsLeftByBits shifts the word array left by
/// shiftBits. ShiftWordsLeftByBits shifts bits out on the left;
/// it does not extend the array.
/// \note shiftBits must be less than WORD_BITS.
/// \since Crypto++ 1.0
inline word ShiftWordsLeftByBits(word *r, size_t n, unsigned int shiftBits)
{
CRYPTOPP_ASSERT (shiftBits<WORD_BITS);
word u, carry=0;
if (shiftBits)
for (size_t i=0; i<n; i++)
{
u = r[i];
r[i] = (u << shiftBits) | carry;
carry = u >> (WORD_BITS-shiftBits);
}
return carry;
}
/// \brief Right shift word array
/// \param r word array
/// \param n size of the word array, in elements
/// \param shiftBits number of bits to shift
/// \return word shifted out
/// \details ShiftWordsRightByBits shifts the word array shight by
/// shiftBits. ShiftWordsRightByBits shifts bits out on the right.
/// \note shiftBits must be less than WORD_BITS.
/// \since Crypto++ 1.0
inline word ShiftWordsRightByBits(word *r, size_t n, unsigned int shiftBits)
{
CRYPTOPP_ASSERT (shiftBits<WORD_BITS);
word u, carry=0;
if (shiftBits)
for (size_t i=n; i>0; i--)
{
u = r[i-1];
r[i-1] = (u >> shiftBits) | carry;
carry = u << (WORD_BITS-shiftBits);
}
return carry;
}
/// \brief Left shift word array
/// \param r word array
/// \param n size of the word array, in elements
/// \param shiftWords number of words to shift
/// \details ShiftWordsLeftByWords shifts the word array left by
/// shiftWords. ShiftWordsLeftByWords shifts bits out on the left;
/// it does not extend the array.
/// \since Crypto++ 1.0
inline void ShiftWordsLeftByWords(word *r, size_t n, size_t shiftWords)
{
shiftWords = STDMIN(shiftWords, n);
if (shiftWords)
{
for (size_t i=n-1; i>=shiftWords; i--)
r[i] = r[i-shiftWords];
SetWords(r, 0, shiftWords);
}
}
/// \brief Right shift word array
/// \param r word array
/// \param n size of the word array, in elements
/// \param shiftWords number of words to shift
/// \details ShiftWordsRightByWords shifts the word array right by
/// shiftWords. ShiftWordsRightByWords shifts bits out on the right.
/// \since Crypto++ 1.0
inline void ShiftWordsRightByWords(word *r, size_t n, size_t shiftWords)
{
shiftWords = STDMIN(shiftWords, n);
if (shiftWords)
{
for (size_t i=0; i+shiftWords<n; i++)
r[i] = r[i+shiftWords];
SetWords(r+n-shiftWords, 0, shiftWords);
}
}
NAMESPACE_END
#endif