AWS-KMS signature always changing - signature

I'm currently exploring to generate private keys on kms, I already get the public key, however every time I use KMS.SignRequest with the same message, it generate different signature. was that the expected output? I thought it should be the same?
async function sign(msgHash: Buffer, keyId: string) {
const params : KMS.SignRequest = {
KeyId: keyId,
Message: msgHash,
// 'ECDSA_SHA_256' is the one compatible with ECC_SECG_P256K1.
SigningAlgorithm: 'ECDSA_SHA_256',
MessageType: 'DIGEST'
};
// console.debug("params: ",params)
const res = await kms.sign(params).promise();
return res;
}

Related

My global object doesn't contain a key/value pair, but when I access it directly by key, it's actually there. How come?

declare global {
var client: Client | undefined;
}
const _client = global.redisClient;
global.client = _client;
export const initializeClient = async () => {
global.client = await startClient();
};
The idea here is that I'm creating a global with the key client. At first, it'll be undefined, but, once initializeClient is called, it will have a value of type Client.
However, in my code, when I log global, I see client as undefined, however, if I console.log(global.client), the proper object is there. The same line. How can this be?

Error while running cliper bechmeark for hyperledger farbic: "message=Peer endorsements do not match"

For my hyperledger fabric chain code, i craeted a chaincode which implements Hybrid Encryption using RSA and Symetric AES.
I have used the cliper documentation's tutorial itself.
encryptString (plaintext,publicKey) {
// publicEncrypt() method with its parameters
const encrypted = crypto.publicEncrypt(
publicKey, Buffer.from(plaintext));
return encrypted.toString("base64");
}
encryptAsset (cipher,asset) {
return cipher.update(JSON.stringify(asset), 'utf8', 'hex') + cipher.final('hex');
}
hybridEncryption(assetIn,id){
var token = crypto.createHash('sha256').update(String("")).digest('base64').substr(0, 32);
const iv = crypto.randomBytes(16).toString('hex').slice(0, 16);
const keyPair = crypto.generateKeyPairSync('rsa', {
modulusLength: 1024,
publicKeyEncoding: {
type: 'spki',
format: 'pem'
},
privateKeyEncoding: {
type: 'pkcs8',
format: 'pem',
cipher: 'aes-256-cbc',
passphrase: ''
}
});
//Encrypting the entry
var cipher = crypto.createCipheriv("aes256",token,iv);
var encryptedAsset = this.encryptAsset(cipher,assetIn);
//Encrypting the token
let encrypterToken = this.encryptString(JSON.stringify(token),keyPair.publicKey);
const asset = {
ID: id,
token:encrypterToken,
asset: encryptedAsset,
}
return asset;
}
// CreateAsset issues a new asset to the world state with given details.
async CreateAsset(ctx, id, color, size, owner, appraisedValue) {
const exists = await this.AssetExists(ctx, id);
if (exists) {
throw new Error(`The asset ${id} does not exist`);
}
const asset = {
ID: id,
Color: color,
Size: size,
Owner: owner,
AppraisedValue: appraisedValue,
};
this.hybridEncryption(asset,id)
return await ctx.stub.putState(id, Buffer.from(JSON.stringify(this.hybridEncryption(asset,id))));
}
When running he benchmark, I get this error:
error: [DiscoveryHandler]: compareProposalResponseResults[undefined] - read/writes result sets do not match index=1
2022-01-26T11:04:20.087Z - error: [Transaction]: Error: No valid responses from any peers. Errors:
peer=undefined, status=grpc, message=Peer endorsements do not match
2022.01.26-16:34:20.087 error [caliper] [connectors/v2/FabricGateway] Failed to perform submit transaction [CreateAsset] using arguments [0_1_3,blue,20,penguin,500], with error: Error: No valid responses from any peers. Errors:
peer=undefined, status=grpc, message=Peer endorsements do not match
at newEndorsementError (/mnt/e/MIT/capstone/capstone/sdk/node_modules/fabric-network/lib/transaction.js:49:12)
at getResponsePayload (/mnt/e/MIT/capstone/capstone/sdk/node_modules/fabric-network/lib/transaction.js:17:23)
at Transaction.submit (/mnt/e/MIT/capstone/capstone/sdk/node_modules/fabric-network/lib/transaction.js:212:28)
at processTicksAndRejections (node:internal/process/task_queues:96:5)
at async V2FabricGateway._submitOrEvaluateTransaction (/mnt/e/MIT/capstone/capstone/sdk/node_modules/#hyperledger/caliper-fabric/lib/connector-versions/v2/FabricGateway.js:376:26)
at async V2FabricGateway._sendSingleRequest (/mnt/e/MIT/capstone/capstone/sdk/node_modules/#hyperledger/caliper-fabric/lib/connector-versions/v2/FabricGateway.js:170:16)
at async V2FabricGateway.sendRequests (/mnt/e/MIT/capstone/capstone/sdk/node_modules/#hyperledger/caliper-core/lib/common/core/connector-base.js:78:28)
at async MyWorkload.submitTransaction (/mnt/e/MIT/capstone/capstone/sdk/fabric3wsl/newcliperall/fabric-samples/caliper-workspace/workload/createAsset.js:28:13)
If I run just this code for the chain code, there is no problem while running it:
async CreateAsset(ctx, id, color, size, owner, appraisedValue) {
const exists = await this.AssetExists(ctx, id);
if (exists) {
throw new Error(`The asset ${id} does not exist`);
}
const asset = {
ID: id,
Color: color,
Size: size,
Owner: owner,
AppraisedValue: appraisedValue,
};
return await ctx.stub.putState(id, Buffer.from(JSON.stringify(asset)));
}
Also I check my encryption too separately. There is not problem in encryption code.
Also if I do a simply replace this in my encryption based chaincode:
return await ctx.stub.putState(id, Buffer.from(JSON.stringify(this.hybridEncryption(asset,id))));
with
return await ctx.stub.putState(id, Buffer.from(JSON.stringify(asset)));
the code works just fine.
I have also checked the logs of the docker images. There the transactions are showing as successful. There is no error in the logs of any docker image.
What exactly is the problem.
Is it due to caliper is not waiting long enough to get a response?
If it is the case can't find a way to change it.
NOTE: Its not related to the bug in the code of "await" missing.
Chaincode must be deterministic and in your case it looks like it isn't. For chaincode to be deterministic it must produce the same result given the same inputs when run, what is happening in your case is that the chaincode executes on 2 peers simultaneously but the data being put into the world state is not the same. Looking at the code I'm guessing that this line is causing the issue
const iv = crypto.randomBytes(16).toString('hex').slice(0, 16);
as the value of iv will differ between peers

Compare API response against itself

I am trying to:
Poll a public API every 5 seconds
Store the resulting JSON in a variable
Store the next query to this same API in a second variable
Compare the first variable to the second
Print the second variable if it is different from the first
Else: Print the phrase: 'The objects are the same' if they haven't changed
Unfortunately, the comparison part appears to fail. I am realizing that this implementation is probably lacking the appropriate variable scoping but I can't put my finger on it. Any advice would be highly appreciated.
data: {
chatters: {
viewers: {
},
},
},
};
//prints out pretty JSON
function prettyJSON(obj) {
console.log(JSON.stringify(obj, null, 2));
}
// Gets Users from Twitch API endpoint via axios request
const getUsers = async () => {
try {
return await axios.get("http://tmi.twitch.tv/group/user/sixteenbitninja/chatters");
} catch (error) {
console.error(error);
}
};
//Intended to display
const displayViewers = async (previousResponse) => {
const usersInChannel = await getUsers();
if (usersInChannel.data.chatters.viewers === previousResponse){
console.log("The objects are the same");
} else {
if (usersInChannel.data.chatters) {
prettyJSON(usersInChannel.data.chatters.viewers);
const previousResponse = usersInChannel.data.chatters.viewers;
console.log(previousResponse);
intervalFunction(previousResponse);
}
}
};
// polls display function every 5 seconds
const interval = setInterval(function () {
// Calls Display Function
displayViewers()
}, 5000);```
The issue is that you are using equality operator === on objects. two objects are equal if they have the same reference. While you want to know if they are identical. Check this:
console.log({} === {})
For your usecase you might want to store stringified version of the previousResponse and compare it with stringified version of the new object (usersInChannel.data.chatters.viewers) like:
console.log(JSON.stringify({}) === JSON.stringify({}))
Note: There can be issues with this approach too, if the order of property changes in the response. In which case, you'd have to check individual properties within the response objects.
May be you can use npm packages like following
https://www.npmjs.com/package/#radarlabs/api-diff

Only getting the audio of the last request when doing multiple requests at once using Google's Text to Speech API

When doing multiple requests at once, using Promise.all, I seem to only get the audioContent of the last resolving request.
I'm synthesizing large text's and need to split it up using the API's character limit.
I had this working before, so I know it should work, but stopped working recently.
I'm doing the exact same with Amazon's Polly, and there it works. It's exactly the same code, but with a different client and different request options.
So that made me think maybe it's a library thing? Or a Google service issue?
I'm using the latest version of: https://github.com/googleapis/nodejs-text-to-speech
export const googleSsmlToSpeech = async (
index: number,
ssmlPart: string,
type: SynthesizerType,
identifier: string,
synthesizerOptions: GoogleSynthesizerOptions,
storageUploadPath: string
) => {
let extension = 'mp3';
if (synthesizerOptions.audioConfig.audioEncoding === 'OGG_OPUS') {
extension = 'opus';
}
if (synthesizerOptions.audioConfig.audioEncoding === 'LINEAR16') {
extension = 'wav';
}
synthesizerOptions.input.ssml = ssmlPart;
const tempLocalAudiofilePath = `${appRootPath}/temp/${storageUploadPath}-${index}.${extension}`;
try {
// Make sure the path exists, if not, we create it
await fsExtra.ensureFile(tempLocalAudiofilePath);
// Performs the Text-to-Speech request
const [response] = await client.synthesizeSpeech(synthesizerOptions);
// Write the binary audio content to a local file
await fsExtra.writeFile(tempLocalAudiofilePath, response.audioContent, 'binary');
return tempLocalAudiofilePath;
} catch (err) {
throw err;
}
};
/**
* Synthesizes the SSML parts into seperate audiofiles
*/
export const googleSsmlPartsToSpeech = async (
ssmlParts: string[],
type: SynthesizerType,
identifier: string,
synthesizerOptions: GoogleSynthesizerOptions,
storageUploadPath: string
) => {
const promises: Promise<string>[] = [];
ssmlParts.forEach((ssmlPart: string, index: number) => {
promises.push(googleSsmlToSpeech(index, ssmlPart, type, identifier, synthesizerOptions, storageUploadPath));
});
const tempAudioFiles = await Promise.all(promises);
tempAudioFiles.sort((a: any, b: any) => b - a); // Sort: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 etc...
return tempAudioFiles;
};
The above code creates multiple files with the correct naming and index number, however, they all contain the same audio. That is; the audio response that resolved the fastest.
824163ed-b4d9-4830-99da-6e6f985727e2-0.mp3
824163ed-b4d9-4830-99da-6e6f985727e2-1.mp3
824163ed-b4d9-4830-99da-6e6f985727e2-2.mp3
Replacing the Promise.all with a simple for loop, makes it work. But this takes way longer as it waits for every request to resolve. I know a Promise.all can work, because I had it working before, and would like to see it working again.
const tempAudioFiles = [];
for (var i = 0; i < ssmlParts.length; i++) {
tempAudioFiles[i] = await googleSsmlToSpeech(i, ssmlParts[i], type, identifier, synthesizerOptions, storageUploadPath);
}
I just can't seem to get it to work anymore with a Promise.all.
Got it working. The library seems to do things differently than I thought. Creating a copy of the synthesizerOptions using Object.assign did the trick
Working code: https://github.com/googleapis/nodejs-text-to-speech/issues/210#issuecomment-487832411
ssmlParts.forEach((ssmlPart: string, index: number) => {
const synthesizerOptionsCopy = Object.assign({}, synthesizerOptions);
promises.push(googleSsmlToSpeech(index, ssmlPart, type, identifier, synthesizerOptionsCopy, storageUploadPath));
});
// Inside googleSsmlToSpeech()
const ssmlPartSynthesizerOptions = Object.assign(synthesizerOptions, {
input: {
ssml: ssmlPart
}
});

Use Sinon.fakeServer with promises and mocha

My problem is the following: I want to test a method that uploads a buch of data into an AWS S3 bucket. The problem is: I don't want to really upload data every time I am testing and I don't want to care about credentials sitting in the env. So I want to setup Sinon's fake-server module to simulate the upload and return the same results then S3 would. Sadly, it seems to be difficult to find a working example with code using async/await.
My test looks like this:
import {skip, test, suite} from "mocha-typescript";
import Chai from "chai";
import {S3Uploader} from "./s3-uploader.class";
import Sinon from "sinon";
#suite
class S3UploaderTest {
public server : Sinon.SinonFakeServer | undefined;
before() {
this.server = Sinon.fakeServer.create();
}
after() {
if (this.server != null) this.server.restore();
}
#test
async "should upload a file to s3 correctly"(){
let spy = Sinon.spy();
const uploader : S3Uploader = new S3Uploader();
const upload = await uploader.send("HalloWelt").toBucket("onetimeupload.test").toFolder("test/hw.txt").upload();
Chai.expect(upload).to.be.a("object");
}
}
Inside of the uploader.upload() method, I resolved a promise out of a callback. So how can I simulate the uploading-process?
Edit: Here is the code of the s3-uploader:
import AWS from "aws-sdk";
export class S3Uploader {
private s3 = new AWS.S3({ accessKeyId : process.env.ACCESS_KEY_ID, secretAccessKey : process.env.SECRET_ACCESS_KEY });
private params = {
Body: null || Object,
Bucket: "",
Key: ""
};
public send(stream : any) {
this.params.Body = stream;
return this;
}
public toBucket(bucket : string) {
this.params.Bucket = bucket;
return this;
}
public toFolder(path : string) {
this.params.Key = path;
return this;
}
public upload() {
return new Promise((resolve, reject) => {
if (process.env.ACCESS_KEY_ID == null || process.env.SECRET_ACCESS_KEY == null) {
return reject("ERR_NO_AWS_CREDENTIALS");
}
this.s3.upload(this.params, (error : any, data : any) => {
return error ? reject(error) : resolve(data);
});
});
}
}
Sinon fake servers are something you might use to develop a client that itself makes requests, instead of a wrapper around an existing client like AWS.S3, like you're doing. In this case, you're better off just stubbing the behavior of AWS.S3 instead of testing the actual requests it makes. That way you can avoid testing the implementation details of AWS.S3.
Since you're using TypeScript and you've made your s3 client private, you're going to need to make some changes to expose it to your tests. Otherwise, you won't be able to stub its methods without the TS compiler complaining about it. You also won't be able to write assertions using the params object, for similar reasons.
Since I don't use TS regularly, I'm not too familiar with it's common dependency injection techniques, but one thing you could do is add optional constructor arguments to your S3Uploader class that can overwrite the default s3 and arguments properties, like so:
constructor(s3, params) {
if (s3) this.s3 = s3;
if (params) this.params = params;
}
After which, you can create a stub instance and pass it to your test instance like this:
const s3 = sinon.createStubInstance(AWS.S3);
const params = { foo: 'bar' };
const uploader = new S3Uploader(s3, params);
Once you have the stub instance in place, you can write assertions to make sure the upload method was called the way you want it to be:
sinon.assert.calledOnce(s3.upload);
sinon.assert.calledWith(s3.upload, sinon.match.same(params), sinon.match.func);
You can also affect the behavior the upload method using the sinon stub api. For example, to make it fail like so:
s3.upload.callsArgWith(1, null);
Or make it succeed like so:
const data = { whatever: 'data', you: 'want' };
s3.upload.callsArgWith(1, null, data);
You'll probably want a completely separate test for each of these cases, using an instance before hook to avoid duplicating the common setup stuff. Testing for success will involve simply awaiting the promise and checking that its result is the data. Testing for failure will involve a try/catch that ensures the promise was rejected with the proper error.
Also, since you seem to be doing actual unit tests here, I'll recommend testing each S3Uploader method separately instead of calling them all in once big test. This drastically reduces the number of possible cases you need to cover, making your tests a lot more straightforward. Something like this:
#suite
class S3UploaderTest {
params: any; // Not sure the best way to type this.
s3: any; // Same. Sorry, not too experienced with TS.
uploader: S3Uploader | undefined;
before() {
this.params = {};
this.s3 = sinon.createStubInstance(AWS.S3);
this.uploader = new S3Uploader(this.s3, this.params);
}
#test
"send should set Body param and return instance"() {
const stream = "HalloWelt";
const result = this.uploader.send(stream);
Chai.expect(this.params.Body).to.equal(stream);
Chai.expect(result).to.equal(this.uploader);
}
#test
"toBucket should set Bucket param and return instance"() {
const bucket = "onetimeupload.test"
const result = this.uploader.toBucket(bucket);
Chai.expect(this.params.Bucket).to.equal(bucket);
Chai.expect(result).to.equal(this.uploader);
}
#test
"toFolder should set Key param and return instance"() {
const path = "onetimeupload.test"
const result = this.uploader.toFolder(path);
Chai.expect(this.params.Key).to.equal(path);
Chai.expect(result).to.equal(this.uploader);
}
#test
"upload should attempt upload to s3"() {
this.uploader.upload();
sinon.assert.calledOnce(this.s3.upload);
sinon.assert.calledWith(
this.s3.upload,
sinon.match.same(this.params),
sinon.match.func
);
}
#test
async "upload should resolve with response if successful"() {
const data = { foo: 'bar' };
s3.upload.callsArgWith(1, null, data);
const result = await this.uploader.upload();
Chai.expect(result).to.equal(data);
}
#test
async "upload should reject with error if not"() {
const error = new Error('Test Error');
s3.upload.callsArgWith(1, error, null);
try {
await this.uploader.upload();
throw new Error('Promise should have rejected.');
} catch(err) {
Chai.expect(err).to.equal(err);
}
}
}
If I were doing this with mocha proper, I'd group each method's tests into a nested describe block. I'm not sure if that's encouraged or even possible with mocha-typescript, but if so you might consider it.

Resources