StringX CPasswordCharPool::MakePassword() const { // We don't care if the policy is inconsistent e.g. // number of lower case chars > 1 + make pronounceable // The individual routines (normal, hex, pronounceable) will // ignore what they don't need. // Saves an awful amount of bother with setting values to zero and // back as the user changes their minds! ASSERT(m_pwlen > 0); ASSERT(m_uselowercase || m_useuppercase || m_usedigits || m_usesymbols || m_usehexdigits || m_pronounceable); // pronounceable and hex passwords are handled separately: if (m_pronounceable) return MakePronounceable(); if (m_usehexdigits) return MakeHex(); vector<typeFreq_s> typeFreqs; if (m_uselowercase) typeFreqs.push_back(typeFreq_s(this, LOWERCASE, m_numlowercase)); if (m_useuppercase) typeFreqs.push_back(typeFreq_s(this, UPPERCASE, m_numuppercase)); if (m_usedigits) typeFreqs.push_back(typeFreq_s(this, DIGIT, m_numdigits)); if (m_usesymbols) typeFreqs.push_back(typeFreq_s(this, SYMBOL, m_numsymbols)); // Sort requested char type in decreasing order // of requested (at least) frequency: sort(typeFreqs.begin(), typeFreqs.end(), [](const typeFreq_s &a, const typeFreq_s &b) { return a.numchars > b.numchars; }); StringX temp; // First meet the 'at least' constraints for (auto iter = typeFreqs.begin(); iter != typeFreqs.end(); iter++) for (uint j = 0; j < iter->numchars; j++) { if (!iter->vchars.empty()) { temp.push_back(iter->vchars.back()); iter->vchars.pop_back(); if (temp.length() == m_pwlen) goto do_shuffle; // break out of two loops, goto needed } } // Now fill in the rest while (temp.length() != m_pwlen) { uint i = PWSrand::GetInstance()->RangeRand(typeFreqs.size()); if (!typeFreqs[i].vchars.empty()) { temp.push_back(typeFreqs[i].vchars.back()); typeFreqs[i].vchars.pop_back(); if (temp.length() == m_pwlen) goto do_shuffle; // break out of two loops, goto needed } } do_shuffle: // If 'at least' values were non-zero, we have some unwanted order, // se we mix things up a bit: RandomWrapper rnw; random_shuffle(temp.begin(), temp.end(), rnw); ASSERT(temp.length() == size_t(m_pwlen)); return temp; }