Rclone でファイル名を暗号化するときの長さ
Rclone の crypt
仮想リモート1を使うと、ファイル内容とパス文字列を暗号化してのアップロードができます。
ファイル名を暗号化した場合、元のファイル名より一般に長くなるため、クラウドストレージで許容されるファイル名の長さを超えてしまう可能性があります。
ローカルのファイル名がこれを越さないように linting したかったため、計算式を作成しました。
計算式
obfuscate
(難読化モード)は使用せず、standard
モードでファイル名を暗号化するときのファイル名の長さを計算してみます。
Rclone は、暗号化前に PKCS#7 を使用して平文ファイル名を 16 バイトの倍数にパディングします。その後、256 ビットキーの AES を使用して EME (ECB-Mix-ECB) で暗号化します(ここでの長さの変化は無し)。暗号化後の文字列表現では、デフォルトで Base32 が使用されます。
以下は Python での計算実装です。
def crypt_filename_length(n_bytes, encoding="base32"):
# 元ファイル名長 + 1 を切りのいい 16 倍数で切り上げ
a = n_bytes + 1
p = a % 16
if p:
a += 16 - p
# 各エンコーディング方式による膨張
if encoding == "base32":
b, q = divmod(a * 8, 5)
elif encoding == "base64":
b, q = divmod(a * 8, 6)
elif encoding == "base32768":
b, q = divmod(a * 16, 15)
if q:
b += 1
return b
ドキュメントに元のファイル名長は 143 バイトまでであるべきと書かれている1のは、Base32 エンコーディングのときに、大抵のストレージで安全な 255 バイトに収まるのが 143 バイトまでだからです。
>>> crypt_filename_length(143)
231
>>> crypt_filename_length(144)
256
その他考慮点
文字列エンコードオプションとして、Base32 のほかに Base64, Base32768(ファイル名を UTF-16 で保存するストレージ向け)が使用できます。
Case-sensitive なクラウドストレージは結構あるようなので、Base64 を使用してファイル名を短くできないか検討してみると良いでしょう。例えば、InfiniCLOUD (旧 TeraCLOUD)2 は、case-sensitive なストレージです。
Base64 の場合、175 バイトのファイル名までは 255 に収まります。
>>> crypt_filename_length(175, encoding="base64")
235
>>> crypt_filename_length(176, encoding="base64")
256
ちなみに、Base64 で使用される記号文字は -
と _
です。
ディレクトリ名も同じルールで計算できます。暗号化はノードごとに行われるため、パス名の長さはディレクトリ階層ごとにディレクトリ名長を計算してセパレータ /
の数を含めて合計します。
クラウドストレージでは、ファイル名(リーフ名)の長さだけでなく、パス全体の長さも制限されている場合があるため、そちらも確認すると良いでしょう。
ここは国内企業かつ国内保存で、容量あたりの料金が安いので気に入っていますが、URI 文脈で使われる一部メタ記号を含むファイル名を正しく処理できない不具合が存在するので、ファイル名暗号化が別の意味で役に立ちます。 ↩︎