Skip to content

Instantly share code, notes, and snippets.

@toolboc
Last active August 31, 2018 23:21
Show Gist options
  • Save toolboc/2ab5e578c43e61895d60c90215532847 to your computer and use it in GitHub Desktop.
Save toolboc/2ab5e578c43e61895d60c90215532847 to your computer and use it in GitHub Desktop.
SAS token generation in C; compile with `gcc -o sas sas.c -lm -lssl -lcrypto`
#include <openssl/bio.h>
#include <openssl/evp.h>
#include <openssl/hmac.h>
#include <openssl/crypto.h>
#include <time.h>
#include <string.h>
#include <openssl/buffer.h>
#include <stdint.h>
#include <ctype.h>
#include <math.h>
/*
SAS token generation in C; compile with `gcc -o sas sas.c -lm -lssl -lcrypto`
*/
size_t calcDecodeLength(const char* b64input) {
size_t len = strlen(b64input),
padding = 0;
if (b64input[len-1] == '=' && b64input[len-2] == '=') //last two chars are =
padding = 2;
else if (b64input[len-1] == '=') //last char is =
padding = 1;
return (len*3)/4 - padding;
}
int Base64Decode(char* b64message, unsigned char** buffer, size_t* length) {
BIO *bio, *b64;
int decodeLen = calcDecodeLength(b64message);
*buffer = (unsigned char*)malloc(decodeLen + 1);
(*buffer)[decodeLen] = '\0';
bio = BIO_new_mem_buf(b64message, -1);
b64 = BIO_new(BIO_f_base64());
bio = BIO_push(b64, bio);
BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL); //Do not use newlines to flush buffer
*length = BIO_read(bio, *buffer, strlen(b64message));
// BIO_free_all(bio);
return (0);
}
int Base64Encode2(const char* message, char** buffer) {
BIO *bio, *b64;
FILE* stream;
int encodedSize = 4*ceil((double)strlen(message)/3);
*buffer = (char *)malloc(encodedSize+1);
stream = fmemopen(*buffer, encodedSize+1, "w");
b64 = BIO_new(BIO_f_base64());
bio = BIO_new_fp(stream, BIO_NOCLOSE);
bio = BIO_push(b64, bio);
BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL); //Ignore newlines - write everything in one line
BIO_write(bio, message, strlen(message));
BIO_flush(bio);
BIO_free_all(bio);
fclose(stream);
return (0); //success
}
char rfc3986[256] = {0};
char html5[256] = {0};
void encode(char *s, char *enc, char *tb)
{
for (; *s; s++) {
if (tb[*s]) sprintf(enc, "%c", tb[*s]);
else sprintf(enc, "%%%02X", *s);
while (*++enc);
}
}
int urlEncode(char *enc, char *url)
{
int i;
for (i = 0; i < 256; i++) {
rfc3986[i] = isalnum(i)||i == '~'||i == '-'||i == '.'||i == '_'
? i : 0;
html5[i] = isalnum(i)||i == '*'||i == '-'||i == '.'||i == '_'
? i : (i == ' ') ? '+' : 0;
}
encode(url, enc, rfc3986);
return 0;
}
void main() {
char uri[] = "tiara.azure-devices.net/devices/devicePaho";
char encodedUri[(strlen(uri) * 3) +1];
urlEncode(encodedUri, uri);
printf("encodeduri: %s\n", encodedUri);
unsigned char key[] = "K1VrD7A8YdWWzH8Q3krGztNAmUODB1GUqJ76WOIdA9Q=";
size_t keyLen;
unsigned char *decodedKey;
Base64Decode(key, &decodedKey, &keyLen);
printf("decoded key: ");
int i;
for(i = 0; i < keyLen; i++) printf("%02x", decodedKey[i]);
int toSignLen = strlen(encodedUri) + 12;
unsigned char toSign[toSignLen];
int expiry = 1546300800;
printf("\ntimestamp: %d\n", expiry);
snprintf(toSign, toSignLen, "%s\n%d", encodedUri, expiry);
printf("toSign: %s\n", toSign);
unsigned char* result;
unsigned int resultLen = 32;
result = (unsigned char*) malloc(sizeof(char) * resultLen);
result = HMAC(EVP_sha256(), decodedKey, strlen(decodedKey), toSign, strlen(toSign), NULL, NULL);
printf("sig: ");
for(i = 0; i < resultLen; i++) printf("%02x", result[i]);
char* base64EncodeOutput;
Base64Encode2(result, &base64EncodeOutput);
printf("\nb64: %s\n", base64EncodeOutput);
char enc[(strlen(base64EncodeOutput) * 3) + 1];
urlEncode(enc, base64EncodeOutput);
char token[256];
snprintf(token, sizeof(token), "SharedAccessSignature sr=%s&sig=%s&se=%d", encodedUri, enc, expiry);
printf("final signature: %s\n", token);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment