cancel
Showing results for 
Search instead for 
Did you mean: 
cancel
1978
Views
1
Helpful
20
Replies

type6 passwords

emilgamal
Level 1
Level 1

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

@vleijon @Marcel Zehnder

20 Replies 20

Marcel Zehnder
Spotlight
Spotlight

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.

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
!
!
'''

Marcel Zehnder
Spotlight
Spotlight

Will dig into it.

Marcel Zehnder
Spotlight
Spotlight

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>

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
 !
!

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

Arrgh, overlooked this...sorry about that!

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
!
!

Marcel Zehnder
Spotlight
Spotlight

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}")

Marcel Zehnder
Spotlight
Spotlight

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.

Does this mean that no way to calculate the password6 with Python and then send it to the router?

 

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).

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?

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 {
...