在没有 Python 的情况下生成 Jupyter Notebook 密码
Generate Jupyter Notebook password without Python
在https://jupyter-docker-stacks.readthedocs.io/en/latest/using/common.html#docker-options之后,您可以定义自己的密码,以便在使用docker图像时启动Jupyter Notebook。
docker run -d -p 8888:8888 jupyter/base-notebook start-notebook.sh --NotebookApp.password='sha1:74ba40f8a388:c913541b7ee99d15d5ed31d4226bf7838f83a50e'
我只能发现可以使用 IPython.lib.passwd() 生成使用过的 salted sha1 密码。但是,如何在不使用 Python 的情况下生成它?我没有 IPython 或者可能只是不知道如何使用它。我在 CentOS Stream。
您可以使用以下小 shell 脚本近似原始密码生成算法:
#!/bin/bash
passphrase="hello, world"
# generate salt
salt=$(openssl rand -hex 6)
# generate hash
algorithm=sha1
echo -n "$(echo ${passphrase} | iconv -t utf-8)${salt}" | openssl dgst -${algorithm} | awk -v alg="${algorithm}" -v salt="${salt}" '{print alg ":" salt ":" $NF}'
为什么这个工作(有点)?
您提到原始密码生成算法是基于IPython.lib.passwd
,实际上是在IPython.lib.security
中实现的。相关代码部分为:
salt_len = 12
h = hashlib.new(algorithm)
salt = ('%0' + str(salt_len) + 'x') % random.getrandbits(4 * salt_len)
h.update(encode(passphrase, 'utf-8') + encode(salt, 'ascii'))
return ':'.join((algorithm, salt, h.hexdigest()))
为了理解这段代码的作用,首先再次查看生成的输出是很有用的。根据您的问题,我们有一个生成密码的示例:
sha1:74ba40f8a388:c913541b7ee99d15d5ed31d4226bf7838f83a50e
冒号将这个字符串分成三部分:
<hashing-algorithm> : <salt> : <hashed salted passphrase>
考虑到这一点,让我们看一下 IPython
代码。在顶部,我们定义了用于盐的字符数。让我们仔细检查 - 是的,确实,在您的示例中,盐由 12 个字符组成:74ba40f8a388
.
接下来,创建哈希算法的新实例 h
。正如我们从您的示例中了解到的,algorithm
参数的值为 "sha1"
.
之后,生成随机盐。现在这条线很有趣。如果您没有 Python 背景,百分号 (%
) 可能会让您想起用于格式化字符串的整数 modulo operator. But in fact, it is not, because the parameter left of the percentage sign is of type string
. So, rather, this is (now kind of obsolete) Python 语法,非常类似于printf
in C
,除了你不限于打印 in Python,你可以在任何有字符串的地方使用这个格式化操作。
鉴于我们知道 salt_len
是 12
,这一行基本上简化为:
salt = '%012x' % random.getrandbits(48)
这意味着盐应该是一个48位的位串,格式为12位十六进制字符串。
为什么是 48 位?嗯,你需要两个十六进制字符来编码一个字节(0x00
到 0xff
),所以如果我们的目标是 12 个字符,我们需要 6 个字节 = 48 位。
return
之前的最后一行将 sha1
算法应用于 utf-8 编码密码短语和 ascii 编码盐的串联。
最后,算法、盐和散列加盐密码作为连接字符串返回,冒号 (:
) 作为分隔符。
现在,如果您检查我在上面发布的shell 脚本,您会发现其中的步骤大致相同。但是有一个显着的区别,这就是为什么我最初写道它只是实际算法的近似值。
区别在于生成盐的方式。虽然结果在这两种情况下都是 12 位十六进制字符串,但 IPython
代码使用 Mersenne-Twister, while my script is based on MD5 散列的实现。这将导致不同的加密属性。
但是你可以自己决定是否接受。不幸的是,我无法获取仅可从命令行获得的 Mersenne Twister 的实现。但是,如果您知道生成盐的好替代方法,请随时更新脚本。它的其余部分应该不会受到影响。
或者,如果您更喜欢没有 openssl 的解决方案,您也可以使用此版本:
#!/bin/bash
passphrase="hello, world"
# generate salt
salt=$(tr -dc a-f0-9 < /dev/urandom | head -c 12)
# generate hash
algorithm=sha1
echo -n "$(echo ${passphrase} | iconv -t utf-8)${salt}" | sha1sum | awk -v alg="${algorithm}" -v salt="${salt}" '{print alg ":" salt ":" }'
但不幸的是,我无法说明通过这种方式 /dev/urandom
生成的盐的属性。
在https://jupyter-docker-stacks.readthedocs.io/en/latest/using/common.html#docker-options之后,您可以定义自己的密码,以便在使用docker图像时启动Jupyter Notebook。
docker run -d -p 8888:8888 jupyter/base-notebook start-notebook.sh --NotebookApp.password='sha1:74ba40f8a388:c913541b7ee99d15d5ed31d4226bf7838f83a50e'
我只能发现可以使用 IPython.lib.passwd() 生成使用过的 salted sha1 密码。但是,如何在不使用 Python 的情况下生成它?我没有 IPython 或者可能只是不知道如何使用它。我在 CentOS Stream。
您可以使用以下小 shell 脚本近似原始密码生成算法:
#!/bin/bash
passphrase="hello, world"
# generate salt
salt=$(openssl rand -hex 6)
# generate hash
algorithm=sha1
echo -n "$(echo ${passphrase} | iconv -t utf-8)${salt}" | openssl dgst -${algorithm} | awk -v alg="${algorithm}" -v salt="${salt}" '{print alg ":" salt ":" $NF}'
为什么这个工作(有点)?
您提到原始密码生成算法是基于IPython.lib.passwd
,实际上是在IPython.lib.security
中实现的。相关代码部分为:
salt_len = 12
h = hashlib.new(algorithm)
salt = ('%0' + str(salt_len) + 'x') % random.getrandbits(4 * salt_len)
h.update(encode(passphrase, 'utf-8') + encode(salt, 'ascii'))
return ':'.join((algorithm, salt, h.hexdigest()))
为了理解这段代码的作用,首先再次查看生成的输出是很有用的。根据您的问题,我们有一个生成密码的示例:
sha1:74ba40f8a388:c913541b7ee99d15d5ed31d4226bf7838f83a50e
冒号将这个字符串分成三部分:
<hashing-algorithm> : <salt> : <hashed salted passphrase>
考虑到这一点,让我们看一下 IPython
代码。在顶部,我们定义了用于盐的字符数。让我们仔细检查 - 是的,确实,在您的示例中,盐由 12 个字符组成:74ba40f8a388
.
接下来,创建哈希算法的新实例 h
。正如我们从您的示例中了解到的,algorithm
参数的值为 "sha1"
.
之后,生成随机盐。现在这条线很有趣。如果您没有 Python 背景,百分号 (%
) 可能会让您想起用于格式化字符串的整数 modulo operator. But in fact, it is not, because the parameter left of the percentage sign is of type string
. So, rather, this is (now kind of obsolete) Python 语法,非常类似于printf
in C
,除了你不限于打印 in Python,你可以在任何有字符串的地方使用这个格式化操作。
鉴于我们知道 salt_len
是 12
,这一行基本上简化为:
salt = '%012x' % random.getrandbits(48)
这意味着盐应该是一个48位的位串,格式为12位十六进制字符串。
为什么是 48 位?嗯,你需要两个十六进制字符来编码一个字节(0x00
到 0xff
),所以如果我们的目标是 12 个字符,我们需要 6 个字节 = 48 位。
return
之前的最后一行将 sha1
算法应用于 utf-8 编码密码短语和 ascii 编码盐的串联。
最后,算法、盐和散列加盐密码作为连接字符串返回,冒号 (:
) 作为分隔符。
现在,如果您检查我在上面发布的shell 脚本,您会发现其中的步骤大致相同。但是有一个显着的区别,这就是为什么我最初写道它只是实际算法的近似值。
区别在于生成盐的方式。虽然结果在这两种情况下都是 12 位十六进制字符串,但 IPython
代码使用 Mersenne-Twister, while my script is based on MD5 散列的实现。这将导致不同的加密属性。
但是你可以自己决定是否接受。不幸的是,我无法获取仅可从命令行获得的 Mersenne Twister 的实现。但是,如果您知道生成盐的好替代方法,请随时更新脚本。它的其余部分应该不会受到影响。
或者,如果您更喜欢没有 openssl 的解决方案,您也可以使用此版本:
#!/bin/bash
passphrase="hello, world"
# generate salt
salt=$(tr -dc a-f0-9 < /dev/urandom | head -c 12)
# generate hash
algorithm=sha1
echo -n "$(echo ${passphrase} | iconv -t utf-8)${salt}" | sha1sum | awk -v alg="${algorithm}" -v salt="${salt}" '{print alg ":" salt ":" }'
但不幸的是,我无法说明通过这种方式 /dev/urandom
生成的盐的属性。