Last active
June 10, 2020 13:47
-
-
Save shrys/2d6b4c0c85095a628c261eaeeef34a8b to your computer and use it in GitHub Desktop.
Nodejs implementation to obtain smtp password from signed secret key for AWS SES using node/crypto
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const c = require('crypto'); | |
const utf8 = require('utf8'); | |
const key = 'YOUR_SECRET_KEY'; | |
const region = 'us-east-1'; | |
const date = '11111111'; | |
const service = 'ses'; | |
const terminal = 'aws4_request'; | |
const message = 'SendRawEmail'; | |
const versionInBytes = [0x04]; | |
function sign(key, msg) { | |
return c.createHmac('sha256', Buffer.from(key.map(a => a.charCodeAt(0)))) | |
.update(utf8.encode(msg)) | |
.digest('latin1') | |
.split(''); | |
} | |
let signature = sign((utf8.encode('AWS4' + key)).split(''), date); | |
signature = sign(signature, region); | |
signature = sign(signature, service); | |
signature = sign(signature, terminal); | |
signature = sign(signature, message); | |
const signatureAndVersion = versionInBytes.slice(); //copy of array | |
signature.forEach(a => signatureAndVersion.push(a.charCodeAt(0))); | |
const smtpPassword = Buffer.from(signatureAndVersion).toString('base64'); | |
console.log(smtpPassword); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"name": "sample", | |
"version": "1.0.0", | |
"description": "", | |
"main": "indext.ts", | |
"scripts": { | |
"test": "echo \"Error: no test specified\" && exit 1" | |
}, | |
"author": "", | |
"license": "ISC", | |
"dependencies": { | |
"@types/node": "^14.0.12", | |
"@types/utf8": "^2.1.6", | |
"express": "^4.17.1", | |
"express.js": "^1.0.0", | |
"utf8": "^3.0.0" | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"compilerOptions": { | |
"target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */ | |
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */ | |
"strict": true, /* Enable all strict type-checking options. */ | |
"noImplicitAny": false, /* Raise error on expressions and declarations with an implied 'any' type. */ | |
"esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ | |
"skipLibCheck": true, /* Skip type checking of declaration files. */ | |
"forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */ | |
} | |
} |
Thanks, better with latin1 indeed.
For the others, noImplicitAny can be set to true if desired with that code :
// Convert to SMTP base64 password
const crypto = require('crypto');
const utf8 = require('utf8');
const key = MyKey
const region = MyRegion;
const date = '11111111';
const service = 'ses';
const terminal = 'aws4_request';
const message = 'SendRawEmail';
const versionInBytes = [0x04];
function sign(key: { map: (arg0: (a: any) => any) => ArrayBuffer | SharedArrayBuffer; }, msg: string) {
return crypto.createHmac('sha256', Buffer.from(key.map((a: string) => a.charCodeAt(0))))
.update(utf8.encode(msg))
.digest('latin1')
.split('');
}
let signature = sign((utf8.encode('AWS4' + key)).split(''), date);
signature = sign(signature, region);
signature = sign(signature, service);
signature = sign(signature, terminal);
signature = sign(signature, message);
const signatureAndVersion = versionInBytes.slice(); //copy of array
signature.forEach((a: string) => signatureAndVersion.push(a.charCodeAt(0)));
const smtpPassword = Buffer.from(signatureAndVersion).toString('base64');
But a SMTP connection test don't seems to work, strange. I follow that proc :
https://docs.aws.amazon.com/fr_fr/ses/latest/DeveloperGuide/send-email-smtp-client-command-line.html
I've a :
535 Authentication Credentials Invalid
530 Authentication required
I'm also testing with working credentials from an application using SES; so maybe I doing something wrong with the AWS testing proc.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hi @Cloudrage, thank you for pointing it out. I have updated the gist with working code and the configurations I have been using.
The problems I think are caused by typescript language in vscode, I've used the
"noImplicitAny": false,
option to suppress them. For argument type, I have corrected it tolatin1
as you rightly pointed out. Docs mention it astype HexBase64Latin1Encoding = "latin1" | "hex" | "base64";