diff --git a/build-aux/m4/bitcoin_qt.m4 b/build-aux/m4/bitcoin_qt.m4 index aacf83de2e7f..df28e8d96a52 100644 --- a/build-aux/m4/bitcoin_qt.m4 +++ b/build-aux/m4/bitcoin_qt.m4 @@ -113,6 +113,7 @@ AC_DEFUN([BITCOIN_QT_CONFIGURE],[ if test x$qt_plugin_path != x; then QT_LIBS="$QT_LIBS -L$qt_plugin_path/accessible" QT_LIBS="$QT_LIBS -L$qt_plugin_path/platforms" + QT_LIBS="$QT_LIBS -L$qt_plugin_path/printsupport" fi if test x$use_pkgconfig = xyes; then PKG_CHECK_MODULES([QTPLATFORM], [Qt5PlatformSupport], [QT_LIBS="$QTPLATFORM_LIBS $QT_LIBS"]) @@ -120,6 +121,8 @@ AC_DEFUN([BITCOIN_QT_CONFIGURE],[ _BITCOIN_QT_CHECK_STATIC_PLUGINS([Q_IMPORT_PLUGIN(AccessibleFactory)], [-lqtaccessiblewidgets]) if test x$TARGET_OS = xwindows; then _BITCOIN_QT_CHECK_STATIC_PLUGINS([Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin)],[-lqwindows]) + _BITCOIN_QT_CHECK_STATIC_PLUGINS([Q_IMPORT_PLUGIN(QMinimalIntegrationPlugin)],[-lqminimal]) + _BITCOIN_QT_CHECK_STATIC_PLUGINS([Q_IMPORT_PLUGIN(QWindowsPrinterSupportPlugin)],[-lwindowsprintersupport]) AC_DEFINE(QT_QPA_PLATFORM_WINDOWS, 1, [Define this symbol if the qt platform is windows]) elif test x$TARGET_OS = xlinux; then PKG_CHECK_MODULES([X11XCB], [x11-xcb], [QT_LIBS="$X11XCB_LIBS $QT_LIBS"]) @@ -146,8 +149,9 @@ AC_DEFUN([BITCOIN_QT_CONFIGURE],[ Q_IMPORT_PLUGIN(qjpcodecs) Q_IMPORT_PLUGIN(qtwcodecs) Q_IMPORT_PLUGIN(qkrcodecs) - Q_IMPORT_PLUGIN(AccessibleFactory)], - [-lqcncodecs -lqjpcodecs -lqtwcodecs -lqkrcodecs -lqtaccessiblewidgets]) + Q_IMPORT_PLUGIN(AccessibleFactory) + Q_IMPORT_PLUGIN(QWindowsPrinterSupportPlugin)], + [-lqcncodecs -lqjpcodecs -lqtwcodecs -lqkrcodecs -lqtaccessiblewidgets -lwindowsprintersupport]) fi fi CPPFLAGS=$TEMP_CPPFLAGS @@ -301,7 +305,7 @@ AC_DEFUN([_BITCOIN_QT_FIND_LIBS_WITH_PKGCONFIG],[ QT_LIB_PREFIX=Qt bitcoin_qt_got_major_vers=4 fi - qt5_modules="Qt5Core Qt5Gui Qt5Network Qt5Widgets" + qt5_modules="Qt5Core Qt5Gui Qt5Network Qt5Widgets Qt5PrintSupport" qt4_modules="QtCore QtGui QtNetwork" BITCOIN_QT_CHECK([ if test x$bitcoin_qt_want_version = xqt5 || ( test x$bitcoin_qt_want_version = xauto && test x$auto_priority_version = xqt5 ); then @@ -345,7 +349,7 @@ AC_DEFUN([_BITCOIN_QT_FIND_LIBS_WITHOUT_PKGCONFIG],[ TEMP_LIBS="$LIBS" BITCOIN_QT_CHECK([ if test x$qt_include_path != x; then - QT_INCLUDES="-I$qt_include_path -I$qt_include_path/QtCore -I$qt_include_path/QtGui -I$qt_include_path/QtWidgets -I$qt_include_path/QtNetwork -I$qt_include_path/QtTest -I$qt_include_path/QtDBus" + QT_INCLUDES="-I$qt_include_path -I$qt_include_path/QtCore -I$qt_include_path/QtGui -I$qt_include_path/QtWidgets -I$qt_include_path/QtNetwork -I$qt_include_path/QtTest -I$qt_include_path/QtDBus -I$qt_include_path/QtPrintSupport" CPPFLAGS="$QT_INCLUDES $CPPFLAGS" fi ]) @@ -387,6 +391,7 @@ AC_DEFUN([_BITCOIN_QT_FIND_LIBS_WITHOUT_PKGCONFIG],[ BITCOIN_QT_CHECK(AC_CHECK_LIB([${QT_LIB_PREFIX}Network],[main],,BITCOIN_QT_FAIL(lib$QT_LIB_PREFIXNetwork not found))) if test x$bitcoin_qt_got_major_vers = x5; then BITCOIN_QT_CHECK(AC_CHECK_LIB([${QT_LIB_PREFIX}Widgets],[main],,BITCOIN_QT_FAIL(lib$QT_LIB_PREFIXWidgets not found))) + BITCOIN_QT_CHECK(AC_CHECK_LIB([${QT_LIB_PREFIX}PrintSupport],[main],,BITCOIN_QT_FAIL(lib$QT_LIB_PREFIXPrintSupport not found))) fi QT_LIBS="$LIBS" LIBS="$TEMP_LIBS" @@ -412,4 +417,3 @@ AC_DEFUN([_BITCOIN_QT_FIND_LIBS_WITHOUT_PKGCONFIG],[ CPPFLAGS="$TEMP_CPPFLAGS" LIBS="$TEMP_LIBS" ]) - diff --git a/contrib/darknet-qt.pro b/contrib/darknet-qt.pro index c9581572039f..47d2622dd24e 100644 --- a/contrib/darknet-qt.pro +++ b/contrib/darknet-qt.pro @@ -26,6 +26,7 @@ DEPENDPATH += . \ src/qt/forms \ src/qt/locale \ src/qt/test \ + src/qt/forms/html \ src/secp256k1/include \ src/secp256k1/src \ src/test/data \ @@ -177,6 +178,7 @@ HEADERS += src/activemasternode.h \ src/qt/csvmodelwriter.h \ src/qt/obfuscationconfig.h \ src/qt/editaddressdialog.h \ + src/qt/genandprintdialog.h \ src/qt/guiconstants.h \ src/qt/guiutil.h \ src/qt/intro.h \ @@ -343,6 +345,7 @@ FORMS += src/qt/forms/addressbookpage.ui \ src/qt/forms/coincontroldialog.ui \ src/qt/forms/obfuscationconfig.ui \ src/qt/forms/editaddressdialog.ui \ + src/qt/forms/genandprintdialog.ui \ src/qt/forms/helpmessagedialog.ui \ src/qt/forms/intro.ui \ src/qt/forms/openuridialog.ui \ @@ -474,6 +477,7 @@ SOURCES += src/activemasternode.cpp \ src/qt/darknet.cpp \ src/qt/darknetstrings.cpp \ src/qt/editaddressdialog.cpp \ + src/qt/genandprintdialog.cpp \ src/qt/guiutil.cpp \ src/qt/intro.cpp \ src/qt/networkstyle.cpp \ @@ -642,6 +646,8 @@ SOURCES += src/activemasternode.cpp \ src/leveldb/helpers/memenv/memenv_test.cc \ src/secp256k1/src/java/org_bitcoin_NativeSecp256k1.c RESOURCES += src/qt/darknet.qrc src/qt/darknet_locale.qrc +QT += \ + printsupport TRANSLATIONS += src/qt/locale/darknet_bg.ts \ src/qt/locale/darknet_de.ts \ src/qt/locale/darknet_en.ts \ diff --git a/depends/packages/qt.mk b/depends/packages/qt.mk index 6a8e714a489d..5b9fe65d3379 100644 --- a/depends/packages/qt.mk +++ b/depends/packages/qt.mk @@ -6,7 +6,7 @@ $(package)_sha256_hash=84e924181d4ad6db00239d87250cc89868484a14841f77fb85ab1f1db $(package)_dependencies=openssl $(package)_linux_dependencies=freetype fontconfig dbus libxcb libX11 xproto libXext $(package)_build_subdir=qtbase -$(package)_qt_libs=corelib network widgets gui plugins testlib +$(package)_qt_libs=corelib network widgets gui plugins testlib printsupport $(package)_patches=mac-qmake.conf fix-xcb-include-order.patch qt5-tablet-osx.patch define $(package)_set_vars diff --git a/src/Makefile.am b/src/Makefile.am index 0649dd454bad..8557874a0ee3 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -153,6 +153,13 @@ BITCOIN_CORE_H = \ walletdb.h \ compat/sanity.h +BIP_H = \ + bip/crypto_aesctr.h \ + bip/crypto_scrypt.h \ + bip/sha256.h \ + bip/bip38.h \ + bip/crypto.h + JSON_H = \ json/json_spirit.h \ json/json_spirit_error_position.h \ @@ -204,6 +211,9 @@ libbitcoin_server_a_SOURCES = \ # wallet: shared between darknetd and darknet-qt, but only linked # when wallet enabled + +libbitcoin_wallet_a_CFLAGS = -fPIC + libbitcoin_wallet_a_CPPFLAGS = $(BITCOIN_INCLUDES) libbitcoin_wallet_a_SOURCES = \ activemasternode.cpp \ @@ -224,6 +234,13 @@ libbitcoin_wallet_a_SOURCES = \ wallet_ismine.cpp \ walletdb.cpp \ keepass.cpp \ + bip/crypto_aesctr.c \ + bip/crypto_scrypt-nosse.c \ + bip/crypto_scrypt-ref.c \ + bip/crypto_scrypt-sse.c \ + bip/sha256.c \ + bip/bip38.cpp \ + bip/crypto.c \ $(BITCOIN_CORE_H) # crypto primitives library diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include index f70c3dc22df8..c6a2546d0f70 100755 --- a/src/Makefile.qt.include +++ b/src/Makefile.qt.include @@ -26,6 +26,7 @@ QT_FORMS_UI = \ qt/forms/coincontroldialog.ui \ qt/forms/obfuscationconfig.ui \ qt/forms/editaddressdialog.ui \ + qt/forms/genandprintdialog.ui \ qt/forms/helpmessagedialog.ui \ qt/forms/intro.ui \ qt/forms/openuridialog.ui \ @@ -53,6 +54,7 @@ QT_MOC_CPP = \ qt/moc_csvmodelwriter.cpp \ qt/moc_obfuscationconfig.cpp \ qt/moc_editaddressdialog.cpp \ + qt/moc_genandprintdialog.cpp \ qt/moc_guiutil.cpp \ qt/moc_intro.cpp \ qt/moc_macdockiconhandler.cpp \ @@ -119,6 +121,7 @@ BITCOIN_QT_H = \ qt/csvmodelwriter.h \ qt/obfuscationconfig.h \ qt/editaddressdialog.h \ + qt/genandprintdialog.h \ qt/guiconstants.h \ qt/guiutil.h \ qt/intro.h \ @@ -165,6 +168,7 @@ RES_ICONS = \ qt/res/icons/bitcoin_testnet.ico \ qt/res/icons/bitcoin_testnet.png \ qt/res/icons/browse.png \ + qt/res/icons/cash_icon.png \ qt/res/icons/clock1.png \ qt/res/icons/clock2.png \ qt/res/icons/clock3.png \ @@ -177,6 +181,7 @@ RES_ICONS = \ qt/res/icons/connect3_16.png \ qt/res/icons/connect4_16.png \ qt/res/icons/debugwindow.png \ + qt/res/icons/dnet_cash_print.png \ qt/res/icons/drk_editpaste.png \ qt/res/icons/drk_address-book.png \ qt/res/icons/drk_editcopy.png \ @@ -198,6 +203,7 @@ RES_ICONS = \ qt/res/icons/eye_plus.png \ qt/res/icons/filesave.png \ qt/res/icons/history.png \ + qt/res/icons/import.png \ qt/res/icons/key.png \ qt/res/icons/lock_closed.png \ qt/res/icons/lock_open.png \ @@ -253,6 +259,7 @@ BITCOIN_QT_CPP += \ qt/coincontroltreewidget.cpp \ qt/obfuscationconfig.cpp \ qt/editaddressdialog.cpp \ + qt/genandprintdialog.cpp \ qt/openuridialog.cpp \ qt/overviewpage.cpp \ qt/paymentrequestplus.cpp \ diff --git a/src/bip/bip38.cpp b/src/bip/bip38.cpp new file mode 100644 index 000000000000..31e8a4b39230 --- /dev/null +++ b/src/bip/bip38.cpp @@ -0,0 +1,302 @@ +#include +#include +#include +#include +#include +#include + +#include "crypto.h" +#include "crypto_scrypt.h" +#include "bip38.h" + +#define PASSFACTOR_SIZE 32 +#define PASSPHRASE_MAGIC_SIZE 8 +#define PASSPHRASE_SIZE (PASSPHRASE_MAGIC_SIZE + OWNERSALT_SIZE + 33) +#define DERIVED_SIZE 64 +#define ADDRESSHASH_SIZE 4 +#define OWNERSALT_SIZE 8 + +void print_hex(char * hex, size_t len) { + int i; + for(i=0; i data, size_t len) +{ + std::stringstream ss; + ss << std::hex << std::setfill('0'); + for (std::vector::iterator it = data.begin(); it != data.end(); ++it) { + ss << std::setw(2) << static_cast(*it); + } + return ss.str(); +} + +std::vector decode_base16(const std::string &hex) +{ + std::vector bytes; + + for (unsigned int i = 0; i < hex.length(); i += 2) { + std::string byteString = hex.substr(i, 2); + char byte = (char) strtol(byteString.c_str(), NULL, 16); + bytes.push_back(byte); + } + + return bytes; +} + +std::vector decrypt_bip38_ec(const std::vector key, const std::string& passwd) +{ + int i; + uint8_t passfactor[PASSFACTOR_SIZE]; + + memset(passfactor,0,PASSFACTOR_SIZE); + + const unsigned char * s_key = reinterpret_cast(key.data()); + + crypto_scrypt((const uint8_t *)passwd.c_str(), passwd.length(), + &s_key[3 + ADDRESSHASH_SIZE], OWNERSALT_SIZE, + 16384, 8, 8, passfactor, PASSFACTOR_SIZE ); + + // compute EC point (passpoint) using passfactor + struct bp_key ec_point; + if(!bp_key_init(&ec_point)) { + fprintf(stderr,"%s","cannot init EC point key"); + exit(3); + } + if(!bp_key_secret_set(&ec_point,passfactor,PASSFACTOR_SIZE)) { + fprintf(stderr,"%s","cannot set EC point from passfactor"); + exit(3); + } + + // get the passpoint as bytes + unsigned char * passpoint; + size_t passpoint_len; + + if(!bp_pubkey_get(&ec_point,(unsigned char **)&passpoint,&passpoint_len)) { + fprintf(stderr,"%s","cannot get pubkey for EC point"); + exit(4); + } + + // now we need to decrypt seedb + uint8_t encryptedpart2[16]; + memset(encryptedpart2,0,16); + memcpy(encryptedpart2, &s_key[3 + ADDRESSHASH_SIZE + OWNERSALT_SIZE + 8], 16); + + uint8_t encryptedpart1[16]; + memset(encryptedpart1,0,16); + memcpy(encryptedpart1, &s_key[3 + ADDRESSHASH_SIZE + OWNERSALT_SIZE], 8); + + unsigned char derived[DERIVED_SIZE]; + // get the encryption key for seedb using scrypt + // with passpoint as the key, salt is addresshash+ownersalt + unsigned char derived_scrypt_salt[ADDRESSHASH_SIZE + OWNERSALT_SIZE]; + memcpy(derived_scrypt_salt, &s_key[3], ADDRESSHASH_SIZE); // copy the addresshash + memcpy(derived_scrypt_salt+ADDRESSHASH_SIZE, &s_key[3+ADDRESSHASH_SIZE], OWNERSALT_SIZE); // copy the ownersalt + crypto_scrypt( passpoint, passpoint_len, + derived_scrypt_salt, ADDRESSHASH_SIZE+OWNERSALT_SIZE, + 1024, 1, 1, derived, DERIVED_SIZE ); + + //get decryption key + unsigned char derivedhalf2[DERIVED_SIZE/2]; + memcpy(derivedhalf2, derived+(DERIVED_SIZE/2), DERIVED_SIZE/2); + + unsigned char iv[32]; + memset(iv,0,32); + + EVP_CIPHER_CTX d; + EVP_CIPHER_CTX_init(&d); + EVP_DecryptInit_ex(&d, EVP_aes_256_ecb(), NULL, derivedhalf2, iv); + + unsigned char unencryptedpart2[32]; + int decrypt_len; + + EVP_DecryptUpdate(&d, unencryptedpart2, &decrypt_len, encryptedpart2, 16); + EVP_DecryptUpdate(&d, unencryptedpart2, &decrypt_len, encryptedpart2, 16); + for(i=0; i<16; i++) { + unencryptedpart2[i] ^= derived[i + 16]; + } + unsigned char unencryptedpart1[32]; + memcpy(encryptedpart1+8, unencryptedpart2, 8); + EVP_DecryptUpdate(&d, unencryptedpart1, &decrypt_len, encryptedpart1, 16); + EVP_DecryptUpdate(&d, unencryptedpart1, &decrypt_len, encryptedpart1, 16); + for(i=0; i<16; i++) { + unencryptedpart1[i] ^= derived[i]; + } + + // recoved seedb + unsigned char seedb[24]; + memcpy(seedb, unencryptedpart1, 16); + memcpy(&(seedb[16]), &(unencryptedpart2[8]), 8); + + // turn seedb into factorb (factorb = SHA256(SHA256(seedb))) + unsigned char factorb[32]; + bu_Hash(factorb, seedb, 24); + + // multiply by passfactor (ec_point_pub) + const EC_GROUP * ec_group = EC_KEY_get0_group(ec_point.k); + const EC_POINT * ec_point_pub = EC_KEY_get0_public_key(ec_point.k); + BIGNUM * bn_passfactor = BN_bin2bn(passfactor,32,BN_new()); + BIGNUM * bn_factorb = BN_bin2bn(factorb,32,BN_new()); + BIGNUM * bn_res = BN_new(); + BIGNUM * bn_final = BN_new(); + BIGNUM * bn_n = BN_new(); + BN_CTX * ctx = BN_CTX_new(); + EC_GROUP_get_order(ec_group, bn_n, ctx); + BN_mul(bn_res, bn_passfactor, bn_factorb, ctx); + BN_mod(bn_final, bn_res, bn_n, ctx); + + unsigned char finalKey[32]; + memset(finalKey, 0, 32); + int n = BN_bn2bin(bn_final, finalKey); + + BN_clear_free(bn_passfactor); + BN_clear_free(bn_factorb); + BN_clear_free(bn_res); + BN_clear_free(bn_n); + BN_clear_free(bn_final); + + printf("\n"); + print_hex((char *)finalKey, 32); + printf("\n"); + + std::vector out; + out.assign(finalKey, finalKey + 32); + + return out; +} + +std::vector decrypt_bip38(const std::vector enc_data, const std::string& passwd) +{ + //def decrypt(encrypted_privkey, passphrase, p): + // + //#1. Collect encrypted private key and passphrase from user. + //# passed as parameters + const unsigned char *data = reinterpret_cast(enc_data.data()); + + unsigned char key[64]; + unsigned char addresshash[4]; + unsigned char encryptedhalf1[16], encryptedhalf2[16]; + unsigned char decryptedhalf1[16], decryptedhalf2[16]; + unsigned char derivedhalf1[32], derivedhalf2[32]; + + memcpy(addresshash, &data[3], 4); + memcpy(encryptedhalf1, &data[7], 16); + memcpy(encryptedhalf2, &data[23], 16); + + //#3. Derive decryption key for seedb using scrypt with passpoint, addresshash, and ownersalt + //key = scrypt.hash(passphrase, addresshash, 16384, 8, p) + crypto_scrypt((const uint8_t *)passwd.c_str(), passwd.length(), + &addresshash[0], ADDRESSHASH_SIZE, 16384, 8, 8, key, 64); + + memcpy(derivedhalf1, &key[0], 32); + memcpy(derivedhalf2, &key[32], 32); + // + //#4. Decrypt encryptedpart2 using AES256Decrypt to yield the last 8 bytes of seedb and the last 8 bytes of encryptedpart1. + //Aes = aes.Aes(derivedhalf2) + //decryptedhalf2 = Aes.dec(encryptedhalf2) + + int decrypt_len; + EVP_CIPHER_CTX de; + + EVP_CIPHER_CTX_init(&de); + EVP_DecryptInit_ex(&de, EVP_aes_256_cbc(), NULL, derivedhalf2, NULL); + EVP_DecryptUpdate(&de, decryptedhalf2, &decrypt_len, encryptedhalf2, 16); + + //#5. Decrypt encryptedpart1 to yield the remainder of seedb. + //decryptedhalf1 = Aes.dec(encryptedhalf1) + EVP_DecryptInit_ex(&de, EVP_aes_256_cbc(), NULL, derivedhalf2, NULL); + EVP_DecryptUpdate(&de, decryptedhalf1, &decrypt_len, encryptedhalf1, 16); + + //priv = decryptedhalf1 + decryptedhalf2 + //priv = binascii.unhexlify('%064x' % (long(binascii.hexlify(priv), 16) ^ long(binascii.hexlify(derivedhalf1), 16))) + //return priv, addresshash + + unsigned char priv[32]; + memcpy(priv, decryptedhalf1, 16); + memcpy(priv + 16, decryptedhalf2, 16); + + for (int i = 0; i < 32; i++) { + priv[i] ^= derivedhalf1[i]; + } + +// printf("\n"); +// print_hex((char *)priv, 32); +// printf("\n"); + + std::vector out; + out.assign(priv, priv + 32); + + return out; +} + +std::vector encrypt_bip38(const std::vector priv_key, + const std::string& address, const std::string& passwd) +{ + unsigned char key[64]; + unsigned char derivedhalf1[32], derivedhalf2[32]; + unsigned char encryptedhalf1[16], encryptedhalf2[16]; + unsigned char part1[32], part2[32]; + + const unsigned char * p_address = reinterpret_cast(address.data()); + const unsigned char * p_secret = reinterpret_cast(priv_key.data()); + + // 1. take the first four bytes of SHA256(SHA256()) of it. Let's call this "addresshash". + // addresshash = hashlib.sha256(hashlib.sha256(address).digest()).digest()[:4] # salt + unsigned char addresshash[32]; + bu_Hash(addresshash, &p_address[0], 34); + + // #2. Derive a key from the passphrase using scrypt + // # a. Parameters: passphrase is the passphrase itself encoded in UTF-8. + // # addresshash came from the earlier step, n=16384, r=8, p=8, length=64 + // # (n, r, p are provisional and subject to consensus) + // key = scrypt.hash(passphrase, addresshash, 16384, 8, p) + crypto_scrypt((const uint8_t *)passwd.c_str(), passwd.length(), + &addresshash[0], ADDRESSHASH_SIZE, 16384, 8, 8, key, 64); + + memcpy(derivedhalf1, &key[0], 32); + memcpy(derivedhalf2, &key[32], 32); + + // #3. Do AES256Encrypt(bitcoinprivkey[0...15] xor derivedhalf1[0...15], derivedhalf2), call the 16-byte result encryptedhalf1 + // Aes = aes.Aes(derivedhalf2) + // encryptedhalf1 = Aes.enc(enc.sxor(privK[:16], derivedhalf1[:16])) + // + + for (int i=0; i < 16; i++) + part1[i] = p_secret[i] ^ derivedhalf1[i]; + + for (int i=0; i < 16; i++) + part2[i] = p_secret[i + 16] ^ derivedhalf1[i + 16]; + + int encrypt_len; + EVP_CIPHER_CTX en; + + EVP_CIPHER_CTX_init(&en); + EVP_EncryptInit_ex(&en, EVP_aes_256_cbc(), NULL, derivedhalf2, NULL); + EVP_EncryptUpdate(&en, encryptedhalf1, &encrypt_len, part1, 16); + EVP_EncryptInit_ex(&en, EVP_aes_256_cbc(), NULL, derivedhalf2, NULL); + EVP_EncryptUpdate(&en, encryptedhalf2, &encrypt_len, part2, 16); + + // #5. The encrypted private key is the Base58Check-encoded concatenation of the following, which totals 39 bytes without Base58 checksum: + // # 0x01 0x42 + flagbyte + salt + encryptedhalf1 + encryptedhalf2 + // flagbyte = chr(0b11100000) # 11 no-ec 1 compressed-pub 00 future 0 ec only 00 future + // privkey = ('\x01\x42' + flagbyte + addresshash + encryptedhalf1 + encryptedhalf2) + // check = hashlib.sha256(hashlib.sha256(privkey).digest()).digest()[:4] + // return enc.b58encode(privkey + check) + + unsigned char flagbyte = 0xc0;// 0b11100000; // 11 no-ec 1 compressed-pub 00 future 0 ec only 00 future + unsigned char pref1 = 0x01; + unsigned char pref2 = 0x42; + + unsigned char enc_key[128]; + enc_key[0] = pref1; + enc_key[1] = pref2; + enc_key[2] = flagbyte; + + memcpy(enc_key + 3, addresshash, ADDRESSHASH_SIZE); + memcpy(enc_key + 3 + ADDRESSHASH_SIZE, encryptedhalf1, 16); + memcpy(enc_key + 3 + ADDRESSHASH_SIZE + 16, encryptedhalf2, 16); + + return std::vector(&enc_key[0], &enc_key[3 + ADDRESSHASH_SIZE + 32]); +} diff --git a/src/bip/bip38.h b/src/bip/bip38.h new file mode 100644 index 000000000000..01dfc59537c6 --- /dev/null +++ b/src/bip/bip38.h @@ -0,0 +1,19 @@ +/* + * bip38.h + * + * Created on: 30 дек. 2015 г. + * Author: mac + */ + +#ifndef SRC_BIP_BIP38_H_ +#define SRC_BIP_BIP38_H_ + +#include + +std::vector encrypt_bip38(const std::vector key, const std::string& address, const std::string& passwd); +std::vector decrypt_bip38(const std::vector key, const std::string& passwd); +std::vector decrypt_bip38_ec(const std::vector key, const std::string& passwd); +std::string encode_base16(std::vector data, size_t len); +std::vector decode_base16(const std::string &hex); + +#endif /* SRC_BIP_BIP38_H_ */ diff --git a/src/bip/config.h b/src/bip/config.h new file mode 100644 index 000000000000..b12c6eecabf0 --- /dev/null +++ b/src/bip/config.h @@ -0,0 +1,99 @@ +/* config.h. Generated from config.h.in by configure. */ +/* config.h.in. Generated from configure.ac by autoheader. */ + +/* Define to 1 if you have the `clock_gettime' function. */ +#define HAVE_CLOCK_GETTIME 1 + +/* Define to 1 if you have the declaration of `be64enc', and to 0 if you + don't. */ +#define HAVE_DECL_BE64ENC 0 + +/* Define to 1 if you have the header file. */ +#define HAVE_ERR_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the `rt' library (-lrt). */ +#define HAVE_LIBRT 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the `posix_memalign' function. */ +#define HAVE_POSIX_MEMALIGN 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if the system has the type `struct sysinfo'. */ +#define HAVE_STRUCT_SYSINFO 1 + +/* Define to 1 if `mem_unit' is member of `struct sysinfo'. */ +#define HAVE_STRUCT_SYSINFO_MEM_UNIT 1 + +/* Define to 1 if `totalram' is member of `struct sysinfo'. */ +#define HAVE_STRUCT_SYSINFO_TOTALRAM 1 + +/* Define to 1 if the OS has a hw.usermem sysctl */ +/* #undef HAVE_SYSCTL_HW_USERMEM */ + +/* Define to 1 if you have the `sysinfo' function. */ +#define HAVE_SYSINFO 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_ENDIAN_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_PARAM_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_SYSINFO_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Name of package */ +#define PACKAGE "scrypt" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "scrypt" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "scrypt 1.1.6" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "scrypt" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "1.1.6" + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Version number of package */ +#define VERSION "1.1.6" + +/* Number of bits in a file offset, on hosts where this is settable. */ +#define _FILE_OFFSET_BITS 64 + +/* Define for large files, on AIX-style hosts. */ +/* #undef _LARGE_FILES */ diff --git a/src/bip/crypto.c b/src/bip/crypto.c new file mode 100644 index 000000000000..6b3ab6005791 --- /dev/null +++ b/src/bip/crypto.c @@ -0,0 +1,243 @@ +#include + +#include "bip/crypto_scrypt.h" +#include "bip/crypto.h" + +#include +#include +#include +#include + +//struct bp_key { +// EC_KEY *k; +//}; + + +void bu_Hash(unsigned char *md256, const unsigned char *data, size_t data_len) +{ + unsigned char md1[SHA256_DIGEST_LENGTH]; + + SHA256(data, data_len, md1); + SHA256(md1, SHA256_DIGEST_LENGTH, md256); +} + +/* Generate a private key from just the secret parameter */ +static int EC_KEY_regenerate_key(EC_KEY *eckey, BIGNUM *priv_key) +{ + int ok = 0; + BN_CTX *ctx = NULL; + EC_POINT *pub_key = NULL; + + if (!eckey) return 0; + + const EC_GROUP *group = EC_KEY_get0_group(eckey); + + if ((ctx = BN_CTX_new()) == NULL) + goto err; + + pub_key = EC_POINT_new(group); + + if (pub_key == NULL) + goto err; + + if (!EC_POINT_mul(group, pub_key, priv_key, NULL, NULL, ctx)) + goto err; + + EC_KEY_set_private_key(eckey,priv_key); + EC_KEY_set_public_key(eckey,pub_key); + + ok = 1; + +err: + + if (pub_key) + EC_POINT_free(pub_key); + if (ctx != NULL) + BN_CTX_free(ctx); + + return(ok); +} + +bool bp_key_init(struct bp_key *key) +{ + memset(key, 0, sizeof(*key)); + + key->k = EC_KEY_new_by_curve_name(NID_secp256k1); + if (!key->k) + return false; + + return true; +} + +void bp_key_free(struct bp_key *key) +{ + if (key->k) { + EC_KEY_free(key->k); + key->k = NULL; + } +} + +bool bp_key_generate(struct bp_key *key) +{ + if (!key->k) + return false; + + if (!EC_KEY_generate_key(key->k)) + return false; + if (!EC_KEY_check_key(key->k)) + return false; + + EC_KEY_set_conv_form(key->k, POINT_CONVERSION_COMPRESSED); + + return true; +} + +bool bp_privkey_set(struct bp_key *key, const unsigned char *privkey_, size_t pk_len) +{ + const unsigned char *privkey = privkey_; + if (!d2i_ECPrivateKey(&key->k, &privkey, pk_len)) + return false; + if (!EC_KEY_check_key(key->k)) + return false; + + EC_KEY_set_conv_form(key->k, POINT_CONVERSION_COMPRESSED); + + return true; +} + +bool bp_pubkey_set(struct bp_key *key, const unsigned char *pubkey_, size_t pk_len) +{ + const unsigned char *pubkey = pubkey_; + if (!o2i_ECPublicKey(&key->k, &pubkey, pk_len)) + return false; + if (pk_len == 33) + EC_KEY_set_conv_form(key->k, POINT_CONVERSION_COMPRESSED); + return true; +} + +bool bp_key_secret_set(struct bp_key *key, const unsigned char *privkey_, size_t pk_len) +{ + bp_key_free(key); + + if (!privkey_ || pk_len != 32) + return false; + + const unsigned char *privkey = privkey_; + BIGNUM *bn = BN_bin2bn(privkey, 32, BN_new()); + if (!bn) + return false; + + key->k = EC_KEY_new_by_curve_name(NID_secp256k1); + if (!key->k) + goto err_out; + + if (!EC_KEY_regenerate_key(key->k, bn)) + goto err_out; + if (!EC_KEY_check_key(key->k)) + return false; + + EC_KEY_set_conv_form(key->k, POINT_CONVERSION_COMPRESSED); + + BN_clear_free(bn); + return true; + +err_out: + bp_key_free(key); + BN_clear_free(bn); + return false; +} + +bool bp_privkey_get(const struct bp_key *key, unsigned char **privkey, size_t *pk_len) +{ + if (!EC_KEY_check_key(key->k)) + return false; + + size_t sz = i2d_ECPrivateKey(key->k, 0); + unsigned char *orig_mem, *mem = (unsigned char *)malloc(sz); + orig_mem = mem; + i2d_ECPrivateKey(key->k, &mem); + + *privkey = orig_mem; + *pk_len = sz; + + return true; +} + +bool bp_pubkey_get(const struct bp_key *key, unsigned char **pubkey, size_t *pk_len) +{ + if (!EC_KEY_check_key(key->k)) + return false; + + size_t sz = i2o_ECPublicKey(key->k, 0); + unsigned char *orig_mem, *mem = (unsigned char *)malloc(sz*10); + orig_mem = mem; + i2o_ECPublicKey(key->k, &mem); + *pubkey = orig_mem; + *pk_len = sz; + + return true; +} + +bool bp_key_secret_get(unsigned char *p, size_t len, const struct bp_key *key) +{ + if (!p || len < 32 || !key) + return false; + + /* zero buffer */ + memset(p, 0, len); + + /* get bignum secret */ + const BIGNUM *bn = EC_KEY_get0_private_key(key->k); + if (!bn) + return false; + int nBytes = BN_num_bytes(bn); + + /* store secret at end of buffer */ + int n = BN_bn2bin(bn, p + (len - nBytes)); + if (n != nBytes) + return false; + + return true; +} + +bool bp_sign(const struct bp_key *key, const unsigned char *data, size_t data_len, + unsigned char **sig_, size_t *sig_len_) +{ + size_t sig_sz = ECDSA_size(key->k); + unsigned char *sig = (unsigned char *)calloc(1, sig_sz); + unsigned int sig_sz_out = sig_sz; + + int src = ECDSA_sign(0, data, data_len, sig, &sig_sz_out, key->k); + if (src != 1) { + free(sig); + return false; + } + + *sig_ = sig; + *sig_len_ = sig_sz_out; + + return true; +} + +bool bp_verify(const struct bp_key *key, const unsigned char *data, size_t data_len, + unsigned char *sig_, size_t sig_len) +{ + const unsigned char *sig = sig_; + ECDSA_SIG *esig; + bool b = false; + + esig = ECDSA_SIG_new(); + if (!esig) + goto out; + + if (!d2i_ECDSA_SIG(&esig, &sig, sig_len)) + goto out_free; + + b = ECDSA_do_verify(data, data_len, esig, key->k) == 1; + +out_free: + ECDSA_SIG_free(esig); +out: + return b; +} + diff --git a/src/bip/crypto.h b/src/bip/crypto.h new file mode 100644 index 000000000000..c9ed98e56607 --- /dev/null +++ b/src/bip/crypto.h @@ -0,0 +1,29 @@ +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct bp_key { + EC_KEY *k; +}; + +extern void bu_Hash(unsigned char *md256, const unsigned char *data, size_t data_len); +extern bool bp_key_init(struct bp_key *key); +extern void bp_key_free(struct bp_key *key); +extern bool bp_key_generate(struct bp_key *key); +extern bool bp_privkey_set(struct bp_key *key, const unsigned char *privkey, size_t pk_len); +extern bool bp_pubkey_set(struct bp_key *key, const unsigned char *pubkey, size_t pk_len); +extern bool bp_key_secret_set(struct bp_key *key, const unsigned char *privkey_, size_t pk_len); +extern bool bp_privkey_get(const struct bp_key *key, unsigned char **privkey, size_t *pk_len); +extern bool bp_pubkey_get(const struct bp_key *key, unsigned char **pubkey, size_t *pk_len); +extern bool bp_key_secret_get(unsigned char *p, size_t len, const struct bp_key *key); +extern bool bp_sign(const struct bp_key *key, const unsigned char *data, size_t data_len, + unsigned char **sig_, size_t *sig_len_); +extern bool bp_verify(const struct bp_key *key, const unsigned char *data, size_t data_len, + unsigned char *sig, size_t sig_len); + +#ifdef __cplusplus +} +#endif diff --git a/src/bip/crypto_aesctr.c b/src/bip/crypto_aesctr.c new file mode 100644 index 000000000000..dc2724b9fc3b --- /dev/null +++ b/src/bip/crypto_aesctr.c @@ -0,0 +1,124 @@ +/*- + * Copyright 2007-2009 Colin Percival + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file was originally written by Colin Percival as part of the Tarsnap + * online backup system. + */ +#include "bip/scrypt_platform.h" + +#include +#include + +#include + +#include "bip/sysendian.h" + +#include "bip/crypto_aesctr.h" + +struct crypto_aesctr { + AES_KEY * key; + uint64_t nonce; + uint64_t bytectr; + uint8_t buf[16]; +}; + +/** + * crypto_aesctr_init(key, nonce): + * Prepare to encrypt/decrypt data with AES in CTR mode, using the provided + * expanded key and nonce. The key provided must remain valid for the + * lifetime of the stream. + */ +struct crypto_aesctr * +crypto_aesctr_init(AES_KEY * key, uint64_t nonce) +{ + struct crypto_aesctr * stream; + + /* Allocate memory. */ + if ((stream = malloc(sizeof(struct crypto_aesctr))) == NULL) + goto err0; + + /* Initialize values. */ + stream->key = key; + stream->nonce = nonce; + stream->bytectr = 0; + + /* Success! */ + return (stream); + +err0: + /* Failure! */ + return (NULL); +} + +/** + * crypto_aesctr_stream(stream, inbuf, outbuf, buflen): + * Generate the next ${buflen} bytes of the AES-CTR stream and xor them with + * bytes from ${inbuf}, writing the result into ${outbuf}. If the buffers + * ${inbuf} and ${outbuf} overlap, they must be identical. + */ +void +crypto_aesctr_stream(struct crypto_aesctr * stream, const uint8_t * inbuf, + uint8_t * outbuf, size_t buflen) +{ + uint8_t pblk[16]; + size_t pos; + int bytemod; + + for (pos = 0; pos < buflen; pos++) { + /* How far through the buffer are we? */ + bytemod = stream->bytectr % 16; + + /* Generate a block of cipherstream if needed. */ + if (bytemod == 0) { + be64enc(pblk, stream->nonce); + be64enc(pblk + 8, stream->bytectr / 16); + AES_encrypt(pblk, stream->buf, stream->key); + } + + /* Encrypt a byte. */ + outbuf[pos] = inbuf[pos] ^ stream->buf[bytemod]; + + /* Move to the next byte of cipherstream. */ + stream->bytectr += 1; + } +} + +/** + * crypto_aesctr_free(stream): + * Free the provided stream object. + */ +void +crypto_aesctr_free(struct crypto_aesctr * stream) +{ + int i; + + /* Zero potentially sensitive information. */ + for (i = 0; i < 16; i++) + stream->buf[i] = 0; + stream->bytectr = stream->nonce = 0; + + /* Free the stream. */ + free(stream); +} diff --git a/src/bip/crypto_aesctr.h b/src/bip/crypto_aesctr.h new file mode 100644 index 000000000000..b50398ff8733 --- /dev/null +++ b/src/bip/crypto_aesctr.h @@ -0,0 +1,59 @@ +/*- + * Copyright 2009 Colin Percival + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file was originally written by Colin Percival as part of the Tarsnap + * online backup system. + */ +#ifndef _CRYPTO_AESCTR_H_ +#define _CRYPTO_AESCTR_H_ + +#include + +#include + +/** + * crypto_aesctr_init(key, nonce): + * Prepare to encrypt/decrypt data with AES in CTR mode, using the provided + * expanded key and nonce. The key provided must remain valid for the + * lifetime of the stream. + */ +struct crypto_aesctr * crypto_aesctr_init(AES_KEY *, uint64_t); + +/** + * crypto_aesctr_stream(stream, inbuf, outbuf, buflen): + * Generate the next ${buflen} bytes of the AES-CTR stream and xor them with + * bytes from ${inbuf}, writing the result into ${outbuf}. If the buffers + * ${inbuf} and ${outbuf} overlap, they must be identical. + */ +void crypto_aesctr_stream(struct crypto_aesctr *, const uint8_t *, + uint8_t *, size_t); + +/** + * crypto_aesctr_free(stream): + * Free the provided stream object. + */ +void crypto_aesctr_free(struct crypto_aesctr *); + +#endif /* !_CRYPTO_AESCTR_H_ */ diff --git a/src/bip/crypto_scrypt-nosse.c b/src/bip/crypto_scrypt-nosse.c new file mode 100644 index 000000000000..8447af158c75 --- /dev/null +++ b/src/bip/crypto_scrypt-nosse.c @@ -0,0 +1,338 @@ +/*- + * Copyright 2009 Colin Percival + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file was originally written by Colin Percival as part of the Tarsnap + * online backup system. + */ +#include "bip/scrypt_platform.h" + +#include +#include + +#include +#include +#include +#include + +#include "bip/sha256.h" +#include "bip/sysendian.h" + +#include "bip/crypto_scrypt.h" + +static void blkcpy(void *, void *, size_t); +static void blkxor(void *, void *, size_t); +static void salsa20_8(uint32_t[16]); +static void blockmix_salsa8(uint32_t *, uint32_t *, uint32_t *, size_t); +static uint64_t integerify(void *, size_t); +static void smix(uint8_t *, size_t, uint64_t, uint32_t *, uint32_t *); + +static void +blkcpy(void * dest, void * src, size_t len) +{ + size_t * D = dest; + size_t * S = src; + size_t L = len / sizeof(size_t); + size_t i; + + for (i = 0; i < L; i++) + D[i] = S[i]; +} + +static void +blkxor(void * dest, void * src, size_t len) +{ + size_t * D = dest; + size_t * S = src; + size_t L = len / sizeof(size_t); + size_t i; + + for (i = 0; i < L; i++) + D[i] ^= S[i]; +} + +/** + * salsa20_8(B): + * Apply the salsa20/8 core to the provided block. + */ +static void +salsa20_8(uint32_t B[16]) +{ + uint32_t x[16]; + size_t i; + + blkcpy(x, B, 64); + for (i = 0; i < 8; i += 2) { +#define R(a,b) (((a) << (b)) | ((a) >> (32 - (b)))) + /* Operate on columns. */ + x[ 4] ^= R(x[ 0]+x[12], 7); x[ 8] ^= R(x[ 4]+x[ 0], 9); + x[12] ^= R(x[ 8]+x[ 4],13); x[ 0] ^= R(x[12]+x[ 8],18); + + x[ 9] ^= R(x[ 5]+x[ 1], 7); x[13] ^= R(x[ 9]+x[ 5], 9); + x[ 1] ^= R(x[13]+x[ 9],13); x[ 5] ^= R(x[ 1]+x[13],18); + + x[14] ^= R(x[10]+x[ 6], 7); x[ 2] ^= R(x[14]+x[10], 9); + x[ 6] ^= R(x[ 2]+x[14],13); x[10] ^= R(x[ 6]+x[ 2],18); + + x[ 3] ^= R(x[15]+x[11], 7); x[ 7] ^= R(x[ 3]+x[15], 9); + x[11] ^= R(x[ 7]+x[ 3],13); x[15] ^= R(x[11]+x[ 7],18); + + /* Operate on rows. */ + x[ 1] ^= R(x[ 0]+x[ 3], 7); x[ 2] ^= R(x[ 1]+x[ 0], 9); + x[ 3] ^= R(x[ 2]+x[ 1],13); x[ 0] ^= R(x[ 3]+x[ 2],18); + + x[ 6] ^= R(x[ 5]+x[ 4], 7); x[ 7] ^= R(x[ 6]+x[ 5], 9); + x[ 4] ^= R(x[ 7]+x[ 6],13); x[ 5] ^= R(x[ 4]+x[ 7],18); + + x[11] ^= R(x[10]+x[ 9], 7); x[ 8] ^= R(x[11]+x[10], 9); + x[ 9] ^= R(x[ 8]+x[11],13); x[10] ^= R(x[ 9]+x[ 8],18); + + x[12] ^= R(x[15]+x[14], 7); x[13] ^= R(x[12]+x[15], 9); + x[14] ^= R(x[13]+x[12],13); x[15] ^= R(x[14]+x[13],18); +#undef R + } + for (i = 0; i < 16; i++) + B[i] += x[i]; +} + +/** + * blockmix_salsa8(Bin, Bout, X, r): + * Compute Bout = BlockMix_{salsa20/8, r}(Bin). The input Bin must be 128r + * bytes in length; the output Bout must also be the same size. The + * temporary space X must be 64 bytes. + */ +static void +blockmix_salsa8(uint32_t * Bin, uint32_t * Bout, uint32_t * X, size_t r) +{ + size_t i; + + /* 1: X <-- B_{2r - 1} */ + blkcpy(X, &Bin[(2 * r - 1) * 16], 64); + + /* 2: for i = 0 to 2r - 1 do */ + for (i = 0; i < 2 * r; i += 2) { + /* 3: X <-- H(X \xor B_i) */ + blkxor(X, &Bin[i * 16], 64); + salsa20_8(X); + + /* 4: Y_i <-- X */ + /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ + blkcpy(&Bout[i * 8], X, 64); + + /* 3: X <-- H(X \xor B_i) */ + blkxor(X, &Bin[i * 16 + 16], 64); + salsa20_8(X); + + /* 4: Y_i <-- X */ + /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ + blkcpy(&Bout[i * 8 + r * 16], X, 64); + } +} + +/** + * integerify(B, r): + * Return the result of parsing B_{2r-1} as a little-endian integer. + */ +static uint64_t +integerify(void * B, size_t r) +{ + uint32_t * X = (void *)((uintptr_t)(B) + (2 * r - 1) * 64); + + return (((uint64_t)(X[1]) << 32) + X[0]); +} + +/** + * smix(B, r, N, V, XY): + * Compute B = SMix_r(B, N). The input B must be 128r bytes in length; + * the temporary storage V must be 128rN bytes in length; the temporary + * storage XY must be 256r + 64 bytes in length. The value N must be a + * power of 2 greater than 1. The arrays B, V, and XY must be aligned to a + * multiple of 64 bytes. + */ +static void +smix(uint8_t * B, size_t r, uint64_t N, uint32_t * V, uint32_t * XY) +{ + uint32_t * X = XY; + uint32_t * Y = &XY[32 * r]; + uint32_t * Z = &XY[64 * r]; + uint64_t i; + uint64_t j; + size_t k; + + /* 1: X <-- B */ + for (k = 0; k < 32 * r; k++) + X[k] = le32dec(&B[4 * k]); + + /* 2: for i = 0 to N - 1 do */ + for (i = 0; i < N; i += 2) { + /* 3: V_i <-- X */ + blkcpy(&V[i * (32 * r)], X, 128 * r); + + /* 4: X <-- H(X) */ + blockmix_salsa8(X, Y, Z, r); + + /* 3: V_i <-- X */ + blkcpy(&V[(i + 1) * (32 * r)], Y, 128 * r); + + /* 4: X <-- H(X) */ + blockmix_salsa8(Y, X, Z, r); + } + + /* 6: for i = 0 to N - 1 do */ + for (i = 0; i < N; i += 2) { + /* 7: j <-- Integerify(X) mod N */ + j = integerify(X, r) & (N - 1); + + /* 8: X <-- H(X \xor V_j) */ + blkxor(X, &V[j * (32 * r)], 128 * r); + blockmix_salsa8(X, Y, Z, r); + + /* 7: j <-- Integerify(X) mod N */ + j = integerify(Y, r) & (N - 1); + + /* 8: X <-- H(X \xor V_j) */ + blkxor(Y, &V[j * (32 * r)], 128 * r); + blockmix_salsa8(Y, X, Z, r); + } + + /* 10: B' <-- X */ + for (k = 0; k < 32 * r; k++) + le32enc(&B[4 * k], X[k]); +} + +/** + * crypto_scrypt(passwd, passwdlen, salt, saltlen, N, r, p, buf, buflen): + * Compute scrypt(passwd[0 .. passwdlen - 1], salt[0 .. saltlen - 1], N, r, + * p, buflen) and write the result into buf. The parameters r, p, and buflen + * must satisfy r * p < 2^30 and buflen <= (2^32 - 1) * 32. The parameter N + * must be a power of 2 greater than 1. + * + * Return 0 on success; or -1 on error. + */ +int +crypto_scrypt(const uint8_t * passwd, size_t passwdlen, + const uint8_t * salt, size_t saltlen, uint64_t N, uint32_t r, uint32_t p, + uint8_t * buf, size_t buflen) +{ + void * B0, * V0, * XY0; + uint8_t * B; + uint32_t * V; + uint32_t * XY; + uint32_t i; + + /* Sanity-check parameters. */ +#if SIZE_MAX > UINT32_MAX + if (buflen > (((uint64_t)(1) << 32) - 1) * 32) { + errno = EFBIG; + goto err0; + } +#endif + if ((uint64_t)(r) * (uint64_t)(p) >= (1 << 30)) { + errno = EFBIG; + goto err0; + } + if (((N & (N - 1)) != 0) || (N == 0)) { + errno = EINVAL; + goto err0; + } + if ((r > SIZE_MAX / 128 / p) || +#if SIZE_MAX / 256 <= UINT32_MAX + (r > SIZE_MAX / 256) || +#endif + (N > SIZE_MAX / 128 / r)) { + errno = ENOMEM; + goto err0; + } + + /* Allocate memory. */ +#ifdef HAVE_POSIX_MEMALIGN + if ((errno = posix_memalign(&B0, 64, 128 * r * p)) != 0) + goto err0; + B = (uint8_t *)(B0); + if ((errno = posix_memalign(&XY0, 64, 256 * r + 64)) != 0) + goto err1; + XY = (uint32_t *)(XY0); +#ifndef MAP_ANON + if ((errno = posix_memalign(&V0, 64, 128 * r * N)) != 0) + goto err2; + V = (uint32_t *)(V0); +#endif +#else + if ((B0 = malloc(128 * r * p + 63)) == NULL) + goto err0; + B = (uint8_t *)(((uintptr_t)(B0) + 63) & ~ (uintptr_t)(63)); + if ((XY0 = malloc(256 * r + 64 + 63)) == NULL) + goto err1; + XY = (uint32_t *)(((uintptr_t)(XY0) + 63) & ~ (uintptr_t)(63)); +#ifndef MAP_ANON + if ((V0 = malloc(128 * r * N + 63)) == NULL) + goto err2; + V = (uint32_t *)(((uintptr_t)(V0) + 63) & ~ (uintptr_t)(63)); +#endif +#endif +#ifdef MAP_ANON + if ((V0 = mmap(NULL, 128 * r * N, PROT_READ | PROT_WRITE, +#ifdef MAP_NOCORE + MAP_ANON | MAP_PRIVATE | MAP_NOCORE, +#else + MAP_ANON | MAP_PRIVATE, +#endif + -1, 0)) == MAP_FAILED) + goto err2; + V = (uint32_t *)(V0); +#endif + + /* 1: (B_0 ... B_{p-1}) <-- PBKDF2(P, S, 1, p * MFLen) */ + PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, 1, B, p * 128 * r); + + /* 2: for i = 0 to p - 1 do */ + for (i = 0; i < p; i++) { + /* 3: B_i <-- MF(B_i, N) */ + smix(&B[i * 128 * r], r, N, V, XY); + } + + /* 5: DK <-- PBKDF2(P, B, 1, dkLen) */ + PBKDF2_SHA256(passwd, passwdlen, B, p * 128 * r, 1, buf, buflen); + + /* Free memory. */ +#ifdef MAP_ANON + if (munmap(V0, 128 * r * N)) + goto err2; +#else + free(V0); +#endif + free(XY0); + free(B0); + + /* Success! */ + return (0); + +err2: + free(XY0); +err1: + free(B0); +err0: + /* Failure! */ + return (-1); +} diff --git a/src/bip/crypto_scrypt-ref.c b/src/bip/crypto_scrypt-ref.c new file mode 100644 index 000000000000..ff83bd41ea25 --- /dev/null +++ b/src/bip/crypto_scrypt-ref.c @@ -0,0 +1,284 @@ +/*- + * Copyright 2009 Colin Percival + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file was originally written by Colin Percival as part of the Tarsnap + * online backup system. + */ +#include "bip/scrypt_platform.h" + +#include +#include +#include +#include + +#include "bip/sha256.h" +#include "bip/sysendian.h" + +#include "bip/crypto_scrypt.h" + +static void blkcpy(uint8_t *, uint8_t *, size_t); +static void blkxor(uint8_t *, uint8_t *, size_t); +static void salsa20_8(uint8_t[64]); +static void blockmix_salsa8(uint8_t *, uint8_t *, size_t); +static uint64_t integerify(uint8_t *, size_t); +static void smix(uint8_t *, size_t, uint64_t, uint8_t *, uint8_t *); + +static void +blkcpy(uint8_t * dest, uint8_t * src, size_t len) +{ + size_t i; + + for (i = 0; i < len; i++) + dest[i] = src[i]; +} + +static void +blkxor(uint8_t * dest, uint8_t * src, size_t len) +{ + size_t i; + + for (i = 0; i < len; i++) + dest[i] ^= src[i]; +} + +/** + * salsa20_8(B): + * Apply the salsa20/8 core to the provided block. + */ +static void +salsa20_8(uint8_t B[64]) +{ + uint32_t B32[16]; + uint32_t x[16]; + size_t i; + + /* Convert little-endian values in. */ + for (i = 0; i < 16; i++) + B32[i] = le32dec(&B[i * 4]); + + /* Compute x = doubleround^4(B32). */ + for (i = 0; i < 16; i++) + x[i] = B32[i]; + for (i = 0; i < 8; i += 2) { +#define R(a,b) (((a) << (b)) | ((a) >> (32 - (b)))) + /* Operate on columns. */ + x[ 4] ^= R(x[ 0]+x[12], 7); x[ 8] ^= R(x[ 4]+x[ 0], 9); + x[12] ^= R(x[ 8]+x[ 4],13); x[ 0] ^= R(x[12]+x[ 8],18); + + x[ 9] ^= R(x[ 5]+x[ 1], 7); x[13] ^= R(x[ 9]+x[ 5], 9); + x[ 1] ^= R(x[13]+x[ 9],13); x[ 5] ^= R(x[ 1]+x[13],18); + + x[14] ^= R(x[10]+x[ 6], 7); x[ 2] ^= R(x[14]+x[10], 9); + x[ 6] ^= R(x[ 2]+x[14],13); x[10] ^= R(x[ 6]+x[ 2],18); + + x[ 3] ^= R(x[15]+x[11], 7); x[ 7] ^= R(x[ 3]+x[15], 9); + x[11] ^= R(x[ 7]+x[ 3],13); x[15] ^= R(x[11]+x[ 7],18); + + /* Operate on rows. */ + x[ 1] ^= R(x[ 0]+x[ 3], 7); x[ 2] ^= R(x[ 1]+x[ 0], 9); + x[ 3] ^= R(x[ 2]+x[ 1],13); x[ 0] ^= R(x[ 3]+x[ 2],18); + + x[ 6] ^= R(x[ 5]+x[ 4], 7); x[ 7] ^= R(x[ 6]+x[ 5], 9); + x[ 4] ^= R(x[ 7]+x[ 6],13); x[ 5] ^= R(x[ 4]+x[ 7],18); + + x[11] ^= R(x[10]+x[ 9], 7); x[ 8] ^= R(x[11]+x[10], 9); + x[ 9] ^= R(x[ 8]+x[11],13); x[10] ^= R(x[ 9]+x[ 8],18); + + x[12] ^= R(x[15]+x[14], 7); x[13] ^= R(x[12]+x[15], 9); + x[14] ^= R(x[13]+x[12],13); x[15] ^= R(x[14]+x[13],18); +#undef R + } + + /* Compute B32 = B32 + x. */ + for (i = 0; i < 16; i++) + B32[i] += x[i]; + + /* Convert little-endian values out. */ + for (i = 0; i < 16; i++) + le32enc(&B[4 * i], B32[i]); +} + +/** + * blockmix_salsa8(B, Y, r): + * Compute B = BlockMix_{salsa20/8, r}(B). The input B must be 128r bytes in + * length; the temporary space Y must also be the same size. + */ +static void +blockmix_salsa8(uint8_t * B, uint8_t * Y, size_t r) +{ + uint8_t X[64]; + size_t i; + + /* 1: X <-- B_{2r - 1} */ + blkcpy(X, &B[(2 * r - 1) * 64], 64); + + /* 2: for i = 0 to 2r - 1 do */ + for (i = 0; i < 2 * r; i++) { + /* 3: X <-- H(X \xor B_i) */ + blkxor(X, &B[i * 64], 64); + salsa20_8(X); + + /* 4: Y_i <-- X */ + blkcpy(&Y[i * 64], X, 64); + } + + /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ + for (i = 0; i < r; i++) + blkcpy(&B[i * 64], &Y[(i * 2) * 64], 64); + for (i = 0; i < r; i++) + blkcpy(&B[(i + r) * 64], &Y[(i * 2 + 1) * 64], 64); +} + +/** + * integerify(B, r): + * Return the result of parsing B_{2r-1} as a little-endian integer. + */ +static uint64_t +integerify(uint8_t * B, size_t r) +{ + uint8_t * X = &B[(2 * r - 1) * 64]; + + return (le64dec(X)); +} + +/** + * smix(B, r, N, V, XY): + * Compute B = SMix_r(B, N). The input B must be 128r bytes in length; the + * temporary storage V must be 128rN bytes in length; the temporary storage + * XY must be 256r bytes in length. The value N must be a power of 2. + */ +static void +smix(uint8_t * B, size_t r, uint64_t N, uint8_t * V, uint8_t * XY) +{ + uint8_t * X = XY; + uint8_t * Y = &XY[128 * r]; + uint64_t i; + uint64_t j; + + /* 1: X <-- B */ + blkcpy(X, B, 128 * r); + + /* 2: for i = 0 to N - 1 do */ + for (i = 0; i < N; i++) { + /* 3: V_i <-- X */ + blkcpy(&V[i * (128 * r)], X, 128 * r); + + /* 4: X <-- H(X) */ + blockmix_salsa8(X, Y, r); + } + + /* 6: for i = 0 to N - 1 do */ + for (i = 0; i < N; i++) { + /* 7: j <-- Integerify(X) mod N */ + j = integerify(X, r) & (N - 1); + + /* 8: X <-- H(X \xor V_j) */ + blkxor(X, &V[j * (128 * r)], 128 * r); + blockmix_salsa8(X, Y, r); + } + + /* 10: B' <-- X */ + blkcpy(B, X, 128 * r); +} + +/** + * crypto_scrypt(passwd, passwdlen, salt, saltlen, N, r, p, buf, buflen): + * Compute scrypt(passwd[0 .. passwdlen - 1], salt[0 .. saltlen - 1], N, r, + * p, buflen) and write the result into buf. The parameters r, p, and buflen + * must satisfy r * p < 2^30 and buflen <= (2^32 - 1) * 32. The parameter N + * must be a power of 2. + * + * Return 0 on success; or -1 on error. + */ +int +crypto_scrypt(const uint8_t * passwd, size_t passwdlen, + const uint8_t * salt, size_t saltlen, uint64_t N, uint32_t r, uint32_t p, + uint8_t * buf, size_t buflen) +{ + uint8_t * B; + uint8_t * V; + uint8_t * XY; + uint32_t i; + + /* Sanity-check parameters. */ +#if SIZE_MAX > UINT32_MAX + if (buflen > (((uint64_t)(1) << 32) - 1) * 32) { + errno = EFBIG; + goto err0; + } +#endif + if ((uint64_t)(r) * (uint64_t)(p) >= (1 << 30)) { + errno = EFBIG; + goto err0; + } + if (((N & (N - 1)) != 0) || (N == 0)) { + errno = EINVAL; + goto err0; + } + if ((r > SIZE_MAX / 128 / p) || +#if SIZE_MAX / 256 <= UINT32_MAX + (r > SIZE_MAX / 256) || +#endif + (N > SIZE_MAX / 128 / r)) { + errno = ENOMEM; + goto err0; + } + + /* Allocate memory. */ + if ((B = malloc(128 * r * p)) == NULL) + goto err0; + if ((XY = malloc(256 * r)) == NULL) + goto err1; + if ((V = malloc(128 * r * N)) == NULL) + goto err2; + + /* 1: (B_0 ... B_{p-1}) <-- PBKDF2(P, S, 1, p * MFLen) */ + PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, 1, B, p * 128 * r); + + /* 2: for i = 0 to p - 1 do */ + for (i = 0; i < p; i++) { + /* 3: B_i <-- MF(B_i, N) */ + smix(&B[i * 128 * r], r, N, V, XY); + } + + /* 5: DK <-- PBKDF2(P, B, 1, dkLen) */ + PBKDF2_SHA256(passwd, passwdlen, B, p * 128 * r, 1, buf, buflen); + + /* Free memory. */ + free(V); + free(XY); + free(B); + + /* Success! */ + return (0); + +err2: + free(XY); +err1: + free(B); +err0: + /* Failure! */ + return (-1); +} diff --git a/src/bip/crypto_scrypt-sse.c b/src/bip/crypto_scrypt-sse.c new file mode 100644 index 000000000000..fdccec796f65 --- /dev/null +++ b/src/bip/crypto_scrypt-sse.c @@ -0,0 +1,366 @@ +/*- + * Copyright 2009 Colin Percival + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file was originally written by Colin Percival as part of the Tarsnap + * online backup system. + */ +#include "bip/scrypt_platform.h" + +#include +#include + +#include +#include +#include +#include +#include + +#include "bip/sha256.h" +#include "bip/sysendian.h" + +#include "bip/crypto_scrypt.h" + +static void blkcpy(void *, void *, size_t); +static void blkxor(void *, void *, size_t); +static void salsa20_8(__m128i *); +static void blockmix_salsa8(__m128i *, __m128i *, __m128i *, size_t); +static uint64_t integerify(void *, size_t); +static void smix(uint8_t *, size_t, uint64_t, void *, void *); + +static void +blkcpy(void * dest, void * src, size_t len) +{ + __m128i * D = dest; + __m128i * S = src; + size_t L = len / 16; + size_t i; + + for (i = 0; i < L; i++) + D[i] = S[i]; +} + +static void +blkxor(void * dest, void * src, size_t len) +{ + __m128i * D = dest; + __m128i * S = src; + size_t L = len / 16; + size_t i; + + for (i = 0; i < L; i++) + D[i] = _mm_xor_si128(D[i], S[i]); +} + +/** + * salsa20_8(B): + * Apply the salsa20/8 core to the provided block. + */ +static void +salsa20_8(__m128i B[4]) +{ + __m128i X0, X1, X2, X3; + __m128i T; + size_t i; + + X0 = B[0]; + X1 = B[1]; + X2 = B[2]; + X3 = B[3]; + + for (i = 0; i < 8; i += 2) { + /* Operate on "columns". */ + T = _mm_add_epi32(X0, X3); + X1 = _mm_xor_si128(X1, _mm_slli_epi32(T, 7)); + X1 = _mm_xor_si128(X1, _mm_srli_epi32(T, 25)); + T = _mm_add_epi32(X1, X0); + X2 = _mm_xor_si128(X2, _mm_slli_epi32(T, 9)); + X2 = _mm_xor_si128(X2, _mm_srli_epi32(T, 23)); + T = _mm_add_epi32(X2, X1); + X3 = _mm_xor_si128(X3, _mm_slli_epi32(T, 13)); + X3 = _mm_xor_si128(X3, _mm_srli_epi32(T, 19)); + T = _mm_add_epi32(X3, X2); + X0 = _mm_xor_si128(X0, _mm_slli_epi32(T, 18)); + X0 = _mm_xor_si128(X0, _mm_srli_epi32(T, 14)); + + /* Rearrange data. */ + X1 = _mm_shuffle_epi32(X1, 0x93); + X2 = _mm_shuffle_epi32(X2, 0x4E); + X3 = _mm_shuffle_epi32(X3, 0x39); + + /* Operate on "rows". */ + T = _mm_add_epi32(X0, X1); + X3 = _mm_xor_si128(X3, _mm_slli_epi32(T, 7)); + X3 = _mm_xor_si128(X3, _mm_srli_epi32(T, 25)); + T = _mm_add_epi32(X3, X0); + X2 = _mm_xor_si128(X2, _mm_slli_epi32(T, 9)); + X2 = _mm_xor_si128(X2, _mm_srli_epi32(T, 23)); + T = _mm_add_epi32(X2, X3); + X1 = _mm_xor_si128(X1, _mm_slli_epi32(T, 13)); + X1 = _mm_xor_si128(X1, _mm_srli_epi32(T, 19)); + T = _mm_add_epi32(X1, X2); + X0 = _mm_xor_si128(X0, _mm_slli_epi32(T, 18)); + X0 = _mm_xor_si128(X0, _mm_srli_epi32(T, 14)); + + /* Rearrange data. */ + X1 = _mm_shuffle_epi32(X1, 0x39); + X2 = _mm_shuffle_epi32(X2, 0x4E); + X3 = _mm_shuffle_epi32(X3, 0x93); + } + + B[0] = _mm_add_epi32(B[0], X0); + B[1] = _mm_add_epi32(B[1], X1); + B[2] = _mm_add_epi32(B[2], X2); + B[3] = _mm_add_epi32(B[3], X3); +} + +/** + * blockmix_salsa8(Bin, Bout, X, r): + * Compute Bout = BlockMix_{salsa20/8, r}(Bin). The input Bin must be 128r + * bytes in length; the output Bout must also be the same size. The + * temporary space X must be 64 bytes. + */ +static void +blockmix_salsa8(__m128i * Bin, __m128i * Bout, __m128i * X, size_t r) +{ + size_t i; + + /* 1: X <-- B_{2r - 1} */ + blkcpy(X, &Bin[8 * r - 4], 64); + + /* 2: for i = 0 to 2r - 1 do */ + for (i = 0; i < r; i++) { + /* 3: X <-- H(X \xor B_i) */ + blkxor(X, &Bin[i * 8], 64); + salsa20_8(X); + + /* 4: Y_i <-- X */ + /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ + blkcpy(&Bout[i * 4], X, 64); + + /* 3: X <-- H(X \xor B_i) */ + blkxor(X, &Bin[i * 8 + 4], 64); + salsa20_8(X); + + /* 4: Y_i <-- X */ + /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ + blkcpy(&Bout[(r + i) * 4], X, 64); + } +} + +/** + * integerify(B, r): + * Return the result of parsing B_{2r-1} as a little-endian integer. + */ +static uint64_t +integerify(void * B, size_t r) +{ + uint32_t * X = (void *)((uintptr_t)(B) + (2 * r - 1) * 64); + + return (((uint64_t)(X[13]) << 32) + X[0]); +} + +/** + * smix(B, r, N, V, XY): + * Compute B = SMix_r(B, N). The input B must be 128r bytes in length; + * the temporary storage V must be 128rN bytes in length; the temporary + * storage XY must be 256r + 64 bytes in length. The value N must be a + * power of 2 greater than 1. The arrays B, V, and XY must be aligned to a + * multiple of 64 bytes. + */ +static void +smix(uint8_t * B, size_t r, uint64_t N, void * V, void * XY) +{ + __m128i * X = XY; + __m128i * Y = (void *)((uintptr_t)(XY) + 128 * r); + __m128i * Z = (void *)((uintptr_t)(XY) + 256 * r); + uint32_t * X32 = (void *)X; + uint64_t i, j; + size_t k; + + /* 1: X <-- B */ + for (k = 0; k < 2 * r; k++) { + for (i = 0; i < 16; i++) { + X32[k * 16 + i] = + le32dec(&B[(k * 16 + (i * 5 % 16)) * 4]); + } + } + + /* 2: for i = 0 to N - 1 do */ + for (i = 0; i < N; i += 2) { + /* 3: V_i <-- X */ + blkcpy((void *)((uintptr_t)(V) + i * 128 * r), X, 128 * r); + + /* 4: X <-- H(X) */ + blockmix_salsa8(X, Y, Z, r); + + /* 3: V_i <-- X */ + blkcpy((void *)((uintptr_t)(V) + (i + 1) * 128 * r), + Y, 128 * r); + + /* 4: X <-- H(X) */ + blockmix_salsa8(Y, X, Z, r); + } + + /* 6: for i = 0 to N - 1 do */ + for (i = 0; i < N; i += 2) { + /* 7: j <-- Integerify(X) mod N */ + j = integerify(X, r) & (N - 1); + + /* 8: X <-- H(X \xor V_j) */ + blkxor(X, (void *)((uintptr_t)(V) + j * 128 * r), 128 * r); + blockmix_salsa8(X, Y, Z, r); + + /* 7: j <-- Integerify(X) mod N */ + j = integerify(Y, r) & (N - 1); + + /* 8: X <-- H(X \xor V_j) */ + blkxor(Y, (void *)((uintptr_t)(V) + j * 128 * r), 128 * r); + blockmix_salsa8(Y, X, Z, r); + } + + /* 10: B' <-- X */ + for (k = 0; k < 2 * r; k++) { + for (i = 0; i < 16; i++) { + le32enc(&B[(k * 16 + (i * 5 % 16)) * 4], + X32[k * 16 + i]); + } + } +} + +/** + * crypto_scrypt(passwd, passwdlen, salt, saltlen, N, r, p, buf, buflen): + * Compute scrypt(passwd[0 .. passwdlen - 1], salt[0 .. saltlen - 1], N, r, + * p, buflen) and write the result into buf. The parameters r, p, and buflen + * must satisfy r * p < 2^30 and buflen <= (2^32 - 1) * 32. The parameter N + * must be a power of 2 greater than 1. + * + * Return 0 on success; or -1 on error. + */ +int +crypto_scrypt(const uint8_t * passwd, size_t passwdlen, + const uint8_t * salt, size_t saltlen, uint64_t N, uint32_t r, uint32_t p, + uint8_t * buf, size_t buflen) +{ + void * B0, * V0, * XY0; + uint8_t * B; + uint32_t * V; + uint32_t * XY; + uint32_t i; + + /* Sanity-check parameters. */ +#if SIZE_MAX > UINT32_MAX + if (buflen > (((uint64_t)(1) << 32) - 1) * 32) { + errno = EFBIG; + goto err0; + } +#endif + if ((uint64_t)(r) * (uint64_t)(p) >= (1 << 30)) { + errno = EFBIG; + goto err0; + } + if (((N & (N - 1)) != 0) || (N == 0)) { + errno = EINVAL; + goto err0; + } + if ((r > SIZE_MAX / 128 / p) || +#if SIZE_MAX / 256 <= UINT32_MAX + (r > (SIZE_MAX - 64) / 256) || +#endif + (N > SIZE_MAX / 128 / r)) { + errno = ENOMEM; + goto err0; + } + + /* Allocate memory. */ +#ifdef HAVE_POSIX_MEMALIGN + if ((errno = posix_memalign(&B0, 64, 128 * r * p)) != 0) + goto err0; + B = (uint8_t *)(B0); + if ((errno = posix_memalign(&XY0, 64, 256 * r + 64)) != 0) + goto err1; + XY = (uint32_t *)(XY0); +#ifndef MAP_ANON + if ((errno = posix_memalign(&V0, 64, 128 * r * N)) != 0) + goto err2; + V = (uint32_t *)(V0); +#endif +#else + if ((B0 = malloc(128 * r * p + 63)) == NULL) + goto err0; + B = (uint8_t *)(((uintptr_t)(B0) + 63) & ~ (uintptr_t)(63)); + if ((XY0 = malloc(256 * r + 64 + 63)) == NULL) + goto err1; + XY = (uint32_t *)(((uintptr_t)(XY0) + 63) & ~ (uintptr_t)(63)); +#ifndef MAP_ANON + if ((V0 = malloc(128 * r * N + 63)) == NULL) + goto err2; + V = (uint32_t *)(((uintptr_t)(V0) + 63) & ~ (uintptr_t)(63)); +#endif +#endif +#ifdef MAP_ANON + if ((V0 = mmap(NULL, 128 * r * N, PROT_READ | PROT_WRITE, +#ifdef MAP_NOCORE + MAP_ANON | MAP_PRIVATE | MAP_NOCORE, +#else + MAP_ANON | MAP_PRIVATE, +#endif + -1, 0)) == MAP_FAILED) + goto err2; + V = (uint32_t *)(V0); +#endif + + /* 1: (B_0 ... B_{p-1}) <-- PBKDF2(P, S, 1, p * MFLen) */ + PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, 1, B, p * 128 * r); + + /* 2: for i = 0 to p - 1 do */ + for (i = 0; i < p; i++) { + /* 3: B_i <-- MF(B_i, N) */ + smix(&B[i * 128 * r], r, N, V, XY); + } + + /* 5: DK <-- PBKDF2(P, B, 1, dkLen) */ + PBKDF2_SHA256(passwd, passwdlen, B, p * 128 * r, 1, buf, buflen); + + /* Free memory. */ +#ifdef MAP_ANON + if (munmap(V0, 128 * r * N)) + goto err2; +#else + free(V0); +#endif + free(XY0); + free(B0); + + /* Success! */ + return (0); + +err2: + free(XY0); +err1: + free(B0); +err0: + /* Failure! */ + return (-1); +} diff --git a/src/bip/crypto_scrypt.h b/src/bip/crypto_scrypt.h new file mode 100644 index 000000000000..4cb38dbe27bc --- /dev/null +++ b/src/bip/crypto_scrypt.h @@ -0,0 +1,57 @@ +/*- + * Copyright 2009 Colin Percival + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file was originally written by Colin Percival as part of the Tarsnap + * online backup system. + */ +#ifndef _CRYPTO_SCRYPT_H_ +#define _CRYPTO_SCRYPT_H_ + +#include +#include +#include + +/** + * crypto_scrypt(passwd, passwdlen, salt, saltlen, N, r, p, buf, buflen): + * Compute scrypt(passwd[0 .. passwdlen - 1], salt[0 .. saltlen - 1], N, r, + * p, buflen) and write the result into buf. The parameters r, p, and buflen + * must satisfy r * p < 2^30 and buflen <= (2^32 - 1) * 32. The parameter N + * must be a power of 2 greater than 1. + * + * Return 0 on success; or -1 on error. + */ +#ifdef __cplusplus +extern "C" { +#endif + +int crypto_scrypt(const uint8_t *, size_t, const uint8_t *, size_t, uint64_t, + uint32_t, uint32_t, uint8_t *, size_t); + +#ifdef __cplusplus +} +#endif + + +#endif /* !_CRYPTO_SCRYPT_H_ */ diff --git a/src/bip/scrypt_platform.h b/src/bip/scrypt_platform.h new file mode 100644 index 000000000000..e868d34d5355 --- /dev/null +++ b/src/bip/scrypt_platform.h @@ -0,0 +1,7 @@ + +#ifndef __SCRYPT_CONFIG_PLATFORM +#define __SCRYPT_CONFIG_PLATFORM + +#include "bip/config.h" + +#endif diff --git a/src/bip/sha256.c b/src/bip/sha256.c new file mode 100644 index 000000000000..87c8b4bb9952 --- /dev/null +++ b/src/bip/sha256.c @@ -0,0 +1,412 @@ +/*- + * Copyright 2005,2007,2009 Colin Percival + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#include "bip/scrypt_platform.h" + +#include + +#include +#include + +#include "bip/sysendian.h" + +#include "bip/sha256.h" + +/* + * Encode a length len/4 vector of (uint32_t) into a length len vector of + * (unsigned char) in big-endian form. Assumes len is a multiple of 4. + */ +static void +be32enc_vect(unsigned char *dst, const uint32_t *src, size_t len) +{ + size_t i; + + for (i = 0; i < len / 4; i++) + be32enc(dst + i * 4, src[i]); +} + +/* + * Decode a big-endian length len vector of (unsigned char) into a length + * len/4 vector of (uint32_t). Assumes len is a multiple of 4. + */ +static void +be32dec_vect(uint32_t *dst, const unsigned char *src, size_t len) +{ + size_t i; + + for (i = 0; i < len / 4; i++) + dst[i] = be32dec(src + i * 4); +} + +/* Elementary functions used by SHA256 */ +#define Ch(x, y, z) ((x & (y ^ z)) ^ z) +#define Maj(x, y, z) ((x & (y | z)) | (y & z)) +#define SHR(x, n) (x >> n) +#define ROTR(x, n) ((x >> n) | (x << (32 - n))) +#define S0(x) (ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22)) +#define S1(x) (ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25)) +#define s0(x) (ROTR(x, 7) ^ ROTR(x, 18) ^ SHR(x, 3)) +#define s1(x) (ROTR(x, 17) ^ ROTR(x, 19) ^ SHR(x, 10)) + +/* SHA256 round function */ +#define RND(a, b, c, d, e, f, g, h, k) \ + t0 = h + S1(e) + Ch(e, f, g) + k; \ + t1 = S0(a) + Maj(a, b, c); \ + d += t0; \ + h = t0 + t1; + +/* Adjusted round function for rotating state */ +#define RNDr(S, W, i, k) \ + RND(S[(64 - i) % 8], S[(65 - i) % 8], \ + S[(66 - i) % 8], S[(67 - i) % 8], \ + S[(68 - i) % 8], S[(69 - i) % 8], \ + S[(70 - i) % 8], S[(71 - i) % 8], \ + W[i] + k) + +/* + * SHA256 block compression function. The 256-bit state is transformed via + * the 512-bit input block to produce a new state. + */ +static void +SHA256_Transform(uint32_t * state, const unsigned char block[64]) +{ + uint32_t W[64]; + uint32_t S[8]; + uint32_t t0, t1; + int i; + + /* 1. Prepare message schedule W. */ + be32dec_vect(W, block, 64); + for (i = 16; i < 64; i++) + W[i] = s1(W[i - 2]) + W[i - 7] + s0(W[i - 15]) + W[i - 16]; + + /* 2. Initialize working variables. */ + memcpy(S, state, 32); + + /* 3. Mix. */ + RNDr(S, W, 0, 0x428a2f98); + RNDr(S, W, 1, 0x71374491); + RNDr(S, W, 2, 0xb5c0fbcf); + RNDr(S, W, 3, 0xe9b5dba5); + RNDr(S, W, 4, 0x3956c25b); + RNDr(S, W, 5, 0x59f111f1); + RNDr(S, W, 6, 0x923f82a4); + RNDr(S, W, 7, 0xab1c5ed5); + RNDr(S, W, 8, 0xd807aa98); + RNDr(S, W, 9, 0x12835b01); + RNDr(S, W, 10, 0x243185be); + RNDr(S, W, 11, 0x550c7dc3); + RNDr(S, W, 12, 0x72be5d74); + RNDr(S, W, 13, 0x80deb1fe); + RNDr(S, W, 14, 0x9bdc06a7); + RNDr(S, W, 15, 0xc19bf174); + RNDr(S, W, 16, 0xe49b69c1); + RNDr(S, W, 17, 0xefbe4786); + RNDr(S, W, 18, 0x0fc19dc6); + RNDr(S, W, 19, 0x240ca1cc); + RNDr(S, W, 20, 0x2de92c6f); + RNDr(S, W, 21, 0x4a7484aa); + RNDr(S, W, 22, 0x5cb0a9dc); + RNDr(S, W, 23, 0x76f988da); + RNDr(S, W, 24, 0x983e5152); + RNDr(S, W, 25, 0xa831c66d); + RNDr(S, W, 26, 0xb00327c8); + RNDr(S, W, 27, 0xbf597fc7); + RNDr(S, W, 28, 0xc6e00bf3); + RNDr(S, W, 29, 0xd5a79147); + RNDr(S, W, 30, 0x06ca6351); + RNDr(S, W, 31, 0x14292967); + RNDr(S, W, 32, 0x27b70a85); + RNDr(S, W, 33, 0x2e1b2138); + RNDr(S, W, 34, 0x4d2c6dfc); + RNDr(S, W, 35, 0x53380d13); + RNDr(S, W, 36, 0x650a7354); + RNDr(S, W, 37, 0x766a0abb); + RNDr(S, W, 38, 0x81c2c92e); + RNDr(S, W, 39, 0x92722c85); + RNDr(S, W, 40, 0xa2bfe8a1); + RNDr(S, W, 41, 0xa81a664b); + RNDr(S, W, 42, 0xc24b8b70); + RNDr(S, W, 43, 0xc76c51a3); + RNDr(S, W, 44, 0xd192e819); + RNDr(S, W, 45, 0xd6990624); + RNDr(S, W, 46, 0xf40e3585); + RNDr(S, W, 47, 0x106aa070); + RNDr(S, W, 48, 0x19a4c116); + RNDr(S, W, 49, 0x1e376c08); + RNDr(S, W, 50, 0x2748774c); + RNDr(S, W, 51, 0x34b0bcb5); + RNDr(S, W, 52, 0x391c0cb3); + RNDr(S, W, 53, 0x4ed8aa4a); + RNDr(S, W, 54, 0x5b9cca4f); + RNDr(S, W, 55, 0x682e6ff3); + RNDr(S, W, 56, 0x748f82ee); + RNDr(S, W, 57, 0x78a5636f); + RNDr(S, W, 58, 0x84c87814); + RNDr(S, W, 59, 0x8cc70208); + RNDr(S, W, 60, 0x90befffa); + RNDr(S, W, 61, 0xa4506ceb); + RNDr(S, W, 62, 0xbef9a3f7); + RNDr(S, W, 63, 0xc67178f2); + + /* 4. Mix local working variables into global state */ + for (i = 0; i < 8; i++) + state[i] += S[i]; + + /* Clean the stack. */ + memset(W, 0, 256); + memset(S, 0, 32); + t0 = t1 = 0; +} + +static unsigned char PAD[64] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* Add padding and terminating bit-count. */ +static void +SHA256_Pad(SHA256_CTX * ctx) +{ + unsigned char len[8]; + uint32_t r, plen; + + /* + * Convert length to a vector of bytes -- we do this now rather + * than later because the length will change after we pad. + */ + be32enc_vect(len, ctx->count, 8); + + /* Add 1--64 bytes so that the resulting length is 56 mod 64 */ + r = (ctx->count[1] >> 3) & 0x3f; + plen = (r < 56) ? (56 - r) : (120 - r); + SHA256_Update(ctx, PAD, (size_t)plen); + + /* Add the terminating bit-count */ + SHA256_Update(ctx, len, 8); +} + +/* SHA-256 initialization. Begins a SHA-256 operation. */ +void +SHA256_Init(SHA256_CTX * ctx) +{ + + /* Zero bits processed so far */ + ctx->count[0] = ctx->count[1] = 0; + + /* Magic initialization constants */ + ctx->state[0] = 0x6A09E667; + ctx->state[1] = 0xBB67AE85; + ctx->state[2] = 0x3C6EF372; + ctx->state[3] = 0xA54FF53A; + ctx->state[4] = 0x510E527F; + ctx->state[5] = 0x9B05688C; + ctx->state[6] = 0x1F83D9AB; + ctx->state[7] = 0x5BE0CD19; +} + +/* Add bytes into the hash */ +void +SHA256_Update(SHA256_CTX * ctx, const void *in, size_t len) +{ + uint32_t bitlen[2]; + uint32_t r; + const unsigned char *src = in; + + /* Number of bytes left in the buffer from previous updates */ + r = (ctx->count[1] >> 3) & 0x3f; + + /* Convert the length into a number of bits */ + bitlen[1] = ((uint32_t)len) << 3; + bitlen[0] = (uint32_t)(len >> 29); + + /* Update number of bits */ + if ((ctx->count[1] += bitlen[1]) < bitlen[1]) + ctx->count[0]++; + ctx->count[0] += bitlen[0]; + + /* Handle the case where we don't need to perform any transforms */ + if (len < 64 - r) { + memcpy(&ctx->buf[r], src, len); + return; + } + + /* Finish the current block */ + memcpy(&ctx->buf[r], src, 64 - r); + SHA256_Transform(ctx->state, ctx->buf); + src += 64 - r; + len -= 64 - r; + + /* Perform complete blocks */ + while (len >= 64) { + SHA256_Transform(ctx->state, src); + src += 64; + len -= 64; + } + + /* Copy left over data into buffer */ + memcpy(ctx->buf, src, len); +} + +/* + * SHA-256 finalization. Pads the input data, exports the hash value, + * and clears the context state. + */ +void +SHA256_Final(unsigned char digest[32], SHA256_CTX * ctx) +{ + + /* Add padding */ + SHA256_Pad(ctx); + + /* Write the hash */ + be32enc_vect(digest, ctx->state, 32); + + /* Clear the context state */ + memset((void *)ctx, 0, sizeof(*ctx)); +} + +/* Initialize an HMAC-SHA256 operation with the given key. */ +void +HMAC_SHA256_Init(HMAC_SHA256_CTX * ctx, const void * _K, size_t Klen) +{ + unsigned char pad[64]; + unsigned char khash[32]; + const unsigned char * K = _K; + size_t i; + + /* If Klen > 64, the key is really SHA256(K). */ + if (Klen > 64) { + SHA256_Init(&ctx->ictx); + SHA256_Update(&ctx->ictx, K, Klen); + SHA256_Final(khash, &ctx->ictx); + K = khash; + Klen = 32; + } + + /* Inner SHA256 operation is SHA256(K xor [block of 0x36] || data). */ + SHA256_Init(&ctx->ictx); + memset(pad, 0x36, 64); + for (i = 0; i < Klen; i++) + pad[i] ^= K[i]; + SHA256_Update(&ctx->ictx, pad, 64); + + /* Outer SHA256 operation is SHA256(K xor [block of 0x5c] || hash). */ + SHA256_Init(&ctx->octx); + memset(pad, 0x5c, 64); + for (i = 0; i < Klen; i++) + pad[i] ^= K[i]; + SHA256_Update(&ctx->octx, pad, 64); + + /* Clean the stack. */ + memset(khash, 0, 32); +} + +/* Add bytes to the HMAC-SHA256 operation. */ +void +HMAC_SHA256_Update(HMAC_SHA256_CTX * ctx, const void *in, size_t len) +{ + + /* Feed data to the inner SHA256 operation. */ + SHA256_Update(&ctx->ictx, in, len); +} + +/* Finish an HMAC-SHA256 operation. */ +void +HMAC_SHA256_Final(unsigned char digest[32], HMAC_SHA256_CTX * ctx) +{ + unsigned char ihash[32]; + + /* Finish the inner SHA256 operation. */ + SHA256_Final(ihash, &ctx->ictx); + + /* Feed the inner hash to the outer SHA256 operation. */ + SHA256_Update(&ctx->octx, ihash, 32); + + /* Finish the outer SHA256 operation. */ + SHA256_Final(digest, &ctx->octx); + + /* Clean the stack. */ + memset(ihash, 0, 32); +} + +/** + * PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, c, buf, dkLen): + * Compute PBKDF2(passwd, salt, c, dkLen) using HMAC-SHA256 as the PRF, and + * write the output to buf. The value dkLen must be at most 32 * (2^32 - 1). + */ +void +PBKDF2_SHA256(const uint8_t * passwd, size_t passwdlen, const uint8_t * salt, + size_t saltlen, uint64_t c, uint8_t * buf, size_t dkLen) +{ + HMAC_SHA256_CTX PShctx, hctx; + size_t i; + uint8_t ivec[4]; + uint8_t U[32]; + uint8_t T[32]; + uint64_t j; + int k; + size_t clen; + + /* Compute HMAC state after processing P and S. */ + HMAC_SHA256_Init(&PShctx, passwd, passwdlen); + HMAC_SHA256_Update(&PShctx, salt, saltlen); + + /* Iterate through the blocks. */ + for (i = 0; i * 32 < dkLen; i++) { + /* Generate INT(i + 1). */ + be32enc(ivec, (uint32_t)(i + 1)); + + /* Compute U_1 = PRF(P, S || INT(i)). */ + memcpy(&hctx, &PShctx, sizeof(HMAC_SHA256_CTX)); + HMAC_SHA256_Update(&hctx, ivec, 4); + HMAC_SHA256_Final(U, &hctx); + + /* T_i = U_1 ... */ + memcpy(T, U, 32); + + for (j = 2; j <= c; j++) { + /* Compute U_j. */ + HMAC_SHA256_Init(&hctx, passwd, passwdlen); + HMAC_SHA256_Update(&hctx, U, 32); + HMAC_SHA256_Final(U, &hctx); + + /* ... xor U_j ... */ + for (k = 0; k < 32; k++) + T[k] ^= U[k]; + } + + /* Copy as many bytes as necessary into buf. */ + clen = dkLen - i * 32; + if (clen > 32) + clen = 32; + memcpy(&buf[i * 32], T, clen); + } + + /* Clean PShctx, since we never called _Final on it. */ + memset(&PShctx, 0, sizeof(HMAC_SHA256_CTX)); +} diff --git a/src/bip/sha256.h b/src/bip/sha256.h new file mode 100644 index 000000000000..289a5232f6e5 --- /dev/null +++ b/src/bip/sha256.h @@ -0,0 +1,62 @@ +/*- + * Copyright 2005,2007,2009 Colin Percival + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libmd/sha256.h,v 1.2 2006/01/17 15:35:56 phk Exp $ + */ + +#ifndef _SHA256_H_ +#define _SHA256_H_ + +#include + +#include + +typedef struct SHA256Context { + uint32_t state[8]; + uint32_t count[2]; + unsigned char buf[64]; +} SHA256_CTX; + +typedef struct HMAC_SHA256Context { + SHA256_CTX ictx; + SHA256_CTX octx; +} HMAC_SHA256_CTX; + +void SHA256_Init(SHA256_CTX *); +void SHA256_Update(SHA256_CTX *, const void *, size_t); +void SHA256_Final(unsigned char [32], SHA256_CTX *); +void HMAC_SHA256_Init(HMAC_SHA256_CTX *, const void *, size_t); +void HMAC_SHA256_Update(HMAC_SHA256_CTX *, const void *, size_t); +void HMAC_SHA256_Final(unsigned char [32], HMAC_SHA256_CTX *); + +/** + * PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, c, buf, dkLen): + * Compute PBKDF2(passwd, salt, c, dkLen) using HMAC-SHA256 as the PRF, and + * write the output to buf. The value dkLen must be at most 32 * (2^32 - 1). + */ +void PBKDF2_SHA256(const uint8_t *, size_t, const uint8_t *, size_t, + uint64_t, uint8_t *, size_t); + +#endif /* !_SHA256_H_ */ diff --git a/src/bip/sysendian.h b/src/bip/sysendian.h new file mode 100644 index 000000000000..f6f34949d479 --- /dev/null +++ b/src/bip/sysendian.h @@ -0,0 +1,140 @@ +/*- + * Copyright 2007-2009 Colin Percival + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file was originally written by Colin Percival as part of the Tarsnap + * online backup system. + */ +#ifndef _SYSENDIAN_H_ +#define _SYSENDIAN_H_ + +#include "bip/scrypt_platform.h" + +/* If we don't have be64enc, the we have isn't usable. */ +#if !HAVE_DECL_BE64ENC +#undef HAVE_SYS_ENDIAN_H +#endif + +#ifdef HAVE_SYS_ENDIAN_H + +#include + +#else + +#include + +static inline uint32_t +be32dec(const void *pp) +{ + const uint8_t *p = (uint8_t const *)pp; + + return ((uint32_t)(p[3]) + ((uint32_t)(p[2]) << 8) + + ((uint32_t)(p[1]) << 16) + ((uint32_t)(p[0]) << 24)); +} + +static inline void +be32enc(void *pp, uint32_t x) +{ + uint8_t * p = (uint8_t *)pp; + + p[3] = x & 0xff; + p[2] = (x >> 8) & 0xff; + p[1] = (x >> 16) & 0xff; + p[0] = (x >> 24) & 0xff; +} + +static inline uint64_t +be64dec(const void *pp) +{ + const uint8_t *p = (uint8_t const *)pp; + + return ((uint64_t)(p[7]) + ((uint64_t)(p[6]) << 8) + + ((uint64_t)(p[5]) << 16) + ((uint64_t)(p[4]) << 24) + + ((uint64_t)(p[3]) << 32) + ((uint64_t)(p[2]) << 40) + + ((uint64_t)(p[1]) << 48) + ((uint64_t)(p[0]) << 56)); +} + +static inline void +be64enc(void *pp, uint64_t x) +{ + uint8_t * p = (uint8_t *)pp; + + p[7] = x & 0xff; + p[6] = (x >> 8) & 0xff; + p[5] = (x >> 16) & 0xff; + p[4] = (x >> 24) & 0xff; + p[3] = (x >> 32) & 0xff; + p[2] = (x >> 40) & 0xff; + p[1] = (x >> 48) & 0xff; + p[0] = (x >> 56) & 0xff; +} + +static inline uint32_t +le32dec(const void *pp) +{ + const uint8_t *p = (uint8_t const *)pp; + + return ((uint32_t)(p[0]) + ((uint32_t)(p[1]) << 8) + + ((uint32_t)(p[2]) << 16) + ((uint32_t)(p[3]) << 24)); +} + +static inline void +le32enc(void *pp, uint32_t x) +{ + uint8_t * p = (uint8_t *)pp; + + p[0] = x & 0xff; + p[1] = (x >> 8) & 0xff; + p[2] = (x >> 16) & 0xff; + p[3] = (x >> 24) & 0xff; +} + +static inline uint64_t +le64dec(const void *pp) +{ + const uint8_t *p = (uint8_t const *)pp; + + return ((uint64_t)(p[0]) + ((uint64_t)(p[1]) << 8) + + ((uint64_t)(p[2]) << 16) + ((uint64_t)(p[3]) << 24) + + ((uint64_t)(p[4]) << 32) + ((uint64_t)(p[5]) << 40) + + ((uint64_t)(p[6]) << 48) + ((uint64_t)(p[7]) << 56)); +} + +static inline void +le64enc(void *pp, uint64_t x) +{ + uint8_t * p = (uint8_t *)pp; + + p[0] = x & 0xff; + p[1] = (x >> 8) & 0xff; + p[2] = (x >> 16) & 0xff; + p[3] = (x >> 24) & 0xff; + p[4] = (x >> 32) & 0xff; + p[5] = (x >> 40) & 0xff; + p[6] = (x >> 48) & 0xff; + p[7] = (x >> 56) & 0xff; +} +#endif /* !HAVE_SYS_ENDIAN_H */ + +#endif /* !_SYSENDIAN_H_ */ diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 25683da88f2d..60379f82a2ce 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -228,7 +228,7 @@ BitcoinGUI::BitcoinGUI(const NetworkStyle *networkStyle, QWidget *parent) : // Get restart command-line parameters and handle restart connect(rpcConsole, SIGNAL(handleRestart(QStringList)), this, SLOT(handleRestart(QStringList))); - + // prevents an open debug window from becoming stuck/unusable on client shutdown connect(quitAction, SIGNAL(triggered()), rpcConsole, SLOT(hide())); @@ -372,6 +372,14 @@ void BitcoinGUI::createActions(const NetworkStyle *networkStyle) usedReceivingAddressesAction = new QAction(QIcon(":/icons/address-book"), tr("&Receiving addresses..."), this); usedReceivingAddressesAction->setStatusTip(tr("Show the list of used receiving addresses and labels")); + genAndPrintAddressesAction = new QAction(QIcon(":/icons/cash_icon"), tr("&Print DNET..."), this); + genAndPrintAddressesAction->setIconVisibleInMenu(true); + genAndPrintAddressesAction->setStatusTip(tr("Generate & print address keys && QR codes")); + + loadFromPaperAction = new QAction(QIcon(":/icons/import"), tr("&Import DNET..."), this); + loadFromPaperAction->setIconVisibleInMenu(true); + loadFromPaperAction->setStatusTip(tr("Load addresses from paper wallet")); + openAction = new QAction(QApplication::style()->standardIcon(QStyle::SP_FileIcon), tr("Open &URI..."), this); openAction->setStatusTip(tr("Open a DarkNet: URI or payment request")); @@ -397,6 +405,8 @@ void BitcoinGUI::createActions(const NetworkStyle *networkStyle) connect(verifyMessageAction, SIGNAL(triggered()), this, SLOT(gotoVerifyMessageTab())); connect(usedSendingAddressesAction, SIGNAL(triggered()), walletFrame, SLOT(usedSendingAddresses())); connect(usedReceivingAddressesAction, SIGNAL(triggered()), walletFrame, SLOT(usedReceivingAddresses())); + connect(genAndPrintAddressesAction, SIGNAL(triggered()), walletFrame, SLOT(genAndPrintAddresses())); + connect(loadFromPaperAction, SIGNAL(triggered()), walletFrame, SLOT(loadFromPaper())); connect(openAction, SIGNAL(triggered()), this, SLOT(openClicked())); } #endif // ENABLE_WALLET @@ -424,6 +434,8 @@ void BitcoinGUI::createMenuBar() file->addAction(usedSendingAddressesAction); file->addAction(usedReceivingAddressesAction); file->addSeparator(); + file->addAction(genAndPrintAddressesAction); + file->addAction(loadFromPaperAction); } file->addAction(quitAction); @@ -564,6 +576,8 @@ void BitcoinGUI::setWalletActionsEnabled(bool enabled) verifyMessageAction->setEnabled(enabled); usedSendingAddressesAction->setEnabled(enabled); usedReceivingAddressesAction->setEnabled(enabled); + genAndPrintAddressesAction->setEnabled(enabled); + loadFromPaperAction->setEnabled(enabled); openAction->setEnabled(enabled); } diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h index cc516d6426a7..4c04a5e88a1a 100644 --- a/src/qt/bitcoingui.h +++ b/src/qt/bitcoingui.h @@ -100,6 +100,8 @@ class BitcoinGUI : public QMainWindow QAction *optionsAction; QAction *toggleHideAction; QAction *encryptWalletAction; + QAction *genAndPrintAddressesAction; + QAction *loadFromPaperAction; QAction *backupWalletAction; QAction *changePassphraseAction; QAction *unlockWalletAction; diff --git a/src/qt/darknet.cpp b/src/qt/darknet.cpp index b009605679a6..ac3601bcf6de 100644 --- a/src/qt/darknet.cpp +++ b/src/qt/darknet.cpp @@ -66,7 +66,9 @@ Q_IMPORT_PLUGIN(AccessibleFactory) #if defined(QT_QPA_PLATFORM_XCB) Q_IMPORT_PLUGIN(QXcbIntegrationPlugin); #elif defined(QT_QPA_PLATFORM_WINDOWS) +Q_IMPORT_PLUGIN(QMinimalIntegrationPlugin); Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin); +Q_IMPORT_PLUGIN(QWindowsPrinterSupportPlugin); #elif defined(QT_QPA_PLATFORM_COCOA) Q_IMPORT_PLUGIN(QCocoaIntegrationPlugin); #endif diff --git a/src/qt/darknet.qrc b/src/qt/darknet.qrc index 73100993e11a..20ced1f4dc19 100644 --- a/src/qt/darknet.qrc +++ b/src/qt/darknet.qrc @@ -1,6 +1,9 @@ res/icons/bitcoin.png + res/icons/dnet_cash_print.png + res/icons/cash_icon.png + res/icons/import.png res/icons/address-book.png res/icons/quit.png res/icons/send.png @@ -62,7 +65,10 @@ res/css/drk.css res/css/drk-1.css res/css/drkblue.css - + + + res/html/paperwallet_en.html + res/images/about.png res/images/darknet_logo_horizontal.png diff --git a/src/qt/forms/genandprintdialog.ui b/src/qt/forms/genandprintdialog.ui new file mode 100644 index 000000000000..d0830762563e --- /dev/null +++ b/src/qt/forms/genandprintdialog.ui @@ -0,0 +1,181 @@ + + + GenAndPrintDialog + + + + 0 + 0 + 598 + 211 + + + + + 0 + 0 + + + + + 550 + 0 + + + + Passphrase Dialog + + + + + + Qt::RichText + + + true + + + + + + + QFormLayout::AllNonFixedFieldsGrow + + + + + Enter passphrase + + + + + + + QLineEdit::Normal + + + + + + + New passphrase + + + + + + + QLineEdit::Password + + + + + + + Repeat new passphrase + + + + + + + QLineEdit::Password + + + + + + + + 75 + true + + + + + + + Qt::AlignCenter + + + + + + + + + + + Generate addresses and print QR code(s) + + + Qt::LeftToRight + + + &Print + + + + :/icons/qrcode:/icons/qrcode + + + + + + + Import + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Close + + + + + + + + + + + + + buttonBox + accepted() + GenAndPrintDialog + accept() + + + 20 + 20 + + + 20 + 20 + + + + + buttonBox + rejected() + GenAndPrintDialog + reject() + + + 20 + 20 + + + 20 + 20 + + + + + diff --git a/src/qt/genandprintdialog.cpp b/src/qt/genandprintdialog.cpp new file mode 100644 index 000000000000..b4e044cce533 --- /dev/null +++ b/src/qt/genandprintdialog.cpp @@ -0,0 +1,434 @@ +// Copyright (c) 2011-2014 The Bitcoin developers +// Copyright (c) 2014-2015 The Dash developers +// Copyright (c) 2015-2016 The Darknet developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "genandprintdialog.h" +#include "ui_genandprintdialog.h" + +#include "guiconstants.h" +#include "guiutil.h" +#include "walletmodel.h" + +#include "allocators.h" +#include "../rpcserver.h" +//#include "../rpcprotocol.h" +#include "json/json_spirit_writer.h" +#include + +#include "ecwrapper.h" +#include "bip/bip38.h" +#include "hash.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include "wallet.h" + +#if QT_VERSION < 0x050000 +#include +#include +#else +// Use QT5's new modular classes +#include +#include +//#include +#endif + +#ifdef USE_QRCODE +#include +#endif + +GenAndPrintDialog::GenAndPrintDialog(Mode mode, QWidget *parent) : + QDialog(parent), + ui(new Ui::GenAndPrintDialog), + mode(mode), + model(0), + fCapsLock(false), + salt("12345678") +{ + ui->setupUi(this); + + ui->passEdit1->setMaxLength(MAX_PASSPHRASE_SIZE); + ui->passEdit2->setMaxLength(MAX_PASSPHRASE_SIZE); + ui->passEdit3->setMaxLength(MAX_PASSPHRASE_SIZE); + + // Setup Caps Lock detection. + ui->passEdit1->installEventFilter(this); + ui->passEdit2->installEventFilter(this); + ui->passEdit3->installEventFilter(this); + + switch(mode) + { + case Export: // Ask passphrase x2 and account + setWindowTitle(tr("Export key pair")); + ui->importButton->hide(); + ui->passLabel1->setText(tr("Account name")); + ui->passLabel2->setText(tr("Password")); + ui->passEdit2->setEchoMode(QLineEdit::Password); + ui->passLabel3->setText(tr("Repeat password")); + ui->passEdit3->setEchoMode(QLineEdit::Password); + ui->warningLabel->setText(tr("Enter account and passphrase to the encrypt private key")); + break; + case Import: // Ask old passphrase + new passphrase x2 + setWindowTitle(tr("Import private key")); + ui->printButton->hide(); + ui->passLabel1->setText(tr("Private key")); + ui->passLabel2->setText(tr("Key password")); + ui->passLabel3->setText(tr("Account name")); + ui->passEdit3->setEchoMode(QLineEdit::Normal); + ui->warningLabel->setText(tr("Enter private key and passphrase")); + break; + } + + textChanged(); + connect(ui->passEdit1, SIGNAL(textChanged(QString)), this, SLOT(textChanged())); + connect(ui->passEdit2, SIGNAL(textChanged(QString)), this, SLOT(textChanged())); + connect(ui->passEdit3, SIGNAL(textChanged(QString)), this, SLOT(textChanged())); +} + +GenAndPrintDialog::~GenAndPrintDialog() +{ + // Attempt to overwrite text so that they do not linger around in memory + ui->passEdit1->setText(QString(" ").repeated(ui->passEdit1->text().size())); + ui->passEdit2->setText(QString(" ").repeated(ui->passEdit2->text().size())); + ui->passEdit3->setText(QString(" ").repeated(ui->passEdit3->text().size())); + delete ui; +} + +void GenAndPrintDialog::setModel(WalletModel *model) +{ + this->model = model; +} + +QString GenAndPrintDialog::getURI(){ + return uri; +} + +void GenAndPrintDialog::accept() +{ + SecureString oldpass, newpass1, newpass2; + if(!model) + return; + oldpass.reserve(MAX_PASSPHRASE_SIZE); + newpass1.reserve(MAX_PASSPHRASE_SIZE); + newpass2.reserve(MAX_PASSPHRASE_SIZE); + // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string) + // Alternately, find a way to make this input mlock()'d to begin with. + oldpass.assign(ui->passEdit1->text().toStdString().c_str()); + newpass1.assign(ui->passEdit2->text().toStdString().c_str()); + newpass2.assign(ui->passEdit3->text().toStdString().c_str()); + + switch(mode) + { + case Export: + if (uri != "") { + QDialog::accept(); + return; + } + break; + case Import: + QDialog::reject(); + break; + } +} + +void GenAndPrintDialog::textChanged() +{ + // Validate input, set Ok button to enabled when acceptable + bool acceptable = false; + switch(mode) + { + case Export: + acceptable = !ui->passEdit2->text().isEmpty() + && !ui->passEdit3->text().isEmpty() + && ui->passEdit3->text() == ui->passEdit2->text(); + break; + case Import: + acceptable = true; + break; + } + ui->printButton->setEnabled(acceptable); +} + +void GenAndPrintDialog::on_importButton_clicked() +{ + json_spirit::Array params; + + QString privkey_str = ui->passEdit1->text(); + QString passwd = ui->passEdit2->text(); + QString label_str = ui->passEdit3->text(); + std::string secret = privkey_str.toStdString(); + std::vector priv_data; + + // test keys for bip38 + // With EC + // secret = "6PfLGnQs6VZnrNpmVKfjotbnQuaJK4KZoPFrAjx1JMJUa1Ft8gnf5WxfKd"; + // Without EC + // secret = "6PRVWUbkzzsbcVac2qwfssoUJAN1Xhrg6bNk8J7Nzm5H7kxEbn2Nh2ZoGg"; + + if (!DecodeBase58(secret, priv_data)) { + LogPrintf("DecodeBase58 failed: str=%s\n", secret.c_str()); + return; + } + + CKey key; + model->decryptKey(priv_data, passwd.toStdString(), salt, key); + + if (key.IsValid()) + secret = CBitcoinSecret(key).ToString(); + else if (!secret.compare(0, 2, "6P")) { + if (secret[2] == 'f') { + // With EC + // Passphrase: Satoshi + // Passphrase code: passphraseoRDGAXTWzbp72eVbtUDdn1rwpgPUGjNZEc6CGBo8i5EC1FPW8wcnLdq4ThKzAS + // Encrypted key: 6PfLGnQs6VZnrNpmVKfjotbnQuaJK4KZoPFrAjx1JMJUa1Ft8gnf5WxfKd + // Bitcoin address: 1CqzrtZC6mXSAhoxtFwVjz8LtwLJjDYU3V + // Unencrypted private key (WIF): 5KJ51SgxWaAYR13zd9ReMhJpwrcX47xTJh2D3fGPG9CM8vkv5sH + // Unencrypted private key (hex): C2C8036DF268F498099350718C4A3EF3984D2BE84618C2650F5171DCC5EB660A + priv_data = decrypt_bip38_ec(priv_data, passwd.toStdString()); + key.Set(priv_data.begin(), priv_data.end(), true); + secret = CBitcoinSecret(key).ToString(); + } + else if (secret[2] == 'R' || secret[2] == 'Y') { + bool compressed = secret[2] == 'Y'; + // Without EC + // passwd = "TestingOneTwoThree"; + priv_data = decrypt_bip38(priv_data, passwd.toStdString()); + key.Set(priv_data.begin(), priv_data.end(), compressed); + secret = CBitcoinSecret(key).ToString(); + } + else { + QMessageBox::information(this, tr(""), QString::fromStdString("This BIP38 mode is not implemented")); + return; + } + } + else { + // use secret as is + } + +// QMessageBox::information(this, tr("Info"), QString::fromStdString(secret)); +// return; + + params.push_back(json_spirit::Value(secret.c_str())); + params.push_back(json_spirit::Value(label_str.toStdString().c_str())); + + WalletModel::EncryptionStatus encStatus = model->getEncryptionStatus(); + if(encStatus == model->Locked || encStatus == model->UnlockedForAnonymizationOnly) + { + ui->importButton->setEnabled(false); + WalletModel::UnlockContext ctx(model->requestUnlock(true)); + if(!ctx.isValid()) + { + // Unlock wallet was cancelled + QMessageBox::critical(this, tr("Error"), tr("Cant import key into locked wallet")); + ui->importButton->setEnabled(true); + return; + } + + try + { + importprivkey(params, false); + QMessageBox::information(this, tr(""), tr("Private key imported")); + close(); + } + //catch (json_spirit::Object &err) + // TODO: Cant catch exception of type json_spirit::Object & + // To be investigate + catch (...) + { + cerr << "Import private key error!" << endl; +// for (json_spirit::Object::iterator it = err.begin(); it != err.end(); ++it) +// { +// cerr << it->name_ << " = " << it->value_.get_str() << endl; +// } + QMessageBox::critical(this, tr("Error"), tr("Private key import error")); + ui->importButton->setEnabled(true); + } + } +} + +bool readHtmlTemplate(const QString &res_name, QString &htmlContent) +{ + QFile htmlFile(res_name); + if (!htmlFile.open(QIODevice::ReadOnly | QIODevice::Text)){ + cerr << "Cant open " << res_name.toStdString() << endl; + return false; + } + + QTextStream in(&htmlFile); + htmlContent = in.readAll(); + return true; +} + +void GenAndPrintDialog::on_printButton_clicked() +{ + if (vNodes.size() > 0) { + QMessageBox::critical(this, "Warning: Network Activity Detected", tr("It is recommended to disconnect from the internet before printing paper wallets. Even though paper wallets are generated on your local computer, it is still possible to unknowingly have malware that transmits your screen to a remote location. It is also recommended to print to a local printer vs a network printer since that network traffic can be monitored. Some advanced printers also store copies of each printed document. Proceed with caution relative to the amount of value you plan to store on each address."), QMessageBox::Ok, QMessageBox::Ok); + } + + QString strAccount = ui->passEdit1->text(); + QString passwd = ui->passEdit2->text(); + + uri = ""; + ui->passEdit2->setText(""); + ui->passEdit3->setText(""); + + CKey secret = model->generateNewKey(); + // Test key to encrypt + //std::string test_str = "CBF4B9F70470856BB4F40F80B87EDB90865997FFEE6DF315AB166D713AF433A5"; + //std::vector test_data = decode_base16(test_str); + //CKey secret = CKey(); + //secret.Set(test_data.begin(), test_data.end(), false); + + CPrivKey privkey = secret.GetPrivKey(); + CPubKey pubkey = secret.GetPubKey(); + CKeyID keyid = pubkey.GetID(); + + std::string secret_str = CBitcoinSecret(secret).ToString(); + std::string address = CBitcoinAddress(keyid).ToString(); + + QString qsecret = QString::fromStdString(secret_str); + QString qaddress = QString::fromStdString(address); + + std::vector priv_data; + for (const unsigned char *i = secret.begin(); i != secret.end(); i++ ) { + priv_data.push_back(*i); + } + + // Test address (BTC) for key above + //address = "1Jq6MksXQVWzrznvZzxkV6oY57oWXD9TXB"; + + std::vector crypted_key = encrypt_bip38(priv_data, address, passwd.toStdString()); + std::string crypted = EncodeBase58Check(crypted_key); + + QString qcrypted = QString::fromStdString(crypted); + QPrinter printer; + printer.setResolution(QPrinter::HighResolution); + printer.setPageMargins(0, 10, 0, 0, QPrinter::Millimeter); + + QPrintDialog *dlg = new QPrintDialog(&printer, this); + if(dlg->exec() == QDialog::Accepted) { + + QImage img1(200, 200, QImage::Format_Mono); + QImage img2(200, 200, QImage::Format_Mono); + QPainter painter(&img1); + painter.setRenderHint(QPainter::Antialiasing, false); + painter.setRenderHint(QPainter::TextAntialiasing, false); + painter.setRenderHint(QPainter::SmoothPixmapTransform, false); + painter.setRenderHint(QPainter::HighQualityAntialiasing, false); + painter.setRenderHint(QPainter::NonCosmeticDefaultPen, false); + printAsQR(painter, qaddress, 0); + // QT bug. Painting img on pdf inverts colors + img1.invertPixels(); + bool bEnd = painter.end(); + + painter.begin(&img2); + printAsQR(painter, qcrypted, 0); + img2.invertPixels(); + bEnd = painter.end(); + + QString html; + readHtmlTemplate(":/html/paperwallet", html); + + html.replace("__ACCOUNT__", strAccount); + html.replace("__ADDRESS__", qaddress); + html.replace("__PRIVATE__", qcrypted); + + QTextDocument *document = new QTextDocument(this); + document->addResource(QTextDocument::ImageResource, QUrl(":qr1.png" ), img1); + document->addResource(QTextDocument::ImageResource, QUrl(":qr2.png" ), img2); + document->setHtml(html); + document->setPageSize(QSizeF(printer.pageRect().size())); + document->print(&printer); + + model->setAddressBook(keyid, strAccount.toStdString(), "send"); + SendCoinsRecipient rcp(qaddress, strAccount, 0, ""); + uri = GUIUtil::formatBitcoinURI(rcp); + delete document; + accept(); + } + delete dlg; +} + +void GenAndPrintDialog::printAsQR(QPainter &painter, QString &vchKey, int shift) +{ + QRcode *qr = QRcode_encodeString(vchKey.toStdString().c_str(), 1, QR_ECLEVEL_L, QR_MODE_8, 1); + if(0!=qr) { + QPaintDevice *pd = painter.device(); + const double w = pd->width(); + const double h = pd->height(); + QColor fg("black"); + QColor bg("white"); + painter.setBrush(bg); + painter.fillRect(0, 0, w, h, bg); + painter.setPen(Qt::SolidLine); + painter.setPen(fg); + painter.setBrush(fg); + const int s=qr->width > 0 ? qr->width : 1; + const double aspect = w / h; + const double scale = ((aspect > 1.0) ? h : w) / s;// * 0.3; + for(int y = 0; y < s; y++){ + const int yy = y*s; + for(int x = 0; x < s; x++){ + const int xx = yy + x; + const unsigned char b = qr->data[xx]; + if(b & 0x01){ + const double rx1 = x*scale, ry1 = y*scale; + QRectF r(rx1 + shift, ry1, scale, scale); + painter.drawRects(&r, 1); + } + } + } + QRcode_free(qr); + } +} + +bool GenAndPrintDialog::event(QEvent *event) +{ + // Detect Caps Lock key press. + if (event->type() == QEvent::KeyPress) { + QKeyEvent *ke = static_cast(event); + if (ke->key() == Qt::Key_CapsLock) { + fCapsLock = !fCapsLock; + } + if (fCapsLock) { + ui->capsLabel->setText(tr("Warning: The Caps Lock key is on!")); + } else { + ui->capsLabel->clear(); + } + } + return QWidget::event(event); +} + +bool GenAndPrintDialog::eventFilter(QObject *object, QEvent *event) +{ + /* Detect Caps Lock. + * There is no good OS-independent way to check a key state in Qt, but we + * can detect Caps Lock by checking for the following condition: + * Shift key is down and the result is a lower case character, or + * Shift key is not down and the result is an upper case character. + */ + if (event->type() == QEvent::KeyPress) { + QKeyEvent *ke = static_cast(event); + QString str = ke->text(); + if (str.length() != 0) { + const QChar *psz = str.unicode(); + bool fShift = (ke->modifiers() & Qt::ShiftModifier) != 0; + if ((fShift && *psz >= 'a' && *psz <= 'z') || (!fShift && *psz >= 'A' && *psz <= 'Z')) { + fCapsLock = true; + ui->capsLabel->setText(tr("Warning: The Caps Lock key is on!")); + } else if (psz->isLetter()) { + fCapsLock = false; + ui->capsLabel->clear(); + } + } + } + return QDialog::eventFilter(object, event); +} diff --git a/src/qt/genandprintdialog.h b/src/qt/genandprintdialog.h new file mode 100644 index 000000000000..7194c0ce3099 --- /dev/null +++ b/src/qt/genandprintdialog.h @@ -0,0 +1,60 @@ +// Copyright (c) 2011-2013 The Bitcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef GENANDPRINTDIALOG_H +#define GENANDPRINTDIALOG_H + +#include + +class WalletModel; + +namespace Ui { + class GenAndPrintDialog; +} + +/** Multifunctional dialog to ask for passphrases. Used for encryption, unlocking, and changing the passphrase. + */ +class GenAndPrintDialog : public QDialog +{ + Q_OBJECT + +public: + enum Mode { + Export, /**< Ask passphrase, generate key pair and print them out */ + Import /**< Ask passphrase and load priv key from QR code */ + }; + + explicit GenAndPrintDialog(Mode mode, QWidget *parent); + ~GenAndPrintDialog(); + + void accept(); + + void setModel(WalletModel *model); + QString getURI(); + +private: + Ui::GenAndPrintDialog *ui; + Mode mode; + WalletModel *model; + bool fCapsLock; + std::string salt; + QString uri; + +private slots: + void textChanged(); + + /** Print button clicked */ + void on_printButton_clicked(); + /** Import button clicked */ + void on_importButton_clicked(); + +protected: + bool event(QEvent *event); + bool eventFilter(QObject *object, QEvent *event); + std::string getCurrentKeyPair(); + void printAsQR(QPainter &painter, QString &vchKey, int place); + +}; + +#endif // GENANDPRINTDIALOG_H diff --git a/src/qt/res/html/paperwallet_en.html b/src/qt/res/html/paperwallet_en.html new file mode 100644 index 000000000000..f7e3af6dcd4e --- /dev/null +++ b/src/qt/res/html/paperwallet_en.html @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + + + + + +
+ +

+ Your deposit adress: +

+
+ __ADDRESS__ +
+
+

Use this address for a DNET deposit.

+

The balance and transaction history can be found on the public blockchain: http://dnet.presstab.pw





+ +
+
+ + +

+ Your key to send DNET: +

+
+ __PRIVATE__ +
+
+

To send your DNET you need to import this key in the wallet, installed on smartphone or local PC client

+

Also you need to know the encryption password for the private key. It is set when creating a paper wallet.

+
+
+

+ Attention! +

+
+
    +
  • No one but you should know the password of the key! Anyone who has a key and knows the password can send DNET to any address;
  • +
  • We recommend using a paper wallet once. At the time of import the DNET in the e-wallet you will give them your private key and password;
  • +
  • If you lose your key or password, you can not use DNET from a paper wallet;
  • +
  • All transactions on the DarkNet network are irrevocable, they can not be canceled. Be careful when entering addresses to avoid typos. If possible, use the QR-code reading function.
  • +
+
+
+ + + + + +
+
+ +
+
+
+

DarkNet (DNET)

+
+

+ Paper wallet +

+
+
+
+
+
+ Account: __ACCOUNT__ +
+ + diff --git a/src/qt/res/icons/cash_icon.png b/src/qt/res/icons/cash_icon.png new file mode 100644 index 000000000000..ab6cb4cbd12d Binary files /dev/null and b/src/qt/res/icons/cash_icon.png differ diff --git a/src/qt/res/icons/dnet_cash_print.png b/src/qt/res/icons/dnet_cash_print.png new file mode 100644 index 000000000000..2137e46a82ed Binary files /dev/null and b/src/qt/res/icons/dnet_cash_print.png differ diff --git a/src/qt/res/icons/import.png b/src/qt/res/icons/import.png new file mode 100644 index 000000000000..d65c6cc49c61 Binary files /dev/null and b/src/qt/res/icons/import.png differ diff --git a/src/qt/utilitydialog.cpp b/src/qt/utilitydialog.cpp index aa266b2dc0c3..a73f9c1739e8 100644 --- a/src/qt/utilitydialog.cpp +++ b/src/qt/utilitydialog.cpp @@ -7,20 +7,30 @@ #include "utilitydialog.h" #include "ui_helpmessagedialog.h" +#include "bitcoinunits.h" +#include "optionsmodel.h" #include "bitcoingui.h" #include "clientmodel.h" #include "guiutil.h" #include "clientversion.h" #include "init.h" +#include "util.h" +#include "net.h" #include #include +//#include #include #include #include +#include +#include +#include +#include +#include /** "Help message" or "About" dialog box */ HelpMessageDialog::HelpMessageDialog(QWidget *parent, bool about) : diff --git a/src/qt/walletframe.cpp b/src/qt/walletframe.cpp index e38e25de7d23..ab7ba6dec9d6 100644 --- a/src/qt/walletframe.cpp +++ b/src/qt/walletframe.cpp @@ -196,8 +196,21 @@ void WalletFrame::usedReceivingAddresses() walletView->usedReceivingAddresses(); } +void WalletFrame::genAndPrintAddresses() +{ + WalletView *walletView = currentWalletView(); + if (walletView) + walletView->genAndPrintAddresses(); +} + +void WalletFrame::loadFromPaper() +{ + WalletView *walletView = currentWalletView(); + if (walletView) + walletView->loadFromPaper(); +} + WalletView *WalletFrame::currentWalletView() { return qobject_cast(walletStack->currentWidget()); } - diff --git a/src/qt/walletframe.h b/src/qt/walletframe.h index 57b377b9efef..bec74d8f0332 100644 --- a/src/qt/walletframe.h +++ b/src/qt/walletframe.h @@ -77,6 +77,11 @@ public slots: void usedSendingAddresses(); /** Show used receiving addresses */ void usedReceivingAddresses(); + + /** generateAndPrint addresses */ + void genAndPrintAddresses(); + /** generateAndPrint addresses */ + void loadFromPaper(); }; #endif // BITCOIN_QT_WALLETFRAME_H diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index 0bd34f3f4faa..f6a41540c3e9 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -20,7 +20,7 @@ #include "wallet.h" #include "walletdb.h" // for BackupWallet #include "spork.h" - +#include "../crypter.h" #include #include @@ -472,6 +472,46 @@ bool WalletModel::isAnonymizeOnlyUnlocked() return wallet->fWalletUnlockAnonymizeOnly; } +CKey WalletModel::generateNewKey() const +{ + return wallet->GeneratePrivKey(); +} + +bool WalletModel::setAddressBook(const CTxDestination& address, const string& strName, const string& strPurpose) +{ + LOCK(wallet->cs_wallet); + { + return wallet->SetAddressBook(address, strName, strPurpose); + } +} + +void WalletModel::encryptKey(const CKey key, const std::string &pwd, + const std::string &slt, std::vector &crypted) +{ + CCrypter crpt; + SecureString passwd(pwd.c_str()); + std::vector salt(slt.begin(), slt.end()); + + crpt.SetKeyFromPassphrase(passwd, salt, 14, 0); + CKeyingMaterial mat(key.begin(), key.end()); + crpt.Encrypt(mat, crypted); +} + +void WalletModel::decryptKey(const std::vector &crypted, const std::string &pwd, + const std::string &slt, CKey &key) +{ + CCrypter crpt; + std::vector decrypted; + std::vector salt(slt.begin(), slt.end()); + + SecureString passwd(pwd.c_str()); + crpt.SetKeyFromPassphrase(passwd, salt, 14, 0); + + CKeyingMaterial mat; + crpt.Decrypt(crypted, mat); + key.Set(mat.begin(), mat.end(), true); +} + bool WalletModel::changePassphrase(const SecureString &oldPass, const SecureString &newPass) { bool retval; diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h index e8e82fa58705..a16da688a856 100644 --- a/src/qt/walletmodel.h +++ b/src/qt/walletmodel.h @@ -141,7 +141,11 @@ class WalletModel : public QObject CAmount getWatchUnconfirmedBalance() const; CAmount getWatchImmatureBalance() const; EncryptionStatus getEncryptionStatus() const; - + CKey generateNewKey() const; //for temporary paper wallet key generation + bool setAddressBook(const CTxDestination& address, const string& strName, const string& strPurpose); + void encryptKey(const CKey key, const std::string &pwd, const std::string &slt, std::vector &crypted); + void decryptKey(const std::vector &crypted, const std::string &slt, const std::string &pwd, CKey &key); + // Check address for validity bool validateAddress(const QString &address); diff --git a/src/qt/walletview.cpp b/src/qt/walletview.cpp index 652385958b37..2c798c998c50 100644 --- a/src/qt/walletview.cpp +++ b/src/qt/walletview.cpp @@ -5,6 +5,7 @@ #include "walletview.h" #include "addressbookpage.h" +#include "genandprintdialog.h" #include "askpassphrasedialog.h" #include "bitcoingui.h" #include "clientmodel.h" @@ -110,6 +111,9 @@ void WalletView::setBitcoinGUI(BitcoinGUI *gui) // Pass through transaction notifications connect(this, SIGNAL(incomingTransaction(QString,int,CAmount,QString,QString)), gui, SLOT(incomingTransaction(QString,int,CAmount,QString,QString))); + + // Follow new URI + connect(this, SIGNAL(receivedURI(QString)), gui, SIGNAL(receivedURI(QString))); } } @@ -311,6 +315,34 @@ void WalletView::usedReceivingAddresses() dlg->show(); } +void WalletView::genAndPrintAddresses() +{ + if(!walletModel) + return; + + GenAndPrintDialog dlg(GenAndPrintDialog::Export, this); + dlg.setModel(walletModel); + if (dlg.exec()) + { + QMessageBox::warning(this, tr(""), + tr("Before sending DNET to address please be sure\n" + "that paper wallet has been printed successfully!")); + + QString uri = dlg.getURI(); + emit receivedURI(uri); + } +} + +void WalletView::loadFromPaper() +{ + if(!walletModel) + return; + + GenAndPrintDialog dlg(GenAndPrintDialog::Import, this); + dlg.setModel(walletModel); + dlg.exec(); +} + void WalletView::showProgress(const QString &title, int nProgress) { if (nProgress == 0) diff --git a/src/qt/walletview.h b/src/qt/walletview.h index 691875396bc0..b80dc294803f 100644 --- a/src/qt/walletview.h +++ b/src/qt/walletview.h @@ -103,6 +103,12 @@ public slots: /** Show used receiving addresses */ void usedReceivingAddresses(); + /** Generate and print addresses */ + void genAndPrintAddresses(); + + /** Load keys from QR code */ + void loadFromPaper(); + /** Re-emit encryption status signal */ void updateEncryptionStatus(); @@ -121,6 +127,8 @@ public slots: void encryptionStatusChanged(int status); /** Notify that a new transaction appeared */ void incomingTransaction(const QString& date, int unit, const CAmount& amount, const QString& type, const QString& address); + /** Signal raised when a URI was entered or dragged to the GUI */ + void receivedURI(const QString &uri); }; #endif // BITCOIN_QT_WALLETVIEW_H diff --git a/src/wallet.cpp b/src/wallet.cpp index 8eef38165968..1f3406490f65 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -75,6 +75,22 @@ const CWalletTx* CWallet::GetWalletTx(const uint256& hash) const return &(it->second); } +CKey CWallet::GeneratePrivKey() +{ + AssertLockHeld(cs_wallet); // mapKeyMetadata + bool fCompressed = CanSupportFeature(FEATURE_COMPRPUBKEY); // default to compressed public keys if we want 0.6.0 wallets + + RandAddSeedPerfmon(); + CKey secret; + secret.MakeNewKey(fCompressed); + + // Compressed public keys were introduced in version 0.6.0 + if (fCompressed) + SetMinVersion(FEATURE_COMPRPUBKEY); + + return secret; +} + CPubKey CWallet::GenerateNewKey() { AssertLockHeld(cs_wallet); // mapKeyMetadata diff --git a/src/wallet.h b/src/wallet.h index f7e28eade656..c7722b74cc79 100644 --- a/src/wallet.h +++ b/src/wallet.h @@ -240,11 +240,13 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface void ListLockedCoins(std::vector& vOutpts); int64_t GetTotalValue(std::vector vCoins); - /** - * keystore implementation - * Generate a new key - */ + // keystore implementation + // Generate new priv key without saving + CKey GeneratePrivKey(); + + // Generate a new key CPubKey GenerateNewKey(); + //! Adds a key to the store, and saves it to disk. bool AddKeyPubKey(const CKey& key, const CPubKey &pubkey); //! Adds a key to the store, without saving it to disk (used by LoadWallet)