09-12-2023 01:41 AM
Hello,
I developed an NSO service to configure a keychains on CiscoXR router "CiscoXR 7.4.2 version". NED is not allowing me to send the keystring as cleartext.
'''
<keychain>
<chain-name>{chain_name}</chain-name>
<keys>
<key>
<key-id>1</key-id>
<key-string>
<key-string>{keystring}</key-string>
<encrypt-type>type6</encrypt-type>
</key-string>
'''
NED restricting me to send encryption type6 or type7. but when i try to set it to type6 or type7, i found it sent to the router only in type7!
Is there any work arounds that makes me able to send the keystring as type6?
I also tried to write a python function that takes the keystring as plaintext and the master-key and encrypt it to calculate the type6 keystring. Any help to fix it?
My python code
def encrypt_cbc(): secret = "0123456789abcdef" msg = "1234567890123456" iv = os.urandom(16) #iv = "7bde5a0f3f39fd658efc45de143cbc94" cipher = AES.new(str.encode(secret), AES.MODE_CBC, iv) cipher_text = cipher.encrypt(str.encode(msg)) cipher_text = base64.b16encode(cipher_text) cipher_text = str(cipher_text) cipher_text = cipher_text.replace("'", "", 2) cipher_text = cipher_text.replace("b", "") print(cipher_text.lower())
Expected to get: 4a60445b64695661635f67524a59575f55615047605d624b4e64605e654f4e56584d6062424d68514e62414142
But the code gives: 6cfdab2dcd7308cdb14a629a14b82597
09-13-2023 09:05 AM
Can you post the code of your service? I have no issues sending clear text passwords to XR boxex (running 7.4.1 code, using NED cisco-iosxr-cli-7.44).
I tested it with a simple service as follows.
YANG-Model:
module testkeyring {
namespace "http://com/example/testkeyring";
prefix testkeyring;
import ietf-inet-types {
prefix inet;
}
import tailf-ncs {
prefix ncs;
}
list testkeyring {
key name;
uses ncs:service-data;
ncs:servicepoint "testkeyring";
leaf name {
type string;
}
// may replace this with other ways of refering to the devices.
leaf-list device {
type leafref {
path "/ncs:devices/ncs:device/ncs:name";
}
}
// replace with your own stuff here
leaf cleartextpassword {
type string;
}
}
}
Template:
<config-template xmlns="http://tail-f.com/ns/config/1.0" servicepoint="testkeyring">
<devices xmlns="http://tail-f.com/ns/ncs">
<device>
<name>{/device}</name>
<config>
<key xmlns="http://tail-f.com/ned/cisco-ios-xr">
<chain>
<name>TEST</name>
<key>
<id>1</id>
<key-string>
<password>{/cleartextpassword}</password>
</key-string>
</key>
</chain>
</key>
</config>
</device>
</devices>
</config-template>
Output
developer@ncs(config)# testkeyring BLA device core-rtr02 cleartextpassword mycleartextpassword
developer@ncs(config-testkeyring-BLA)# commit dry-run outformat xml
result-xml {
local-node {
data <devices xmlns="http://tail-f.com/ns/ncs">
<device>
<name>core-rtr02</name>
<config>
<key xmlns="http://tail-f.com/ned/cisco-ios-xr">
<chain>
<name>TEST</name>
<key>
<id>1</id>
<key-string>
<password>mycleartextpassword</password>
</key-string>
</key>
</chain>
</key>
</config>
</device>
</devices>
<testkeyring xmlns="http://com/example/testkeyring">
<name>BLA</name>
<device>core-rtr02</device>
<cleartextpassword>mycleartextpassword</cleartextpassword>
</testkeyring>
}
}
developer@ncs(config-testkeyring-BLA)# commit
Commit complete.
09-13-2023 10:53 AM
Hello Marcel,
Thank you for your support, In my use case it is required to use Netconf NED, not using CLI NED.
I'm searchig for one from the below options:
option1: method that help me to push the keystring as cleartext to router using the Netconf NED.
option2: method to create the type6 keystring with like a python function then send it to the router.
option3: Any method to fit with the solution
Below is my service configuration:
'''
Template:
<?xml version="1.0" encoding="UTF-8"?>
<config-template xmlns="http://tail-f.com/ns/config/1.0">
<devices xmlns="http://tail-f.com/ns/ncs">
<device>
<name>{/device}</name>
<config>
<keychains xmlns="http://cisco.com/ns/yang/Cisco-IOS-XR-lib-keychain-cfg">
<keychain>
<chain-name>test</chain-name>
<keys>
<key>
<key-id>1</key-id>
<key-string>
<key-string>{keystring}</key-string>
<encrypt-type>type6</encrypt-type>
</key-string>
</key>
</keys>
</keychain>
</keychains>
</config>
</device>
</devices>
</config-template>
'''
'''
YANG-MODEL:
module key_chains {
namespace "http://com/example/key_chains";
prefix key_chains;
import ietf-inet-types {
prefix inet;
}
import tailf-ncs {
prefix ncs;
}
list key_chains {
key name;
uses ncs:service-data;
ncs:servicepoint "key_chains";
leaf name {
type string;
}
// may replace this with other ways of refering to the devices.
leaf-list device {
type leafref {
path "/ncs:devices/ncs:device/ncs:name";
}
}
leaf keystring {
type string;
}
}
}
'''
'''
OUTPUT:
RP/0/RP0/CPU0:R1#show running-config key chain
Wed Sep 13 19:47:41.759 CEST
key chain test
key 1
key-string password6 1234567890123456
!
!
'''
09-13-2023 10:56 AM
Will dig into it.
09-15-2023 05:29 AM - edited 09-15-2023 05:35 AM
Hi @emilgamal
I had no time to check this in NSO, but from looking at the IOS-XR 7.4.2 YANG modules, I see the key-string is of type Proprietary-password:
(default) maercu@CHLT303344:~/dev/yang/vendor/cisco/xr/742$ pyang Cisco-IOS-XR-lib-keychain-cfg.yang -f tree --tree-path /keychains/keychain/keys/key/key-string/key-string
module: Cisco-IOS-XR-lib-keychain-cfg
+--rw keychains
+--rw keychain* [chain-name]
+--rw keys
+--rw key* [key-id]
+--rw key-string
+--rw key-string? xr:Proprietary-password
(default) maercu@CHLT303344:~/dev/yang/vendor/cisco/xr/742$ grep -A 51 Proprietary-password Cisco-IOS-XR-types.yang
typedef Proprietary-password {
type string {
pattern "(!.+)|([^!].+)";
}
description
"The Proprietary-password type is used to store password
using the Cisco proprietary hash function.
When a clear text value is set to a leaf of this type, the
server calculates a password hash and stores the result
in the datastore. The password is never stored in clear text.
When a leaf of this type is read, the stored password hash is
returned.
A value of this type matches one of the forms:
!<clear text password>
<password hash>
The '!' prefix signals that the value is clear text. When
such a value is received by the server, a hash value is
calculated. This value is stored in the configuration data
store.
If a value starting without '!' is received, the server knows
that the value already represents a hashed value, and stores
it as is in the data store.";
}
typedef Type6-password {
type string {
pattern "(!.+)|([^!].+)";
}
description
"The Type6-password type is used to store password
using the Cisco type 6 hash function.
When a clear text value is set to a leaf of this type, the
server calculates a password hash and stores the result
in the datastore. The password is never stored in clear text.
When a leaf of this type is read, the stored password hash is
returned.
A value of this type matches one of the forms:
!<clear text password>
<password hash>
The '!' prefix signals that the value is clear text. When
such a value is received by the server, a hash value is
calculated. This value is stored in the configuration data
store.
If a value starting without '!' is received, the server knows
that the value already represents a hashed value, and stores
it as is in the data store.";
}
So, I would try set the encrypt-type to type6 and enter the key-string with the "!"-prefix, according the YANG module, the XR box should automatically create the hash for the password provided:
<keychains xmlns="http://cisco.com/ns/yang/Cisco-IOS-XR-lib-keychain-cfg">
<keychain>
<chain-name>test</chain-name>
<keys>
<key>
<key-id>1</key-id>
<key-string>
<key-string>!thecleartextpassword</key-string>
<encrypt-type>type6</encrypt-type>
</key-string>
</key>
</keys>
</keychain>
</keychains>
09-15-2023 06:08 AM
I tested the above in plain NETCONF, seems to work:
from ncclient import manager
from rich import print as pp
username = "admin"
password = "C1sco12345"
host = "sandbox-iosxr-1.cisco.com"
with manager.connect(host=host, username=username, password=password, hostkey_verify=False) as m:
cfg = """
<config xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
<keychains xmlns="http://cisco.com/ns/yang/Cisco-IOS-XR-lib-keychain-cfg">
<keychain>
<chain-name>TEST</chain-name>
<keys>
<key>
<key-id>1</key-id>
<key-string>
<key-string>!test</key-string>
<encrypt-type>type6</encrypt-type>
</key-string>
</key>
</keys>
</keychain>
</keychains>
</config>
"""
reply = m.edit_config(cfg,target="candidate")
if reply.ok:
pp(reply.xml)
m.commit()
(default) maercu@CHLT303344:~/dev/ciscocomtest$ python keychaintest.py
<?xml version="1.0"?>
<rpc-reply message-id="urn:uuid:da2c8ad6-bbea-48ab-b4dd-2b4168d476ea"
xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
<ok/>
</rpc-reply>
RP/0/RP0/CPU0:ansible-cisco.iosxr.iosxr#sh run key chain
Fri Sep 15 13:01:19.864 UTC
key chain TEST
key 1
key-string password6 111D1C1603
!
!
09-15-2023 06:18 AM
Hello Marcel,
I made the same steps but noticed that the encrypted password 111D1C1603 is encrypted as type7, not as type6
if you checked it online with this site it will decrypt it as type7 https://www.firewall.cx/cisco/cisco-routers/cisco-type7-password-crack.html
this is the issue, how to make the NSO encrypt type6 passwords or even send the key string as plaintext and let the router encrypt it as type6
09-15-2023 06:25 AM
Arrgh, overlooked this...sorry about that!
09-15-2023 06:23 AM
If you configured the router through CLI:
you will find the router encrypted the password as type6 as per below
RP/0/RP0/CPU0:R1#config
Fri Sep 15 15:20:49.971 CEST
RP/0/RP0/CPU0:R1(config)#key chain test
RP/0/RP0/CPU0:R1(config-test)#key 1
RP/0/RP0/CPU0:R1(config-test-1)#key-string clear test
RP/0/RP0/CPU0:R1(config-test-1)#commit
Fri Sep 15 15:21:09.572 CEST
RP/0/RP0/CPU0:R1#show running-config key chain test
Fri Sep 15 15:21:24.135 CEST
key chain test
key 1
key-string password6 564c634450664f5760535559645c4342536451676250445b414142
!
!
09-15-2023 12:05 PM
For the password generation, maybe this code helps (pycryptodome library):
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
from Crypto.Random import get_random_bytes
import hashlib
import base64
def encrypt(key, iv, text):
text = text.encode()
cipher = AES.new(key, AES.MODE_CBC, iv)
return cipher.encrypt(pad(text, AES.block_size))
def decrypt(key, iv, ciphertext):
cipher = AES.new(key, AES.MODE_CBC, iv)
return unpad(cipher.decrypt(ciphertext), AES.block_size).decode()
if __name__ == "__main__":
iv = get_random_bytes(16)
password = "somePasswordOfAnySize"
key = hashlib.sha256(password.encode()).digest()
# or static key of 16 bytes
#key = "0123456789abcdef".encode()
text = "1234567890123456"
ciphertext = encrypt(key, iv, text)
print(f"ciphertext in bytes: {ciphertext}")
print(f"ciphertext in hex: {base64.b16encode(ciphertext).decode().lower()}")
plaintext = decrypt(key, iv, ciphertext)
print(f"plaintext after decryption: {plaintext}")
09-16-2023 01:20 AM
BTW: Are you sure CBC mode is correct? I thought CTR mode is used in type 6.
What I'm asking myself - does this even work creating secrets external to the box? How would the box be able to decrypt such a ciphertext - the password is configured as master password on the box, but what about the IV (CBC) or nounce (CTR) used for the encryption? Without knowing these the box would never be able to get the cleartext value of a ciphertext.
09-16-2023 03:37 AM
Does this mean that no way to calculate the password6 with Python and then send it to the router?
09-16-2023 04:52 AM
Well, I‘m by far no securety expert, but from an AES point of view I doubt this works. From my point of view the router must encrypt the keystring local with his masterkey + IV or nounce (I think the details describing the creation of the type6 secret are not even public available).
09-16-2023 05:09 AM
OK, so I think the only way is to send the key-string as plaintext to the router.
is there any work around to do that with the Netconf NED?
09-19-2023 01:07 AM
I believe NSO will not do anything to the string you configured with the key-string leaf and will send it to the device as-is.
container key-string {
description
"Configure a clear text/encrypted Key string ";
leaf key-string {
type xr:Proprietary-password;
description
"Key String";
}
...
typedef Proprietary-password {
type string {
...
Discover and save your favorite ideas. Come back to expert answers, step-by-step guides, recent topics, and more.
New here? Get started with these tips. How to use Community New member guide