nss_obfuscate.c revision 911c75f1555742d78568635f1bc0549116eabd4a
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen Password obfuscation logic
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen Author: Jakub Hrozek <jhrozek@redhat.com>
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen Copyright (C) Red Hat, Inc 2010
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen This program is free software; you can redistribute it and/or modify
39ee82dad4d4fa61e3ed074d191afc6a9b82e249Timo Sirainen it under the terms of the GNU General Public License as published by
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen the Free Software Foundation; either version 3 of the License, or
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen (at your option) any later version.
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen This program is distributed in the hope that it will be useful,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen but WITHOUT ANY WARRANTY; without even the implied warranty of
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen GNU General Public License for more details.
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen You should have received a copy of the GNU General Public License
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen along with this program. If not, see <http://www.gnu.org/licenses/>.
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen * Please note that password obfuscation does not improve security in any
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen * way. It is just a mechanism to make the password human-unreadable. If you
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen * need to secure passwords in your application, you should probably take a
39ee82dad4d4fa61e3ed074d191afc6a9b82e249Timo Sirainen * look at storing passwords in NSS-backed database.
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen#define MAKE_SECITEM(sdata, slen, sitem) do { \
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* AES with automatic padding, 256b key, 128b block */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* sentinel */
39ee82dad4d4fa61e3ed074d191afc6a9b82e249Timo Sirainenstatic struct crypto_mech_data *get_crypto_mech_data(enum obfmethod meth)
39ee82dad4d4fa61e3ed074d191afc6a9b82e249Timo Sirainenstatic int generate_random_key(TALLOC_CTX *mem_ctx,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen randkey = PK11_KeyGen(slot, mech_props->cipher,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen DEBUG(1, ("Failure to generate key (err %d)\n",
8d35582f2577c64517b2341c5d6477c7010e0a0cPhil Carmody DEBUG(1, ("Failure to extract key value (err %d)\n",
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen DEBUG(1, ("Failure to get key data (err %d)\n",
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* randkeydata is valid until randkey is. Copy with talloc to
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen * get a nice memory hierarchy symmetrical in encrypt
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen * and decrypt case */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen key->data = talloc_memdup(key, randkeydata->data, randkeydata->len);
414b2d3b63412c4bef6a4caa7a7222f3abbdbabaTimo Sirainenstatic int sss_nss_crypto_ctx_destructor(struct sss_nss_crypto_ctx *cctx)
414b2d3b63412c4bef6a4caa7a7222f3abbdbabaTimo Sirainen if (cctx->ectx) PK11_DestroyContext(cctx->ectx, PR_TRUE);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (cctx->sparam) SECITEM_FreeItem(cctx->sparam, PR_TRUE);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (cctx->keyobj) PK11_FreeSymKey(cctx->keyobj);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen cctx = talloc_zero(mem_ctx, struct sss_nss_crypto_ctx);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen talloc_set_destructor(cctx, sss_nss_crypto_ctx_destructor);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen cctx->slot = PK11_GetBestSlot(mech_props->cipher, NULL);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen DEBUG(1, ("Unable to find security device (err %d)\n",
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenstatic int nss_encrypt_decrypt_init(TALLOC_CTX *mem_ctx,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* turn the raw key into a key object */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen cctx->keyobj = PK11_ImportSymKey(cctx->slot, mech_props->cipher,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen DEBUG(1, ("Failure to import key into NSS (err %d)\n",
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* turn the raw IV into a initialization vector object */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen cctx->sparam = PK11_ParamFromIV(mech_props->cipher, cctx->iv);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen DEBUG(1, ("Failure to set up PKCS11 param (err %d)\n",
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* Create cipher context */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen cctx->ectx = PK11_CreateContextBySymKey(mech_props->cipher, op,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen DEBUG(1, ("Cannot create cipher context (err %d)\n",
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen/* NSS wraps b64 encoded buffers with CRLF automatically after 64 chars. This
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen * function strips the CRLF double-chars. The buffer can be decoded with plain
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen * NSS calls */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen unsigned char *inbuf,
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen b64encoded = BTOA_DataToAscii(inbuf, inbufsize);
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen outbuf = talloc_array(mem_ctx, char, b64size);
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen for (i=0, j=0; i < b64size; i++) {
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen if (b64encoded[i] == '\n' || b64encoded[i] == '\r') {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen outbuf[j++] = b64encoded[i]; /* will also copy the trailing \0 char */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenint sss_password_encrypt(TALLOC_CTX *mem_ctx, const char *password, int plen,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen unsigned char *plaintext;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen unsigned char *cryptotext;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen unsigned char *obfbuf;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* initialize NSS if needed */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen ret = nss_ctx_init(tmp_ctx, mech_props, &cctx);
e3df4d9063a06e0cd228a1713677ec105b0a4aa2Timo Sirainen DEBUG(1, ("Cannot initialize NSS context\n"));
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* generate random encryption and IV key */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen ret = generate_random_key(cctx, cctx->slot, mech_props, &cctx->key);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen DEBUG(1, ("Could not generate encryption key\n"));
e3df4d9063a06e0cd228a1713677ec105b0a4aa2Timo Sirainen ret = generate_random_key(cctx, cctx->slot, mech_props, &cctx->iv);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen DEBUG(1, ("Could not generate initialization vector\n"));
e3df4d9063a06e0cd228a1713677ec105b0a4aa2Timo Sirainen ret = nss_encrypt_decrypt_init(tmp_ctx, mech_props, true, cctx);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen DEBUG(1, ("Cannot initialize NSS context properties\n"));
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen plaintext = (unsigned char *) talloc_strndup(tmp_ctx, password, plen);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* cryptotext buffer must be at least len(plaintext)+blocksize */
e3df4d9063a06e0cd228a1713677ec105b0a4aa2Timo Sirainen cryptotext = talloc_array(tmp_ctx, unsigned char, ct_maxsize);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* sample data we'll encrypt and decrypt */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen sret = PK11_CipherOp(cctx->ectx, cryptotext, &ctlen, ct_maxsize,
c307328f59c963eba21091ecd36c9435d42b47d8Timo Sirainen DEBUG(1, ("Cannot execute the encryption operation (err %d)\n",
c307328f59c963eba21091ecd36c9435d42b47d8Timo Sirainen sret = PK11_DigestFinal(cctx->ectx, cryptotext+ctlen, &digestlen,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen DEBUG(1, ("Cannot execute the digest operation (err %d)\n",
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* Pack the obfuscation buffer */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* The buffer consists of:
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen * uint16_t the type of the cipher
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen * uint32_t length of the cryptotext in bytes (clen)
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen * uint8_t[klen] key
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen * uint8_t[blen] IV
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen * uint8_t[clen] cryptotext
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen * 4 bytes of "sentinel" denoting end of the buffer
985acc0cfd9184b3f4f4cfd6b9e5686a65226147Timo Sirainen obufsize = sizeof(uint16_t) + sizeof(uint32_t) +
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen obfbuf = talloc_array(tmp_ctx, unsigned char, obufsize);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen DEBUG(8, ("Writing bufsize: %d\n", result_len));
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen SAFEALIGN_SET_UINT16(&obfbuf[p], result_len, &p);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen safealign_memcpy(&obfbuf[p], cctx->key->data, mech_props->keylen, &p);
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen safealign_memcpy(&obfbuf[p], cctx->iv->data, mech_props->bsize, &p);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen safealign_memcpy(&obfbuf[p], cryptotext, result_len, &p);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen safealign_memcpy(&obfbuf[p], OBF_BUFFER_SENTINEL,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* Base64 encode the resulting buffer */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen *obfpwd = b64_encode(mem_ctx, obfbuf, obufsize);
39ee82dad4d4fa61e3ed074d191afc6a9b82e249Timo Sirainenint sss_password_decrypt(TALLOC_CTX *mem_ctx, char *b64encoded,
39ee82dad4d4fa61e3ed074d191afc6a9b82e249Timo Sirainen unsigned int obflen;
39ee82dad4d4fa61e3ed074d191afc6a9b82e249Timo Sirainen /* for unmarshaling data */
39ee82dad4d4fa61e3ed074d191afc6a9b82e249Timo Sirainen unsigned char *cryptotext;
39ee82dad4d4fa61e3ed074d191afc6a9b82e249Timo Sirainen unsigned char *keybuf;
39ee82dad4d4fa61e3ed074d191afc6a9b82e249Timo Sirainen unsigned char *ivbuf;
39ee82dad4d4fa61e3ed074d191afc6a9b82e249Timo Sirainen unsigned char sentinel_check[OBF_BUFFER_SENTINEL_SIZE];
39ee82dad4d4fa61e3ed074d191afc6a9b82e249Timo Sirainen /* initialize NSS if needed */
39ee82dad4d4fa61e3ed074d191afc6a9b82e249Timo Sirainen /* Base64 decode the incoming buffer */
39ee82dad4d4fa61e3ed074d191afc6a9b82e249Timo Sirainen obfbuf = ATOB_AsciiToData(b64encoded, &obflen);
39ee82dad4d4fa61e3ed074d191afc6a9b82e249Timo Sirainen /* unpack obfuscation buffer */
39ee82dad4d4fa61e3ed074d191afc6a9b82e249Timo Sirainen SAFEALIGN_COPY_UINT16_CHECK(&meth, obfbuf+p, obflen, &p);
39ee82dad4d4fa61e3ed074d191afc6a9b82e249Timo Sirainen SAFEALIGN_COPY_UINT16_CHECK(&ctsize, obfbuf+p, obflen, &p);
39ee82dad4d4fa61e3ed074d191afc6a9b82e249Timo Sirainen /* check that we got sane mechanism properties and cryptotext size */
39ee82dad4d4fa61e3ed074d191afc6a9b82e249Timo Sirainen obfbuf + p + mech_props->keylen + mech_props->bsize + ctsize,
39ee82dad4d4fa61e3ed074d191afc6a9b82e249Timo Sirainen if (memcmp(sentinel_check, OBF_BUFFER_SENTINEL, OBF_BUFFER_SENTINEL_SIZE) != 0) {
39ee82dad4d4fa61e3ed074d191afc6a9b82e249Timo Sirainen DEBUG(0, ("Obfuscation buffer seems corrupt, aborting\n"));
39ee82dad4d4fa61e3ed074d191afc6a9b82e249Timo Sirainen /* copy out key, ivbuf and cryptotext */
39ee82dad4d4fa61e3ed074d191afc6a9b82e249Timo Sirainen keybuf = talloc_array(tmp_ctx, unsigned char, mech_props->keylen);
39ee82dad4d4fa61e3ed074d191afc6a9b82e249Timo Sirainen safealign_memcpy(keybuf, obfbuf+p, mech_props->keylen, &p);
39ee82dad4d4fa61e3ed074d191afc6a9b82e249Timo Sirainen ivbuf = talloc_array(tmp_ctx, unsigned char, mech_props->bsize);
39ee82dad4d4fa61e3ed074d191afc6a9b82e249Timo Sirainen safealign_memcpy(ivbuf, obfbuf+p, mech_props->bsize, &p);
39ee82dad4d4fa61e3ed074d191afc6a9b82e249Timo Sirainen cryptotext = talloc_array(tmp_ctx, unsigned char, ctsize);
39ee82dad4d4fa61e3ed074d191afc6a9b82e249Timo Sirainen safealign_memcpy(cryptotext, obfbuf+p, ctsize, &p);
39ee82dad4d4fa61e3ed074d191afc6a9b82e249Timo Sirainen ret = nss_ctx_init(tmp_ctx, mech_props, &cctx);
39ee82dad4d4fa61e3ed074d191afc6a9b82e249Timo Sirainen DEBUG(1, ("Cannot initialize NSS context\n"));
39ee82dad4d4fa61e3ed074d191afc6a9b82e249Timo Sirainen MAKE_SECITEM(ivbuf, mech_props->bsize, cctx->iv);
39ee82dad4d4fa61e3ed074d191afc6a9b82e249Timo Sirainen MAKE_SECITEM(keybuf, mech_props->keylen, cctx->key);
299451d50b891c83f4f5d921bc22715f24094236Timo Sirainen ret = nss_encrypt_decrypt_init(tmp_ctx, mech_props, false, cctx);
299451d50b891c83f4f5d921bc22715f24094236Timo Sirainen sret = PK11_CipherOp(cctx->ectx, (unsigned char *) pwdbuf, &plainlen, ctsize,
299451d50b891c83f4f5d921bc22715f24094236Timo Sirainen DEBUG(1, ("Cannot execute the encryption operation (err %d)\n",
299451d50b891c83f4f5d921bc22715f24094236Timo Sirainen sret = PK11_DigestFinal(cctx->ectx, (unsigned char *) pwdbuf+plainlen, &digestlen,
299451d50b891c83f4f5d921bc22715f24094236Timo Sirainen DEBUG(1, ("Cannot execute the encryption operation (err %d)\n",
PR_GetError()));
goto done;
done:
return ret;