File indexing completed on 2024-04-28 04:43:46
0001 /* 0002 * Copyright (C) 2006 Brad Hards <bradh@frogmouth.net> 0003 * 0004 * This library is free software; you can redistribute it and/or 0005 * modify it under the terms of the GNU Lesser General Public 0006 * License as published by the Free Software Foundation; either 0007 * version 2.1 of the License, or (at your option) any later version. 0008 * 0009 * This library is distributed in the hope that it will be useful, 0010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0012 * Lesser General Public License for more details. 0013 * 0014 * You should have received a copy of the GNU Lesser General Public 0015 * License along with this library; if not, write to the Free Software 0016 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA 0017 * 0018 */ 0019 #include "hasht.h" 0020 #include "nss.h" 0021 #include "pk11func.h" 0022 0023 #include <QtCrypto> 0024 0025 #include <QDebug> 0026 #include <QStringList> 0027 #include <QtPlugin> 0028 0029 //----------------------------------------------------------- 0030 class nssHashContext : public QCA::HashContext 0031 { 0032 Q_OBJECT 0033 public: 0034 nssHashContext(QCA::Provider *p, const QString &type) 0035 : QCA::HashContext(p, type) 0036 { 0037 SECStatus s; 0038 0039 NSS_NoDB_Init("."); 0040 0041 m_status = 0; 0042 0043 /* Get a slot to use for the crypto operations */ 0044 m_slot = PK11_GetInternalKeySlot(); 0045 if (!m_slot) { 0046 qDebug() << "GetInternalKeySlot failed"; 0047 m_status = 1; 0048 return; 0049 } 0050 0051 if (QLatin1String("md2") == type) { 0052 m_hashAlgo = SEC_OID_MD2; 0053 } else if (QLatin1String("md5") == type) { 0054 m_hashAlgo = SEC_OID_MD5; 0055 } else if (QLatin1String("sha1") == type) { 0056 m_hashAlgo = SEC_OID_SHA1; 0057 } else if (QLatin1String("sha256") == type) { 0058 m_hashAlgo = SEC_OID_SHA256; 0059 } else if (QLatin1String("sha384") == type) { 0060 m_hashAlgo = SEC_OID_SHA384; 0061 } else if (QLatin1String("sha512") == type) { 0062 m_hashAlgo = SEC_OID_SHA512; 0063 } else { 0064 qDebug() << "Unknown provider type: " << type; 0065 return; /* this will probably cause a segfault... */ 0066 } 0067 0068 m_context = PK11_CreateDigestContext(m_hashAlgo); 0069 if (!m_context) { 0070 qDebug() << "CreateDigestContext failed"; 0071 return; 0072 } 0073 0074 s = PK11_DigestBegin(m_context); 0075 if (s != SECSuccess) { 0076 qDebug() << "DigestBegin failed"; 0077 return; 0078 } 0079 } 0080 0081 ~nssHashContext() override 0082 { 0083 PK11_DestroyContext(m_context, PR_TRUE); 0084 if (m_slot) 0085 PK11_FreeSlot(m_slot); 0086 } 0087 0088 Context *clone() const override 0089 { 0090 return new nssHashContext(provider(), type()); 0091 } 0092 0093 void clear() override 0094 { 0095 SECStatus s; 0096 0097 PK11_DestroyContext(m_context, PR_TRUE); 0098 0099 m_context = PK11_CreateDigestContext(m_hashAlgo); 0100 if (!m_context) { 0101 qDebug() << "CreateDigestContext failed"; 0102 return; 0103 } 0104 0105 s = PK11_DigestBegin(m_context); 0106 if (s != SECSuccess) { 0107 qDebug() << "DigestBegin failed"; 0108 return; 0109 } 0110 } 0111 0112 void update(const QCA::MemoryRegion &a) override 0113 { 0114 PK11_DigestOp(m_context, (const unsigned char *)a.data(), a.size()); 0115 } 0116 0117 QCA::MemoryRegion final() override 0118 { 0119 unsigned int len = 0; 0120 QCA::SecureArray a(64); 0121 PK11_DigestFinal(m_context, (unsigned char *)a.data(), &len, a.size()); 0122 a.resize(len); 0123 return a; 0124 } 0125 0126 private: 0127 PK11SlotInfo *m_slot; 0128 int m_status; 0129 PK11Context *m_context; 0130 SECOidTag m_hashAlgo; 0131 }; 0132 0133 //----------------------------------------------------------- 0134 class nssHmacContext : public QCA::MACContext 0135 { 0136 Q_OBJECT 0137 public: 0138 nssHmacContext(QCA::Provider *p, const QString &type) 0139 : QCA::MACContext(p, type) 0140 { 0141 NSS_NoDB_Init("."); 0142 0143 m_context = nullptr; 0144 m_status = 0; 0145 0146 /* Get a slot to use for the crypto operations */ 0147 m_slot = PK11_GetInternalKeySlot(); 0148 if (!m_slot) { 0149 qDebug() << "GetInternalKeySlot failed"; 0150 m_status = 1; 0151 return; 0152 } 0153 0154 if (QLatin1String("hmac(md5)") == type) { 0155 m_macAlgo = CKM_MD5_HMAC; 0156 } else if (QLatin1String("hmac(sha1)") == type) { 0157 m_macAlgo = CKM_SHA_1_HMAC; 0158 } else if (QLatin1String("hmac(sha256)") == type) { 0159 m_macAlgo = CKM_SHA256_HMAC; 0160 } else if (QLatin1String("hmac(sha384)") == type) { 0161 m_macAlgo = CKM_SHA384_HMAC; 0162 } else if (QLatin1String("hmac(sha512)") == type) { 0163 m_macAlgo = CKM_SHA512_HMAC; 0164 } else if (QLatin1String("hmac(ripemd160)") == type) { 0165 m_macAlgo = CKM_RIPEMD160_HMAC; 0166 } else { 0167 qDebug() << "Unknown provider type: " << type; 0168 return; /* this will probably cause a segfault... */ 0169 } 0170 } 0171 0172 ~nssHmacContext() override 0173 { 0174 if (m_context) 0175 PK11_DestroyContext(m_context, PR_TRUE); 0176 if (m_slot) 0177 PK11_FreeSlot(m_slot); 0178 } 0179 0180 Context *clone() const override 0181 { 0182 return new nssHmacContext(provider(), type()); 0183 } 0184 0185 void clear() 0186 { 0187 PK11_DestroyContext(m_context, PR_TRUE); 0188 0189 SECItem noParams; 0190 noParams.data = nullptr; 0191 noParams.len = 0; 0192 0193 m_context = PK11_CreateContextBySymKey(m_macAlgo, CKA_SIGN, m_nssKey, &noParams); 0194 if (!m_context) { 0195 qDebug() << "CreateContextBySymKey failed"; 0196 return; 0197 } 0198 0199 SECStatus s = PK11_DigestBegin(m_context); 0200 if (s != SECSuccess) { 0201 qDebug() << "DigestBegin failed"; 0202 return; 0203 } 0204 } 0205 0206 QCA::KeyLength keyLength() const override 0207 { 0208 return anyKeyLength(); 0209 } 0210 0211 void setup(const QCA::SymmetricKey &key) override 0212 { 0213 /* turn the raw key into a SECItem */ 0214 SECItem keyItem; 0215 keyItem.data = (unsigned char *)key.data(); 0216 keyItem.len = key.size(); 0217 0218 m_nssKey = PK11_ImportSymKey(m_slot, m_macAlgo, PK11_OriginUnwrap, CKA_SIGN, &keyItem, nullptr); 0219 0220 SECItem noParams; 0221 noParams.data = nullptr; 0222 noParams.len = 0; 0223 0224 m_context = PK11_CreateContextBySymKey(m_macAlgo, CKA_SIGN, m_nssKey, &noParams); 0225 if (!m_context) { 0226 qDebug() << "CreateContextBySymKey failed"; 0227 return; 0228 } 0229 0230 SECStatus s = PK11_DigestBegin(m_context); 0231 if (s != SECSuccess) { 0232 qDebug() << "DigestBegin failed"; 0233 return; 0234 } 0235 } 0236 0237 void update(const QCA::MemoryRegion &a) override 0238 { 0239 PK11_DigestOp(m_context, (const unsigned char *)a.data(), a.size()); 0240 } 0241 0242 void final(QCA::MemoryRegion *out) override 0243 { 0244 // NSS doesn't appear to be able to tell us how big the digest will 0245 // be for a given algorithm until after we finalise it, so we work 0246 // around the problem a bit. 0247 QCA::SecureArray sa(HASH_LENGTH_MAX, 0); // assume the biggest hash size we know 0248 unsigned int len = 0; 0249 PK11_DigestFinal(m_context, (unsigned char *)sa.data(), &len, sa.size()); 0250 sa.resize(len); // and fix it up later 0251 *out = sa; 0252 } 0253 0254 private: 0255 PK11SlotInfo *m_slot; 0256 int m_status; 0257 PK11Context *m_context; 0258 CK_MECHANISM_TYPE m_macAlgo; 0259 PK11SymKey *m_nssKey; 0260 }; 0261 0262 //----------------------------------------------------------- 0263 class nssCipherContext : public QCA::CipherContext 0264 { 0265 Q_OBJECT 0266 public: 0267 nssCipherContext(QCA::Provider *p, const QString &type) 0268 : QCA::CipherContext(p, type) 0269 { 0270 NSS_NoDB_Init("."); 0271 0272 if (QLatin1String("aes128-ecb") == type) { 0273 m_cipherMechanism = CKM_AES_ECB; 0274 } else if (QLatin1String("aes128-cbc") == type) { 0275 m_cipherMechanism = CKM_AES_CBC; 0276 } else if (QLatin1String("des-ecb") == type) { 0277 m_cipherMechanism = CKM_DES_ECB; 0278 } else if (QLatin1String("des-cbc") == type) { 0279 m_cipherMechanism = CKM_DES_CBC; 0280 } else if (QLatin1String("des-cbc-pkcs7") == type) { 0281 m_cipherMechanism = CKM_DES_CBC_PAD; 0282 } else if (QLatin1String("tripledes-ecb") == type) { 0283 m_cipherMechanism = CKM_DES3_ECB; 0284 } else { 0285 qDebug() << "Unknown provider type: " << type; 0286 return; /* this will probably cause a segfault... */ 0287 } 0288 } 0289 0290 ~nssCipherContext() override 0291 { 0292 } 0293 0294 void setup(QCA::Direction dir, 0295 const QCA::SymmetricKey &key, 0296 const QCA::InitializationVector &iv, 0297 const QCA::AuthTag &tag) override 0298 { 0299 Q_UNUSED(tag); 0300 /* Get a slot to use for the crypto operations */ 0301 m_slot = PK11_GetBestSlot(m_cipherMechanism, nullptr); 0302 if (!m_slot) { 0303 qDebug() << "GetBestSlot failed"; 0304 return; 0305 } 0306 0307 /* turn the raw key into a SECItem */ 0308 SECItem keyItem; 0309 keyItem.data = (unsigned char *)key.data(); 0310 keyItem.len = key.size(); 0311 0312 if (QCA::Encode == dir) { 0313 m_nssKey = PK11_ImportSymKey(m_slot, m_cipherMechanism, PK11_OriginUnwrap, CKA_ENCRYPT, &keyItem, nullptr); 0314 } else { 0315 // decryption 0316 m_nssKey = PK11_ImportSymKey(m_slot, m_cipherMechanism, PK11_OriginUnwrap, CKA_DECRYPT, &keyItem, nullptr); 0317 } 0318 0319 SECItem ivItem; 0320 ivItem.data = (unsigned char *)iv.data(); 0321 ivItem.len = iv.size(); 0322 0323 m_params = PK11_ParamFromIV(m_cipherMechanism, &ivItem); 0324 0325 if (QCA::Encode == dir) { 0326 m_context = PK11_CreateContextBySymKey(m_cipherMechanism, CKA_ENCRYPT, m_nssKey, m_params); 0327 } else { 0328 // decryption 0329 m_context = PK11_CreateContextBySymKey(m_cipherMechanism, CKA_DECRYPT, m_nssKey, m_params); 0330 } 0331 0332 if (!m_context) { 0333 qDebug() << "CreateContextBySymKey failed"; 0334 return; 0335 } 0336 } 0337 0338 QCA::Provider::Context *clone() const override 0339 { 0340 return new nssCipherContext(*this); 0341 } 0342 0343 int blockSize() const override 0344 { 0345 return PK11_GetBlockSize(m_cipherMechanism, m_params); 0346 } 0347 0348 QCA::AuthTag tag() const override 0349 { 0350 // For future implementation 0351 return QCA::AuthTag(); 0352 } 0353 0354 bool update(const QCA::SecureArray &in, QCA::SecureArray *out) override 0355 { 0356 out->resize(in.size() + blockSize()); 0357 int resultLength; 0358 0359 PK11_CipherOp( 0360 m_context, (unsigned char *)out->data(), &resultLength, out->size(), (unsigned char *)in.data(), in.size()); 0361 out->resize(resultLength); 0362 0363 return true; 0364 } 0365 0366 bool final(QCA::SecureArray *out) override 0367 { 0368 out->resize(blockSize()); 0369 unsigned int resultLength; 0370 0371 PK11_DigestFinal(m_context, (unsigned char *)out->data(), &resultLength, out->size()); 0372 out->resize(resultLength); 0373 0374 return true; 0375 } 0376 0377 QCA::KeyLength keyLength() const override 0378 { 0379 int min = 0; 0380 int max = 0; 0381 int multiple = 0; 0382 0383 switch (m_cipherMechanism) { 0384 case CKM_AES_ECB: 0385 case CKM_AES_CBC: 0386 min = max = 16; 0387 multiple = 1; 0388 break; 0389 0390 case CKM_DES_ECB: 0391 case CKM_DES_CBC: 0392 case CKM_DES_CBC_PAD: 0393 min = max = 8; 0394 multiple = 1; 0395 break; 0396 0397 case CKM_DES3_ECB: 0398 min = 16; 0399 max = 24; 0400 multiple = 1; 0401 break; 0402 } 0403 0404 return QCA::KeyLength(min, max, multiple); 0405 } 0406 0407 private: 0408 PK11SymKey *m_nssKey; 0409 CK_MECHANISM_TYPE m_cipherMechanism; 0410 PK11SlotInfo *m_slot; 0411 PK11Context *m_context; 0412 SECItem *m_params; 0413 }; 0414 0415 //========================================================== 0416 class nssProvider : public QCA::Provider 0417 { 0418 public: 0419 void init() override 0420 { 0421 } 0422 0423 ~nssProvider() override 0424 { 0425 } 0426 0427 int qcaVersion() const override 0428 { 0429 return QCA_VERSION; 0430 } 0431 0432 QString name() const override 0433 { 0434 return QStringLiteral("qca-nss"); 0435 } 0436 0437 QStringList features() const override 0438 { 0439 QStringList list; 0440 0441 list += QStringLiteral("md2"); 0442 list += QStringLiteral("md5"); 0443 list += QStringLiteral("sha1"); 0444 list += QStringLiteral("sha256"); 0445 list += QStringLiteral("sha384"); 0446 list += QStringLiteral("sha512"); 0447 0448 list += QStringLiteral("hmac(md5)"); 0449 list += QStringLiteral("hmac(sha1)"); 0450 list += QStringLiteral("hmac(sha256)"); 0451 list += QStringLiteral("hmac(sha384)"); 0452 list += QStringLiteral("hmac(sha512)"); 0453 // appears to not be implemented in NSS yet 0454 // list += QStringLiteral("hmac(ripemd160)"); 0455 0456 list += QStringLiteral("aes128-ecb"); 0457 list += QStringLiteral("aes128-cbc"); 0458 list += QStringLiteral("des-ecb"); 0459 list += QStringLiteral("des-cbc"); 0460 list += QStringLiteral("des-cbc-pkcs7"); 0461 list += QStringLiteral("tripledes-ecb"); 0462 0463 return list; 0464 } 0465 0466 Context *createContext(const QString &type) override 0467 { 0468 if (type == QLatin1String("md2")) 0469 return new nssHashContext(this, type); 0470 if (type == QLatin1String("md5")) 0471 return new nssHashContext(this, type); 0472 if (type == QLatin1String("sha1")) 0473 return new nssHashContext(this, type); 0474 if (type == QLatin1String("sha256")) 0475 return new nssHashContext(this, type); 0476 if (type == QLatin1String("sha384")) 0477 return new nssHashContext(this, type); 0478 if (type == QLatin1String("sha512")) 0479 return new nssHashContext(this, type); 0480 0481 if (type == QLatin1String("hmac(md5)")) 0482 return new nssHmacContext(this, type); 0483 if (type == QLatin1String("hmac(sha1)")) 0484 return new nssHmacContext(this, type); 0485 if (type == QLatin1String("hmac(sha256)")) 0486 return new nssHmacContext(this, type); 0487 if (type == QLatin1String("hmac(sha384)")) 0488 return new nssHmacContext(this, type); 0489 if (type == QLatin1String("hmac(sha512)")) 0490 return new nssHmacContext(this, type); 0491 if (type == QLatin1String("hmac(ripemd160)")) 0492 return new nssHmacContext(this, type); 0493 0494 if (type == QLatin1String("aes128-ecb")) 0495 return new nssCipherContext(this, type); 0496 if (type == QLatin1String("aes128-cbc")) 0497 return new nssCipherContext(this, type); 0498 if (type == QLatin1String("des-ecb")) 0499 return new nssCipherContext(this, type); 0500 if (type == QLatin1String("des-cbc")) 0501 return new nssCipherContext(this, type); 0502 if (type == QLatin1String("des-cbc-pkcs7")) 0503 return new nssCipherContext(this, type); 0504 if (type == QLatin1String("tripledes-ecb")) 0505 return new nssCipherContext(this, type); 0506 else 0507 return nullptr; 0508 } 0509 }; 0510 0511 class nssPlugin : public QObject, public QCAPlugin 0512 { 0513 Q_OBJECT 0514 Q_PLUGIN_METADATA(IID "com.affinix.qca.Plugin/1.0") 0515 Q_INTERFACES(QCAPlugin) 0516 public: 0517 QCA::Provider *createProvider() override 0518 { 0519 return new nssProvider; 0520 } 0521 }; 0522 0523 #include "qca-nss.moc"