90021


環境 python3.8.3

**bycryptから抜粋**

[code]

    def gensalt(rounds: int = 12, prefix: bytes = b"2b") -> bytes:
        if prefix not in (b"2a", b"2b"):
            raise ValueError("Supported prefixes are b'2a' or b'2b'")
    
        if rounds < 4 or rounds > 31:
            raise ValueError("Invalid rounds")
    
        salt = os.urandom(16)
        output = _bcrypt.ffi.new("char[]", 30)
        _bcrypt.lib.encode_base64(output, salt, len(salt))
    
        return (
            b"$"
            + prefix
            + b"$"
            + ("%2.2u" % rounds).encode("ascii")
            + b"$"
            + _bcrypt.ffi.string(output)
        )
    
[/code]

### わからないこと

  1. 上記のbcryptから抜粋したコード`_bcrypt.lib.encode_base64(output, salt, len(salt))`にて`output`の処理後の値が認識と合わない.
  2. `_bcrypt.ffi.new("char[]", 30)`の部分のコードの理解ができていない.

### 現在の解釈

  1. `encode_base64`とのことなので`os.urandom`で取得した16byteをbase64にエンコードしている解釈.  
試しに以下のコードを実行したが、同値ならないので自分の解釈が間違っている模様.

**コード**

[code]     import os

    from base64 import b64encode
    salt = os.urandom(16)
    output = _bcrypt.ffi.new("char[]", 16)
    _bcrypt.lib.encode_base64(output, salt, len(salt))
    print(b64encode(salt).decode('utf-8'))
    print(_bcrypt.ffi.string(output))
    
[/code]

**アウトプット**

[code]     b64encode: +cyf2Ik/7hDgLbukT3dlRQ==

    _bcrypt  : b'8awd0Gi95fBeJZsi'
    
[/code]

  2. C言語のポインタのようにメモリ確保を実施していると解釈.  
今回は16byteの`urandom`なのでなぜ30byteも用意しているのか不明(余分にしても多すぎな感じ).

### 試したこと

  1.     * デバッグツールpdbで中身を見る. 
      * 対象の関数にステップインできなったので諦めた.
    * 入力値を固定`salt= b'\x1f'`などにして関数の処理後に値を確認して際から判断. 
      * 同じ値が流れるだけで進展なし.

説明不足の部分もあると思いますので情報が足りない場合は質問を重ねていただいて問題ありません.  
もしも、自己解決した際は共有いたします.


CC BY-SA 4.0
2022-07-16T06:38:09.130
90016
2022-07-16T09:11:32.990
2022-07-16T09:11:32.990
3060
53554
question
python python3
Python bcryptの内容が理解できない


「bcrypt」 は <https://github.com/pyca/bcrypt> のバージョン 3.2.2 を指すものとします。

### 実装はC言語

Pythonのデバッガで対象の関数にステップインできなかったのは、C言語で実装されているから  
です。  
ソース:
[`encode_base64`](https://github.com/pyca/bcrypt/blob/3.2.2/src/_csrc/bcrypt.c#L240)

### Base64で使われる記号表が非標準的

`_bcrypt.lib.encode_base64` と `b64encode` の結果が異なるのは、bcrypt
が[使っている文字テーブル](https://github.com/pyca/bcrypt/blob/3.2.2/src/_csrc/bcrypt.c#L178)が標準的なものと違うからです。また、`=`
によるパディングも行なわれていません。

確認コード:

[code]

    from base64 import b64encode
    from bcrypt import _bcrypt
    
    table = str.maketrans(
        "./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",
    )
    
    salt = b"1234567890123456"
    
    output = _bcrypt.ffi.new("char[]", 30)
    _bcrypt.lib.encode_base64(output, salt, len(salt))
    
    by_stdlib = b64encode(salt).decode("utf-8")
    by_bcrypt_orig = _bcrypt.ffi.string(output).decode("utf-8")
    by_bcrypt_trans = by_bcrypt_orig.translate(table)
    
    print("by_stdlib:       ", by_stdlib)
    print("by_bcrypt_trans: ", by_bcrypt_trans)
    print("by_bcrypt_orig:  ", by_bcrypt_orig)
    
    
[/code]

結果:

[code]

    by_stdlib:        MTIzNDU2Nzg5MDEyMzQ1Ng==
    by_bcrypt_trans:  MTIzNDU2Nzg5MDEyMzQ1Ng
    by_bcrypt_orig:   KRGxLBS0Lxe3KBCwKxOzLe
    
[/code]

### 多めのメモリ確保は、Base64にすると膨らむから

メモリ確保が16byteより多いのは、Base64にすると膨らむからでしょう。まあ30byteは必要なさそうですが、そこは適当なのではないでしょうか。


CC BY-SA 4.0
2022-07-16T09:04:20.883
90021
2022-07-16T09:04:20.883
3054
90016
answer