
# गैर-विंडोज़ प्लेटफ़ॉर्म के लिए Python DPAPI NG डिक्रिप्टर
DPAPI NG के लिए लाइब्रेरी, जिसे CNG DPAPI भी कहा जाता है, Python में डी- और एन्क्रिप्शन के लिए। इसे NCryptUnprotectSecret और NCryptProtectSecret के व्यवहार को दोहराने के लिए डिज़ाइन किया गया है। इसका उपयोग गैर-विंडोज़ होस्ट पर DPAPI NG संरक्षित रहस्यों को डी-/एन्क्रिप्ट करने के लिए किया जा सकता है, जैसे PFX उपयोगकर्ता संरक्षित पासवर्ड, या LAPS एन्क्रिप्टेड पासवर्ड। यह या तो डोमेन की रूट की की ऑफ़लाइन प्रति का उपयोग करके किसी भी DPAPI NG ब्लॉब को डिक्रिप्ट कर सकता है या आपूर्ति किए गए उपयोगकर्ता के क्रेडेंशियल का उपयोग करके RPC के माध्यम से आवश्यक जानकारी प्राप्त करके डी-/एन्क्रिप्ट कर सकता है।
वर्तमान में केवल ये सुरक्षा डिस्क्रिप्टर समर्थित हैं:
| Type | Purpose |
|---|---|
| SID | केवल SID उपयोगकर्ता या SID समूह के सदस्य ही गोपनीय जानकारी को डिक्रिप्ट कर सकते हैं |
यह MS-GKDI ग्रुप की डिस्ट्रीब्यूशन प्रोटोकॉल को लागू करता है।
सभी बुनियादी सुविधाओं के साथ dpapi-ng इंस्टॉल करने के लिए, यह चलाएँ:
python -m pip install dpapi-ng
केर्बेरोस प्रमाणीकरण समर्थन डिफ़ॉल्ट रूप से इंस्टॉल नहीं किया जाएगा क्योंकि यह सिस्टम लाइब्रेरी और एक मान्य कंपाइलर की उपस्थिति पर निर्भर करता है। krb5 लाइब्रेरी और कंपाइलर को इन पैकेजों को इंस्टॉल करके स्थापित किया जा सकता है:
# Debian/Ubuntu
apt-get install gcc python3-dev libkrb5-dev
# Centos/RHEL
yum install gcc python-devel krb5-devel
# Fedora
dnf install gcc python-devel krb5-devel
# Arch Linux
pacman -S gcc krb5
एक बार इंस्टॉल हो जाने पर, केर्बेरोस Python एक्स्ट्रा को इसके साथ इंस्टॉल किया जा सकता है:
python -m pip install dpapi-ng[kerberos]
केर्बेरोस को डोमेन से संवाद करने के लिए भी कॉन्फ़िगर करने की आवश्यकता होती है, लेकिन यह इस पृष्ठ के दायरे से बाहर है।
git clone https://github.com/jborean93/dpapi-ng.git
cd dpapi-ng
pip install -e .
ब्लॉब को डी-/एन्क्रिप्ट करने के लिए एक सिंक और asyncio API दोनों उपलब्ध हैं।
import dpapi_ng
### DECRYPTION ###
dpapi_ng_blob = b"..."
decrypted_blob = dpapi_ng.ncrypt_unprotect_secret(dpapi_ng_blob)
# async equivalent to the above
decrypted_blob = await dpapi_ng.async_ncrypt_unprotect_secret(dpapi_ng_blob)
### ENCRYPTION ###
data = b"..."
target_sid = "S-1-5-21-XXXXXXXXXX-XXXXXXXXXX-XXXXXXXXXX-XXXX"
dpapi_ng_blob = dpapi_ng.ncrypt_protect_secret(data, target_sid)
# async equivalent to the above
dpapi_ng_blob = await dpapi_ng.async_ncrypt_protect_secret(data, target_sid)
ब्लॉब को डिक्रिप्ट करने के लिए, ब्लॉब में निर्दिष्ट कुंजी को उस डोमेन नियंत्रक से प्राप्त करने की आवश्यकता होती है जिसके द्वारा ब्लॉब उत्पन्न किया गया था।
ब्लॉब को एन्क्रिप्ट करने के लिए, निर्दिष्ट लक्ष्य SID की ग्रुप कुंजी प्राप्त करने की आवश्यकता होती है।
डिक्रिप्शन के लिए, डोमेन नियंत्रक का होस्टनाम DPAPI-NG ब्लॉब में पाए गए डोमेन नाम के साथ _ldap._tcp.dc._msdcs.{domain_name} की DNS SRV लुकअप के माध्यम से स्वचालित रूप से प्राप्त किया जाता है या server kwarg में निर्दिष्ट मान के साथ।
एन्क्रिप्शन के लिए, डोमेन नियंत्रक का होस्टनाम या तो DNS SRV लुकअप के लिए domain_name kwarg का उपयोग करके, सीधे server kwarg का उपयोग करके, या सिस्टम के खोज डोमेन (यदि उपलब्ध हो) का उपयोग करके निर्धारित किया जाता है।
यह वर्तमान उपयोगकर्ता पहचान के साथ प्रमाणित करने का प्रयास करेगा, जो Linux पर केवल तभी मौजूद होगी यदि उपयोगकर्ता का टिकट प्राप्त करने के लिए kinit पहले ही कॉल किया जा चुका है।
अन्यथा यदि कोई पहचान उपलब्ध नहीं है, तो कस्टम उपयोगकर्ता निर्दिष्ट करने के लिए username और password kwargs का उपयोग किया जा सकता है।
निम्नलिखित kwargs का उपयोग ncrypt_unprotect_secret, async_ncrypt_unprotect_secret, ncrypt_protect_secret और async_ncrypt_protect_secret के लिए किया जा सकता है।
server: यदि कोई कुंजी प्राप्त करने की आवश्यकता हो तो इस सर्वर को RPC लक्ष्य के रूप में उपयोग करेंusername: RPC कनेक्शन के लिए प्रमाणित होने हेतु उपयोगकर्ता नामpassword: RPC कनेक्शन के लिए प्रमाणित करने हेतु पासवर्डauth_protocol: RPC कनेक्शन के लिए उपयोग किया जाने वाला प्रमाणीकरण प्रोटोकॉल (negotiate, kerberos, ntlm)cache: भविष्य के संचालन के लिए प्राप्त कुंजियों को संग्रहीत करने हेतु एक कैशइसके अलावा, ncrypt_protect_secret और async_ncrypt_protect_secret निम्नलिखित अतिरिक्त kwarg लेते हैं।
domain_name: कुंजी जानकारी प्राप्त करते समय उपयोग करने हेतु RPC लक्ष्य की खोज करते समय उपयोग किए जाने वाले डोमेन/फ़ॉरेस्ट का नामroot_key_identifier: रूट कुंजी पहचानकर्ता UUID, इन फ़ंक्शनों के लिए कैश को कार्यशील बनाने के लिए आवश्यकडोमेन में संग्रहीत रूट कुंजी प्रदान करके DPAPI-NG ब्लॉब को एन्क्रिप्ट और डिक्रिप्ट करना भी संभव है। इसे या तो ऑफ़लाइन हमले का उपयोग करके या डोमेन व्यवस्थापक उपयोगकर्ता के रूप में चलने पर LDAP क्वेरी के माध्यम से प्राप्त किया जा सकता है। PowerShell का उपयोग करके डोमेन रूट कुंजियों को प्राप्त करने के लिए निम्नलिखित चलाया जा सकता है:
$configurationContext = (Get-ADRootDSE).configurationNamingContext
$getParams = @{
LDAPFilter = '(objectClass=msKds-ProvRootKey)'
SearchBase = "CN=Master Root Keys,CN=Group Key Distribution Service,CN=Services,$configurationContext"
SearchScope = 'OneLevel'
Properties = @(
'cn'
'msKds-KDFAlgorithmID'
'msKds-KDFParam'
'msKds-SecretAgreementAlgorithmID'
'msKds-SecretAgreementParam'
'msKds-PrivateKeyLength'
'msKds-PublicKeyLength'
'msKds-RootKeyData'
)
}
Get-ADObject @getParams | ForEach-Object {
[PSCustomObject]@{
Version = 1
RootKeyId = [Guid]::new($_.cn)
KdfAlgorithm = $_.'msKds-KDFAlgorithmID'
KdfParameters = [System.Convert]::ToBase64String($_.'msKds-KDFParam')
SecretAgreementAlgorithm = $_.'msKds-SecretAgreementAlgorithmID'
SecretAgreementParameters = [System.Convert]::ToBase64String($_.'msKds-SecretAgreementParam')
PrivateKeyLength = $_.'msKds-PrivateKeyLength'
PublicKeyLength = $_.'msKds-PublicKeyLength'
RootKeyData = [System.Convert]::ToBase64String($_.'msKds-RootKeyData')
}
}
विंडोज़ के बाहर निम्नलिखित ldapsearch कमांड का उपयोग किया जा सकता है:
ldapsearch \
-b 'CN=Master Root Keys,CN=Group Key Distribution Service,CN=Services,CN=Configuration,DC=domain,DC=test' \
-s one \
'(objectClass=msKds-ProvRootKey)' \
cn \
msKds-KDFAlgorithmID \
msKds-KDFParam \
msKds-SecretAgreementAlgorithmID \
msKds-SecretAgreementParam \
msKds-PrivateKeyLength \
msKds-PublicKeyLength \
msKds-RootKeyData
नोट: सफल होने के लिए ldapsearch को संभवतः -H और यूज़र बाइंड जानकारी की आवश्यकता होगी।
वहाँ से प्राप्त जानकारी को कैश में संग्रहीत किया जा सकता है और बाद के ncrypt_protect_secret और ncrypt_unprotect_secret कॉल के लिए उपयोग किया जा सकता है:
import uuid
import dpapi_ng
cache = dpapi_ng.KeyCache()
root_key_id = uuid.UUID("76ec8b2d-d444-4f67-9db7-2f62b4358b35")
cache.load_key(
b"...", # msKds-RootKeydata
root_key_id, # cn
version=1,
kdf_algorithm="SP800_108_CTR_HMAC", # msKds-KDFAlgorithmID
kdf_parameters=b"...", # msKds-KDFParam
secret_algorithm="DH", # mskds-SecretAgreementAlgorithmID
secret_parameters=b"...", # msKds-SecretAgreementParam
private_key_length=512, # msKds-PrivateKeyLength
public_key_length=2048, # msKds-PublicKeyLength
)
dpapi_ng.ncrypt_unprotect_secret(b"...", cache=cache)
वर्तमान में SP800_108_CTR_HMAC KDF एल्गोरिथम और DH, ECDH_P256, और ECDH_P384 सीक्रेट एग्रीमेंट एल्गोरिथम को कार्य करने के लिए परीक्षण किया गया है।
ECDH_P521 सीक्रेट एग्रीमेंट एल्गोरिथम को भी कार्य करना चाहिए, लेकिन इसका परीक्षण नहीं किया गया है क्योंकि अभी इसके साथ परीक्षण वातावरण नहीं बनाया जा सकता है।
मैं इस परियोजना पर उनकी मदद के लिए निम्नलिखित लोगों (कोष्ठक में GitHub या Twitter हैंडल) को धन्यवाद देना चाहता हूँ:
उनके धैर्य और ज्ञान के बिना यह संभवतः संभव नहीं होता।