tst_cryptokey.cpp 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. /* Ricochet - https://ricochet.im/
  2. * Copyright (C) 2014, John Brooks <john.brooks@dereferenced.net>
  3. *
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions are
  6. * met:
  7. *
  8. * * Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. *
  11. * * Redistributions in binary form must reproduce the above
  12. * copyright notice, this list of conditions and the following disclaimer
  13. * in the documentation and/or other materials provided with the
  14. * distribution.
  15. *
  16. * * Neither the names of the copyright owners nor the names of its
  17. * contributors may be used to endorse or promote products derived from
  18. * this software without specific prior written permission.
  19. *
  20. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  21. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  22. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  23. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  24. * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  25. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  26. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  27. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  28. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  29. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  30. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  31. */
  32. #include <QtTest>
  33. #include "utils/CryptoKey.h"
  34. class TestCryptoKey : public QObject
  35. {
  36. Q_OBJECT
  37. private slots:
  38. void load();
  39. void publicKeyDigest();
  40. void encodedPublicKey();
  41. void encodedPrivateKey();
  42. void torServiceID();
  43. void sign();
  44. };
  45. const char *alice =
  46. "-----BEGIN RSA PRIVATE KEY-----\n"
  47. "MIICXQIBAAKBgQDAS9nLWyK0jWZ8yduqVEhSyZRplTaeUpGWYRi14n1C4sjO6nqm\n"
  48. "ES31UCGDH4nIor2R/XMJCJkJwK+t2XrtiH+jUEHwUGhnMkm3hW5NHt5g39s9YK7l\n"
  49. "xD39O8N2tHUycVq8guhrb1WBQ2/bmZ85nOIuBDZxIuVQZA1U1L6rWGvm+wIDAQAB\n"
  50. "AoGAewYL6JX9thVgpCVga7BQNObSFFpp/xBEJDkqXfLwwIHmhrpsjSIgjPke94yN\n"
  51. "0daMAYJsvjLJ9ftYaZjhlGXngbBJiAU95gcZoTAsn2hNJP22ndGuhi6WEKhYwRxK\n"
  52. "U5d+3Khzy/ysuoay7DSVtpSmpiacWPSiiptEkxNbcbGba8ECQQDeEGoPASmxZoh4\n"
  53. "I2JNQkqSwMKsOZpp/SJhnmLCPoA1oDwlGtu4HF7t9hBXeyIXgLvbfJudFEa+LqR7\n"
  54. "wrKQPn0fAkEA3a7cR7eSRNu1ak7gVfQfnP4tFl3+7UC2hUqVHLA5ks4pLl7/ITa+\n"
  55. "3P04SOs3WpvZJHYJ+hi/anqEPYrD/3B+pQJBAKmjnnHh8IjODDjCxyjAGJntWYoZ\n"
  56. "4yVOtEIgrc830delley+jNUkDzz3+dnqfcu4k0oD8hjYUYaduRe2T5Szt/8CQQDC\n"
  57. "EVt8WUNujp0R9P1FohKu4IFeLGmJD/b5V2KUm927HEpG8xkM3Z1XX0KP64MpCnid\n"
  58. "B80SKeog8CKmsb2F+NiVAkBT1CEAdiFYtf72hnZCLBw5HrqpN+zjw00GjtlrmmNV\n"
  59. "+ILb/YRp5flCY5Se95ExzQqRKzvK5iJg0yEOVF0OcbO+\n"
  60. "-----END RSA PRIVATE KEY-----";
  61. const char *aliceDigest = "623a1ffc94d8f8edcd5e47fbd45e08deb911d1bc";
  62. const char *aliceTorID = "mi5b77eu3d4o3tk6";
  63. const char *aliceSignedTestData = "23fdcd5c7d40b44a7e49619d9048c81931166a0adb80c8981cc8f9a9e02c3923d5fba6d92ea03dc672d009a5fe1be2b582fb935076f880d9aa55511c33620d2aa23336b579dd7ccd1dbf4c845e4100a114d8ac20dd47229e876444f79d5152456a8e26fefa67a12436b3c33728a2ff7cb12250c486f786647574e48bb9208f64";
  64. const char *bob =
  65. "-----BEGIN RSA PUBLIC KEY-----\n"
  66. "MIGJAoGBAMP8GyAg/kzwXizpUWjWIMw/lvDffXjsxcq1qmZWZxXJQH/oE8bX+WAf\n"
  67. "VS8iUHVqTykubR0W3QNL6aWSZKBqDQUTN0QBJUF4qdkg3x56C0kwcWa+seDMAvJw\n"
  68. "pcHK9wN7mtWHIhFwhikP//NylrY1MaUxcPjvOKcdJ90k988nnmpZAgMBAAE=\n"
  69. "-----END RSA PUBLIC KEY-----\n";
  70. const char *bobDigest = "b4780cabdfc3593004431644977cf73bf8475848";
  71. const char *bobTorID = "wr4azk67ynmtabcd";
  72. void TestCryptoKey::load()
  73. {
  74. CryptoKey key;
  75. QVERIFY(!key.isLoaded());
  76. // Private key
  77. QVERIFY(key.loadFromData(alice, CryptoKey::PrivateKey));
  78. QVERIFY(key.isLoaded());
  79. QVERIFY(key.isPrivate());
  80. QCOMPARE(key.bits(), 1024);
  81. key.clear();
  82. QVERIFY(!key.isLoaded());
  83. // Public key
  84. QVERIFY(key.loadFromData(bob, CryptoKey::PublicKey));
  85. QVERIFY(key.isLoaded());
  86. QVERIFY(!key.isPrivate());
  87. QCOMPARE(key.bits(), 1024);
  88. // DER public key
  89. QByteArray derEncoded = key.encodedPublicKey(CryptoKey::DER);
  90. key.clear();
  91. QVERIFY(key.loadFromData(derEncoded, CryptoKey::PublicKey, CryptoKey::DER));
  92. QCOMPARE(key.encodedPublicKey(CryptoKey::DER), derEncoded);
  93. key.clear();
  94. // Invalid key
  95. QVERIFY(!key.loadFromData(QByteArray(alice).mid(0, 150), CryptoKey::PrivateKey));
  96. QVERIFY(!key.isLoaded());
  97. // Invalid DER key
  98. QVERIFY(!key.loadFromData(derEncoded.mid(0, derEncoded.size()-2), CryptoKey::PublicKey, CryptoKey::DER));
  99. QVERIFY(!key.isLoaded());
  100. // Empty key
  101. QVERIFY(!key.loadFromData("", CryptoKey::PublicKey));
  102. QVERIFY(!key.isLoaded());
  103. }
  104. void TestCryptoKey::publicKeyDigest()
  105. {
  106. CryptoKey key;
  107. QVERIFY(key.loadFromData(bob, CryptoKey::PublicKey));
  108. QCOMPARE(key.publicKeyDigest().toHex(), QByteArray(bobDigest));
  109. key.clear();
  110. QVERIFY(key.loadFromData(alice, CryptoKey::PrivateKey));
  111. QCOMPARE(key.publicKeyDigest().toHex(), QByteArray(aliceDigest));
  112. }
  113. void TestCryptoKey::encodedPublicKey()
  114. {
  115. CryptoKey key;
  116. QVERIFY(key.loadFromData(bob, CryptoKey::PublicKey));
  117. QByteArray pemEncoded = key.encodedPublicKey(CryptoKey::PEM);
  118. QVERIFY(pemEncoded.contains("BEGIN RSA PUBLIC KEY"));
  119. QByteArray derEncoded = key.encodedPublicKey(CryptoKey::DER);
  120. QCOMPARE(derEncoded.size(), 140);
  121. CryptoKey key2;
  122. QVERIFY(key2.loadFromData(pemEncoded, CryptoKey::PublicKey));
  123. QCOMPARE(key.encodedPublicKey(CryptoKey::PEM), key2.encodedPublicKey(CryptoKey::PEM));
  124. QCOMPARE(key.publicKeyDigest(), key2.publicKeyDigest());
  125. CryptoKey key3;
  126. QVERIFY(key3.loadFromData(derEncoded, CryptoKey::PublicKey, CryptoKey::DER));
  127. QCOMPARE(key.encodedPublicKey(CryptoKey::DER), key3.encodedPublicKey(CryptoKey::DER));
  128. QCOMPARE(key.publicKeyDigest(), key3.publicKeyDigest());
  129. // Doesn't contain a private key
  130. CryptoKey key4;
  131. QVERIFY(!key4.loadFromData(pemEncoded, CryptoKey::PrivateKey));
  132. }
  133. void TestCryptoKey::encodedPrivateKey()
  134. {
  135. CryptoKey key;
  136. QVERIFY(key.loadFromData(alice, CryptoKey::PrivateKey));
  137. QByteArray pemEncoded = key.encodedPrivateKey(CryptoKey::PEM);
  138. QVERIFY(pemEncoded.contains("BEGIN RSA PRIVATE KEY"));
  139. QByteArray derEncoded = key.encodedPrivateKey(CryptoKey::DER);
  140. QVERIFY(!derEncoded.isEmpty());
  141. CryptoKey key2;
  142. QVERIFY(key2.loadFromData(pemEncoded, CryptoKey::PrivateKey));
  143. QCOMPARE(key.encodedPrivateKey(CryptoKey::PEM), key2.encodedPrivateKey(CryptoKey::PEM));
  144. QCOMPARE(key.publicKeyDigest(), key2.publicKeyDigest());
  145. CryptoKey key3;
  146. QVERIFY(key3.loadFromData(derEncoded, CryptoKey::PrivateKey, CryptoKey::DER));
  147. QCOMPARE(key.encodedPrivateKey(CryptoKey::DER), key3.encodedPrivateKey(CryptoKey::DER));
  148. QCOMPARE(key.publicKeyDigest(), key3.publicKeyDigest());
  149. }
  150. void TestCryptoKey::torServiceID()
  151. {
  152. CryptoKey key;
  153. QVERIFY(key.loadFromData(bob, CryptoKey::PublicKey));
  154. QString id = key.torServiceID();
  155. QCOMPARE(id.size(), 16);
  156. QCOMPARE(id, QLatin1String(bobTorID));
  157. }
  158. void TestCryptoKey::sign()
  159. {
  160. CryptoKey key;
  161. QVERIFY(key.loadFromData(alice, CryptoKey::PrivateKey));
  162. QByteArray data = "test data";
  163. QByteArray data2 = "different";
  164. // Good signature
  165. QByteArray signature = key.signData(data);
  166. QVERIFY(!signature.isEmpty());
  167. QVERIFY(key.verifyData(data, signature));
  168. // Bad signature
  169. QVERIFY(!key.verifyData(data2, signature));
  170. // Corrupt signature
  171. QVERIFY(!key.verifyData(data, signature.mid(0, signature.size() - 10)));
  172. // Wrong public key
  173. CryptoKey key2;
  174. QVERIFY(key2.loadFromData(bob, CryptoKey::PublicKey));
  175. QVERIFY(!key2.verifyData(data, signature));
  176. // Compare to signSHA256
  177. QByteArray dataDigest = QCryptographicHash::hash(data, QCryptographicHash::Sha256);
  178. QByteArray signature2 = key.signSHA256(dataDigest);
  179. QVERIFY(!signature2.isEmpty());
  180. // signSHA256 and verifySHA256
  181. QVERIFY(key.verifySHA256(dataDigest, signature2));
  182. // signSHA256 and verifyData
  183. QVERIFY(key.verifyData(data, signature2));
  184. // signData and verifySHA256
  185. QVERIFY(key.verifySHA256(dataDigest, signature));
  186. // Compare to precomputed signature
  187. QByteArray signaturep = QByteArray::fromHex(aliceSignedTestData);
  188. QVERIFY(key.verifyData(data, signaturep));
  189. QVERIFY(key.verifySHA256(dataDigest, signaturep));
  190. }
  191. QTEST_MAIN(TestCryptoKey)
  192. #include "tst_cryptokey.moc"