summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--python/vyos/snmpv3_hashgen.py109
-rwxr-xr-xsrc/conf_mode/snmp.py18
2 files changed, 56 insertions, 71 deletions
diff --git a/python/vyos/snmpv3_hashgen.py b/python/vyos/snmpv3_hashgen.py
index a8300353a..324c3274d 100644
--- a/python/vyos/snmpv3_hashgen.py
+++ b/python/vyos/snmpv3_hashgen.py
@@ -1,65 +1,50 @@
-# Copyright [2017] [Adam Bishop]
+# Copyright 2020 VyOS maintainers and contributors <maintainers@vyos.io>
#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
#
-# http://www.apache.org/licenses/LICENSE-2.0
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# Imported from https://github.com/TheMysteriousX/SNMPv3-Hash-Generator
-
-import hashlib
-import string
-import secrets
-
-from itertools import repeat
-
-P_LEN = 32
-E_LEN = 16
-
-class Hashgen(object):
- @staticmethod
- def md5(bytes):
- return hashlib.md5(bytes).digest().hex()
-
- @staticmethod
- def sha1(bytes):
- return hashlib.sha1(bytes).digest().hex()
-
- @staticmethod
- def expand(s, l):
- reps = l // len(s) + 1 # approximation; worst case: overrun = l + len(s)
- return ''.join(list(repeat(s, reps)))[:l]
-
- @classmethod
- def kdf(cls, password):
- data = cls.expand(password, 1048576).encode('utf-8')
- return hashlib.sha1(data).digest()
-
- @staticmethod
- def random_string(len=P_LEN, alphabet=(string.ascii_letters + string.digits)):
- return ''.join(secrets.choice(alphabet) for _ in range(len))
-
- @staticmethod
- def random_engine(len=E_LEN):
- return secrets.token_hex(len)
-
- @classmethod
- def derive_msg(cls, passphrase, engine):
- # Parameter derivation รก la rfc3414
- Ku = cls.kdf(passphrase)
- E = bytearray.fromhex(engine)
-
- return b''.join([Ku, E, Ku])
-
- # Define available hash algorithms
- algs = {
- 'sha1': sha1,
- 'md5': md5,
- }
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library. If not, see <http://www.gnu.org/licenses/>.
+
+# Documentation / Inspiration
+# - https://tools.ietf.org/html/rfc3414#appendix-A.3
+# - https://github.com/TheMysteriousX/SNMPv3-Hash-Generator
+
+key_length = 1048576
+
+def random(l):
+ # os.urandom(8) returns 8 bytes of random data
+ import os
+ from binascii import hexlify
+ return hexlify(os.urandom(l)).decode('utf-8')
+
+def expand(s, l):
+ """ repead input string (s) as long as we reach the desired length in bytes """
+ from itertools import repeat
+ reps = l // len(s) + 1 # approximation; worst case: overrun = l + len(s)
+ return ''.join(list(repeat(s, reps)))[:l].encode('utf-8')
+
+def plaintext_to_md5(passphrase, engine):
+ """ Convert input plaintext passphrase to MD5 hashed version usable by net-snmp """
+ from hashlib import md5
+ tmp = expand(passphrase, key_length)
+ hash = md5(tmp).digest()
+ engine = bytearray.fromhex(engine)
+ out = b''.join([hash, engine, hash])
+ return md5(out).digest().hex()
+
+def plaintext_to_sha1(passphrase, engine):
+ """ Convert input plaintext passphrase to SHA1hashed version usable by net-snmp """
+ from hashlib import sha1
+ tmp = expand(passphrase, key_length)
+ hash = sha1(tmp).digest()
+ engine = bytearray.fromhex(engine)
+ out = b''.join([hash, engine, hash])
+ return sha1(out).digest().hex()
diff --git a/src/conf_mode/snmp.py b/src/conf_mode/snmp.py
index f3c91d987..e9806ef47 100755
--- a/src/conf_mode/snmp.py
+++ b/src/conf_mode/snmp.py
@@ -20,7 +20,7 @@ from sys import exit
from vyos.config import Config
from vyos.configverify import verify_vrf
-from vyos.snmpv3_hashgen import Hashgen
+from vyos.snmpv3_hashgen import plaintext_to_md5, plaintext_to_sha1, random
from vyos.template import render
from vyos.util import call
from vyos.validate import is_ipv4, is_addr_assigned
@@ -86,9 +86,8 @@ def get_config():
snmp['version'] = version_data['version']
# create an internal snmpv3 user of the form 'vyosxxxxxxxxxxxxxxxx'
- # os.urandom(8) returns 8 bytes of random data
- snmp['vyos_user'] = 'vyos' + Hashgen.random_string(len=8)
- snmp['vyos_user_pass'] = Hashgen.random_string(len=16)
+ snmp['vyos_user'] = 'vyos' + random(8)
+ snmp['vyos_user_pass'] = random(16)
if conf.exists('community'):
for name in conf.list_nodes('community'):
@@ -524,19 +523,20 @@ def generate(snmp):
os.environ["vyos_libexec_dir"] = "/usr/libexec/vyos"
for user in snmp['v3_users']:
- hash = Hashgen.sha1 if user['authProtocol'] in 'sha1' else Hashgen.md5
+ if user['authProtocol'] == 'sha':
+ hash = plaintext_to_sha1
+ else:
+ hash = plaintext_to_md5
if user['authPassword']:
- Kul_auth = Hashgen.derive_msg(user['authPassword'], snmp['v3_engineid'])
- user['authMasterKey'] = hash(Kul_auth)
+ user['authMasterKey'] = hash(user['authPassword'], snmp['v3_engineid'])
user['authPassword'] = ''
call('/opt/vyatta/sbin/my_set service snmp v3 user "{name}" auth encrypted-password "{authMasterKey}" > /dev/null'.format(**user))
call('/opt/vyatta/sbin/my_delete service snmp v3 user "{name}" auth plaintext-password > /dev/null'.format(**user))
if user['privPassword']:
- Kul_priv = Hashgen.derive_msg(user['privPassword'], snmp['v3_engineid'])
- user['privMasterKey'] = hash(Kul_priv)
+ user['privMasterKey'] = hash(user['privPassword'], snmp['v3_engineid'])
user['privPassword'] = ''
call('/opt/vyatta/sbin/my_set service snmp v3 user "{name}" privacy encrypted-password "{privMasterKey}" > /dev/null'.format(**user))