nss_obfuscate.c revision 9faab6d48145d3a0d7b9a225ed35bdcaa32eca2c
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek Password obfuscation logic
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek Author: Jakub Hrozek <jhrozek@redhat.com>
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek Copyright (C) Red Hat, Inc 2010
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek This program is free software; you can redistribute it and/or modify
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek it under the terms of the GNU General Public License as published by
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek the Free Software Foundation; either version 3 of the License, or
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek (at your option) any later version.
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek This program is distributed in the hope that it will be useful,
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek but WITHOUT ANY WARRANTY; without even the implied warranty of
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek GNU General Public License for more details.
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek You should have received a copy of the GNU General Public License
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek along with this program. If not, see <http://www.gnu.org/licenses/>.
fd72f761edb0b11265ce3293b56a4a4fa0d1a317Jakub Hrozek * Please note that password obfuscation does not improve security in any
fd72f761edb0b11265ce3293b56a4a4fa0d1a317Jakub Hrozek * way. It is just a mechanism to make the password human-unreadable. If you
fd72f761edb0b11265ce3293b56a4a4fa0d1a317Jakub Hrozek * need to secure passwords in your application, you should probably take a
fd72f761edb0b11265ce3293b56a4a4fa0d1a317Jakub Hrozek * look at storing passwords in NSS-backed database.
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek /* AES with automatic padding, 256b key, 128b block */
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek /* sentinel */
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozekstatic struct crypto_mech_data *get_crypto_mech_data(enum obfmethod meth)
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov DEBUG(SSSDBG_CRIT_FAILURE, "Unsupported cipher type\n");
fd72f761edb0b11265ce3293b56a4a4fa0d1a317Jakub Hrozekstatic int generate_random_key(TALLOC_CTX *mem_ctx,
fd72f761edb0b11265ce3293b56a4a4fa0d1a317Jakub Hrozek randkey = PK11_KeyGen(slot, mech_props->cipher,
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov DEBUG(SSSDBG_CRIT_FAILURE, "Failure to generate key (err %d)\n",
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov DEBUG(SSSDBG_CRIT_FAILURE, "Failure to extract key value (err %d)\n",
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov DEBUG(SSSDBG_CRIT_FAILURE, "Failure to get key data (err %d)\n",
fd72f761edb0b11265ce3293b56a4a4fa0d1a317Jakub Hrozek /* randkeydata is valid until randkey is. Copy with talloc to
fd72f761edb0b11265ce3293b56a4a4fa0d1a317Jakub Hrozek * get a nice memory hierarchy symmetrical in encrypt
fd72f761edb0b11265ce3293b56a4a4fa0d1a317Jakub Hrozek * and decrypt case */
fd72f761edb0b11265ce3293b56a4a4fa0d1a317Jakub Hrozek key->data = talloc_memdup(key, randkeydata->data, randkeydata->len);
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozekstatic int sss_nss_crypto_ctx_destructor(struct sss_nss_crypto_ctx *cctx)
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek if (cctx->ectx) PK11_DestroyContext(cctx->ectx, PR_TRUE);
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek if (cctx->sparam) SECITEM_FreeItem(cctx->sparam, PR_TRUE);
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek if (cctx->keyobj) PK11_FreeSymKey(cctx->keyobj);
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek cctx = talloc_zero(mem_ctx, struct sss_nss_crypto_ctx);
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek talloc_set_destructor(cctx, sss_nss_crypto_ctx_destructor);
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek cctx->slot = PK11_GetBestSlot(mech_props->cipher, NULL);
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov DEBUG(SSSDBG_CRIT_FAILURE, "Unable to find security device (err %d)\n",
ac3a1f3da772cf101101c31675c63dc3549b21b5Jakub Hrozekstatic int nss_encrypt_decrypt_init(struct crypto_mech_data *mech_props,
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek /* turn the raw key into a key object */
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek cctx->keyobj = PK11_ImportSymKey(cctx->slot, mech_props->cipher,
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov DEBUG(SSSDBG_CRIT_FAILURE, "Failure to import key into NSS (err %d)\n",
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek /* turn the raw IV into a initialization vector object */
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek cctx->sparam = PK11_ParamFromIV(mech_props->cipher, cctx->iv);
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov DEBUG(SSSDBG_CRIT_FAILURE, "Failure to set up PKCS11 param (err %d)\n",
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek /* Create cipher context */
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek cctx->ectx = PK11_CreateContextBySymKey(mech_props->cipher, op,
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov DEBUG(SSSDBG_CRIT_FAILURE, "Cannot create cipher context (err %d)\n",
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozekint sss_password_encrypt(TALLOC_CTX *mem_ctx, const char *password, int plen,
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek unsigned char *plaintext;
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek unsigned char *cryptotext;
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek unsigned char *obfbuf;
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek /* initialize NSS if needed */
fd72f761edb0b11265ce3293b56a4a4fa0d1a317Jakub Hrozek ret = nss_ctx_init(tmp_ctx, mech_props, &cctx);
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov DEBUG(SSSDBG_CRIT_FAILURE, "Cannot initialize NSS context\n");
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek /* generate random encryption and IV key */
fd72f761edb0b11265ce3293b56a4a4fa0d1a317Jakub Hrozek ret = generate_random_key(cctx, cctx->slot, mech_props, &cctx->key);
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov DEBUG(SSSDBG_CRIT_FAILURE, "Could not generate encryption key\n");
fd72f761edb0b11265ce3293b56a4a4fa0d1a317Jakub Hrozek ret = generate_random_key(cctx, cctx->slot, mech_props, &cctx->iv);
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov "Could not generate initialization vector\n");
ac3a1f3da772cf101101c31675c63dc3549b21b5Jakub Hrozek ret = nss_encrypt_decrypt_init(mech_props, true, cctx);
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov "Cannot initialize NSS context properties\n");
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek plaintext = (unsigned char *) talloc_strndup(tmp_ctx, password, plen);
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek /* cryptotext buffer must be at least len(plaintext)+blocksize */
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek cryptotext = talloc_array(tmp_ctx, unsigned char, ct_maxsize);
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek /* sample data we'll encrypt and decrypt */
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek sret = PK11_CipherOp(cctx->ectx, cryptotext, &ctlen, ct_maxsize,
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov "Cannot execute the encryption operation (err %d)\n",
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek sret = PK11_DigestFinal(cctx->ectx, cryptotext+ctlen, &digestlen,
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov "Cannot execute the digest operation (err %d)\n",
9faab6d48145d3a0d7b9a225ed35bdcaa32eca2cLukas Slebodnik if (result_len < 0 || result_len > UINT16_MAX) {
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek /* Pack the obfuscation buffer */
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek /* The buffer consists of:
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek * uint16_t the type of the cipher
9faab6d48145d3a0d7b9a225ed35bdcaa32eca2cLukas Slebodnik * uint16_t length of the cryptotext in bytes (clen)
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek * uint8_t[klen] key
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek * uint8_t[blen] IV
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek * uint8_t[clen] cryptotext
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek * 4 bytes of "sentinel" denoting end of the buffer
9faab6d48145d3a0d7b9a225ed35bdcaa32eca2cLukas Slebodnik obufsize = sizeof(uint16_t) + sizeof(uint16_t) +
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek obfbuf = talloc_array(tmp_ctx, unsigned char, obufsize);
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov DEBUG(SSSDBG_TRACE_INTERNAL, "Writing method: %d\n", meth);
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov DEBUG(SSSDBG_TRACE_INTERNAL, "Writing bufsize: %d\n", result_len);
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek SAFEALIGN_SET_UINT16(&obfbuf[p], result_len, &p);
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek safealign_memcpy(&obfbuf[p], cctx->key->data, mech_props->keylen, &p);
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek safealign_memcpy(&obfbuf[p], cctx->iv->data, mech_props->bsize, &p);
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek safealign_memcpy(&obfbuf[p], cryptotext, result_len, &p);
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek safealign_memcpy(&obfbuf[p], OBF_BUFFER_SENTINEL,
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek /* Base64 encode the resulting buffer */
c7919a4fe41133cc466aa3d9431bfceee5784e7bJan Cholasta *obfpwd = sss_base64_encode(mem_ctx, obfbuf, obufsize);
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozekint sss_password_decrypt(TALLOC_CTX *mem_ctx, char *b64encoded,
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek /* for unmarshaling data */
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek unsigned char *cryptotext;
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek unsigned char *keybuf;
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek unsigned char *ivbuf;
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek unsigned char sentinel_check[OBF_BUFFER_SENTINEL_SIZE];
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek /* initialize NSS if needed */
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek /* Base64 decode the incoming buffer */
c7919a4fe41133cc466aa3d9431bfceee5784e7bJan Cholasta obfbuf = sss_base64_decode(tmp_ctx, b64encoded, &obflen);
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek /* unpack obfuscation buffer */
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek SAFEALIGN_COPY_UINT16_CHECK(&meth, obfbuf+p, obflen, &p);
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov DEBUG(SSSDBG_TRACE_INTERNAL, "Read method: %d\n", meth);
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek SAFEALIGN_COPY_UINT16_CHECK(&ctsize, obfbuf+p, obflen, &p);
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov DEBUG(SSSDBG_TRACE_INTERNAL, "Read bufsize: %d\n", ctsize);
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek /* check that we got sane mechanism properties and cryptotext size */
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek obfbuf + p + mech_props->keylen + mech_props->bsize + ctsize,
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek if (memcmp(sentinel_check, OBF_BUFFER_SENTINEL, OBF_BUFFER_SENTINEL_SIZE) != 0) {
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov "Obfuscation buffer seems corrupt, aborting\n");
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek /* copy out key, ivbuf and cryptotext */
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek keybuf = talloc_array(tmp_ctx, unsigned char, mech_props->keylen);
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek safealign_memcpy(keybuf, obfbuf+p, mech_props->keylen, &p);
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek ivbuf = talloc_array(tmp_ctx, unsigned char, mech_props->bsize);
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek safealign_memcpy(ivbuf, obfbuf+p, mech_props->bsize, &p);
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek cryptotext = talloc_array(tmp_ctx, unsigned char, ctsize);
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek safealign_memcpy(cryptotext, obfbuf+p, ctsize, &p);
fd72f761edb0b11265ce3293b56a4a4fa0d1a317Jakub Hrozek ret = nss_ctx_init(tmp_ctx, mech_props, &cctx);
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov DEBUG(SSSDBG_CRIT_FAILURE, "Cannot initialize NSS context\n");
fd72f761edb0b11265ce3293b56a4a4fa0d1a317Jakub Hrozek MAKE_SECITEM(ivbuf, mech_props->bsize, cctx->iv);
fd72f761edb0b11265ce3293b56a4a4fa0d1a317Jakub Hrozek MAKE_SECITEM(keybuf, mech_props->keylen, cctx->key);
ac3a1f3da772cf101101c31675c63dc3549b21b5Jakub Hrozek ret = nss_encrypt_decrypt_init(mech_props, false, cctx);
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek sret = PK11_CipherOp(cctx->ectx, (unsigned char *) pwdbuf, &plainlen, ctsize,
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov "Cannot execute the encryption operation (err %d)\n",
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek sret = PK11_DigestFinal(cctx->ectx, (unsigned char *) pwdbuf+plainlen, &digestlen,
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov "Cannot execute the encryption operation (err %d)\n",