如何在Python中用Base64编码long?

2024-04-20 06:12:20 发布

您现在位置:Python中文网/ 问答频道 /正文

在Java中,我可以将BigInteger编码为:

java.math.BigInteger bi = new java.math.BigInteger("65537L");
String encoded = Base64.encodeBytes(bi.toByteArray(), Base64.ENCODE|Base64.DONT_GUNZIP);

// result: 65537L encodes as "AQAB" in Base64

byte[] decoded = Base64.decode(encoded, Base64.DECODE|Base64.DONT_GUNZIP);
java.math.BigInteger back = new java.math.BigInteger(decoded);

在C#:

System.Numerics.BigInteger bi = new System.Numerics.BigInteger("65537L");
string encoded = Convert.ToBase64(bi);
byte[] decoded = Convert.FromBase64String(encoded);
System.Numerics.BigInteger back = new System.Numerics.BigInteger(decoded);

如何将Python中的长整数编码为Base64编码字符串?到目前为止,我所尝试的结果与其他语言的实现不同(到目前为止,我在Java和C#中也尝试过),特别是它产生了较长长度的Base64编码字符串。

import struct
encoded = struct.pack('I', (1<<16)+1).encode('base64')[:-1]
# produces a longer string, 'AQABAA==' instead of the expected 'AQAB'

当使用此Python代码生成Base64编码的字符串时,Java中生成的解码整数(例如)将代替预期的65537生成16777472。首先,我遗漏了什么?

其次,我必须手工确定在struct.pack中使用的长度格式是什么;如果我试图编码一个长数字(大于(1<<64)-1),那么'Q'格式规范太短,无法容纳表示。这是否意味着我必须手工进行表示,或者是否存在用于struct.pack函数的未记录格式说明符?(我并不是被迫使用struct,但乍一看,它似乎做了我需要的事情。)


Tags: 字符串编码newmathjavasystemstructpack
3条回答

^{} module

… performs conversions between Python values and C structs represented as Python strings.

因为C没有无限长的整数,所以没有打包它们的功能。

但你自己写起来很容易。例如:

def pack_bigint(i):
    b = bytearray()
    while i:
        b.append(i & 0xFF)
        i >>= 8
    return b

或:

def pack_bigint(i):
    bl = (i.bit_length() + 7) // 8
    fmt = '<{}B'.format(bl)
    # ...

等等。

当然,您还需要一个unpack函数,就像jbatista的注释:

def unpack_bigint(b):
    b = bytearray(b) # in case you're passing in a bytes/str
    return sum((1 << (bi*8)) * bb for (bi, bb) in enumerate(b))

现在有点晚了,但我想我应该把帽子扔进戒指里:

def inttob64(n):                                                              
    """                                                                       
    Given an integer returns the base64 encoded version of it (no trailing ==)
    """
    parts = []                                                                
    while n:                                                                  
        parts.insert(0,n & limit)                                             
        n >>= 32                                                              
    data = struct.pack('>' + 'L'*len(parts),*parts)                           
    s = base64.urlsafe_b64encode(data).rstrip('=')                            
    return s                                                                  

def b64toint(s):                                                              
    """                                                                       
    Given a string with a base64 encoded value, return the integer representation
    of it                                                                     
    """                                                                       
    data = base64.urlsafe_b64decode(s + '==')                                 
    n = 0                                                                     
    while data:                                                               
        n <<= 32                                                              
        (toor,) = struct.unpack('>L',data[:4])                                
        n |= toor & 0xffffffff                                                
        data = data[4:]                                                       
    return n

这些函数将任意大小的长数字转换为/从大端base64表示。

converting integer to base64上查看此页。

import base64
import struct

def encode(n):
    data = struct.pack('<Q', n).rstrip('\x00')
    if len(data)==0:
        data = '\x00'
    s = base64.urlsafe_b64encode(data).rstrip('=')
    return s

def decode(s):
    data = base64.urlsafe_b64decode(s + '==')
    n = struct.unpack('<Q', data + '\x00'* (8-len(data)) )
    return n[0]

相关问题 更多 >