//--------------------------------------------------------------------- bool PeerContactProfile::setPrivateProfile(ElementPtr newProfileElement) { AutoRecursiveLock lock(mLock); if (!mDocument) return false; PeerFilesPtr outer; IPeerFilePrivatePtr privatePeer; if (!isExternal()) { outer = mPeerFiles.lock(); if (!outer) return false; privatePeer = outer->getPrivate(); if (!privatePeer) return false; } try { ElementPtr contactProfileElement = getContactProfileElement(); if (!contactProfileElement) return false; ElementPtr privateElement = contactProfileElement->findFirstChildElementChecked("private"); ElementPtr encryptedProfileElement = privateElement->findFirstChildElement("encryptedProfile"); ElementPtr saltElement = privateElement->findFirstChildElementChecked("salt"); String saltAsBase64 = saltElement->getText(true); if (!newProfileElement) { // erasing the profile element to clean newProfileElement = Element::create(); newProfileElement->setValue("profile"); } DocumentPtr tempDoc = Document::create(); tempDoc->adoptAsLastChild(newProfileElement->clone()); // write out the new value boost::shared_array<char> output = tempDoc->write(); // encrypt it String encryptedProfileAsBase64 = encryptToBase64( "profile", mContactProfileSecret.c_str(), saltAsBase64, (const BYTE *)(output.get()), strlen(output.get()) ); ElementPtr tempNewEncryptedProfileElement = Element::create(); tempNewEncryptedProfileElement->setValue("encryptedProfile"); TextPtr encryptedProfileText = Text::create(); encryptedProfileText->setValue(encryptedProfileAsBase64); tempNewEncryptedProfileElement->adoptAsLastChild(encryptedProfileText); if (encryptedProfileElement) { encryptedProfileElement->adoptAsNextSibling(tempNewEncryptedProfileElement); encryptedProfileElement->orphan(); } else { privateElement->adoptAsLastChild(tempNewEncryptedProfileElement); } // upgrade the document version number UINT version = getVersionNumber(); ++version; contactProfileElement->setAttribute("version", Stringize<UINT>(version).string()); if (!isExternal()) { // now this this must be signed privatePeer->signElement(contactProfileElement); } } catch (zsLib::XML::Exceptions::CheckFailed &) { return false; } return true; }
//--------------------------------------------------------------------- PeerContactProfilePtr PeerContactProfile::createExternalFromPrivateProfile(ElementPtr privateProfileElement) { if (!privateProfileElement) return PeerContactProfilePtr(); privateProfileElement = (privateProfileElement->clone())->toElementChecked(); static const char *contactProfileSkeleton = "<contactProfile version=\"0\">\n" " <private>\n" " <salt />\n" " <proof cipher=\"sha256/aes256\" />\n" " <encryptedProfile cipher=\"sha256/aes256\" />\n" " <contactProfileSecret cipher=\"sha256/aes256\" />\n" " </private>\n" "</contactProfile>"; DocumentPtr contactProfileDoc = Document::create(); contactProfileDoc->parse(contactProfileSkeleton); String contactID = services::IHelper::randomString(32); String contactProfileSecret = services::IHelper::randomString(32); // generate external profile { std::string contactSalt; // generate salt { AutoSeededRandomPool rng; SecureByteBlock contactSaltRaw(32); rng.GenerateBlock(contactSaltRaw, contactSaltRaw.size()); contactSalt = convertToBase64(contactSaltRaw, contactSaltRaw.size()); } ElementPtr contactProfileElement = contactProfileDoc->getFirstChildElementChecked(); contactProfileElement->setAttribute("id", contactID); ElementPtr privateElement = contactProfileElement->getFirstChildElementChecked(); ElementPtr saltElement = privateElement->getFirstChildElementChecked(); TextPtr saltText = Text::create(); saltText->setValue(contactSalt); saltElement->adoptAsLastChild(saltText); SecureByteBlock contactProofHash(32); SHA256 contactProof; contactProof.Update((const BYTE *)"proof:", strlen("proof:")); contactProof.Update((const BYTE *)contactProfileSecret.c_str(), contactProfileSecret.size()); contactProof.Final(contactProofHash); String contactProofInBase64 = convertToBase64(contactProofHash, contactProofHash.size()); ElementPtr proofElement = saltElement->getNextSiblingElementChecked(); TextPtr proofText = Text::create(); proofText->setValue(contactProofInBase64); proofElement->adoptAsLastChild(proofText); DocumentPtr privateProfileDocument = Document::create(); privateProfileDocument->adoptAsLastChild(privateProfileElement); ULONG length = 0; boost::shared_array<char> output; output = privateProfileDocument->write(&length); ElementPtr encryptedProfileElement = proofElement->getNextSiblingElementChecked(); String encryptedProfileString = encryptToBase64("profile", contactProfileSecret, contactSalt, (const BYTE *)(output.get()), length); TextPtr encryptProfileText = Text::create(); encryptProfileText->setValue(encryptedProfileString); encryptedProfileElement->adoptAsLastChild(encryptProfileText); ElementPtr contactProfileSecretElement = encryptedProfileElement->getNextSiblingElementChecked(); TextPtr contactProfileSecretText = Text::create(); contactProfileSecretText->setValue(contactProfileSecret); contactProfileSecretElement->adoptAsLastChild(contactProfileSecretText); } PeerContactProfilePtr pThis(new PeerContactProfile); pThis->mThisWeak = pThis; pThis->mDocument = contactProfileDoc; pThis->mContactProfileSecret = contactProfileSecret; return pThis; }