Commit 4e0ca38a authored by jan.koester's avatar jan.koester
Browse files

bugfix fold algo krb5

parent 8c5160bb
Loading
Loading
Loading
Loading
Loading
+7 −1
Changes for src/admin.cpp: 7 added lines, 1 removed line.
Original line number Diff line number Diff line
@@ -466,9 +466,15 @@ namespace authdb {
                        std::transform(realm.begin(), realm.end(), realm.begin(),
                                       [](unsigned char c){ return std::toupper(c); });
                        std::string salt = realm + uname;
                        std::cerr << "[ADMIN] editUser krbkey: realm=" << realm
                                  << " uname=" << uname << " salt=" << salt
                                  << " rawpw.len=" << editRawPw.size() << std::endl;
                        auto krbKeyBytes = Krb5Crypto::string2key(
                            editRawPw, salt, KRB5_ENCTYPE_AES256_CTS_HMAC_SHA1);
                        udat.setKrbKey(hexEncode(krbKeyBytes));
                        std::string hexKey = hexEncode(krbKeyBytes);
                        std::cerr << "[ADMIN] editUser krbkey: hex=" << hexKey.substr(0, 32)
                                  << "... len=" << krbKeyBytes.size() << std::endl;
                        udat.setKrbKey(hexKey);
                        upos = sizeof(AuthHeader);
                        user.edit(*backend, udat, upos);
                    }
+67 −37
Changes for src/krb5.cpp: 67 added lines, 37 removed lines.
Original line number Diff line number Diff line
@@ -2163,50 +2163,54 @@ Krb5EncType Krb5Crypto::selectEncType(const std::vector<Krb5EncType> &etypes) {

std::vector<uint8_t> Krb5Crypto::nfold(const std::vector<uint8_t> &input, size_t nbytes) {
    /*
     * n-fold operation from RFC 3961 §5.1
     * Folds inbits into nbytes*8 bits using right-rotation and addition mod 2^8
     * n-fold operation – direct port of MIT krb5int_nfold (nfold.c).
     * input length = inbits (in bytes); output = nbytes bytes (outbits bits).
     */
    size_t inbits = input.size() * 8;
    size_t outbits = nbytes * 8;
    size_t total_bits = lcm(inbits, outbits);
    int inbytes  = static_cast<int>(input.size());
    int outbytes = static_cast<int>(nbytes);

    std::vector<uint8_t> result(nbytes, 0);
    /* lcm(inbytes, outbytes) */
    int a = outbytes, b = inbytes, c;
    while (b != 0) { c = b; b = a % b; a = c; }
    int lcmVal = outbytes * inbytes / a;

    for (size_t i = 0; i < total_bits / inbits; ++i) {
        /* Rotate input right by 13*i bits */
        size_t shift = (13 * i) % inbits;
        std::vector<uint8_t> rotated(input.size(), 0);
    std::vector<uint8_t> out(outbytes, 0);
    int byte = 0;

        for (size_t j = 0; j < inbits; ++j) {
            size_t src_bit = (j + shift) % inbits;
            size_t src_byte = src_bit / 8;
            size_t src_boff = 7 - (src_bit % 8);
            size_t dst_byte = j / 8;
            size_t dst_boff = 7 - (j % 8);
            if (input[src_byte] & (1 << src_boff))
                rotated[dst_byte] |= (1 << dst_boff);
        }
    for (int i = lcmVal - 1; i >= 0; --i) {
        /* compute the msbit in k which gets added into this byte */
        int msbit = (
            ((inbytes << 3) - 1)
            + (((inbytes << 3) + 13) * (i / inbytes))
            + ((inbytes - (i % inbytes)) << 3)
        ) % (inbytes << 3);

        /* Add rotated to result with carry, aligned from the right */
        uint16_t carry = 0;
        for (int k = static_cast<int>(nbytes) - 1; k >= 0; --k) {
            size_t rot_byte = rotated.size() - 1 - (((nbytes - 1 - k) % rotated.size()));
            uint16_t sum = static_cast<uint16_t>(result[k]) +
                           static_cast<uint16_t>(rotated[rot_byte]) + carry;
            result[k] = static_cast<uint8_t>(sum & 0xFF);
            carry = sum >> 8;
        }
        /* Propagate final carry */
        if (carry) {
            for (int k = static_cast<int>(nbytes) - 1; k >= 0 && carry; --k) {
                uint16_t sum = static_cast<uint16_t>(result[k]) + carry;
                result[k] = static_cast<uint8_t>(sum & 0xFF);
                carry = sum >> 8;
        /* pull out the byte value itself */
        int idx1 = ((inbytes - 1) - (msbit >> 3)) % inbytes;
        int idx2 = ((inbytes) - (msbit >> 3)) % inbytes;
        if (idx1 < 0) idx1 += inbytes;
        if (idx2 < 0) idx2 += inbytes;
        byte += (((input[idx1] << 8) | input[idx2])
                  >> ((msbit & 7) + 1)) & 0xff;

        /* do the addition */
        byte += out[i % outbytes];
        out[i % outbytes] = byte & 0xff;

        /* keep around the carry bit, if any */
        byte >>= 8;
    }

    /* if there's a carry bit left over, add it back in */
    if (byte) {
        for (int i = outbytes - 1; i >= 0; --i) {
            byte += out[i];
            out[i] = byte & 0xff;
            byte >>= 8;
        }
    }

    return result;
    return out;
}

std::vector<uint8_t> Krb5Crypto::dk(const std::vector<uint8_t> &key,
@@ -2275,10 +2279,28 @@ std::vector<uint8_t> Krb5Crypto::string2key(const std::string &password,
    std::vector<uint8_t> saltBytes(salt.begin(), salt.end());
    auto tkey = pbkdf2HmacSha1(password, saltBytes, iterations, kLen);

    /* DEBUG: dump PBKDF2 output */
    {
        std::cerr << "[KDC] string2key: password=\"" << password
                  << "\" salt=\"" << salt << "\" kLen=" << kLen << std::endl;
        std::cerr << "[KDC] string2key: PBKDF2 tkey=";
        for (auto b : tkey) std::cerr << std::hex << std::setfill('0') << std::setw(2) << (int)b;
        std::cerr << std::dec << std::endl;
    }

    /* DK(tkey, "kerberos") */
    std::string kerbStr = "kerberos";
    std::vector<uint8_t> kerbConst(kerbStr.begin(), kerbStr.end());
    return dk(tkey, kerbConst, kLen);
    auto finalKey = dk(tkey, kerbConst, kLen);

    /* DEBUG: dump final key */
    {
        std::cerr << "[KDC] string2key: final key=";
        for (auto b : finalKey) std::cerr << std::hex << std::setfill('0') << std::setw(2) << (int)b;
        std::cerr << std::dec << std::endl;
    }

    return finalKey;
}

std::vector<uint8_t> Krb5Crypto::deriveKey(const std::vector<uint8_t> &baseKey,
@@ -2943,6 +2965,8 @@ std::vector<uint8_t> Krb5KDC::handleStandardAsReq(const uint8_t *data, size_t le

                if (pdType == KRB5_PADATA_ENC_TIMESTAMP && !pdValue.empty()) {
                    foundPaEncTimestamp = true;
                    std::cerr << "[KDC] PA-ENC-TIMESTAMP found, pdValue.size=" << pdValue.size()
                              << " client_key.size=" << client_key.size() << std::endl;
                    try {
                        auto pa_plain = Krb5Crypto::decrypt(client_key, pdValue,
                                                             KRB5_KU_AS_REQ_PA_ENC_TS);
@@ -2955,8 +2979,9 @@ std::vector<uint8_t> Krb5KDC::handleStandardAsReq(const uint8_t *data, size_t le
                                paVerified = true;
                            }
                        }
                    } catch (const AuthBackendError &) {
                    } catch (const AuthBackendError &e) {
                        /* Decryption failed = wrong key */
                        std::cerr << "[KDC] PA-ENC-TIMESTAMP decrypt FAILED: " << e.what() << std::endl;
                    }
                }
            }
@@ -3502,6 +3527,10 @@ bool Krb5KDC::lookupUser(AuthBackend &backend, const Krb5Principal &principal,
                     * compatibility with users created before krbkey support.
                     */
                    std::string krbkeyHex = udat.getKrbKey();
                    std::cerr << "[KDC] lookupUser: principal=" << principal.name
                              << " realm=" << principal.realm
                              << " krbkeyHex.len=" << krbkeyHex.size()
                              << " krbkeyHex=" << krbkeyHex.substr(0, 32) << "..." << std::endl;
                    if (!krbkeyHex.empty()) {
                        key = hexDecode(krbkeyHex);
                    } else {
@@ -3510,6 +3539,7 @@ bool Krb5KDC::lookupUser(AuthBackend &backend, const Krb5Principal &principal,
                        key = Krb5Crypto::string2key(pwhash, salt,
                                                      KRB5_ENCTYPE_AES256_CTS_HMAC_SHA1);
                    }
                    std::cerr << "[KDC] lookupUser: key.size=" << key.size() << std::endl;
                    return true;
                }
            }