diff --git a/CMakeLists.txt b/CMakeLists.txt index 67953906..0c25a749 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -98,7 +98,7 @@ get_filename_component(C_COMPILER "${CMAKE_C_COMPILER}" NAME) # Sources # Main lib -set(PIP_FOLDERS "." "core" "containers" "thread" "system" "io" "console" "math" "code" "geo" "resources" "opencl") +set(PIP_FOLDERS "." "core" "containers" "thread" "system" "io" "console" "math" "code" "geo" "resources" "opencl" "crypt") include_directories("${PIP_SRC_MAIN}") foreach(F ${PIP_FOLDERS}) include_directories("${PIP_SRC_MAIN}/${F}") @@ -382,7 +382,7 @@ endif() find_package(OpenCL QUIET) if(OpenCL_FOUND) message(STATUS "Building with OpenCL support") - if(APPLE) + if(APPLE) include_directories(${OpenCL_INCLUDE_DIRS}/Headers) else() include_directories(${OpenCL_INCLUDE_DIRS}) @@ -403,7 +403,7 @@ endif() # Test program add_executable(pip_test "main.cpp") -target_link_libraries(pip_test pip) +target_link_libraries(pip_test pip pip_crypt) # Install @@ -479,3 +479,30 @@ foreach(LIB_ ${LIBS_STATUS}) message(WARNING "Library ${LIB_} not found, please install it") endif() endforeach() + + +# +# Build Documentation +# + +find_package(Doxygen QUIET) +if(Doxygen_FOUND) + message(STATUS "Building with documentation via Doxygen") + + #set(DOXYFILE_IN ${CMAKE_CURRENT_SOURCE_DIR}/doc/Doxyfile.in) + set(DOXYFILE ${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile) + #configure_file(${DOXYFILE_IN} ${DOXYFILE} @ONLY) + + add_custom_target(DOC + COMMAND ${DOXYGEN_EXECUTABLE} ${DOXYFILE} + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + COMMENT "Generating API documentation with Doxygen" + VERBATIM) + + add_custom_command(TARGET DOC + POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/source/doc/Documentation.html ${CMAKE_SOURCE_DIR}/doc + ) + install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/html DESTINATION share/doc) +endif() + diff --git a/doc/doxygen_sqlite3.db b/doc/doxygen_sqlite3.db deleted file mode 100644 index b340e9ce..00000000 Binary files a/doc/doxygen_sqlite3.db and /dev/null differ diff --git a/main.cpp b/main.cpp index ebe1131a..28f999b1 100644 --- a/main.cpp +++ b/main.cpp @@ -1,10 +1,98 @@ #include "pip.h" +#include "piauth.h" + + +class Obj : public PIObject { + PIOBJECT(Obj) +public: + Obj() : PIObject() {} + + EVENT_HANDLER2(void, authorizeServer, PIByteArray, info, bool *, ok) { + piCout << "[authorizeServer]" << PIString(info); + //*ok = true; + } + EVENT_HANDLER2(void, passwordCheck, PIByteArray, phash, bool *, ok) { + piCout << "[passwordCheck]" << phash.toHex(); + PIByteArray ph = PICrypt::passwordHash("secret", PIByteArray::fromHex("AABBCCDD")); + piCout << "[passwordCheck]" << ph.toHex(); + if (phash == ph) *ok = true; + } + EVENT_HANDLER1(void, userEnterPassword, PIString *, password) { + *password = "secret"; + piCout << "[userEnterPassword]" << *password; + } +}; + int main(int argc, char *argv[]) { - //S s; - //s.i; - //PICodeParser cp; - //cp.parseFile("cp.h"); + piCout << "start"; + PICrypt crypt; + PIByteArray skey1, pkey1; + crypt.generateKeypair(pkey1, skey1); + PIByteArray skey2, pkey2; + crypt.generateKeypair(pkey2, skey2); + PIByteArray sign = PIAuth::generateSign(PICrypt::generateKey()); + piCout << "sign" << sign.toHex(); + + piCout << "key1 " << pkey1.toHex() << skey1.toHex(); + piCout << "key2 " << pkey2.toHex() << skey2.toHex(); + PIString msg = "what the f*ck?"; + PIByteArray ba = msg.toUTF8(); + piCout << "source" << ba.toHex() << msg; + PIByteArray cba = crypt.crypt(ba, pkey2, skey1); + PIByteArray psign = crypt.extractSignPublicKey(sign); + PIByteArray scba = crypt.signMessage(cba, sign); + piCout << "crypted" << cba.toHex(); + piCout << "signed" << scba.toHex() << psign.toHex(); + PIByteArray dba = crypt.decrypt(cba, pkey1, skey2); + piCout << "decrypted" << dba.toHex() << PIString(dba); + piCout << "verify" << crypt.verifySign(cba, scba, psign); + cba = crypt.crypt(ba, pkey1, skey2); + piCout << "crypted" << cba.toHex(); + //cba[7] = 0; + dba = crypt.decrypt(cba, pkey2, skey1); + piCout << "decrypted" << dba.toHex() << PIString(dba); + + + piCout << "======================================="; + PIAuth server(PIAuth::generateSign(pkey1)); + msg = "This is Server with PIAuth"; + server.setInfoData(msg.toUTF8()); + PIAuth client(PIAuth::generateSign(pkey2)); + client.setAuthorizedPublicKeys(PIVector() << server.getSignPublicKey()); + Obj o; + CONNECTU(&client, authorize, &o, authorizeServer); + CONNECTU(&client, passwordRequest, &o, userEnterPassword); + CONNECTU(&server, passwordCheck, &o, passwordCheck); + client.startClient(); + ba = server.startServer(); + int st = PIAuth::AuthProbe; + piCout << "server" << st << ba.toHex() << ba.size(); +// ba[40] = 2; +// { +// int s; +// ba >> s; +// PIByteArray rinfo; +// PIByteArray rsign; +// PIByteArray rsign_pk; +// PIByteArray box_pk; +// PIByteArray noise; +// ba >> rinfo >> rsign_pk >> box_pk >> noise >> rsign; +// ba.clear(); +// PIByteArray sign2 = PIAuth::generateSign(PICrypt::generateRandomBuff(100)); +// msg = "Server"; +// ba << s << msg.toUTF8() << crypt.extractSignPublicKey(sign2) << box_pk << noise; +// rsign = crypt.signMessage(ba, sign2); +// ba << rsign; +// } + st = client.receive(ba); + piCout << "client" << st << ba.toHex() << ba.size(); + st = server.receive(ba); + piCout << "server" << st << ba.toHex() << ba.size(); + st = client.receive(ba); + piCout << "client" << st << ba.toHex() << ba.size(); + st = server.receive(ba); + piCout << "server" << st << ba.toHex() << ba.size(); return 0; } diff --git a/src_crypt/piauth.cpp b/src_crypt/piauth.cpp new file mode 100644 index 00000000..9db6cec3 --- /dev/null +++ b/src_crypt/piauth.cpp @@ -0,0 +1,257 @@ +/* + PIP - Platform Independent Primitives + PIP Authentication API + Copyright (C) 2018 Andrey Bychkov work.a.b@yandex.ru + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "piauth.h" + + +PIAuth::PIAuth(const PIByteArray & sign) : PIObject() { + setName("Client"); + role = Client; + state = NotConnected; + sign_sk = sign; + sign_pk = crypt.extractSignPublicKey(sign); +} + + +void PIAuth::stop() { + role = Client; + state = NotConnected; + auth_sign.clear(); + box_sk.clear(); + box_pk.clear(); + my_pk.clear(); +} + + +void PIAuth::startClient() { + role = Client; + state = AuthProbe; +} + + +PIByteArray PIAuth::startServer() { + setName("Server"); + role = Server; + state = AuthProbe; + PIByteArray ba; + crypt.generateKeypair(my_pk, box_sk); + PIByteArray noise = crypt.generateRandomBuff(randomi()%256+128); + ba << (int)state << info << sign_pk << my_pk << noise; + PIByteArray sign = crypt.signMessage(ba, sign_sk); + ba << sign; + return ba; +} + + +PIAuth::State PIAuth::receive(PIByteArray & ba) { + if (ba.size() < sizeof(int)) return disconnect(ba, "invalid data size"); + State rstate; + int s; + ba >> s; + rstate = (State)s; +// if (state != rstate) return disconect(ba); + + //client side + if (role == Client) { + if (state == AuthProbe && rstate == AuthProbe) { + if (ba.size() < sizeof(int)*5) return disconnect(ba, "invalid data size"); + PIByteArray rinfo; + PIByteArray rsign; + PIByteArray rsign_pk; + PIByteArray noise; + ba >> rinfo >> rsign_pk >> box_pk >> noise >> rsign; + if (rsign_pk.isEmpty() || box_pk.isEmpty() || rsign.isEmpty()) return disconnect(ba, "invalid key size"); + + PIByteArray tba; + tba << (int)rstate << rinfo << rsign_pk << box_pk << noise; + if (!crypt.verifySign(tba, rsign, rsign_pk)) return disconnect(ba, "Incorrect sign"); + bool auth = false; + if (isAuthorizedKey(rsign_pk)) { + auth = true; + } else { + authorize(rinfo, &auth); + if (auth) auth_pkeys << rsign_pk; + } + if (!auth) return disconnect(ba, "Unauthorised"); + ba.clear(); + auth_sign = rsign_pk; + crypt.generateKeypair(my_pk, box_sk); + tba.clear(); + tba << sign_pk << my_pk << box_pk; + PIByteArray sign = crypt.signMessage(tba, sign_sk); + tba << sign; + tba = crypt.crypt(tba, box_pk, box_sk); + state = AuthReply; + noise = crypt.generateRandomBuff(randomi()%256); + ba << (int)state << tba << my_pk << noise; + sign = crypt.signMessage(ba, sign_sk); + ba << sign; + return state; + } + if (state == AuthReply && rstate == PassRequest) { + PIByteArray ctba, tba; + PIByteArray noise; + PIByteArray rsign, rsign_pk; + ba >> ctba >> rsign; + bool ok = false; + tba = crypt.decrypt(ctba, box_pk, box_sk, &ok); + if (tba.isEmpty() || !ok) return disconnect(ba, "Message corrupted"); + ba.clear(); + ba << (int)rstate << ctba; + if (!crypt.verifySign(ba, rsign, auth_sign)) return disconnect(ba, "Incorrect sign"); + ctba.clear(); + tba >> rsign_pk >> noise >> ctba; + if (rsign_pk != auth_sign || ctba != my_pk) return disconnect(ba, "Invalid public key"); + PIString ps; + PIByteArray ph; + passwordRequest(&ps); + if (ps.isEmpty()) return disconnect(ba, "Canceled by user"); + ph = crypt.passwordHash(ps, PIByteArray::fromHex("AABBCCDD")); + ps.fill(0); + tba.clear(); + tba << ph << auth_sign << sign_pk; + tba = crypt.crypt(tba, box_pk, box_sk); + ba.clear(); + state = PassRequest; + ba << (int)state << tba; + rsign = crypt.signMessage(ba, sign_sk); + ba << rsign; + return state; + } + if (state == AuthReply && rstate == KeyExchange) { + + } + } + + // server side + if (role == Server) { + if (state == AuthProbe && rstate == AuthReply) { + if (ba.size() < sizeof(int)*4) return disconnect(ba, "invalid data size"); + PIByteArray ctba, tba; + PIByteArray noise; + PIByteArray rsign1, rsign2; + PIByteArray rsign_pk; + PIByteArray pk, mpk; + ba >> ctba >> pk >> noise >> rsign1; + bool ok = false; + tba = crypt.decrypt(ctba, pk, box_sk, &ok); + if (tba.isEmpty() || !ok) return disconnect(ba, "Message corrupted"); + if (tba.size() < sizeof(int)*3) return disconnect(tba, "invalid data size"); + tba >> rsign_pk >> box_pk >> mpk >> rsign2; + if (pk != box_pk || mpk != my_pk) return disconnect(ba, "Invalid public key"); + ba.clear(); + ba << (int)rstate << ctba << box_pk << noise; + if (!crypt.verifySign(ba, rsign1, rsign_pk)) return disconnect(ba, "Incorrect sign"); + ba.clear(); + ba << rsign_pk << box_pk << my_pk; + if (!crypt.verifySign(ba, rsign2, rsign_pk)) return disconnect(ba, "Incorrect sign"); + auth_sign = rsign_pk; + if (isAuthorizedKey(rsign_pk)) { + state = KeyExchange; + ba = createSKMessage(); + return state; + } else { + ba.clear(); + tba.clear(); + state = PassRequest; + noise = crypt.generateRandomBuff(randomi()%256); + tba << sign_pk << noise << box_pk; + tba = crypt.crypt(tba, box_pk, box_sk); + ba << (int)state << tba; + rsign1 = crypt.signMessage(ba, sign_sk); + ba << rsign1; + return state; + } + } + if (state == PassRequest && rstate == PassRequest) { + PIByteArray tba, ctba; + PIByteArray rsign_pk, rsign, mpk; + ba >> ctba >> rsign; + bool ok = false; + tba = crypt.decrypt(ctba, box_pk, box_sk, &ok); + if (tba.isEmpty() || !ok) return disconnect(ba, "Message corrupted"); + ba.clear(); + ba << (int)rstate << ctba; + if (!crypt.verifySign(ba, rsign, auth_sign)) return disconnect(ba, "Incorrect sign"); + ctba.clear(); + tba >> ctba >> mpk >> rsign_pk; + if (rsign_pk != auth_sign || mpk != sign_pk) return disconnect(ba, "Invalid public key"); + bool auth = false; + passwordCheck(ctba, &auth); + if (!auth) { + piSleep(1); + return disconnect(ba, "Invalid password"); + } + state = KeyExchange; + ba = createSKMessage(); + return state; + } + } + + return disconnect(ba, "invalid state " + PIString::fromNumber((int)state)); +} + + +PIByteArray PIAuth::getSecretKey() { + if (state == Connected) return secret_key; + return PIByteArray(); +} + + +PIByteArray PIAuth::generateSign(const PIByteArray & seed) { + PIByteArray pk, sk; + PICrypt::generateSignKeys(pk, sk, seed); + return sk; +} + + +PIAuth::State PIAuth::disconnect(PIByteArray & ba, const PIString & error) { + if (!error.isEmpty()) piCoutObj << error; + auth_sign.clear(); + box_sk.clear(); + box_pk.clear(); + my_pk.clear(); + secret_key.clear(); + ba.clear(); + state = NotConnected; + disconnected(); + return state; +} + + +bool PIAuth::isAuthorizedKey(const PIByteArray & pkey) { + for (int i=0; i. + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ #include "picrypt.h" @@ -22,6 +22,7 @@ # include #endif +#define PICRYPT_DISABLED_WARNING piCout << "[PICrypt]" << "Warning: PICrypt is disabled, to enable install sodium library and rebuild pip"; const char hash_def_key[] = "_picrypt_"; @@ -34,7 +35,7 @@ PICrypt::PICrypt() { randombytes_buf(key_.data(), key_.size()); randombytes_buf(nonce_.data(), nonce_.size()); #else - piCout << "[PICrypt]" << "Warning: PICrypt is disabled, to enable install libsodium-dev library and build pip_crypt library"; + PICRYPT_DISABLED_WARNING #endif } @@ -72,22 +73,22 @@ PIByteArray PICrypt::crypt(const PIByteArray & data) { PIByteArray PICrypt::crypt(const PIByteArray & data, PIByteArray key) { - PIByteArray retba; + PIByteArray ret; #ifdef PIP_CRYPT if (key.size() != crypto_secretbox_KEYBYTES) key.resize(crypto_secretbox_KEYBYTES, ' '); //return PIByteArray(); - if (!init()) return retba; + if (!init()) return ret; PIByteArray n; - retba.resize(data.size() + crypto_secretbox_MACBYTES); + ret.resize(data.size() + crypto_secretbox_MACBYTES); n.resize(crypto_secretbox_NONCEBYTES); randombytes_buf(n.data(), n.size()); - crypto_secretbox_easy(retba.data(), data.data(), data.size(), n.data(), key.data()); - retba.append(n); + crypto_secretbox_easy(ret.data(), data.data(), data.size(), n.data(), key.data()); + ret.append(n); #else - piCout << "[PICrypt]" << "Warning: PICrypt is disabled, to enable install sodium library and build pip with -DCRYPT=1"; + PICRYPT_DISABLED_WARNING #endif - return retba; + return ret; } @@ -112,7 +113,7 @@ PIByteArray PICrypt::decrypt(const PIByteArray & crypt_data, bool *ok) { PIByteArray PICrypt::decrypt(const PIByteArray & crypt_data, PIByteArray key, bool *ok) { - PIByteArray retba; + PIByteArray ret; #ifdef PIP_CRYPT if (key.size() != crypto_secretbox_KEYBYTES) key.resize(crypto_secretbox_KEYBYTES, ' '); @@ -123,21 +124,20 @@ PIByteArray PICrypt::decrypt(const PIByteArray & crypt_data, PIByteArray key, bo if (ok) *ok = false; return PIByteArray(); } - if (!init()) return retba; + if (!init()) return ret; PIByteArray n; n.resize(crypto_secretbox_NONCEBYTES); - retba.resize(crypt_data.size() - n.size() - crypto_secretbox_MACBYTES); + ret.resize(crypt_data.size() - n.size() - crypto_secretbox_MACBYTES); memcpy(n.data(), crypt_data.data(crypt_data.size() - n.size()), n.size()); - if (crypto_secretbox_open_easy(retba.data(), crypt_data.data(), crypt_data.size() - n.size(), n.data(), key.data()) != 0) { + if (crypto_secretbox_open_easy(ret.data(), crypt_data.data(), crypt_data.size() - n.size(), n.data(), key.data()) != 0) { if (ok) *ok = false; // piCout << "[PICrypt]" << "bad key_"; return PIByteArray(); - } + } else if (ok) *ok = true; #else - piCout << "[PICrypt]" << "Warning: PICrypt is disabled, to enable install sodium library and build pip with -DCRYPT="; + PICRYPT_DISABLED_WARNING #endif - if (ok) *ok = true; - return retba; + return ret; } @@ -149,7 +149,7 @@ PIByteArray PICrypt::hash(const PIString & secret) { PIByteArray s(secret.data(), secret.size()); crypto_generichash(hash.data(), hash.size(), s.data(), s.size(), (const uchar*)hash_def_key, sizeof(hash_def_key) - 1); #else - piCout << "[PICrypt]" << "Warning: PICrypt is disabled, to enable install sodium library and build pip with -DCRYPT="; + PICRYPT_DISABLED_WARNING #endif return hash; } @@ -167,7 +167,7 @@ ullong PICrypt::shorthash(const PIString& s, PIByteArray key) { PIByteArray in(s.data(), s.size()); crypto_shorthash((uchar *)&hash, in.data(), in.size(), key.data()); #else - piCout << "[PICrypt]" << "Warning: PICrypt is disabled, to enable install sodium library and build pip with -DCRYPT="; + PICRYPT_DISABLED_WARNING #endif return hash; } @@ -180,7 +180,20 @@ PIByteArray PICrypt::generateKey() { hash.resize(crypto_secretbox_KEYBYTES); randombytes_buf(hash.data(), hash.size()); #else - piCout << "[PICrypt]" << "Warning: PICrypt is disabled, to enable install sodium library and build pip with -DCRYPT="; + PICRYPT_DISABLED_WARNING +#endif + return hash; +} + + +PIByteArray PICrypt::generateRandomBuff(int size) { + PIByteArray hash; +#ifdef PIP_CRYPT + if (!init() || size <= 0) return hash; + hash.resize(size); + randombytes_buf(hash.data(), hash.size()); +#else + PICRYPT_DISABLED_WARNING #endif return hash; } @@ -190,7 +203,7 @@ size_t PICrypt::sizeKey() { #ifdef PIP_CRYPT return crypto_secretbox_KEYBYTES; #else - piCout << "[PICrypt]" << "Warning: PICrypt is disabled, to enable install sodium library and build pip with -DCRYPT="; + PICRYPT_DISABLED_WARNING #endif return 0; } @@ -200,12 +213,170 @@ size_t PICrypt::sizeCrypt() { #ifdef PIP_CRYPT return crypto_secretbox_MACBYTES + crypto_secretbox_NONCEBYTES; #else - piCout << "[PICrypt]" << "Warning: PICrypt is disabled, to enable install sodium library and build pip with -DCRYPT="; + PICRYPT_DISABLED_WARNING #endif return 0; } +void PICrypt::generateSignKeys(PIByteArray & public_key, PIByteArray & secret_key) { +#ifdef PIP_CRYPT + if (!init()) return; + public_key.resize(crypto_sign_PUBLICKEYBYTES); + secret_key.resize(crypto_sign_SECRETKEYBYTES); + crypto_sign_keypair(public_key.data(), secret_key.data()); +#else + PICRYPT_DISABLED_WARNING + #endif +} + + +void PICrypt::generateSignKeys(PIByteArray & public_key, PIByteArray & secret_key, const PIByteArray & seed) { +#ifdef PIP_CRYPT + if (!init() || seed.isEmpty()) return; + public_key.resize(crypto_sign_PUBLICKEYBYTES); + secret_key.resize(crypto_sign_SECRETKEYBYTES); + crypto_sign_seed_keypair(public_key.data(), secret_key.data(), hash(seed).data()); +#else + PICRYPT_DISABLED_WARNING + #endif +} + + +PIByteArray PICrypt::extractSignPublicKey(const PIByteArray & secret_key) { + PIByteArray pk; +#ifdef PIP_CRYPT + if (!init() || secret_key.size() != crypto_sign_SECRETKEYBYTES) return pk; + pk.resize(crypto_sign_PUBLICKEYBYTES); + crypto_sign_ed25519_sk_to_pk(pk.data(), secret_key.data()); +#else + PICRYPT_DISABLED_WARNING +#endif + return pk; +} + + +PIByteArray PICrypt::signMessage(const PIByteArray & data, PIByteArray secret_key) { + PIByteArray sign; +#ifdef PIP_CRYPT + if (!init()) return sign; + sign.resize(crypto_sign_BYTES); + crypto_sign_detached(sign.data(), 0, data.data(), data.size(), secret_key.data()); +#else + PICRYPT_DISABLED_WARNING +#endif + return sign; +} + + +bool PICrypt::verifySign(const PIByteArray & data, const PIByteArray & signature, PIByteArray public_key) { +#ifdef PIP_CRYPT + if (!init()) return false; + return (crypto_sign_verify_detached(signature.data(), data.data(), data.size(), public_key.data()) == 0); +#else + PICRYPT_DISABLED_WARNING + return false; +#endif +} + + +void PICrypt::generateKeypair(PIByteArray & public_key, PIByteArray & secret_key) { +#ifdef PIP_CRYPT + if (!init()) return; + public_key.resize(crypto_box_PUBLICKEYBYTES); + secret_key.resize(crypto_box_SECRETKEYBYTES); + crypto_box_keypair(public_key.data(), secret_key.data()); +#else + PICRYPT_DISABLED_WARNING +#endif +} + + +void PICrypt::generateKeypair(PIByteArray & public_key, PIByteArray & secret_key, const PIByteArray & seed) { +#ifdef PIP_CRYPT + if (!init()) return; + public_key.resize(crypto_box_PUBLICKEYBYTES); + secret_key.resize(crypto_box_SECRETKEYBYTES); + crypto_box_seed_keypair(public_key.data(), secret_key.data(), hash(seed).data()); +#else + PICRYPT_DISABLED_WARNING +#endif +} + + +PIByteArray PICrypt::crypt(const PIByteArray & data, const PIByteArray & public_key, const PIByteArray & secret_key) { + PIByteArray ret; +#ifdef PIP_CRYPT + if (!init()) return ret; + if (public_key.size() != crypto_box_PUBLICKEYBYTES) + return ret; + if (secret_key.size() != crypto_box_SECRETKEYBYTES) + return ret; + PIByteArray n; + ret.resize(data.size() + crypto_box_MACBYTES); + n.resize(crypto_box_NONCEBYTES); + randombytes_buf(n.data(), n.size()); + if (crypto_box_easy(ret.data(), data.data(), data.size(), n.data(), public_key.data(), secret_key.data()) != 0) + return PIByteArray(); + ret.append(n); +#else + PICRYPT_DISABLED_WARNING +#endif + return ret; +} + + +PIByteArray PICrypt::decrypt(const PIByteArray & crypt_data, const PIByteArray & public_key, const PIByteArray & secret_key, bool * ok) { + PIByteArray ret; +#ifdef PIP_CRYPT + if (!init()) return ret; + if (public_key.size() != crypto_box_PUBLICKEYBYTES) { + if (ok) *ok = false; + return ret; + } + if (secret_key.size() != crypto_box_SECRETKEYBYTES) { + if (ok) *ok = false; + return ret; + } + if (crypt_data.size() < crypto_box_NONCEBYTES + crypto_box_MACBYTES) { + if (ok) *ok = false; + return ret; + } + PIByteArray n; + n.resize(crypto_secretbox_NONCEBYTES); + ret.resize(crypt_data.size() - n.size() - crypto_secretbox_MACBYTES); + memcpy(n.data(), crypt_data.data(crypt_data.size() - n.size()), n.size()); + if (crypto_box_open_easy(ret.data(), crypt_data.data(), crypt_data.size() - n.size(), n.data(), public_key.data(), secret_key.data()) != 0) { + if (ok) *ok = false; + // piCout << "[PICrypt]" << "bad key_"; + return PIByteArray(); + } else if (ok) *ok = true; +#else + PICRYPT_DISABLED_WARNING +#endif + return ret; +} + + +PIByteArray PICrypt::passwordHash(const PIString & password, const PIByteArray & seed) { +// char out[crypto_pwhash_STRBYTES]; + PIByteArray pass = password.toUTF8(); + PIByteArray n; + PIByteArray ph; + ph.resize(crypto_box_SEEDBYTES); + n.resize(crypto_pwhash_SALTBYTES); +// randombytes_buf(n.data(), n.size()); + crypto_shorthash(n.data(), seed.data(), seed.size(), PIByteArray(crypto_shorthash_KEYBYTES).data()); + int r = crypto_pwhash(ph.data(), ph.size(), (const char*)pass.data(), pass.size(), n.data(), crypto_pwhash_argon2i_opslimit_moderate(), crypto_pwhash_argon2i_memlimit_moderate(), crypto_pwhash_ALG_ARGON2I13); + //crypto_pwhash_str(out, (const char*)pass.data(), pass.size(), crypto_pwhash_argon2i_opslimit_moderate(), crypto_pwhash_argon2i_memlimit_moderate()); + pass.fill(0); + if (r != 0) return PIByteArray(); + PIByteArray ret; + ret << ph << n << crypto_pwhash_argon2i_opslimit_moderate() << crypto_pwhash_argon2i_memlimit_moderate(); + return ret; +} + + bool PICrypt::init() { #ifdef PIP_CRYPT static bool inited = false; @@ -215,7 +386,7 @@ bool PICrypt::init() { //piCout << "[PICrypt]" << "init" << inited; return inited; #else - piCout << "[PICrypt]" << "Warning: PICrypt is disabled, to enable install sodium library and build pip with -DCRYPT="; + PICRYPT_DISABLED_WARNING #endif return false; } diff --git a/src_main/crypt/piauth.h b/src_main/crypt/piauth.h new file mode 100644 index 00000000..87960419 --- /dev/null +++ b/src_main/crypt/piauth.h @@ -0,0 +1,81 @@ +/*! \file piauth.h + * \brief PIP Authentication API +*/ +/* + PIP - Platform Independent Primitives + PIP Authentication API + Copyright (C) 2018 Andrey Bychkov work.a.b@yandex.ru + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef PIAUTH_H +#define PIAUTH_H + +#include "piobject.h" +#include "picrypt.h" + + +class PIP_EXPORT PIAuth : public PIObject +{ + PIOBJECT(PIAuth) +public: + enum Role {Client, Server}; + enum State {NotConnected, AuthProbe, PassRequest, AuthReply, KeyExchange, Connected}; + + PIAuth(const PIByteArray & sign); + + void setInfoData(const PIByteArray & info_) {info = info_;} + void setAuthorizedPublicKeys(const PIVector & pkeys) {auth_pkeys = pkeys;} + PIVector getAuthorizedPublicKeys() {return auth_pkeys;} + PIByteArray getSignPublicKey() {return sign_pk;} + + + void stop(); + void startClient(); + PIByteArray startServer(); + State receive(PIByteArray & ba); + PIByteArray getSecretKey(); + + + static PIByteArray generateSign(const PIByteArray & seed); + + EVENT(disconnected) + EVENT(connected) + EVENT2(authorize, PIByteArray, data, bool *, ok) + EVENT1(passwordRequest, PIString *, pass) + EVENT2(passwordCheck, PIByteArray, phash, bool *, ok) + + + //EVENT_HANDLER1(void, received, PIByteArray, data); + +private: + State disconnect(PIByteArray & ba, const PIString & error = PIString()); + bool isAuthorizedKey(const PIByteArray & pkey); + + PIByteArray createSKMessage(); + + Role role; + State state; + PIByteArray info; + PICrypt crypt; + PIByteArray sign_sk, sign_pk; + PIByteArray auth_sign; + PIByteArray box_sk, box_pk; + PIByteArray my_pk; + PIByteArray secret_key; + PIVector auth_pkeys; +}; + +#endif // PIAUTH_H diff --git a/src_main/crypt/picrypt.h b/src_main/crypt/picrypt.h new file mode 100644 index 00000000..cf58fbda --- /dev/null +++ b/src_main/crypt/picrypt.h @@ -0,0 +1,110 @@ +/*! \file picrypt.h + * \brief Cryptographic class using lib Sodium +*/ +/* + PIP - Platform Independent Primitives + Cryptographic class using lib Sodium + Copyright (C) 2018 Andrey Bychkov work.a.b@yandex.ru + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef PICRYPT_H +#define PICRYPT_H + +#include "pistring.h" + +class PIP_EXPORT PICrypt { +public: + //! Construct and generate random key + PICrypt(); + + //! Set key to "key", key size must be a \a sizeKey() + bool setKey(const PIByteArray & key); + + //! Generate and set key from keyphrase "secret" + PIByteArray setKey(const PIString & secret); + + //! Returns current key + PIByteArray key() {return key_;} + + //! Encrypt given data "data", result size will be increased by \a sizeCrypt() + PIByteArray crypt(const PIByteArray & data); + + //! Decrypt given data "crypt_data" + PIByteArray decrypt(const PIByteArray & crypt_data, bool * ok = 0); + + //! Encrypt given data "data" with key "key", result size will be increased by \a sizeCrypt() + static PIByteArray crypt(const PIByteArray & data, PIByteArray key); + + //! Decrypt given data "crypt_data" with key "key" + static PIByteArray decrypt(const PIByteArray & crypt_data, PIByteArray key, bool * ok = 0); + + //! Generate hash from keyphrase "secret", may be used as a key for encryption + static PIByteArray hash(const PIString & secret); + + //! Generate short hash from string "s", may be used for hash table + static ullong shorthash(const PIString & s, PIByteArray key = PIByteArray()); + + //! Generate random key + static PIByteArray generateKey(); + + //! Generate random buffer + static PIByteArray generateRandomBuff(int size); + + //! Returns key size + static size_t sizeKey(); + + //! Returns size which be added to data size in encryption process + static size_t sizeCrypt(); + + //! Function randomly generates a secret key and a corresponding public key for digital signature + static void generateSignKeys(PIByteArray & public_key, PIByteArray & secret_key); + + //! Function generates a secret key from input data and a corresponding public key for digital signature + static void generateSignKeys(PIByteArray & public_key, PIByteArray & secret_key, const PIByteArray & seed); + + //! Function extract sign public key from sing secret key + static PIByteArray extractSignPublicKey(const PIByteArray & secret_key); + + //! Calculate digital signature for data + PIByteArray signMessage(const PIByteArray & data, PIByteArray secret_key); + + //! Verify digital signature of signed message + bool verifySign(const PIByteArray & data, const PIByteArray & signature, PIByteArray public_key); + + //! Function randomly generates a secret key and a corresponding public key for authenticated encryption + static void generateKeypair(PIByteArray & public_key, PIByteArray & secret_key); + + //! Function generates a secret key from input data and a corresponding public key for authenticated encryption + static void generateKeypair(PIByteArray & public_key, PIByteArray & secret_key, const PIByteArray & seed); + + //! Encrypt given data "data" + PIByteArray crypt(const PIByteArray &data, const PIByteArray & public_key, const PIByteArray & secret_key); + + //! Decrypt given data "crypt_data" + PIByteArray decrypt(const PIByteArray & crypt_data, const PIByteArray & public_key, const PIByteArray & secret_key, bool * ok = 0); + + //! Generate password hash from "password" + static PIByteArray passwordHash(const PIString & password, const PIByteArray & seed); + + +private: + static bool init(); + + PIByteArray nonce_, key_; + +}; + +#endif // PICRYPT_H diff --git a/src_main/crypt/picryptmodule.h b/src_main/crypt/picryptmodule.h new file mode 100644 index 00000000..0bc23702 --- /dev/null +++ b/src_main/crypt/picryptmodule.h @@ -0,0 +1,26 @@ +/* + PIP - Platform Independent Primitives + Module includes + Copyright (C) 2018 Andrey Bychkov work.a.b@yandex.ru + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef PIMATHMODULE_H +#define PIMATHMODULE_H + +#include "picrypt.h" +#include "piauth.h" + +#endif // PIMATHMODULE_H diff --git a/src_main/math/picrypt.h b/src_main/math/picrypt.h deleted file mode 100644 index 623ce83f..00000000 --- a/src_main/math/picrypt.h +++ /dev/null @@ -1,76 +0,0 @@ -/*! \file picrypt.h - * \brief Cryptographic class using lib Sodium -*/ -/* - PIP - Platform Independent Primitives - Cryptographic class using lib Sodium - Copyright (C) 2018 Andrey Bychkov work.a.b@yandex.ru - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -#ifndef PICRYPT_H -#define PICRYPT_H - -#include "pistring.h" - -class PIP_EXPORT PICrypt { -public: - //! Construct and generate random key - PICrypt(); - - //! Set key to "key", key size must be a \a sizeKey() - bool setKey(const PIByteArray & key); - - //! Generate and set key from keyphrase "secret" - PIByteArray setKey(const PIString & secret); - - //! Returns current key - PIByteArray key() {return key_;} - - //! Encrypt given data "data", result size will be increased by \a sizeCrypt() - PIByteArray crypt(const PIByteArray & data); - - //! Decrypt given data "crypt_data" - PIByteArray decrypt(const PIByteArray & crypt_data, bool * ok = 0); - - //! Encrypt given data "data" with key "key", result size will be increased by \a sizeCrypt() - static PIByteArray crypt(const PIByteArray & data, PIByteArray key); - - //! Decrypt given data "crypt_data" with key "key" - static PIByteArray decrypt(const PIByteArray & crypt_data, PIByteArray key, bool * ok = 0); - - //! Generate hash from keyphrase "secret", may be used as a key for encryption - static PIByteArray hash(const PIString & secret); - - //! Generate short hash from string "s", may be used for hash table - static ullong shorthash(const PIString & s, PIByteArray key = PIByteArray()); - - //! Generate random key - static PIByteArray generateKey(); - - //! Returns key size - static size_t sizeKey(); - - //! Returns size which be added to data size in encryption process - static size_t sizeCrypt(); - -private: - static bool init(); - - PIByteArray nonce_, key_; - -}; - -#endif // PICRYPT_H diff --git a/src_main/math/pimathmodule.h b/src_main/math/pimathmodule.h index f52fbe01..5650ccdc 100644 --- a/src_main/math/pimathmodule.h +++ b/src_main/math/pimathmodule.h @@ -25,7 +25,6 @@ #include "pievaluator.h" #include "pifft.h" #include "picrc.h" -#include "picrypt.h" #include "pifixedpoint.h" #include "piquaternion.h" diff --git a/src_main/pip.h b/src_main/pip.h index 84d51677..7224b59d 100755 --- a/src_main/pip.h +++ b/src_main/pip.h @@ -1,20 +1,20 @@ /* - PIP - Platform Independent Primitives - All includes - Copyright (C) 2018 Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru + PIP - Platform Independent Primitives + All includes + Copyright (C) 2018 Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. - You should have received a copy of the GNU General Public License - along with this program. If not, see . + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ #ifndef PIP_H @@ -28,5 +28,6 @@ #include "pimathmodule.h" #include "pisystemmodule.h" #include "pigeomodule.h" +#include "picryptmodule.h" #endif // PIP_H