Open-Transactions  0.93.0-ge03d287
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
OTKeyring.cpp
Go to the documentation of this file.
1 /************************************************************
2  *
3  * OTKeyring.cpp
4  *
5  * Mac has Keychain, Windows has DPAPI, Linux has Gnome-
6  * Keyring, KWallet, etc. The purpose of this class is to
7  * provide a simple, unified, cross-platform interface to
8  * all of them.
9  */
10 
11 /************************************************************
12  -----BEGIN PGP SIGNED MESSAGE-----
13  Hash: SHA1
14 
15  * OPEN TRANSACTIONS
16  *
17  * Financial Cryptography and Digital Cash
18  * Library, Protocol, API, Server, CLI, GUI
19  *
20  * -- Anonymous Numbered Accounts.
21  * -- Untraceable Digital Cash.
22  * -- Triple-Signed Receipts.
23  * -- Cheques, Vouchers, Transfers, Inboxes.
24  * -- Basket Currencies, Markets, Payment Plans.
25  * -- Signed, XML, Ricardian-style Contracts.
26  * -- Scripted smart contracts.
27  *
28  * Copyright (C) 2010-2013 by "Fellow Traveler" (A pseudonym)
29  *
30  * EMAIL:
32  *
33  * BITCOIN: 1NtTPVVjDsUfDWybS4BwvHpG2pdS9RnYyQ
34  *
35  * KEY FINGERPRINT (PGP Key in license file):
36  * 9DD5 90EB 9292 4B48 0484 7910 0308 00ED F951 BB8E
37  *
38  * OFFICIAL PROJECT WIKI(s):
39  * https://github.com/FellowTraveler/Moneychanger
40  * https://github.com/FellowTraveler/Open-Transactions/wiki
41  *
42  * WEBSITE:
43  * http://www.OpenTransactions.org/
44  *
45  * Components and licensing:
46  * -- Moneychanger..A Java client GUI.....LICENSE:.....GPLv3
47  * -- otlib.........A class library.......LICENSE:...LAGPLv3
48  * -- otapi.........A client API..........LICENSE:...LAGPLv3
49  * -- opentxs/ot....Command-line client...LICENSE:...LAGPLv3
50  * -- otserver......Server Application....LICENSE:....AGPLv3
51  * Github.com/FellowTraveler/Open-Transactions/wiki/Components
52  *
53  * All of the above OT components were designed and written by
54  * Fellow Traveler, with the exception of Moneychanger, which
55  * was contracted out to Vicky C ([email protected]).
56  * The open-source community has since actively contributed.
57  *
58  * -----------------------------------------------------
59  *
60  * LICENSE:
61  * This program is free software: you can redistribute it
62  * and/or modify it under the terms of the GNU Affero
63  * General Public License as published by the Free Software
64  * Foundation, either version 3 of the License, or (at your
65  * option) any later version.
66  *
67  * ADDITIONAL PERMISSION under the GNU Affero GPL version 3
68  * section 7: (This paragraph applies only to the LAGPLv3
69  * components listed above.) If you modify this Program, or
70  * any covered work, by linking or combining it with other
71  * code, such other code is not for that reason alone subject
72  * to any of the requirements of the GNU Affero GPL version 3.
73  * (==> This means if you are only using the OT API, then you
74  * don't have to open-source your code--only your changes to
75  * Open-Transactions itself must be open source. Similar to
76  * LGPLv3, except it applies to software-as-a-service, not
77  * just to distributing binaries.)
78  *
79  * Extra WAIVER for OpenSSL, Lucre, and all other libraries
80  * used by Open Transactions: This program is released under
81  * the AGPL with the additional exemption that compiling,
82  * linking, and/or using OpenSSL is allowed. The same is true
83  * for any other open source libraries included in this
84  * project: complete waiver from the AGPL is hereby granted to
85  * compile, link, and/or use them with Open-Transactions,
86  * according to their own terms, as long as the rest of the
87  * Open-Transactions terms remain respected, with regard to
88  * the Open-Transactions code itself.
89  *
90  * Lucre License:
91  * This code is also "dual-license", meaning that Ben Lau-
92  * rie's license must also be included and respected, since
93  * the code for Lucre is also included with Open Transactions.
94  * See Open-Transactions/src/otlib/lucre/LUCRE_LICENSE.txt
95  * The Laurie requirements are light, but if there is any
96  * problem with his license, simply remove the Lucre code.
97  * Although there are no other blind token algorithms in Open
98  * Transactions (yet. credlib is coming), the other functions
99  * will continue to operate.
100  * See Lucre on Github: https://github.com/benlaurie/lucre
101  * -----------------------------------------------------
102  * You should have received a copy of the GNU Affero General
103  * Public License along with this program. If not, see:
104  * http://www.gnu.org/licenses/
105  *
106  * If you would like to use this software outside of the free
107  * software license, please contact FellowTraveler.
108  * (Unfortunately many will run anonymously and untraceably,
109  * so who could really stop them?)
110  *
111  * DISCLAIMER:
112  * This program is distributed in the hope that it will be
113  * useful, but WITHOUT ANY WARRANTY; without even the implied
114  * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
115  * PURPOSE. See the GNU Affero General Public License for
116  * more details.
117 
118  -----BEGIN PGP SIGNATURE-----
119  Version: GnuPG v1.4.9 (Darwin)
120 
121  iQIcBAEBAgAGBQJRSsfJAAoJEAMIAO35UbuOQT8P/RJbka8etf7wbxdHQNAY+2cC
122  vDf8J3X8VI+pwMqv6wgTVy17venMZJa4I4ikXD/MRyWV1XbTG0mBXk/7AZk7Rexk
123  KTvL/U1kWiez6+8XXLye+k2JNM6v7eej8xMrqEcO0ZArh/DsLoIn1y8p8qjBI7+m
124  aE7lhstDiD0z8mwRRLKFLN2IH5rAFaZZUvj5ERJaoYUKdn4c+RcQVei2YOl4T0FU
125  LWND3YLoH8naqJXkaOKEN4UfJINCwxhe5Ke9wyfLWLUO7NamRkWD2T7CJ0xocnD1
126  sjAzlVGNgaFDRflfIF4QhBx1Ddl6wwhJfw+d08bjqblSq8aXDkmFA7HeunSFKkdn
127  oIEOEgyj+veuOMRJC5pnBJ9vV+7qRdDKQWaCKotynt4sWJDGQ9kWGWm74SsNaduN
128  TPMyr9kNmGsfR69Q2Zq/FLcLX/j8ESxU+HYUB4vaARw2xEOu2xwDDv6jt0j3Vqsg
129  x7rWv4S/Eh18FDNDkVRChiNoOIilLYLL6c38uMf1pnItBuxP3uhgY6COm59kVaRh
130  nyGTYCDYD2TK+fI9o89F1297uDCwEJ62U0Q7iTDp5QuXCoxkPfv8/kX6lS6T3y9G
131  M9mqIoLbIQ1EDntFv7/t6fUTS2+46uCrdZWbQ5RjYXdrzjij02nDmJAm2BngnZvd
132  kamH0Y/n11lCvo1oQxM+
133  =uSzz
134  -----END PGP SIGNATURE-----
135  **************************************************************/
136 
137 #include "stdafx.hpp"
138 
139 #include "crypto/OTKeyring.hpp"
140 
141 #include "crypto/OTASCIIArmor.hpp"
142 #include "crypto/OTCachedKey.hpp"
143 #include "OTLog.hpp"
144 #include "crypto/OTPassword.hpp"
145 #include "util/OTPaths.hpp"
146 #include "OTPayload.hpp"
147 #include "OTStorage.hpp"
148 
149 #include <fstream>
150 
151 #ifndef _WIN32
152 #pragma GCC diagnostic ignored "-Wunused-parameter"
153 #endif
154 
155 #if defined(OT_KEYRING_WINDOWS) && defined(_WIN32)
156 //
157 // Windows DPAPI
158 //
159 
160 #include <cstdio>
161 extern "C" {
162 //#include <cstdio>
163 #include <wincrypt.h>
164 //#define MY_ENCODING_TYPE (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING)
165 }
166 
167 #pragma comment(lib, "crypt32.lib")
168 
169 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
170 #elif defined(OT_KEYRING_MAC) && defined(__APPLE__)
171 
172 //
173 // Mac Keychain
174 //
175 
176 #import <Security/Security.h>
177 
178 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
179 #elif defined(OT_KEYRING_GNOME)
180 //
181 // Gnome Keyring
182 //
183 extern "C" {
184 // "Try: sudo apt-get install libgnome-keyring-dev"
185 // http://nullroute.eu.org/~grawity/gnome-keyring-autologin.html
186 // http://harpreet.in/blog/2009/11/30/how-to-unlock-gnome-keyring-automatically/
187 // http://askubuntu.com/questions/38326/automatic-unlocking-of-keyring
188 
189 #include <gnome-keyring.h>
190 #include <glib.h>
191 }
192 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
193 //
194 // KDE / KWallet
195 //
196 #elif defined(OT_KEYRING_KWALLET)
197 
198 #include <glib.h>
199 
200 #ifndef G_GNUC_nullptr_TERMINATED
201 #if __GNUC__ >= 4
202 #define G_GNUC_nullptr_TERMINATED __attribute__((__sentinel__))
203 #else
204 #define G_GNUC_nullptr_TERMINATED
205 #endif
206 #endif
207 
208 #include <kapplication.h>
209 #include <kaboutdata.h>
210 #include <kcmdlineargs.h>
211 #include <kwallet.h>
212 #include <klocale.h>
213 
214 // For KWallet, must be compiled with g++, not gcc.
215 // Requries the header locations for KDE and Qt.
216 // They are commonly in:
217 // /usr/include/kde
218 // /usr/lib/qt-3.3/include
219 // This plugin must link to lkwalletclient.
220 // When compiling, use the following flags (for example):
221 // CC=g++
222 // CFLAGS="-I/usr/include/kde -I/usr/lib/qt-3.3/include"
223 // LDFLAGS="-lkwalletclient"
224 // kwallet_password.so
225 
226 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
227 //
228 // FlatFile (Dangerous, do not use !)
229 //
230 #elif defined(OT_KEYRING_FLATFILE)
231 
232 #endif
233 
234 namespace opentxs
235 {
236 
237 #if defined(OT_KEYRING_WINDOWS) && defined(_WIN32)
238 
239 //
240 // Windows DPAPI
241 //
242 
243 // static
244 bool OTKeyring::Windows_StoreSecret(const OTString& strUser,
245  const OTPassword& thePassword,
246  const std::string& str_display)
247 {
248  OT_ASSERT(strUser.Exists());
249  OT_ASSERT(thePassword.getMemorySize() > 0);
250 
251  DATA_BLOB input;
252  input.pbData = const_cast<BYTE*>(
253  reinterpret_cast<const BYTE*>(thePassword.getMemory()));
254  input.cbData = static_cast<DWORD>(thePassword.getMemorySize());
255 
256  // CRYPTPROTECT_PROMPTSTRUCT PromptStruct;
257  // ZeroMemory(&PromptStruct, sizeof(PromptStruct));
258  // PromptStruct.cbSize = sizeof(PromptStruct);
259  // PromptStruct.dwPromptFlags = CRYPTPROTECT_PROMPT_ON_PROTECT;
260  // PromptStruct.szPrompt = L"This is a user prompt.";
261 
262  DATA_BLOB output;
263 
264  BOOL result = CryptProtectData(&input, L"", // description string
265  nullptr, // optional entropy
266  nullptr, // reserved
267  nullptr, //&PromptStruct
268  0, &output);
269  if (!result) {
270  otErr << __FUNCTION__ << ": Failed calling Win32: CryptProtectData \n";
271  return false;
272  }
273 
274  //
275  // this does a copy
276  //
277  // std::string ciphertext;
278  // ciphertext.assign(reinterpret_cast<std::string::value_type*>(output.pbData),
279  // output.cbData);
280 
281  OTData theOutput;
282  theOutput.Assign(static_cast<void*>(output.pbData),
283  static_cast<uint32_t>(output.cbData));
284 
285  LocalFree(output.pbData); // Note: should have a check for nullptr here... ?
286  // And above...
287 
288  // Success encrypting to ciphertext (std::string or OTData)
289 
290  //
291  // Write it to local storage.
292  //
293  if (theOutput.IsEmpty()) {
294  otErr << __FUNCTION__
295  << ": Error: Output of Win32 CryptProtectData was empty.\n";
296  }
297  else {
298  OTASCIIArmor ascData(theOutput);
299  const OTString strFoldername("win32_data"); // todo hardcoding.
300 
301  if (ascData.Exists())
302  return ascData.WriteArmoredFile(strFoldername,
303  strUser, // this is filename
304  "WINDOWS KEYRING MASTERKEY");
305  }
306 
307  return false;
308 }
309 
310 // static
311 bool OTKeyring::Windows_RetrieveSecret(const OTString& strUser,
312  OTPassword& thePassword,
313  const std::string& str_display)
314 {
315  OT_ASSERT(strUser.Exists());
316 
317  OTString strFoldername("win32_data"); // todo hardcoding.
318  OTASCIIArmor ascFileContents;
319  bool bLoaded = (strFoldername.Exists() &&
320  ascFileContents.LoadFromFile(strFoldername, strUser) &&
321  ascFileContents.Exists());
322  if (!bLoaded) {
323  otWarn << "%s: No cached ciphertext of master key loaded during "
324  "attempted retrieval. "
325  "(However, once one is available, it WILL be cached using "
326  "DPAPI.) \n";
327  return false;
328  }
329  // Below this point, we know for sure the ciphertext of the master
330  // key loaded, and exists.
331  //
332  const OTPayload theCipherblob(ascFileContents);
333  //
334  if (theCipherblob.IsEmpty()) {
335  otErr << __FUNCTION__ << ": Error: OTPayload is empty after decoding "
336  "OTASCIIArmor (that wasn't empty.)\n";
337  }
338  else {
339  DATA_BLOB input;
340  input.pbData = const_cast<BYTE*>(
341  reinterpret_cast<const BYTE*>(theCipherblob.GetPayloadPointer()));
342  input.cbData = static_cast<DWORD>(theCipherblob.GetSize());
343 
344  // CRYPTPROTECT_PROMPTSTRUCT PromptStruct;
345  // ZeroMemory(&PromptStruct, sizeof(PromptStruct));
346  // PromptStruct.cbSize = sizeof(PromptStruct);
347  // PromptStruct.dwPromptFlags = CRYPTPROTECT_PROMPT_ON_PROTECT;
348  // PromptStruct.szPrompt = L"This is a user prompt.";
349 
350  // LPWSTR pDescrOut = nullptr;
351 
352  DATA_BLOB output;
353  BOOL result = CryptUnprotectData(&input, nullptr, // &pDescrOut
354  nullptr, // optional entropy
355  nullptr, // reserved
356  nullptr, //&PromptStruct
357  0, &output);
358  if (!result) {
359  otErr << __FUNCTION__
360  << ": Error: Output of Win32 CryptUnprotectData was empty.\n";
361  }
362  else {
363  thePassword.setMemory(reinterpret_cast<void*>(output.pbData),
364  static_cast<uint32_t>(output.cbData));
365  SecureZeroMemory(output.pbData, output.cbData);
366  LocalFree(output.pbData);
367  // LocalFree(pDescrOut);
368  return true;
369  }
370  }
371 
372  return false;
373 }
374 
375 // static
376 bool OTKeyring::Windows_DeleteSecret(const OTString& strUser,
377  const std::string& str_display)
378 {
379  OT_ASSERT(strUser.Exists());
380 
381  OTString strFoldername("win32_data"); // todo hardcoding.
382 
383  const bool bErased =
384  OTDB::EraseValueByKey(strFoldername.Get(), strUser.Get());
385 
386  if (!bErased)
387  otErr << __FUNCTION__
388  << ": Failed attempt to erase file: " << OTPaths::AppDataFolder()
389  << OTLog::PathSeparator() << strFoldername
390  << OTLog::PathSeparator() << strUser << " \n";
391 
392  return bErased;
393 }
394 
395 //#endif
396 #elif defined(OT_KEYRING_MAC) && defined(__APPLE__)
397 
398 //
399 // Mac Keychain
400 //
401 
402 class OTMacKeychain
403 {
404 public:
405  OSStatus FindSecret(CFTypeRef keychainOrArray, uint32_t serviceNameLength,
406  const char* serviceName, uint32_t accountNameLength,
407  const char* accountName, uint32_t* passwordLength,
408  void** passwordData, SecKeychainItemRef* itemRef) const;
409 
410  OSStatus AddSecret(SecKeychainRef keychain, uint32_t serviceNameLength,
411  const char* serviceName, uint32_t accountNameLength,
412  const char* accountName, uint32_t passwordLength,
413  const void* passwordData,
414  SecKeychainItemRef* itemRef) const;
415 
416  OSStatus ItemFreeContent(SecKeychainAttributeList* attrList,
417  void* data) const;
418 
419  OSStatus ItemDelete(SecKeychainItemRef itemRef) const;
420 
421  OSStatus SearchCreateFromAttributes(
422  CFTypeRef keychainOrArray, CFTypeRef SecItemClass, // unused here.
423  CFTypeRef itemClass, const SecKeychainAttributeList* attrList,
424  SecKeychainSearchRef* searchRef) const;
425 
426  OSStatus SearchCopyNext(SecKeychainSearchRef searchRef,
427  SecKeychainItemRef* itemRef) const;
428 };
429 
430 OSStatus OTMacKeychain::FindSecret(
431  CFTypeRef keychainOrArray, uint32_t serviceNameLength,
432  const char* serviceName, uint32_t accountNameLength,
433  const char* accountName, uint32_t* passwordLength, void** passwordData,
434  SecKeychainItemRef* itemRef) const
435 {
436  return SecKeychainFindGenericPassword(
437  keychainOrArray, serviceNameLength, serviceName, accountNameLength,
438  accountName, passwordLength, passwordData, itemRef);
439 }
440 
441 OSStatus OTMacKeychain::AddSecret(
442  SecKeychainRef keychain, uint32_t serviceNameLength,
443  const char* serviceName, uint32_t accountNameLength,
444  const char* accountName, uint32_t passwordLength, const void* passwordData,
445  SecKeychainItemRef* itemRef) const
446 {
447  return SecKeychainAddGenericPassword(
448  keychain, serviceNameLength, serviceName, accountNameLength,
449  accountName, passwordLength, passwordData, itemRef);
450 }
451 
452 OSStatus OTMacKeychain::ItemDelete(SecKeychainItemRef itemRef) const
453 {
454  return SecKeychainItemDelete(itemRef);
455 }
456 
457 OSStatus OTMacKeychain::SearchCreateFromAttributes(
458  CFTypeRef keychainOrArray, CFTypeRef SecItemClass, CFTypeRef itemClass,
459  const SecKeychainAttributeList* attrList,
460  SecKeychainSearchRef* searchRef) const
461 {
462  return SecKeychainSearchCreateFromAttributes(keychainOrArray, itemClass,
463  attrList, searchRef);
464 }
465 
466 OSStatus OTMacKeychain::SearchCopyNext(SecKeychainSearchRef searchRef,
467  SecKeychainItemRef* itemRef) const
468 {
469  return SecKeychainSearchCopyNext(searchRef, itemRef);
470 }
471 
472 OSStatus OTMacKeychain::ItemFreeContent(SecKeychainAttributeList* attrList,
473  void* data) const
474 {
475  return SecKeychainItemFreeContent(attrList, data);
476 }
477 
478 // static
479 bool OTKeyring::Mac_StoreSecret(const OTString& strUser,
480  const OTPassword& thePassword,
481  const std::string& str_display)
482 {
483  OT_ASSERT(strUser.Exists());
484  OT_ASSERT(thePassword.getMemorySize() > 0);
485 
486  const std::string service_name = "opentxs";
487  const std::string account_name = strUser.Get();
488 
489  OTMacKeychain theKeychain;
490  void* vData =
491  const_cast<void*>(static_cast<const void*>(thePassword.getMemory()));
492 
493  OSStatus theError = theKeychain.AddSecret(
494  nullptr, service_name.size(), service_name.data(), account_name.size(),
495  account_name.data(), thePassword.getMemorySize(),
496  vData, // thePassword.getMemory()
497  nullptr);
498  if (theError != noErr) {
499  otErr
500  << "OTKeyring::Mac_StoreSecret: Error in theKeychain.AddSecret.\n";
501  return false;
502  }
503 
504  return true;
505 }
506 
507 // static
508 bool OTKeyring::Mac_RetrieveSecret(const OTString& strUser,
509  OTPassword& thePassword,
510  const std::string& str_display)
511 {
512  OT_ASSERT(strUser.Exists());
513 
514  const std::string service_name = "opentxs";
515  const std::string account_name = strUser.Get();
516 
517  uint32_t password_length = 0;
518  void* password_data = nullptr;
519 
520  OTMacKeychain theKeychain;
521 
522  OSStatus theError = theKeychain.FindSecret(
523  nullptr, service_name.size(), service_name.data(), account_name.size(),
524  account_name.data(), &password_length, // output.
525  &password_data, nullptr);
526  if (theError == noErr) {
527  thePassword.setMemory(password_data, password_length);
528  theKeychain.ItemFreeContent(nullptr, password_data);
529  return true;
530  }
531  else
532  otErr << "OTKeyring::Mac_RetrieveSecret: Error in "
533  "theKeychain.FindSecret.\n";
534 
535  return false;
536 }
537 
538 // static
539 bool OTKeyring::Mac_DeleteSecret(const OTString& strUser,
540  const std::string& str_display)
541 {
542  OT_ASSERT(strUser.Exists());
543 
544  const std::string service_name = "opentxs";
545  const std::string account_name = strUser.Get();
546 
547  OTMacKeychain theKeychain;
548 
549  // Setup the attributes the for the keychain item
550  SecKeychainAttribute attrs[] = {{kSecServiceItemAttr, service_name.length(),
551  (char*)service_name.c_str()},
552  {kSecAccountItemAttr, account_name.length(),
553  (char*)account_name.c_str()}};
554  SecKeychainAttributeList attributes = {sizeof(attrs) / sizeof(attrs[0]),
555  attrs};
556 
557  SecKeychainItemRef theItem = nullptr;
558  SecKeychainSearchRef theSearch = nullptr;
559  OSStatus theStatus = 0;
560  OSErr theResult;
561 
562  theResult = theKeychain.SearchCreateFromAttributes(
563  nullptr, nullptr, // CFTypeRef SecItemClass, // unused here.
564  kSecGenericPasswordItemClass, &attributes, &theSearch);
565 
566  bool bReturnVal = false;
567 
568  if (errSecSuccess == theResult) // Success searching, now let's iterate the
569  // results and count them.
570  {
571  int32_t numberOfItemsFound = 0;
572  while (theKeychain.SearchCopyNext(theSearch, &theItem) == noErr) {
573  numberOfItemsFound++;
574  }
575 
576  if (numberOfItemsFound > 0) {
577  theStatus = theKeychain.ItemDelete(theItem);
578 
579  if (theStatus != 0)
580  otErr << "OTKeyring::Mac_DeleteSecret: Error deleting item "
581  "from keychain.\n";
582  else
583  bReturnVal = true;
584  }
585 
586  CFRelease(theItem);
587  CFRelease(theSearch);
588  }
589 
590  return bReturnVal;
591 }
592 
593 //#endif
594 #elif defined(OT_KEYRING_IOS) && defined(__APPLE__)
595 
596 //
597 // iOS Keychain
598 //
599 
600 #import <Security/Security.h> // this has to be included after OTStorage.h to avoid conflicts with msgpack/type/nil.hpp
601 #import <CoreFoundation/CoreFoundation.h>
602 
603 // static
604 bool OTKeyring::IOS_StoreSecret(const OTString& strUser,
605  const OTPassword& thePassword,
606  const std::string& str_display)
607 {
608  OT_ASSERT(strUser.Exists());
609  OT_ASSERT(thePassword.getMemorySize() > 0);
610 
611  CFStringRef service_name = CFSTR("opentxs");
612  CFStringRef account_name = CFStringCreateWithCString(nullptr, strUser.Get(),
613  kCFStringEncodingUTF8);
614  CFDataRef vData = CFDataCreateWithBytesNoCopy(
615  nullptr, thePassword.getMemory_uint8(), thePassword.getMemorySize(),
616  kCFAllocatorNull);
617 
618  const void* keys[] = {kSecClass, kSecAttrService, kSecAttrAccount,
619  kSecValueData};
620  const void* values[] = {kSecClassGenericPassword, service_name,
621  account_name, vData};
622  CFDictionaryRef item =
623  CFDictionaryCreate(nullptr, keys, values, 4, nullptr, nullptr);
624 
625  OSStatus theError = SecItemAdd(item, nullptr);
626 
627  CFRelease(item);
628  CFRelease(vData);
629  CFRelease(account_name);
630 
631  if (theError != noErr) {
632  otErr << "OTKeyring::IOS_StoreSecret: Error in SecItemAdd.\n";
633  return false;
634  }
635 
636  return true;
637 }
638 
639 // static
640 bool OTKeyring::IOS_RetrieveSecret(const OTString& strUser,
641  OTPassword& thePassword,
642  const std::string& str_display)
643 {
644  OT_ASSERT(strUser.Exists());
645 
646  CFStringRef service_name = CFSTR("opentxs");
647  CFStringRef account_name = CFStringCreateWithCString(nullptr, strUser.Get(),
648  kCFStringEncodingUTF8);
649  CFDataRef vData = nullptr;
650 
651  const void* keys[] = {kSecClass, kSecAttrService, kSecAttrAccount,
652  kSecReturnData};
653  const void* values[] = {kSecClassGenericPassword, service_name,
654  account_name, kCFBooleanTrue};
655  CFDictionaryRef query =
656  CFDictionaryCreate(nullptr, keys, values, 4, nullptr, nullptr);
657 
658  OSStatus theError = SecItemCopyMatching(query, (CFTypeRef*)&vData);
659 
660  CFRelease(query);
661  CFRelease(account_name);
662 
663  if (theError != noErr) {
664  otErr
665  << "OTKeyring::IOS_RetrieveSecret: Error in SecItemCopyMatching.\n";
666  return false;
667  }
668 
669  thePassword.setMemory(CFDataGetBytePtr(vData), CFDataGetLength(vData));
670  CFRelease(vData);
671 
672  return true;
673 }
674 
675 // static
676 bool OTKeyring::IOS_DeleteSecret(const OTString& strUser,
677  const std::string& str_display)
678 {
679  OT_ASSERT(strUser.Exists());
680 
681  CFStringRef service_name = CFSTR("opentxs");
682  CFStringRef account_name = CFStringCreateWithCString(nullptr, strUser.Get(),
683  kCFStringEncodingUTF8);
684 
685  const void* keys[] = {kSecClass, kSecAttrService, kSecAttrAccount};
686  const void* values[] = {kSecClassGenericPassword, service_name,
687  account_name};
688  CFDictionaryRef query =
689  CFDictionaryCreate(nullptr, keys, values, 3, nullptr, nullptr);
690 
691  OSStatus theError = SecItemDelete(query);
692 
693  CFRelease(query);
694  CFRelease(account_name);
695 
696  if (theError != noErr) {
697  otErr << "OTKeyring::IOS_RetrieveSecret: Error in SecItemDelete.\n";
698  return false;
699  }
700 
701  return true;
702 }
703 
704 //#endif
705 #elif defined(OT_KEYRING_GNOME)
706 
707 //
708 // Gnome Keyring
709 //
710 
711 // The predefined schema is:
712 //
713 // GNOME_KEYRING_NETWORK_PASSWORD
714 //
715 // With attributes:
716 //
717 // user: A string for the user login.
718 // server: A string for the server being connected to.
719 // protocol: A string for the protocol used to access the server, such
720 // as 'http' or 'smb'.
721 // domain: A string for the realm or domain, such as a Windows login
722 // domain.
723 // port: An integer describing the network port to used to connect
724 // to the server.
725 //
726 
727 // static
728 bool OTKeyring::Gnome_StoreSecret(const OTString& strUser,
729  const OTPassword& thePassword,
730  const std::string& str_display)
731 {
732  OT_ASSERT(strUser.Exists());
733  OT_ASSERT(thePassword.getMemorySize() > 0);
734 
735  OTData theData(thePassword.getMemory(), thePassword.getMemorySize());
736  OTASCIIArmor ascData(theData);
737  theData.zeroMemory(); // security reasons.
738 
739  OTString strOutput;
740  const bool bSuccess =
741  ascData.Exists() &&
742  ascData.WriteArmoredString(strOutput, "DERIVED KEY"); // There's no
743  // default, to
744  // force you to
745  // enter the right
746  // string.
747  ascData.zeroMemory();
748 
749  GnomeKeyringResult theResult = GNOME_KEYRING_RESULT_IO_ERROR;
750 
751  if (bSuccess && strOutput.Exists()) {
752  theResult = gnome_keyring_store_password_sync(
753  GNOME_KEYRING_NETWORK_PASSWORD,
754  GNOME_KEYRING_DEFAULT, // GNOME_KEYRING_SESSION,
755  str_display.c_str(), strOutput.Get(), "user", strUser.Get(),
756  "protocol", "opentxs", // todo: hardcoding.
757  nullptr);
758  strOutput.zeroMemory();
759 
760  bool bResult = false;
761 
762  if (theResult == GNOME_KEYRING_RESULT_OK)
763  bResult = true;
764  else
765  otErr << "OTKeyring::Gnome_StoreSecret: "
766  << "Failure in gnome_keyring_store_password_sync: "
767  << gnome_keyring_result_to_message(theResult) << '\n';
768 
769  return bResult;
770  }
771 
772  otOut << "OTKeyring::Gnome_StoreSecret: No secret to store.\n";
773 
774  return false;
775 }
776 
777 /*
778  typedef enum {
779  GNOME_KEYRING_RESULT_OK,
780  GNOME_KEYRING_RESULT_DENIED,
781  GNOME_KEYRING_RESULT_NO_KEYRING_DAEMON,
782  GNOME_KEYRING_RESULT_ALREADY_UNLOCKED,
783  GNOME_KEYRING_RESULT_NO_SUCH_KEYRING,
784  GNOME_KEYRING_RESULT_BAD_ARGUMENTS,
785  GNOME_KEYRING_RESULT_IO_ERROR,
786  GNOME_KEYRING_RESULT_CANCELLED,
787  GNOME_KEYRING_RESULT_KEYRING_ALREADY_EXISTS,
788  GNOME_KEYRING_RESULT_NO_MATCH
789 } GnomeKeyringResult;
790  */
791 // static
792 bool OTKeyring::Gnome_RetrieveSecret(const OTString& strUser,
793  OTPassword& thePassword,
794  const std::string& str_display)
795 {
796  OT_ASSERT(strUser.Exists());
797 
798  GnomeKeyringResult theResult = GNOME_KEYRING_RESULT_IO_ERROR;
799  gchar* gchar_p_password = nullptr;
800 
801  // if the password exists in the keyring, set it in
802  // thePassword (output argument.)
803  //
804  int32_t nCount = -1;
805  int64_t lSleep = 1;
806 
807  while ((GNOME_KEYRING_RESULT_OK != theResult)) {
808  ++nCount; // 0 on first iteration.
809 
810  theResult = gnome_keyring_find_password_sync(
811  GNOME_KEYRING_NETWORK_PASSWORD, &gchar_p_password, "user",
812  strUser.Get(), "protocol", "opentxs", // todo: hardcoding.
813  nullptr);
814 
815  if (GNOME_KEYRING_RESULT_OK == theResult) break;
816 
817  if (nCount > 2) // todo hardcoding.
818  break; // we try a few times -- not infinite times!
819 
820  OTString strGnomeError(gnome_keyring_result_to_message(theResult));
821 
822  // OTString strGnomeError;
823  // switch (theResult) {
824  // case GNOME_KEYRING_RESULT_OK: strGnomeError
825  // = "GNOME_KEYRING_RESULT_OK"; break;
826  // case GNOME_KEYRING_RESULT_DENIED: strGnomeError
827  // = "GNOME_KEYRING_RESULT_DENIED"; break;
828  // case GNOME_KEYRING_RESULT_NO_KEYRING_DAEMON: strGnomeError
829  // = "GNOME_KEYRING_RESULT_NO_KEYRING_DAEMON"; break;
830  // case GNOME_KEYRING_RESULT_ALREADY_UNLOCKED: strGnomeError
831  // = "GNOME_KEYRING_RESULT_ALREADY_UNLOCKED"; break;
832  // case GNOME_KEYRING_RESULT_NO_SUCH_KEYRING: strGnomeError
833  // = "GNOME_KEYRING_RESULT_NO_SUCH_KEYRING"; break;
834  // case GNOME_KEYRING_RESULT_BAD_ARGUMENTS: strGnomeError
835  // = "GNOME_KEYRING_RESULT_BAD_ARGUMENTS"; break;
836  // case GNOME_KEYRING_RESULT_IO_ERROR: strGnomeError
837  // = "GNOME_KEYRING_RESULT_IO_ERROR"; break;
838  // case GNOME_KEYRING_RESULT_CANCELLED: strGnomeError
839  // = "GNOME_KEYRING_RESULT_CANCELLED"; break;
840  // case GNOME_KEYRING_RESULT_KEYRING_ALREADY_EXISTS:
841  // strGnomeError = "GNOME_KEYRING_RESULT_KEYRING_ALREADY_EXISTS"; break;
842  // case GNOME_KEYRING_RESULT_NO_MATCH: strGnomeError
843  // = "GNOME_KEYRING_RESULT_NO_MATCH"; break;
844  //
845  // default:
846  // strGnomeError = "Unknown! Very strange!";
847  // break;
848  // }
849 
850  otErr << __FUNCTION__ << ": gnome_keyring_find_password_sync returned "
851  << strGnomeError.Get() << '\n';
852  otErr << "Remedy: Sleeping for " << lSleep
853  << " seconds and then retrying (attempt " << (nCount + 2) << '\n';
854  // on first iteration, nCount is 0, and this will say "attempt 2" aka
855  // "second attempt," which is correct.
856 
857  OTLog::SleepSeconds(lSleep);
858  lSleep *= 2; // double it each time
859  }
860 
861  if ((theResult == GNOME_KEYRING_RESULT_OK) &&
862  (nullptr != gchar_p_password)) {
863  size_t sizePassword =
864  OTString::safe_strlen(gchar_p_password, MAX_STRING_LENGTH);
865 
866  if (sizePassword > 0) {
867  OTString strData(gchar_p_password, sizePassword);
868 
869  gnome_keyring_free_password(gchar_p_password);
870  gchar_p_password = nullptr;
871 
872  OTASCIIArmor ascData;
873  const bool bLoaded =
874  strData.Exists() && ascData.LoadFromString(strData);
875  strData.zeroMemory();
876 
877  if (!bLoaded)
878  otErr << __FUNCTION__ << ": Failed trying to decode secret "
879  "from Gnome Keyring contents:\n\n"
880  << strData.Get() << "\n\n";
881  else {
882  OTPayload thePayload(ascData);
883  ascData.zeroMemory();
884  if (thePayload.IsEmpty())
885  otErr << __FUNCTION__ << ": Failed trying to decode secret "
886  "OTPayload from OTASCIIArmor "
887  << "from Gnome Keyring contents:\n\n" << strData.Get()
888  << "\n\n";
889  else {
890  thePassword.setMemory(thePayload.GetPayloadPointer(),
891  thePayload.GetSize());
892  thePayload.zeroMemory(); // for security.
893  return true;
894  }
895  return false;
896  }
897  }
898  }
899 
900  // Not an error: what if it just hasn't been set there yet?
901  //
902  otOut << "OTKeyring::Gnome_RetrieveSecret: "
903  << "No secret found: gnome_keyring_find_password_sync: "
904  << gnome_keyring_result_to_message(theResult) << '\n';
905 
906  return false;
907 }
908 
909 // static
910 bool OTKeyring::Gnome_DeleteSecret(const OTString& strUser,
911  const std::string& str_display)
912 {
913  OT_ASSERT(strUser.Exists());
914 
915  GnomeKeyringResult theResult = gnome_keyring_delete_password_sync(
916  GNOME_KEYRING_NETWORK_PASSWORD, "user", strUser.Get(), "protocol",
917  "opentxs", // todo: hardcoding.
918  nullptr); // Always end with nullptr
919 
920  if (theResult == GNOME_KEYRING_RESULT_OK) {
921  return true;
922  }
923  else {
924  otErr << "OTKeyring::Gnome_DeleteSecret: "
925  << "Failure in gnome_keyring_delete_password_sync: "
926  << gnome_keyring_result_to_message(theResult) << '\n';
927  }
928 
929  return false;
930 }
931 
932 #elif defined(OT_KEYRING_KWALLET)
933 
934 //
935 // KDE / KWallet
936 //
937 
938 // static
939 
940 KWallet::Wallet* OTKeyring::s_pWallet = nullptr;
941 KApplication* OTKeyring::s_pApp = nullptr;
942 
943 bool OTKeyring::InitKApp()
944 {
945  static bool bInitialized = false;
946 
947  if (!bInitialized) {
948  if (!KApplication::instance()) {
949  static char kdeAppName[] = "opentxs-kwallet";
950  int32_t argc = 1;
951  char* argv[2] = {kdeAppName, nullptr};
952  QByteArray qbApp(kdeAppName);
953  KAboutData about(qbApp, qbApp, KLocalizedString(),
954  QByteArray("1.0"));
955  KCmdLineArgs::init(argc, argv, &about);
956  if (!qApp)
957  OTKeyring::s_pApp = new KApplication(true); // todo cleanup ?
958  else
959  otErr << "OTKeyring::InitKApp: Error: qApp already existed.\n";
960  }
961 
962  bInitialized = true;
963  }
964 
965  return bInitialized;
966 }
967 
968 KWallet::Wallet* OTKeyring::OpenKWallet()
969 {
970  if (OTKeyring::InitKApp()) {
971  OT_ASSERT(nullptr != OTKeyring::s_pApp);
972  // Below this point, we know OTKeyring::s_pApp is created.
973 
974  if (nullptr == OTKeyring::s_pWallet) {
975  OTKeyring::s_pWallet = KWallet::Wallet::openWallet(
976  KWallet::Wallet::NetworkWallet(), nullptr);
977 
978  if (nullptr == OTKeyring::s_pWallet) {
979  otErr << "OTKeyring::OpenKWallet: Failed "
980  << "calling: KWallet::Wallet::openWallet"
981  << "(KWallet::Wallet::NetworkWallet(), nullptr)\n";
982  return nullptr;
983  }
984  }
985  // Below this point, we know OTKeyring::s_pWallet was opened at
986  // some time in the past, and may still be open.
987 
988  //
989  if (!KWallet::Wallet::isOpen(KWallet::Wallet::NetworkWallet())) {
990  // See if it's still open -- if not, re-open it.
991  //
992  if (nullptr != OTKeyring::s_pWallet) delete OTKeyring::s_pWallet;
993  OTKeyring::s_pWallet = KWallet::Wallet::openWallet(
994  KWallet::Wallet::NetworkWallet(), nullptr);
995 
996  if (nullptr == OTKeyring::s_pWallet) {
997  otErr << "OTKeyring::OpenKWallet (while re-opening): Failed "
998  << "calling: KWallet::Wallet::openWallet"
999  << "(KWallet::Wallet::NetworkWallet(), nullptr)\n";
1000  return nullptr;
1001  }
1002  }
1003  // Below this point, we know OTKeyring::s_pWallet is currently open.
1004 
1005  //
1006  if (!OTKeyring::s_pWallet->setFolder(
1007  QString::fromAscii("opentxs"))) // todo hardcoding.
1008  {
1009  OTKeyring::s_pWallet->createFolder(QString::fromAscii("opentxs"));
1010 
1011  if (!OTKeyring::s_pWallet->setFolder(
1012  QString::fromAscii("opentxs"))) {
1013  otErr << "OTKeyring::OpenKWallet: Failed calling: "
1014  "KWallet::Wallet::setFolder"
1015  << "(QString::fromAscii(\"opentxs\")) -- Tried creating "
1016  "it, too!\n";
1017  return nullptr;
1018  }
1019  }
1020  // Below this point, we know the folder was properly set to "opentxs".
1021  }
1022 
1023  return OTKeyring::s_pWallet;
1024 }
1025 
1026 // bool OTKeyring::DoesPasswordExist( QString key)
1027 //{
1028 // KWallet::Wallet * pWallet = OTKeyring::OpenKWallet();
1029 //
1030 // if (nullptr != pWallet)
1031 // {
1032 // if (pWallet->hasEntry(key) == 0)
1033 // return true;
1034 // else
1035 // return false;
1036 // }
1037 //
1038 // return false;
1039 //}
1040 
1041 // static
1042 bool OTKeyring::KWallet_StoreSecret(const OTString& strUser,
1043  const OTPassword& thePassword,
1044  const std::string& str_display)
1045 {
1046  OT_ASSERT(strUser.Exists());
1047  OT_ASSERT(thePassword.getMemorySize() > 0);
1048 
1049  KWallet::Wallet* pWallet = OTKeyring::OpenKWallet();
1050 
1051  if (nullptr != pWallet) {
1052  const QString qstrKey(strUser.Get());
1053 
1054  OTData theData(thePassword.getMemory(), thePassword.getMemorySize());
1055  OTASCIIArmor ascData(theData);
1056  theData.zeroMemory(); // security reasons.
1057 
1058  OTString strOutput;
1059  const bool bSuccess =
1060  ascData.Exists() &&
1061  ascData.WriteArmoredString(
1062  strOutput, "DERIVED KEY"); // There's no default, to force you
1063  // to enter the right string.
1064  ascData.zeroMemory();
1065 
1066  // Set the password
1067  //
1068  bool bReturnVal = false;
1069 
1070  if (bSuccess && strOutput.Exists() &&
1071  pWallet->writePassword(qstrKey,
1072  QString::fromUtf8(strOutput.Get())) == 0)
1073  bReturnVal = true;
1074  else
1075  otErr << "OTKeyring::KWallet_StoreSecret: Failed trying to store "
1076  "secret into KWallet.\n";
1077 
1078  strOutput.zeroMemory();
1079 
1080  return bReturnVal;
1081  }
1082 
1083  otErr << "OTKeyring::KWallet_StoreSecret: Unable to open kwallet.\n";
1084 
1085  return false;
1086 }
1087 
1088 // static
1089 bool OTKeyring::KWallet_RetrieveSecret(const OTString& strUser,
1090  OTPassword& thePassword,
1091  const std::string& str_display)
1092 {
1093  OT_ASSERT(strUser.Exists());
1094 
1095  KWallet::Wallet* pWallet = OTKeyring::OpenKWallet();
1096 
1097  if (nullptr != pWallet) {
1098  const QString qstrKey(strUser.Get());
1099  QString qstrPwd;
1100 
1101  // Get the password
1102  //
1103  if (pWallet->readPassword(qstrKey, qstrPwd) == 0) {
1104  const std::string str_password =
1105  qstrPwd.toStdString(); // todo security: notice str_password
1106  // isn't zero'd here.
1107 
1108  OTString strData(str_password);
1109  OTASCIIArmor ascData;
1110 
1111  const bool bLoaded =
1112  strData.Exists() && ascData.LoadFromString(strData);
1113  strData.zeroMemory();
1114 
1115  if (!bLoaded)
1116  otErr << __FUNCTION__ << ": Failed trying to decode secret "
1117  "from KWallet contents.\n";
1118  else {
1119  OTPayload thePayload(ascData);
1120  ascData.zeroMemory();
1121  if (thePayload.IsEmpty())
1122  otErr << __FUNCTION__ << ": Failed trying to decode secret "
1123  "OTPayload from OTASCIIArmor from "
1124  "KWallet contents.\n";
1125  else {
1126  thePassword.setMemory(thePayload.GetPayloadPointer(),
1127  thePayload.GetSize());
1128  thePayload.zeroMemory(); // for security.
1129  return true;
1130  }
1131  }
1132  }
1133  else
1134  otErr << __FUNCITON__
1135  << ": Failed trying to retrieve secret from KWallet.\n";
1136  }
1137 
1138  // Not an error: what if it just hasn't been set there yet?
1139  //
1140  otWarn << "OTKeyring::KWallet_RetrieveSecret: No secret found.\n";
1141 
1142  return false;
1143 }
1144 
1145 // static
1146 bool OTKeyring::KWallet_DeleteSecret(const OTString& strUser,
1147  const std::string& str_display)
1148 {
1149  OT_ASSERT(strUser.Exists());
1150 
1151  KWallet::Wallet* pWallet = OTKeyring::OpenKWallet();
1152 
1153  if (nullptr != pWallet) {
1154  const QString qstrKey(strUser.Get());
1155 
1156  bool bResult = false;
1157 
1158  if (pWallet->removeEntry(qstrKey) == 0) // delete the entry
1159  bResult = true;
1160  else
1161  otErr << "OTKeyring::KWallet_DeleteSecret: Failed trying to erase "
1162  "secret from KWallet.\n";
1163 
1164  return bResult;
1165  }
1166 
1167  otErr << "OTKeyring::KWallet_DeleteSecret: Unable to open kwallet.\n";
1168 
1169  return false;
1170 }
1171 
1172 #elif defined(OT_KEYRING_FLATFILE)
1173 
1174 //
1175 // Store the derived key in a flat file.
1176 //
1177 // Dangerous! For testing only! Not for use in production!
1178 //
1179 
1180 std::string OTKeyring::s_str_passwd_folder;
1181 
1182 // static
1183 void OTKeyring::FlatFile_SetPasswordFolder(std::string folder)
1184 {
1185  OTKeyring::s_str_passwd_folder = folder;
1186 }
1187 
1188 // static
1189 const char* OTKeyring::FlatFile_GetPasswordFolder()
1190 {
1191  return s_str_passwd_folder.c_str();
1192 }
1193 
1194 // static
1195 bool OTKeyring::FlatFile_StoreSecret(const OTString& strUser,
1196  const OTPassword& thePassword,
1197  const std::string& str_display)
1198 {
1199  OT_ASSERT(strUser.Exists());
1200  OT_ASSERT(thePassword.getMemorySize() > 0);
1201 
1202  const std::string str_pw_folder(OTKeyring::FlatFile_GetPasswordFolder());
1203  if (!str_pw_folder.empty()) {
1204  OTString strExactPath;
1205  strExactPath.Format("%s%s%s", str_pw_folder.c_str(),
1206  OTLog::PathSeparator(), strUser.Get());
1207  const std::string str_ExactPath(strExactPath.Get());
1208 
1209  OTData theData(thePassword.getMemory(), thePassword.getMemorySize());
1210  OTASCIIArmor ascData(theData);
1211  theData.zeroMemory(); // security reasons.
1212 
1213  // Save the password
1214  //
1215  const bool bSaved =
1216  ascData.Exists() && ascData.SaveToExactPath(str_ExactPath);
1217  ascData.zeroMemory();
1218 
1219  if (!bSaved)
1220  otErr << "OTKeyring::FlatFile_StoreSecret: Failed trying to store "
1221  "secret.\n";
1222 
1223  return bSaved;
1224  }
1225 
1226  otErr << "OTKeyring::FlatFile_StoreSecret: Unable to cache derived key, "
1227  "since password_folder not provided in config file.\n";
1228 
1229  return false;
1230 }
1231 
1232 // static
1233 bool OTKeyring::FlatFile_RetrieveSecret(const OTString& strUser,
1234  OTPassword& thePassword,
1235  const std::string& str_display)
1236 {
1237  OT_ASSERT(strUser.Exists());
1238  const std::string str_pw_folder(OTKeyring::FlatFile_GetPasswordFolder());
1239  if (!str_pw_folder.empty()) {
1240  OTString strExactPath;
1241  strExactPath.Format("%s%s%s", str_pw_folder.c_str(),
1242  OTLog::PathSeparator(), strUser.Get());
1243  const std::string str_ExactPath(strExactPath.Get());
1244 
1245  // Get the password
1246  //
1247  OTASCIIArmor ascData;
1248 
1249  if (!ascData.LoadFromExactPath(str_ExactPath))
1250  otErr << "OTKeyring::FlatFile_RetrieveSecret: "
1251  << "Failed trying to decode secret from flat file contents."
1252  << "\n";
1253  else {
1254  OTPayload thePayload(ascData);
1255  ascData.zeroMemory();
1256  if (thePayload.IsEmpty())
1257  otErr << __FUNCTION__ << ": Failed trying to decode secret "
1258  "OTPayload from OTASCIIArmor from "
1259  "flat file contents.\n";
1260  else {
1261  thePassword.setMemory(thePayload.GetPayloadPointer(),
1262  thePayload.GetSize());
1263  thePayload.zeroMemory(); // for security.
1264  return true;
1265  }
1266  }
1267  }
1268 
1269  // Not an error: what if it just hasn't been set there yet?
1270  //
1271  otWarn << __FUNCTION__ << ": Unable to retrieve any derived key, since "
1272  "password_folder not provided in config file.\n";
1273 
1274  return false;
1275 }
1276 
1277 // static
1278 bool OTKeyring::FlatFile_DeleteSecret(const OTString& strUser,
1279  const std::string& str_display)
1280 {
1281  OT_ASSERT(strUser.Exists());
1282 
1283  const std::string str_pw_folder(OTKeyring::FlatFile_GetPasswordFolder());
1284  if (!str_pw_folder.empty()) {
1285  OTString strExactPath;
1286  strExactPath.Format("%s%s%s", str_pw_folder.c_str(),
1287  OTLog::PathSeparator(), strUser.Get());
1288  const std::string str_ExactPath(strExactPath.Get());
1289 
1290  std::ofstream ofs(str_ExactPath.c_str(),
1291  std::ios::out | std::ios::binary);
1292 
1293  if (ofs.fail()) {
1294  otErr << __FUNCTION__ << ": Error opening file (to delete it): "
1295  << str_ExactPath.c_str() << '\n';
1296  return false;
1297  }
1298  ofs.clear();
1299  ofs << "(This space intentionally left blank.)\n";
1300 
1301  bool bSuccess = ofs.good() ? true : false;
1302  ofs.close();
1303  // Note: I bet you think I should be overwriting the file 7 times here
1304  // with
1305  // random data, right? Wrong: YOU need to override OTKeyring and create
1306  // your
1307  // own subclass, where you can override DeleteSecret and do that stuff
1308  // yourself. It's outside of the scope of OT.
1309 
1310  //
1311  if (remove(str_ExactPath.c_str()) != 0) {
1312  bSuccess = false;
1313  otErr << "** (OTKeyring::FlatFile_DeleteSecret) Failed trying to "
1314  << "delete file (containing secret): "
1315  << str_ExactPath.c_str() << '\n';
1316  }
1317  else {
1318  bSuccess = true;
1319  otInfo << "** (OTKeyring::FlatFile_DeleteSecret) Success "
1320  << "deleting file: " << str_ExactPath.c_str() << '\n';
1321  }
1322 
1323  return bSuccess;
1324  }
1325 
1326  otErr << "OTKeyring::FlatFile_DeleteSecret: Unable to delete any derived "
1327  "key, since password_folder not provided in config file.\n";
1328 
1329  return false;
1330 }
1331 
1332 #endif
1333 
1334 // static
1335 bool OTKeyring::StoreSecret(const OTString& strUser,
1336  const OTPassword& thePassword,
1337  const std::string& str_display)
1338 {
1339  if (OTCachedKey::It()->IsUsingSystemKeyring()) {
1340 #if defined(OT_KEYRING_WINDOWS) && defined(_WIN32)
1341  return OTKeyring::Windows_StoreSecret(strUser, thePassword,
1342  str_display);
1343 #elif defined(OT_KEYRING_MAC) && defined(__APPLE__)
1344  return OTKeyring::Mac_StoreSecret(strUser, thePassword, str_display);
1345 #elif defined(OT_KEYRING_IOS) && defined(__APPLE__)
1346  return OTKeyring::IOS_StoreSecret(strUser, thePassword, str_display);
1347 #elif defined(OT_KEYRING_GNOME)
1348  return OTKeyring::Gnome_StoreSecret(strUser, thePassword, str_display);
1349 #elif defined(OT_KEYRING_KWALLET)
1350  return OTKeyring::KWallet_StoreSecret(strUser, thePassword,
1351  str_display);
1352 #elif defined(OT_KEYRING_FLATFILE)
1353  return OTKeyring::FlatFile_StoreSecret(strUser, thePassword,
1354  str_display);
1355 #else
1356  otErr << "OTKeyring::StoreSecret: WARNING: The OT config file says to "
1357  "use the system keyring, "
1358  "but OT wasn't compiled to support any keyrings.\n";
1359 #endif
1360  }
1361  return false;
1362 }
1363 
1364 // static
1365 bool OTKeyring::RetrieveSecret(const OTString& strUser, OTPassword& thePassword,
1366  const std::string& str_display)
1367 {
1368  if (OTCachedKey::It()->IsUsingSystemKeyring()) {
1369 #if defined(OT_KEYRING_WINDOWS) && defined(_WIN32)
1370  return OTKeyring::Windows_RetrieveSecret(strUser, thePassword,
1371  str_display);
1372 #elif defined(OT_KEYRING_MAC) && defined(__APPLE__)
1373  return OTKeyring::Mac_RetrieveSecret(strUser, thePassword, str_display);
1374 #elif defined(OT_KEYRING_IOS) && defined(__APPLE__)
1375  return OTKeyring::IOS_RetrieveSecret(strUser, thePassword, str_display);
1376 #elif defined(OT_KEYRING_GNOME)
1377  return OTKeyring::Gnome_RetrieveSecret(strUser, thePassword,
1378  str_display);
1379 #elif defined(OT_KEYRING_KWALLET)
1380  return OTKeyring::KWallet_RetrieveSecret(strUser, thePassword,
1381  str_display);
1382 #elif defined(OT_KEYRING_FLATFILE)
1383  return OTKeyring::FlatFile_RetrieveSecret(strUser, thePassword,
1384  str_display);
1385 #else
1386  otErr << "OTKeyring::RetrieveSecret: WARNING: The OT config file says "
1387  "to use the system keyring, "
1388  "but OT wasn't compiled to support any keyrings.\n";
1389 #endif
1390  }
1391  return false;
1392 }
1393 
1394 // static
1395 bool OTKeyring::DeleteSecret(const OTString& strUser,
1396  const std::string& str_display)
1397 {
1398  if (OTCachedKey::It()->IsUsingSystemKeyring()) {
1399 #if defined(OT_KEYRING_WINDOWS) && defined(_WIN32)
1400  return OTKeyring::Windows_DeleteSecret(strUser, str_display);
1401 #elif defined(OT_KEYRING_MAC) && defined(__APPLE__)
1402  return OTKeyring::Mac_DeleteSecret(strUser, str_display);
1403 #elif defined(OT_KEYRING_IOS) && defined(__APPLE__)
1404  return OTKeyring::IOS_DeleteSecret(strUser, str_display);
1405 #elif defined(OT_KEYRING_GNOME)
1406  return OTKeyring::Gnome_DeleteSecret(strUser, str_display);
1407 #elif defined(OT_KEYRING_KWALLET)
1408  return OTKeyring::KWallet_DeleteSecret(strUser, str_display);
1409 #elif defined(OT_KEYRING_FLATFILE)
1410  return OTKeyring::FlatFile_DeleteSecret(strUser, str_display);
1411 #else
1412  otErr << "OTKeyring::DeleteSecret: WARNING: The OT config file says to "
1413  "use the system keyring, "
1414  "but OT wasn't compiled to support any keyrings.\n";
1415 #endif
1416  }
1417  return false;
1418 }
1419 
1420 } // namespace opentxs
static EXPORT const char * PathSeparator()
Definition: OTLog.cpp:408
OTLOG_IMPORT OTLogStream otOut
#define MAX_STRING_LENGTH
Definition: OTString.hpp:147
uint8_t BYTE
Definition: stdafx.hpp:21
static EXPORT std::shared_ptr< OTCachedKey > It(OTIdentifier *pIdentifier=nullptr)
static EXPORT const OTString & AppDataFolder()
Definition: OTPaths.cpp:254
static size_t safe_strlen(const char *s, size_t max)
Definition: OTString.cpp:388
#define OT_ASSERT(x)
Definition: Assert.hpp:150
EXPORT bool EraseValueByKey(std::string strFolder, std::string oneStr="", std::string twoStr="", std::string threeStr="")
Definition: OTStorage.cpp:843
OTLOG_IMPORT OTLogStream otInfo
static EXPORT bool SleepSeconds(int64_t lSeconds)
Definition: OTLog.cpp:640
OTLOG_IMPORT OTLogStream otWarn
OTLOG_IMPORT OTLogStream otErr
static EXPORT bool RetrieveSecret(const OTString &strUser, OTPassword &thePassword, const std::string &str_display)
Definition: OTKeyring.cpp:1365
static EXPORT bool DeleteSecret(const OTString &strUser, const std::string &str_display)
Definition: OTKeyring.cpp:1395
static EXPORT bool StoreSecret(const OTString &strUser, const OTPassword &thePassword, const std::string &str_display)
Definition: OTKeyring.cpp:1335