Loading src/admin.cpp +7 −1 Changes for src/admin.cpp: 7 added lines, 1 removed line. Original line number Diff line number Diff line Loading @@ -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); } Loading src/krb5.cpp +67 −37 Changes for src/krb5.cpp: 67 added lines, 37 removed lines. Original line number Diff line number Diff line Loading @@ -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, Loading Loading @@ -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, Loading Loading @@ -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); Loading @@ -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; } } } Loading Loading @@ -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 { Loading @@ -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; } } Loading Loading
src/admin.cpp +7 −1 Changes for src/admin.cpp: 7 added lines, 1 removed line. Original line number Diff line number Diff line Loading @@ -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); } Loading
src/krb5.cpp +67 −37 Changes for src/krb5.cpp: 67 added lines, 37 removed lines. Original line number Diff line number Diff line Loading @@ -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, Loading Loading @@ -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, Loading Loading @@ -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); Loading @@ -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; } } } Loading Loading @@ -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 { Loading @@ -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; } } Loading