OAuth library for twitter. Original: http://mbed.org/users/soramimi/programs/Twitter/
Revision 0:0048b264a3ad, committed 2011-12-12
- Comitter:
- takahashim
- Date:
- Mon Dec 12 18:47:10 2011 +0000
- Commit message:
- publish library
Changed in this revision
diff -r 000000000000 -r 0048b264a3ad OAuth4Tw.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OAuth4Tw.cpp Mon Dec 12 18:47:10 2011 +0000 @@ -0,0 +1,28 @@ +#include "OAuth4Tw.h" +#include "mbed.h" +#include "oauth.h" + +OAuth4Tw::OAuth4Tw(const char *c_key, const char *c_secret, + const char *t_key, const char *t_secret) + :consumer_key(c_key), + consumer_secret(c_secret), + token_key(t_key), + token_secret(t_secret) { } + +std::string OAuth4Tw::url_escape(const char *str) { + return oauth_url_escape(str); +} + +std::string OAuth4Tw::post(const char *uri, std::string postarg) { + + std::string req_url; + std::string postres; + + req_url = oauth_sign_url2(uri, &postarg, OA_HMAC, 0, + consumer_key, consumer_secret, token_key, token_secret); + printf("req_url2:%s\n", req_url.c_str()); + + postres = oauth_http_post(req_url.c_str(), postarg.c_str()); + return postres; +} +
diff -r 000000000000 -r 0048b264a3ad OAuth4Tw.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OAuth4Tw.h Mon Dec 12 18:47:10 2011 +0000 @@ -0,0 +1,23 @@ +#ifndef MBED_OAUTH4TW_H +#define MBED_OAUTH4TW_H + +#include "mbed.h" +#include "oauth.h" + +class OAuth4Tw { +public: + OAuth4Tw(const char *c_key, const char *c_secret, + const char *t_key, const char *t_secret); + + static std::string url_escape(const char *str); + + std::string post(const char *uri, std::string postarg); + +private: + const char *consumer_key; + const char *consumer_secret; + const char *token_key; + const char *token_secret; +}; + +#endif
diff -r 000000000000 -r 0048b264a3ad hash.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hash.cpp Mon Dec 12 18:47:10 2011 +0000 @@ -0,0 +1,56 @@ + +#include "oauth.h" // base64 encode fn's. +#include "sha1.h" + +#include <string.h> + +void hmac_sha1(unsigned char const *key, size_t keylen, unsigned char const *in, size_t inlen, unsigned char *resbuf) +{ + struct SHA1Context inner; + struct SHA1Context outer; + unsigned char tmpkey[20]; + unsigned char digest[20]; + unsigned char block[64]; + + const int IPAD = 0x36; + const int OPAD = 0x5c; + + if (keylen > 64) { + struct SHA1Context keyhash; + SHA1Reset(&keyhash); + SHA1Input(&keyhash, key, keylen); + SHA1Result(&keyhash, tmpkey); + key = tmpkey; + keylen = 20; + } + + for (size_t i = 0; i < sizeof(block); i++) { + block[i] = IPAD ^ (i < keylen ? key[i] : 0); + } + SHA1Reset(&inner); + SHA1Input(&inner, block, 64); + SHA1Input(&inner, in, inlen); + SHA1Result(&inner, digest); + + for (size_t i = 0; i < sizeof(block); i++) { + block[i] = OPAD ^ (i < keylen ? key[i] : 0); + } + SHA1Reset(&outer); + SHA1Input(&outer, block, 64); + SHA1Input(&outer, digest, 20); + SHA1Result(&outer, resbuf); +} + + +std::string oauth_sign_hmac_sha1(const char *m, const char *k) +{ + return oauth_sign_hmac_sha1_raw(m, strlen(m), k, strlen(k)); +} + +std::string oauth_sign_hmac_sha1_raw(const char *m, const size_t ml, const char *k, const size_t kl) +{ + unsigned char result[20]; + hmac_sha1((unsigned char const *)k, kl, (unsigned char const *)m, ml, result); + return oauth_encode_base64(result, 20); +} +
diff -r 000000000000 -r 0048b264a3ad oauth.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/oauth.cpp Mon Dec 12 18:47:10 2011 +0000 @@ -0,0 +1,719 @@ +/* + * OAuth string functions in POSIX-C. + * + * Copyright 2007-2010 Robin Gareus <robin@gareus.org> + * + * The base64 functions are by Jan-Henrik Haukeland, <hauk@tildeslash.com> + * and un/escape_url() was inspired by libcurl's curl_escape under ISC-license + * many thanks to Daniel Stenberg <daniel@haxx.se>. + * + * 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. + * + */ +#if HAVE_CONFIG_H +# include <config.h> +#endif + +#define WIPE_MEMORY ///< overwrite sensitve data before free()ing it. + +#include <stdio.h> +#include <stdarg.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <math.h> +#include <ctype.h> // isxdigit + +#include "oauth.h" + +#include <vector> +#include <algorithm> +#include <sstream> + +/** + * Base64 encode one byte + */ +char oauth_b64_encode(unsigned char u) +{ + if (u < 26) return 'A' + u; + if (u < 52) return 'a' + (u - 26); + if (u < 62) return '0' + (u - 52); + if (u == 62) return '+'; + return '/'; +} + +/** + * Decode a single base64 character. + */ +unsigned char oauth_b64_decode(char c) +{ + if (c >= 'A' && c <= 'Z') return(c - 'A'); + if (c >= 'a' && c <= 'z') return(c - 'a' + 26); + if (c >= '0' && c <= '9') return(c - '0' + 52); + if (c == '+') return 62; + return 63; +} + +/** + * Return TRUE if 'c' is a valid base64 character, otherwise FALSE + */ +bool oauth_b64_is_base64(char c) +{ + return ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || (c == '+') || (c == '/') || (c == '=')); +} + +/** + * Base64 encode and return size data in 'src'. The caller must free the + * returned string. + * + * @param size The size of the data in src + * @param src The data to be base64 encode + * @return encoded string otherwise NULL + */ +std::string oauth_encode_base64(const unsigned char *src, int size) +{ + int i; + std::stringbuf sb; + + if (!src) return NULL; + if (!size) size= strlen((char *)src); + + for (i = 0; i < size; i += 3) { + unsigned char b1 = 0, b2 = 0, b3 = 0, b4 = 0, b5 = 0, b6 = 0, b7 = 0; + b1= src[i]; + if (i + 1 < size) b2 = src[i + 1]; + if (i + 2 < size) b3 = src[i + 2]; + + b4= b1 >> 2; + b5= ((b1 & 0x3) << 4) | (b2 >> 4); + b6= ((b2 & 0xf) << 2) | (b3 >> 6); + b7= b3 & 0x3f; + + sb.sputc(oauth_b64_encode(b4)); + sb.sputc(oauth_b64_encode(b5)); + + if (i + 1 < size) { + sb.sputc(oauth_b64_encode(b6)); + } else { + sb.sputc('='); + } + + if (i + 2 < size) { + sb.sputc(oauth_b64_encode(b7)); + } else { + sb.sputc('='); + } + } + return sb.str(); +} + +/** + * Decode the base64 encoded string 'src' into the memory pointed to by + * 'dest'. + * + * @param dest Pointer to memory for holding the decoded string. + * Must be large enough to receive the decoded string. + * @param src A base64 encoded string. + * @return the length of the decoded string if decode + * succeeded otherwise 0. + */ +std::string oauth_decode_base64(const char *src) +{ + if (src && *src) { + std::stringbuf sb; + //unsigned char *p= dest; + int k, l= strlen(src)+1; + std::vector<unsigned char> buf(l); + + /* Ignore non base64 chars as per the POSIX standard */ + for (k = 0, l = 0; src[k]; k++) { + if (oauth_b64_is_base64(src[k])) { + buf[l++]= src[k]; + } + } + + for (k = 0; k < l; k += 4) { + char c1='A', c2='A', c3='A', c4='A'; + unsigned char b1 = 0, b2 = 0, b3 = 0, b4 = 0; + c1= buf[k]; + + if (k + 1 < l) c2 = buf[k + 1]; + if (k + 2 < l) c3 = buf[k + 2]; + if (k + 3 < l) c4 = buf[k + 3]; + + b1 = oauth_b64_decode(c1); + b2 = oauth_b64_decode(c2); + b3 = oauth_b64_decode(c3); + b4 = oauth_b64_decode(c4); + + sb.sputc((b1 << 2) | (b2 >> 4)); + + if (c3 != '=') sb.sputc(((b2 & 0xf) << 4) | (b3 >> 2)); + if (c4 != '=') sb.sputc(((b3 & 0x3) << 6) | b4); + } + + return sb.str(); + } + return 0; +} + +/** + * Escape 'string' according to RFC3986 and + * http://oauth.net/core/1.0/#encoding_parameters. + * + * @param string The data to be encoded + * @return encoded string otherwise NULL + * The caller must free the returned string. + */ +std::string oauth_url_escape(const char *string) +{ + unsigned char in; + size_t length; + + if (!string) { + return std::string(); + } + + length = strlen(string); + + std::stringbuf sb; + + while (length--) { + in = *string; + if (strchr("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_~.-", in)) { + sb.sputc(in); + } else { + char tmp[10]; + snprintf(tmp, 4, "%%%02X", in); + sb.sputc(tmp[0]); + sb.sputc(tmp[1]); + sb.sputc(tmp[2]); + } + string++; + } + return sb.str(); +} + +#ifndef ISXDIGIT +# define ISXDIGIT(x) (isxdigit((int) ((unsigned char)x))) +#endif + +/** + * Parse RFC3986 encoded 'string' back to unescaped version. + * + * @param string The data to be unescaped + * @param olen unless NULL the length of the returned string is stored there. + * @return decoded string or NULL + * The caller must free the returned string. + */ +std::string oauth_url_unescape(const char *string) +{ + size_t alloc, strindex=0; + unsigned char in; + long hex; + + if (!string) return NULL; + + alloc = strlen(string)+1; + std::vector<char> ns(alloc); + + while(--alloc > 0) { + in = *string; + if (('%' == in) && ISXDIGIT(string[1]) && ISXDIGIT(string[2])) { + char hexstr[3]; // '%XX' + hexstr[0] = string[1]; + hexstr[1] = string[2]; + hexstr[2] = 0; + hex = strtol(hexstr, NULL, 16); + in = (unsigned char)hex; /* hex is always < 256 */ + string += 2; + alloc -= 2; + } + ns[strindex++] = in; + string++; + } + ns[strindex]=0; + return &ns[0]; +} + +/** + * returns plaintext signature for the given key. + * + * the returned string needs to be freed by the caller + * + * @param m message to be signed + * @param k key used for signing + * @return signature string + */ +std::string oauth_sign_plaintext (const char *m, const char *k) +{ + return oauth_url_escape(k); +} + +/** + * encode strings and concatenate with '&' separator. + * The number of strings to be concatenated must be + * given as first argument. + * all arguments thereafter must be of type (char *) + * + * @param len the number of arguments to follow this parameter + * @param ... string to escape and added (may be NULL) + * + * @return pointer to memory holding the concatenated + * strings - needs to be free(d) by the caller. or NULL + * in case we ran out of memory. + */ +std::string oauth_catenc(int len, ...) +{ + va_list va; + std::string str; + va_start(va, len); + for (int i = 0; i < len; i++) { + char *arg = va_arg(va, char *); + std::string enc = oauth_url_escape(arg); + if (i > 0) str += "&"; + str += enc; + } + va_end(va); + return str; +} + +/** + * splits the given url into a parameter array. + * (see \ref oauth_serialize_url and \ref oauth_serialize_url_parameters for the reverse) + * + * NOTE: Request-parameters-values may include an ampersand character. + * However if unescaped this function will use them as parameter delimiter. + * If you need to make such a request, this function since version 0.3.5 allows + * to use the ASCII SOH (0x01) character as alias for '&' (0x26). + * (the motivation is convenience: SOH is /untypeable/ and much more + * unlikely to appear than '&' - If you plan to sign fancy URLs you + * should not split a query-string, but rather provide the parameter array + * directly to \ref oauth_serialize_url) + * + * @param url the url or query-string to parse. + * @param argv pointer to a (char *) array where the results are stored. + * The array is re-allocated to match the number of parameters and each + * parameter-string is allocated with strdup. - The memory needs to be freed + * by the caller. + * @param qesc use query parameter escape (vs post-param-escape) - if set + * to 1 all '+' are treated as spaces ' ' + * + * @return number of parameter(s) in array. + */ +void oauth_split_post_paramters(const char *url, std::vector<std::string> *argv, short qesc) +{ + int argc=0; + char *token, *tmp; + if (!argv) return; + if (!url) return; + std::vector<char> t1(strlen(url) + 1); + strcpy(&t1[0], url); + + // '+' represents a space, in a URL query string + while ((qesc&1) && (tmp = strchr(&t1[0],'+'))) *tmp = ' '; + + tmp = &t1[0]; + while ((token = strtok(tmp,"&?"))) { + if (!strncasecmp("oauth_signature=", token, 16)) continue; + while (!(qesc & 2) && (tmp = strchr(token, '\001'))) *tmp = '&'; + argv->push_back(oauth_url_unescape(token)); + if (argc == 0 && strstr(token, ":/")) { + // HTTP does not allow empty absolute paths, so the URL + // 'http://example.com' is equivalent to 'http://example.com/' and should + // be treated as such for the purposes of OAuth signing (rfc2616, section 3.2.1) + // see http://groups.google.com/group/oauth/browse_thread/thread/c44b6f061bfd98c?hl=en + char *slash = strstr(token, ":/"); + while (slash && *(++slash) == '/') ; // skip slashes eg /xxx:[\/]*/ +#if 0 + // skip possibly unescaped slashes in the userinfo - they're not allowed by RFC2396 but have been seen. + // the hostname/IP may only contain alphanumeric characters - so we're safe there. + if (slash && strchr(slash,'@')) slash=strchr(slash, '@'); +#endif + if (slash && !strchr(slash,'/')) { +#ifdef DEBUG_OAUTH + fprintf(stderr, "\nliboauth: added trailing slash to URL: '%s'\n\n", token); +#endif + argv->push_back(std::string(token) + "/"); + } + } + if (argc == 0 && (tmp = strstr((char *)argv->at(argc).c_str(), ":80/"))) { + memmove(tmp, tmp + 3, strlen(tmp + 2)); + } + tmp = NULL; + argc++; + } +} + +void oauth_split_url_parameters(const char *url, std::vector<std::string> *argv) +{ + oauth_split_post_paramters(url, argv, 1); +} + +/** + * build a url query string from an array. + * + * @param argc the total number of elements in the array + * @param start element in the array at which to start concatenating. + * @param argv parameter-array to concatenate. + * @return url string needs to be freed by the caller. + * + */ +std::string oauth_serialize_url (std::vector<std::string> const &argv, int start) +{ + return oauth_serialize_url_sep(argv, start, "&", 0); +} + +/** + * encode query parameters from an array. + * + * @param argc the total number of elements in the array + * @param start element in the array at which to start concatenating. + * @param argv parameter-array to concatenate. + * @param sep separator for parameters (usually "&") + * @param mod - bitwise modifiers: + * 1: skip all values that start with "oauth_" + * 2: skip all values that don't start with "oauth_" + * 4: add double quotation marks around values (use with sep=", " to generate HTTP Authorization header). + * @return url string needs to be freed by the caller. + */ +std::string oauth_serialize_url_sep(std::vector<std::string> const &argv, int start, char const *sep, int mod) +{ + int i; + int first = 0; + int seplen = strlen(sep); + std::string query; + for (i = start; i < (int)argv.size(); i++) { + std::string tmp; + + if ((mod & 1) == 1 && (strncmp(argv[i].c_str(), "oauth_", 6) == 0 || strncmp(argv[i].c_str(), "x_oauth_", 8) == 0)) continue; + if ((mod & 2) == 2 && (strncmp(argv[i].c_str(), "oauth_", 6) != 0 && strncmp(argv[i].c_str(), "x_oauth_", 8) != 0) && i != 0) continue; + + if (i == start && i == 0 && strstr(argv[i].c_str(), ":/")) { + tmp = argv[i]; + } else { + char *p = strchr((char *)argv[i].c_str(), '='); + if (p) { + tmp = oauth_url_escape(std::string(argv[i].c_str(), (char const *)p).c_str()); + std::string t2 = oauth_url_escape(p + 1); + tmp += "="; + if (mod & 4) tmp += "\""; + tmp += t2; + if (mod & 4) tmp += "\""; + } else { + // see http://oauth.net/core/1.0/#anchor14 + // escape parameter names and arguments but not the '=' + tmp=argv[i]; + tmp += "="; + } + } + query += ((i == start || first) ? "" : sep); + query += tmp; + first = 0; + if (i == start && i == 0 && strstr((char *)tmp.c_str(), ":/")) { + query += "?"; + first = 1; + } + } + return (query); +} + +/** + * build a query parameter string from an array. + * + * This function is a shortcut for \ref oauth_serialize_url (argc, 1, argv). + * It strips the leading host/path, which is usually the first + * element when using oauth_split_url_parameters on an URL. + * + * @param argc the total number of elements in the array + * @param argv parameter-array to concatenate. + * @return url string needs to be freed by the caller. + */ +std::string oauth_serialize_url_parameters (std::vector<std::string> const &argv) +{ + return oauth_serialize_url(argv, 1); +} + +/** + * generate a random string between 15 and 32 chars length + * and return a pointer to it. The value needs to be freed by the + * caller + * + * @return zero terminated random string. + */ +std::string oauth_gen_nonce() +{ + static const char *chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"; + const unsigned int max = 26 + 26 + 10 + 1; //strlen(chars); + char tmp[50]; + int i, len; + + srand((unsigned int)time(0)); + len = 15 + rand() % 16; + for (i = 0; i < len; i++) { + tmp[i] = chars[rand() % max]; + } + tmp[i]='\0'; + return &tmp[0]; +} + +/** + * string compare function for oauth parameters. + * + * used with qsort. needed to normalize request parameters. + * see http://oauth.net/core/1.0/#anchor14 + */ +int oauth_cmpstringp(const void *p1, const void *p2) +{ + char const *e1; + char const *e2; + e1 = strchr((char *)p1, '='); + e2 = strchr((char *)p2, '='); + if (e1 && e2) { + std::string left((char const *)p1, e1); + std::string right((char const *)p2, e2); + return strcmp(left.c_str(), right.c_str()); + } + + std::string left = oauth_url_escape((char const *)p1); + std::string right = oauth_url_escape((char const *)p2); + return strcmp(left.c_str(), right.c_str()); +} + +bool oauth_cmpstringp_ex(std::string const &left, std::string const &right) +{ + return oauth_cmpstringp(left.c_str(), right.c_str()) < 0; +} + +/** + * search array for parameter key. + * @param argv length of array to search + * @param argc parameter array to search + * @param key key of parameter to check. + * + * @return FALSE (0) if array does not contain a parameter with given key, TRUE (1) otherwise. + */ +bool oauth_param_exists(std::vector<std::string> const &argv, char const *key) +{ + int i; + size_t l = strlen(key); + for (i = 0; i < (int)argv.size(); i++) { + if (!strncmp(argv[i].c_str(), key, l) && argv[i][l] == '=') { + return true; + } + } + return false; +} + +/** + * + */ +void oauth_add_protocol( + std::vector<std::string> *argvp, + OAuthMethod method, + const char *c_key, //< consumer key - posted plain text + const char *t_key //< token key - posted plain text in URL +) +{ + char oarg[1024]; + + // add OAuth specific arguments + if (!oauth_param_exists(*argvp,"oauth_nonce")) { + std::string tmp = oauth_gen_nonce(); + snprintf(oarg, 1024, "oauth_nonce=%s", tmp.c_str()); + argvp->push_back(oarg); + } + + if (!oauth_param_exists(*argvp,"oauth_timestamp")) { + long t = time(0); + snprintf(oarg, 1024, "oauth_timestamp=%u", t); + argvp->push_back(oarg); + } + + if (t_key) { + snprintf(oarg, 1024, "oauth_token=%s", t_key); + argvp->push_back(oarg); + } + + snprintf(oarg, 1024, "oauth_consumer_key=%s", c_key); + argvp->push_back(oarg); + + snprintf(oarg, 1024, "oauth_signature_method=%s", method==0?"HMAC-SHA1":method==1?"RSA-SHA1":"PLAINTEXT"); + argvp->push_back(oarg); + + if (!oauth_param_exists(*argvp,"oauth_version")) { + snprintf(oarg, 1024, "oauth_version=1.0"); + argvp->push_back(oarg); + } + +#if 0 // oauth_version 1.0 Rev A + if (!oauth_param_exists(argv,argc,"oauth_callback")) { + snprintf(oarg, 1024, "oauth_callback=oob"); + argvp->push_back(oarg); + } +#endif + +} + +std::string oauth_sign_url( + const char *url, + std::string *postargs, + OAuthMethod method, + const char *c_key, //< consumer key - posted plain text + const char *c_secret, //< consumer secret - used as 1st part of secret-key + const char *t_key, //< token key - posted plain text in URL + const char *t_secret //< token secret - used as 2st part of secret-key +) +{ + return oauth_sign_url2(url, postargs, method, NULL, c_key, c_secret, t_key, t_secret); +} + +std::string oauth_sign_url2( + const char *url, + std::string *postargs, + OAuthMethod method, + const char *http_method, //< HTTP request method + const char *c_key, //< consumer key - posted plain text + const char *c_secret, //< consumer secret - used as 1st part of secret-key + const char *t_key, //< token key - posted plain text in URL + const char *t_secret //< token secret - used as 2st part of secret-key +) +{ + //char **argv = NULL; + std::vector<std::string> argv; + std::string rv; + + if (postargs) { + oauth_split_post_paramters(url, &argv, 0); + } else { + oauth_split_url_parameters(url, &argv); + } + + rv = oauth_sign_array2(&argv, postargs, method, http_method, c_key, c_secret, t_key, t_secret); + + return(rv); +} + +std::string oauth_sign_array( + std::vector<std::string> *argvp, + std::string *postargs, + OAuthMethod method, + const char *c_key, //< consumer key - posted plain text + const char *c_secret, //< consumer secret - used as 1st part of secret-key + const char *t_key, //< token key - posted plain text in URL + const char *t_secret //< token secret - used as 2st part of secret-key +) +{ + return oauth_sign_array2( + argvp, + postargs, method, + NULL, + c_key, c_secret, + t_key, t_secret + ); +} + +void oauth_sign_array2_process( + std::vector<std::string> *argvp, + std::string *postargs, + OAuthMethod method, + const char *http_method, //< HTTP request method + const char *c_key, //< consumer key - posted plain text + const char *c_secret, //< consumer secret - used as 1st part of secret-key + const char *t_key, //< token key - posted plain text in URL + const char *t_secret //< token secret - used as 2st part of secret-key +) +{ + char oarg[1024]; + std::string query; + std::string sign; + std::string http_request_method; + + if (!http_method) { + http_request_method = postargs ? "POST" : "GET"; + } else { + std::vector<char> tmp(strlen(http_method) + 1); + int i; + for (i = 0; http_method[i]; i++) { + tmp[i] = toupper(http_method[i]); + } + tmp[i] = 0; + http_request_method = &tmp[0]; + } + + // add required OAuth protocol parameters + oauth_add_protocol(argvp, method, c_key, t_key); + + // sort parameters + //qsort(&(*argvp)[1], (*argcp)-1, sizeof(char *), oauth_cmpstringp); + std::sort(argvp->begin() + 1, argvp->end(), oauth_cmpstringp_ex); + + // serialize URL - base-url + query= oauth_serialize_url_parameters(*argvp); + + // generate signature + std::string okey = oauth_catenc(2, c_secret, t_secret); + std::string odat = oauth_catenc(3, http_request_method.c_str(), (*argvp)[0].c_str(), query.c_str()); // base-string +#ifdef DEBUG_OAUTH + fprintf (stderr, "\nliboauth: data to sign='%s'\n\n", odat.c_str()); + fprintf (stderr, "\nliboauth: key='%s'\n\n", okey.c_str()); +#endif + switch(method) { + //case OA_RSA: + // sign = oauth_sign_rsa_sha1(odat.c_str(), okey.c_str()); // XXX okey needs to be RSA key! + // break; + case OA_PLAINTEXT: + sign = oauth_sign_plaintext(odat.c_str(), okey.c_str()).c_str(); + break; + default: + sign = oauth_sign_hmac_sha1(odat.c_str(), okey.c_str()); + break; + } + + // append signature to query args. + snprintf(oarg, 1024, "oauth_signature=%s",sign.c_str()); + argvp->push_back(oarg); +} + +std::string oauth_sign_array2( + std::vector<std::string> *argvp, + std::string *postargs, + OAuthMethod method, + const char *http_method, //< HTTP request method + const char *c_key, //< consumer key - posted plain text + const char *c_secret, //< consumer secret - used as 1st part of secret-key + const char *t_key, //< token key - posted plain text in URL + const char *t_secret //< token secret - used as 2st part of secret-key +) +{ + + std::string result; + oauth_sign_array2_process(argvp, postargs, method, http_method, c_key, c_secret, t_key, t_secret); + + // build URL params + result = oauth_serialize_url(*argvp, (postargs?1:0)); + + if (postargs) { + *postargs = result; + result = argvp->at(0); + } + + return result; +} +
diff -r 000000000000 -r 0048b264a3ad oauth.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/oauth.h Mon Dec 12 18:47:10 2011 +0000 @@ -0,0 +1,476 @@ +/** + * @brief OAuth.net implementation in POSIX-C. + * @file oauth.h + * @author Robin Gareus <robin@gareus.org> + * + * Copyright 2007-2010 Robin Gareus <robin@gareus.org> + * + * 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. + * + */ +#ifndef _OAUTH_H +#define _OAUTH_H 1 + +#include <vector> +#include <string> + +#include <stdlib.h> + +#ifndef DOXYGEN_IGNORE +// liboauth version +#define LIBOAUTH_VERSION "0.8.9" +#define LIBOAUTH_VERSION_MAJOR 0 +#define LIBOAUTH_VERSION_MINOR 8 +#define LIBOAUTH_VERSION_MICRO 9 + +//interface revision number +//http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html +#define LIBOAUTH_CUR 7 +#define LIBOAUTH_REV 0 +#define LIBOAUTH_AGE 7 +#endif + +#ifdef __GNUC__ +# define OA_GCC_VERSION_AT_LEAST(x,y) (__GNUC__ > x || __GNUC__ == x && __GNUC_MINOR__ >= y) +#else +# define OA_GCC_VERSION_AT_LEAST(x,y) 0 +#endif + +#ifndef attribute_deprecated +#if OA_GCC_VERSION_AT_LEAST(3,1) +# define attribute_deprecated __attribute__((deprecated)) +#else +# define attribute_deprecated +#endif +#endif + +/** \enum OAuthMethod + * signature method to used for signing the request. + */ +typedef enum { + OA_HMAC=0, ///< use HMAC-SHA1 request signing method + OA_RSA, ///< use RSA signature + OA_PLAINTEXT ///< use plain text signature (for testing only) + } OAuthMethod; + +/** + * Base64 encode and return size data in 'src'. The caller must free the + * returned string. + * + * @param size The size of the data in src + * @param src The data to be base64 encode + * @return encoded string otherwise NULL + */ +std::string oauth_encode_base64(const unsigned char *src, int size); + +/** + * Decode the base64 encoded string 'src' into the memory pointed to by + * 'dest'. + * + * @param dest Pointer to memory for holding the decoded string. + * Must be large enough to receive the decoded string. + * @param src A base64 encoded string. + * @return the length of the decoded string if decode + * succeeded otherwise 0. + */ +std::string oauth_decode_base64(const char *src); + +/** + * Escape 'string' according to RFC3986 and + * http://oauth.net/core/1.0/#encoding_parameters. + * + * @param string The data to be encoded + * @return encoded string otherwise NULL + * The caller must free the returned string. + */ +std::string oauth_url_escape(const char *string); + +/** + * Parse RFC3986 encoded 'string' back to unescaped version. + * + * @param string The data to be unescaped + * @param olen unless NULL the length of the returned string is stored there. + * @return decoded string or NULL + * The caller must free the returned string. + */ +std::string oauth_url_unescape(const char *string); + + +/** + * returns base64 encoded HMAC-SHA1 signature for + * given message and key. + * both data and key need to be urlencoded. + * + * the returned string needs to be freed by the caller + * + * @param m message to be signed + * @param k key used for signing + * @return signature string. + */ +std::string oauth_sign_hmac_sha1 (const char *m, const char *k); + +/** + * same as \ref oauth_sign_hmac_sha1 but allows + * to specify length of message and key (in case they contain null chars). + * + * @param m message to be signed + * @param ml length of message + * @param k key used for signing + * @param kl length of key + * @return signature string. + */ +std::string oauth_sign_hmac_sha1_raw(const char *m, const size_t ml, const char *k, const size_t kl); + +/** + * returns plaintext signature for the given key. + * + * the returned string needs to be freed by the caller + * + * @param m message to be signed + * @param k key used for signing + * @return signature string + */ +std::string oauth_sign_plaintext(const char *m, const char *k); + +/** + * returns RSA-SHA1 signature for given data. + * the returned signature needs to be freed by the caller. + * + * @param m message to be signed + * @param k private-key PKCS and Base64-encoded + * @return base64 encoded signature string. + */ +//std::string oauth_sign_rsa_sha1 (const char *m, const char *k); + +/** + * verify RSA-SHA1 signature. + * + * returns the output of EVP_VerifyFinal() for a given message, + * cert/pubkey and signature. + * + * @param m message to be verified + * @param c public-key or x509 certificate + * @param s base64 encoded signature + * @return 1 for a correct signature, 0 for failure and -1 if some other error occurred + */ +int oauth_verify_rsa_sha1(const char *m, const char *c, const char *s); + +/** + * url-escape strings and concatenate with '&' separator. + * The number of strings to be concatenated must be + * given as first argument. + * all arguments thereafter must be of type (char *) + * + * @param len the number of arguments to follow this parameter + * + * @return pointer to memory holding the concatenated + * strings - needs to be free(d) by the caller. or NULL + * in case we ran out of memory. + */ +std::string oauth_catenc(int len, ...); + +/** + * splits the given url into a parameter array. + * (see \ref oauth_serialize_url and \ref oauth_serialize_url_parameters for the reverse) + * (see \ref oauth_split_post_paramters for a more generic version) + * + * @param url the url or query-string to parse; may be NULL + * @param argv pointer to a (char *) array where the results are stored. + * The array is re-allocated to match the number of parameters and each + * parameter-string is allocated with strdup. - The memory needs to be freed + * by the caller. + * + * @return number of parameter(s) in array. + */ +void oauth_split_url_parameters(const char *url, char ***argv); + +/** + * splits the given url into a parameter array. + * (see \ref oauth_serialize_url and \ref oauth_serialize_url_parameters for the reverse) + * + * @param url the url or query-string to parse. + * @param argv pointer to a (char *) array where the results are stored. + * The array is re-allocated to match the number of parameters and each + * parameter-string is allocated with strdup. - The memory needs to be freed + * by the caller. + * @param qesc use query parameter escape (vs post-param-escape) - if set + * to 1 all '+' are treated as spaces ' ' + * + * @return number of parameter(s) in array. + */ +void oauth_split_post_paramters(const char *url, char ***argv, short qesc); + +/** + * build a url query string from an array. + * + * @param argc the total number of elements in the array + * @param start element in the array at which to start concatenating. + * @param argv parameter-array to concatenate. + * @return url string needs to be freed by the caller. + * + */ +std::string oauth_serialize_url (std::vector<std::string> const &argv, int start); + +/** + * encode query parameters from an array. + * + * @param argc the total number of elements in the array + * @param start element in the array at which to start concatenating. + * @param argv parameter-array to concatenate. + * @param sep separator for parameters (usually "&") + * @param mod - bitwise modifiers: + * 1: skip all values that start with "oauth_" + * 2: skip all values that don't start with "oauth_" + * 4: double quotation marks are added around values (use with sep ", " for HTTP Authorization header). + * @return url string needs to be freed by the caller. + */ +std::string oauth_serialize_url_sep (std::vector<std::string> const &argv, int start, char const *sep, int mod); + +/** + * build a query parameter string from an array. + * + * This function is a shortcut for \ref oauth_serialize_url (argc, 1, argv). + * It strips the leading host/path, which is usually the first + * element when using oauth_split_url_parameters on an URL. + * + * @param argc the total number of elements in the array + * @param argv parameter-array to concatenate. + * @return url string needs to be freed by the caller. + */ +std::string oauth_serialize_url_parameters (std::vector<std::string> const &argv); + +/** + * generate a random string between 15 and 32 chars length + * and return a pointer to it. The value needs to be freed by the + * caller + * + * @return zero terminated random string. + */ +std::string oauth_gen_nonce(); + +/** + * string compare function for oauth parameters. + * + * used with qsort. needed to normalize request parameters. + * see http://oauth.net/core/1.0/#anchor14 + */ +int oauth_cmpstringp(const void *p1, const void *p2); + + +/** + * search array for parameter key. + * @param argv length of array to search + * @param argc parameter array to search + * @param key key of parameter to check. + * + * @return FALSE (0) if array does not contain a parameter with given key, TRUE (1) otherwise. + */ +bool oauth_param_exists(std::vector<std::string> const &argv, char const *key); + +/** + * free array args + * + * @param argcp pointer to array length int + * @param argvp pointer to array values to be free()d + */ +void oauth_free_array(int *argcp, std::vector<std::string> *argvp); + +/** + * calculate OAuth-signature for a given HTTP request URL, parameters and oauth-tokens. + * + * if 'postargs' is NULL a "GET" request is signed and the + * signed URL is returned. Else this fn will modify 'postargs' + * to point to memory that contains the signed POST-variables + * and returns the base URL. + * + * both, the return value and (if given) 'postargs' need to be freed + * by the caller. + * + * @param url The request URL to be signed. append all GET or POST + * query-parameters separated by either '?' or '&' to this parameter. + * + * @param postargs This parameter points to an area where the return value + * is stored. If 'postargs' is NULL, no value is stored. + * + * @param method specify the signature method to use. It is of type + * \ref OAuthMethod and most likely \ref OA_HMAC. + * + * @param http_method The HTTP request method to use (ie "GET", "PUT",..) + * If NULL is given as 'http_method' this defaults to "GET" when + * 'postargs' is also NULL and when postargs is not NULL "POST" is used. + * + * @param c_key consumer key + * @param c_secret consumer secret + * @param t_key token key + * @param t_secret token secret + * + * @return the signed url or NULL if an error occurred. + * + */ +std::string oauth_sign_url2 (const char *url, std::string *postargs, + OAuthMethod method, + const char *http_method, //< HTTP request method + const char *c_key, //< consumer key - posted plain text + const char *c_secret, //< consumer secret - used as 1st part of secret-key + const char *t_key, //< token key - posted plain text in URL + const char *t_secret //< token secret - used as 2st part of secret-key + ); + +/** + * @deprecated Use oauth_sign_url2() instead. + */ +std::string oauth_sign_url (const char *url, std::string *postargs, + OAuthMethod method, + const char *c_key, //< consumer key - posted plain text + const char *c_secret, //< consumer secret - used as 1st part of secret-key + const char *t_key, //< token key - posted plain text in URL + const char *t_secret //< token secret - used as 2st part of secret-key + ) attribute_deprecated; + + +/** + * the back-end behind by /ref oauth_sign_array2. + * however it does not serialize the signed URL again. + * The user needs to call /ref oauth_serialize_url (oA) + * and /ref oauth_free_array to do so. + * + * This allows to split parts of the URL to be used for + * OAuth HTTP Authorization header: + * see http://oauth.net/core/1.0a/#consumer_req_param + * the oauthtest2 example code does so. + * + * + * @param argcp pointer to array length int + * @param argvp pointer to array values + * (argv[0]="http://example.org:80/" argv[1]="first=QueryParamater" .. + * the array is modified: fi. oauth_ parameters are added) + * These arrays can be generated with /ref oauth_split_url_parameters + * or /ref oauth_split_post_paramters. + * + * @param postargs This parameter points to an area where the return value + * is stored. If 'postargs' is NULL, no value is stored. + * + * @param method specify the signature method to use. It is of type + * \ref OAuthMethod and most likely \ref OA_HMAC. + * + * @param http_method The HTTP request method to use (ie "GET", "PUT",..) + * If NULL is given as 'http_method' this defaults to "GET" when + * 'postargs' is also NULL and when postargs is not NULL "POST" is used. + * + * @param c_key consumer key + * @param c_secret consumer secret + * @param t_key token key + * @param t_secret token secret + * + * @return void + * + */ +void oauth_sign_array2_process (std::vector<std::string> *argvp, + std::string *postargs, + OAuthMethod method, + const char *http_method, //< HTTP request method + const char *c_key, //< consumer key - posted plain text + const char *c_secret, //< consumer secret - used as 1st part of secret-key + const char *t_key, //< token key - posted plain text in URL + const char *t_secret //< token secret - used as 2st part of secret-key + ); + +/** + * same as /ref oauth_sign_url + * with the url already split into parameter array + * + * @param argcp pointer to array length int + * @param argvp pointer to array values + * (argv[0]="http://example.org:80/" argv[1]="first=QueryParamater" .. + * the array is modified: fi. oauth_ parameters are added) + * These arrays can be generated with /ref oauth_split_url_parameters + * or /ref oauth_split_post_paramters. + * + * @param postargs This parameter points to an area where the return value + * is stored. If 'postargs' is NULL, no value is stored. + * + * @param method specify the signature method to use. It is of type + * \ref OAuthMethod and most likely \ref OA_HMAC. + * + * @param http_method The HTTP request method to use (ie "GET", "PUT",..) + * If NULL is given as 'http_method' this defaults to "GET" when + * 'postargs' is also NULL and when postargs is not NULL "POST" is used. + * + * @param c_key consumer key + * @param c_secret consumer secret + * @param t_key token key + * @param t_secret token secret + * + * @return the signed url or NULL if an error occurred. + */ +std::string oauth_sign_array2 (std::vector<std::string> *argvp, + std::string *postargs, + OAuthMethod method, + const char *http_method, //< HTTP request method + const char *c_key, //< consumer key - posted plain text + const char *c_secret, //< consumer secret - used as 1st part of secret-key + const char *t_key, //< token key - posted plain text in URL + const char *t_secret //< token secret - used as 2st part of secret-key + ); + +/** + * @deprecated Use oauth_sign_array2() instead. + */ +char *oauth_sign_array( + std::vector<std::string> *argvp, + char **postargs, + OAuthMethod method, + const char *c_key, //< consumer key - posted plain text + const char *c_secret, //< consumer secret - used as 1st part of secret-key + const char *t_key, //< token key - posted plain text in URL + const char *t_secret //< token secret - used as 2st part of secret-key + ) attribute_deprecated; + +/** + * do a HTTP POST request, wait for it to finish + * and return the content of the reply. + * (requires libcurl or a command-line HTTP client) + * + * If compiled <b>without</b> libcurl this function calls + * a command-line executable defined in the environment variable + * OAUTH_HTTP_CMD - it defaults to + * <tt>curl -sA 'liboauth-agent/0.1' -d '%%p' '%%u'</tt> + * where %%p is replaced with the postargs and %%u is replaced with + * the URL. + * + * bash & wget example: + * <tt>export OAUTH_HTTP_CMD="wget -q -U 'liboauth-agent/0.1' --post-data='%p' '%u' "</tt> + * + * NOTE: This function uses the curl's default HTTP-POST Content-Type: + * application/x-www-form-urlencoded which is the only option allowed + * by oauth core 1.0 spec. Experimental code can use the Environment variable + * to transmit custom HTTP headers or parameters. + * + * WARNING: this is a tentative function. it's convenient and handy for testing + * or developing OAuth code. But don't rely on this function + * to become a stable part of this API. It does not do + * much error checking for one thing.. + * + * @param u url to query + * @param p postargs to send along with the HTTP request. + * @return replied content from HTTP server. needs to be freed by caller. + */ +std::string oauth_http_post(const char *u, const char *p); + +#endif
diff -r 000000000000 -r 0048b264a3ad oauth_http.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/oauth_http.cpp Mon Dec 12 18:47:10 2011 +0000 @@ -0,0 +1,61 @@ +/* + * OAuth http functions in POSIX-C. + * + * Copyright 2007, 2008, 2009, 2010 Robin Gareus <robin@gareus.org> + * + * 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. + * + */ +#if HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stdio.h> +#include <stdarg.h> +#include <stdlib.h> +#include <string.h> + +#include "oauth.h" + +#include <HTTPClient.h> + +/* wrapper functions */ + +/** + * do a HTTP POST request, wait for it to finish + * and return the content of the reply. + * (requires libcurl or a command-line HTTP client) + * + * more documentation in oauth.h + * + * @param u url to query + * @param p postargs to send along with the HTTP request. + * @return In case of an error NULL is returned; otherwise a pointer to the + * replied content from HTTP server. latter needs to be freed by caller. + */ +std::string oauth_http_post(const char *u, const char *p) +{ + HTTPClient http; + HTTPText req("application/x-www-form-urlencoded"); + HTTPText res; + req.set(p); + http.post(u, req, &res); + return res.get(); +} +
diff -r 000000000000 -r 0048b264a3ad sha1.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sha1.c Mon Dec 12 18:47:10 2011 +0000 @@ -0,0 +1,385 @@ +/* + * sha1.c + * + * Description: + * This file implements the Secure Hashing Algorithm 1 as + * defined in FIPS PUB 180-1 published April 17, 1995. + * + * The SHA-1, produces a 160-bit message digest for a given + * data stream. It should take about 2**n steps to find a + * message with the same digest as a given message and + * 2**(n/2) to find any two messages with the same digest, + * when n is the digest size in bits. Therefore, this + * algorithm can serve as a means of providing a + * "fingerprint" for a message. + * + * Portability Issues: + * SHA-1 is defined in terms of 32-bit "words". This code + * uses <stdint.h> (included via "sha1.h" to define 32 and 8 + * bit unsigned integer types. If your C compiler does not + * support 32 bit unsigned integers, this code is not + * appropriate. + * + * Caveats: + * SHA-1 is designed to work with messages less than 2^64 bits + * long. Although SHA-1 allows a message digest to be generated + * for messages of any number of bits less than 2^64, this + * implementation only works with messages with a length that is + * a multiple of the size of an 8-bit character. + * + */ + +#include "sha1.h" + + +/* + * Define the SHA1 circular left shift macro + */ +#define SHA1CircularShift(bits,word) \ + (((word) << (bits)) | ((word) >> (32-(bits)))) + +/* Local Function Prototyptes */ +void SHA1PadMessage(SHA1Context *); +void SHA1ProcessMessageBlock(SHA1Context *); + +/* + * SHA1Reset + * + * Description: + * This function will initialize the SHA1Context in preparation + * for computing a new SHA1 message digest. + * + * Parameters: + * context: [in/out] + * The context to reset. + * + * Returns: + * sha Error Code. + * + */ +int SHA1Reset(SHA1Context *context) +{ + if (!context) + { + return shaNull; + } + + context->Length_Low = 0; + context->Length_High = 0; + context->Message_Block_Index = 0; + + context->Intermediate_Hash[0] = 0x67452301; + context->Intermediate_Hash[1] = 0xEFCDAB89; + context->Intermediate_Hash[2] = 0x98BADCFE; + context->Intermediate_Hash[3] = 0x10325476; + context->Intermediate_Hash[4] = 0xC3D2E1F0; + + context->Computed = 0; + context->Corrupted = 0; + + return shaSuccess; +} + +/* + * SHA1Result + * + * Description: + * This function will return the 160-bit message digest into the + * Message_Digest array provided by the caller. + * NOTE: The first octet of hash is stored in the 0th element, + * the last octet of hash in the 19th element. + * + * Parameters: + * context: [in/out] + * The context to use to calculate the SHA-1 hash. + * Message_Digest: [out] + * Where the digest is returned. + * + * Returns: + * sha Error Code. + * + */ +int SHA1Result( SHA1Context *context, + uint8_t Message_Digest[SHA1HashSize]) +{ + int i; + + if (!context || !Message_Digest) + { + return shaNull; + } + + if (context->Corrupted) + { + return context->Corrupted; + } + + if (!context->Computed) + { + SHA1PadMessage(context); + for(i=0; i<64; ++i) + { + /* message may be sensitive, clear it out */ + context->Message_Block[i] = 0; + } + context->Length_Low = 0; /* and clear length */ + context->Length_High = 0; + context->Computed = 1; + } + + for(i = 0; i < SHA1HashSize; ++i) + { + Message_Digest[i] = context->Intermediate_Hash[i>>2] >> 8 * ( 3 - ( i & 0x03 ) ); + } + + return shaSuccess; +} + +/* + * SHA1Input + * + * Description: + * This function accepts an array of octets as the next portion + * of the message. + * + * Parameters: + * context: [in/out] + * The SHA context to update + * message_array: [in] + * An array of characters representing the next portion of + * the message. + * length: [in] + * The length of the message in message_array + * + * Returns: + * sha Error Code. + * + */ +int SHA1Input( SHA1Context *context, + const uint8_t *message_array, + unsigned length) +{ + if (!length) + { + return shaSuccess; + } + + if (!context || !message_array) + { + return shaNull; + } + + if (context->Computed) + { + context->Corrupted = shaStateError; + return shaStateError; + } + + if (context->Corrupted) + { + return context->Corrupted; + } + while(length-- && !context->Corrupted) + { + context->Message_Block[context->Message_Block_Index++] = + (*message_array & 0xFF); + + context->Length_Low += 8; + if (context->Length_Low == 0) + { + context->Length_High++; + if (context->Length_High == 0) + { + /* Message is too long */ + context->Corrupted = 1; + } + } + + if (context->Message_Block_Index == 64) + { + SHA1ProcessMessageBlock(context); + } + + message_array++; + } + + return shaSuccess; +} + +/* + * SHA1ProcessMessageBlock + * + * Description: + * This function will process the next 512 bits of the message + * stored in the Message_Block array. + * + * Parameters: + * None. + * + * Returns: + * Nothing. + * + * Comments: + * Many of the variable names in this code, especially the + * single character names, were used because those were the + * names used in the publication. + * + * + */ +void SHA1ProcessMessageBlock(SHA1Context *context) +{ + const uint32_t K[] = { /* Constants defined in SHA-1 */ + 0x5A827999, + 0x6ED9EBA1, + 0x8F1BBCDC, + 0xCA62C1D6 + }; + int t; /* Loop counter */ + uint32_t temp; /* Temporary word value */ + uint32_t W[80]; /* Word sequence */ + uint32_t A, B, C, D, E; /* Word buffers */ + + /* + * Initialize the first 16 words in the array W + */ + for(t = 0; t < 16; t++) + { + W[t] = context->Message_Block[t * 4] << 24; + W[t] |= context->Message_Block[t * 4 + 1] << 16; + W[t] |= context->Message_Block[t * 4 + 2] << 8; + W[t] |= context->Message_Block[t * 4 + 3]; + } + + for(t = 16; t < 80; t++) + { + W[t] = SHA1CircularShift(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]); + } + + A = context->Intermediate_Hash[0]; + B = context->Intermediate_Hash[1]; + C = context->Intermediate_Hash[2]; + D = context->Intermediate_Hash[3]; + E = context->Intermediate_Hash[4]; + + for(t = 0; t < 20; t++) + { + temp = SHA1CircularShift(5,A) + + ((B & C) | ((~B) & D)) + E + W[t] + K[0]; + E = D; + D = C; + C = SHA1CircularShift(30,B); + B = A; + A = temp; + } + + for(t = 20; t < 40; t++) + { + temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[1]; + E = D; + D = C; + C = SHA1CircularShift(30,B); + B = A; + A = temp; + } + + for(t = 40; t < 60; t++) + { + temp = SHA1CircularShift(5,A) + + ((B & C) | (B & D) | (C & D)) + E + W[t] + K[2]; + E = D; + D = C; + C = SHA1CircularShift(30,B); + B = A; + A = temp; + } + + for(t = 60; t < 80; t++) + { + temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[3]; + E = D; + D = C; + C = SHA1CircularShift(30,B); + B = A; + A = temp; + } + + context->Intermediate_Hash[0] += A; + context->Intermediate_Hash[1] += B; + context->Intermediate_Hash[2] += C; + context->Intermediate_Hash[3] += D; + context->Intermediate_Hash[4] += E; + + context->Message_Block_Index = 0; +} + + +/* + * SHA1PadMessage + * + * Description: + * According to the standard, the message must be padded to an even + * 512 bits. The first padding bit must be a '1'. The last 64 + * bits represent the length of the original message. All bits in + * between should be 0. This function will pad the message + * according to those rules by filling the Message_Block array + * accordingly. It will also call the ProcessMessageBlock function + * provided appropriately. When it returns, it can be assumed that + * the message digest has been computed. + * + * Parameters: + * context: [in/out] + * The context to pad + * ProcessMessageBlock: [in] + * The appropriate SHA*ProcessMessageBlock function + * Returns: + * Nothing. + * + */ + +void SHA1PadMessage(SHA1Context *context) +{ + /* + * Check to see if the current message block is too small to hold + * the initial padding bits and length. If so, we will pad the + * block, process it, and then continue padding into a second + * block. + */ + if (context->Message_Block_Index > 55) + { + context->Message_Block[context->Message_Block_Index++] = 0x80; + while(context->Message_Block_Index < 64) + { + context->Message_Block[context->Message_Block_Index++] = 0; + } + + SHA1ProcessMessageBlock(context); + + while(context->Message_Block_Index < 56) + { + context->Message_Block[context->Message_Block_Index++] = 0; + } + } + else + { + context->Message_Block[context->Message_Block_Index++] = 0x80; + while(context->Message_Block_Index < 56) + { + context->Message_Block[context->Message_Block_Index++] = 0; + } + } + + /* + * Store the message length as the last 8 octets + */ + context->Message_Block[56] = context->Length_High >> 24; + context->Message_Block[57] = context->Length_High >> 16; + context->Message_Block[58] = context->Length_High >> 8; + context->Message_Block[59] = context->Length_High; + context->Message_Block[60] = context->Length_Low >> 24; + context->Message_Block[61] = context->Length_Low >> 16; + context->Message_Block[62] = context->Length_Low >> 8; + context->Message_Block[63] = context->Length_Low; + + SHA1ProcessMessageBlock(context); +} +
diff -r 000000000000 -r 0048b264a3ad sha1.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sha1.h Mon Dec 12 18:47:10 2011 +0000 @@ -0,0 +1,85 @@ +/* + * sha1.h + * + * Description: + * This is the header file for code which implements the Secure + * Hashing Algorithm 1 as defined in FIPS PUB 180-1 published + * April 17, 1995. + * + * Many of the variable names in this code, especially the + * single character names, were used because those were the names + * used in the publication. + * + * Please read the file sha1.c for more information. + * + */ + +#ifndef _SHA1_H_ +#define _SHA1_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +//#include <stdint.h> +typedef unsigned long uint32_t; +typedef int int_least16_t; +typedef unsigned char uint8_t; + +/* + * If you do not have the ISO standard stdint.h header file, then you + * must typdef the following: + * name meaning + * uint32_t unsigned 32 bit integer + * uint8_t unsigned 8 bit integer (i.e., unsigned char) + * int_least16_t integer of >= 16 bits + * + */ + +#ifndef _SHA_enum_ +#define _SHA_enum_ +enum +{ + shaSuccess = 0, + shaNull, /* Null pointer parameter */ + shaInputTooLong, /* input data too long */ + shaStateError /* called Input after Result */ +}; +#endif +#define SHA1HashSize 20 + +/* + * This structure will hold context information for the SHA-1 + * hashing operation + */ +typedef struct SHA1Context +{ + uint32_t Intermediate_Hash[SHA1HashSize/4]; /* Message Digest */ + + uint32_t Length_Low; /* Message length in bits */ + uint32_t Length_High; /* Message length in bits */ + + /* Index into message block array */ + int_least16_t Message_Block_Index; + uint8_t Message_Block[64]; /* 512-bit message blocks */ + + int Computed; /* Is the digest computed? */ + int Corrupted; /* Is the message digest corrupted? */ +} SHA1Context; + +/* + * Function Prototypes + */ + +int SHA1Reset( SHA1Context *); +int SHA1Input( SHA1Context *, + const uint8_t *, + unsigned int); +int SHA1Result( SHA1Context *, + uint8_t Message_Digest[SHA1HashSize]); + +#ifdef __cplusplus +} +#endif + +#endif