パスワードに従って文字列をエンコードする簡単な方法は?


122

Pythonには、パスワードを使用して文字列をエンコード/デコードする組み込みの簡単な方法がありますか?

このようなもの:

>>> encode('John Doe', password = 'mypass')
'sjkl28cn2sx0'
>>> decode('sjkl28cn2sx0', password = 'mypass')
'John Doe'

したがって、「John Doe」という文字列は「sjkl28cn2sx0」として暗号化されます。元の文字列を取得するには、ソースコードのパスワードであるキー「mypass」でその文字列を「ロック解除」します。これを、Word文書をパスワードで暗号化/復号化できる方法にしたいのですが。

これらの暗号化された文字列をURLパラメータとして使用したいと思います。私の目標は、強力なセキュリティではなく難読化です。ミッションクリティカルなものがエンコードされていません。データベーステーブルを使用してキーと値を格納できることはわかっていますが、最小限に抑えようとしています。


28
ここでの「パスワード」という用語は不適切です。あなたは、暗号鍵としてこれを使用している、あなたはなど、あなたの質問だけでなく、任意のドキュメント、コメント、仕様、テスト計画、で回避の混乱にその用語を使用する必要があります
ジム・デニス

2
「Word文書をパスワードで暗号化/復号化できる方法にしたいのですが。」Word文書だけを暗号化する必要がある場合、Wordには既に文書を暗号化するオプションが組み込まれています
Byron Filer 2016年

2
興味深いことに、このようなパスワードストレージの落とし穴に関するこのリサーチペーパーによると、Stack Overflowを使用する開発者は安全性の低いコードを生成する傾向があります。ああ、なんでかしら?
フォレスト

また、security.SE
kelalaka

単にエンコーディング/デコーディングを実装するだけではありません
luckyging3r

回答:


70

あなたが非常にカジュアルなオブザーバーから物事をあいまいにする単純な難読化だけを探していると仮定し、サードパーティのライブラリを使用するつもりはないと仮定します。Vigenere暗号のようなものをお勧めします。これは、単純な古代暗号の中で最強の1つです。

Vigenère暗号

すばやく簡単に実装できます。何かのようなもの:

import base64

def encode(key, string):
    encoded_chars = []
    for i in xrange(len(string)):
        key_c = key[i % len(key)]
        encoded_c = chr(ord(string[i]) + ord(key_c) % 256)
        encoded_chars.append(encoded_c)
    encoded_string = "".join(encoded_chars)
    return base64.urlsafe_b64encode(encoded_string)

デコードはキーを差し引くことを除いてほとんど同じです。

エンコードする文字列が短い場合、および/または使用されるパスフレーズの長さを推測するのが難しい場合は、解読がはるかに困難になります。

暗号化されたものを探している場合は、おそらくPyCryptoが最善の策ですが、以前の回答ではいくつかの詳細を見落としていました。PyCryptoのECBモードでは、メッセージの長さが16文字の倍数である必要があります。だから、パディングする必要があります。また、URLパラメータとして使用するbase64.urlsafe_b64_encode()場合は、標準のパラメータではなくを使用します。これは、base64アルファベットのいくつかの文字をURLセーフな文字に置き換えます(名前が示すとおり)。

ただし、これを使用する前に、この非常に薄い難読化の層で十分であることが確実にわかるはずです。私がリンクしたWikipediaの記事には、暗号を解読するための詳細な手順が記載されているため、適度な決意を持っていれば誰でも簡単に解読できます。


6
私はsmehmoodのスクリプトを修正し、デコード関数gist.github.com/ilogik/6f9431e4588015ecb194
Adrian Mester

3
注意!smehmoodのコードとAdrian Mesterの修正はどちらも、低いASCII範囲の文字を含む文字列に対してのみ機能します。%演算子の優先順位、Unicode入力などを参照してください。実際のコードについては、qneillの回答を参照してください
le_m

2
@smehmood次のエラーが発生します'str' object cannot be interpreted as an integer
Rohit Khatri

3
「for i in xrange(string)」は「for i in xrange(len(string))」に変更する必要があるかもしれません
user3113626

2
:パイソン2および3のエンコーダおよびデコーダgist.github.com/gowhari/fea9c559f08a310e5cfd62978bc86a1a
イマン

71

セキュリティではなく不明瞭にしたいことを明示的に述べているので、提案されている内容の弱点を非難することは避けます:)

したがって、PyCryptoを使用します。

import base64
from Crypto.Cipher import AES

msg_text = b'test some plain text here'.rjust(32)
secret_key = b'1234567890123456'

cipher = AES.new(secret_key,AES.MODE_ECB) # never use ECB in strong systems obviously
encoded = base64.b64encode(cipher.encrypt(msg_text))
print(encoded)
decoded = cipher.decrypt(base64.b64decode(encoded))
print(decoded)

誰かがデータベースとコードベースを手に入れれば、暗号化されたデータをデコードすることができます。secret_key安全に保管してください。


3
AES暗号化には16の倍数の長さのブロックが必要なので、msg_textが16バイトの倍数の長さでない限り、これは機能しないと思います。任意の長さのmsg_textの実際の実装では、長さが16の倍数になるように文字列にパディングを追加する必要があります。
tohster 2013

6
パディングの例:paste.ubuntu.com/11024555任意のパスワードとメッセージ長で機能します。
イマン

3
@いいえ、この特定のencrypt関数はステートフルなdlitz.net/software/pycrypto/api/current/…なので、再利用しないでください。
ウィル

1
@Will +1情報とリンクをありがとう。将来、非常に高価なバグ修正から救われました。
イーサン、

3
re-「明らかにECBを強力なシステムで使用しないでください」:私は自分の楽しみのためにこれを実験しているだけです。しかし、私はあなたのコードに上記のコメントを見ました。最小限のセキュリティ/暗号化/情報理論の背景を持つ私たちにとって、なぜ「使用しない」のですか?多分別の質問が必要です...または多分それにリンクがあります。
Trevor Boyd Smith

68

Pythonには組み込みの暗号化スキームはありません。また、暗号化されたデータストレージを真剣に考えるべきです。1人の開発者が安全でないと理解している簡単な暗号化スキームとおもちゃのスキームは、経験の浅い開発者が安全なスキームと間違える可能性があります。暗号化する場合は、適切に暗号化してください。

ただし、適切な暗号化スキームを実装するために多くの作業を行う必要はありません。まず、暗号化ホイールを再発明せずに、信頼できる暗号化ライブラリを使用してこれを処理します。Python 3の場合、その信頼できるライブラリはcryptographyです。

暗号化と復号化をバイトに適用することもお勧めします。最初にテキストメッセージをバイトにエンコードします。stringvalue.encode()UTF8にエンコードし、を使用して簡単に再び元に戻すことができbytesvalue.decode()ます。

最後に重要なことですが、暗号化と復号化では、パスワードではなくキーについて説明します。鍵は人間が覚えやすいものではなく、秘密の場所に保存されているもので、機械が読み取れるものです。一方、パスワードは人間が読み取ったり記憶したりすることができます。少し注意して、パスワードからキー派生させることができます。

しかし、人間の注意を払わずにクラスターで実行されているWebアプリケーションまたはプロセスを実行し続けるには、キーを使用します。パスワードは、エンドユーザーだけが特定の情報にアクセスする必要がある場合に使用します。それでも、通常はパスワードでアプリケーションを保護し、ユーザーアカウントに関連付けられているキーを使用して暗号化された情報を交換します。

対称鍵暗号化

Fernet – AES CBC + HMAC、強く推奨

cryptographyライブラリは、Fernetレシピ、暗号を使用するためのベスト・プラクティスのレシピを。Fernetはオープンスタンダードであり、幅広いプログラミング言語ですぐに実装でき、バージョン情報、タイムスタンプ、およびHMAC署名とともにAES CBC暗号化をパッケージ化して、メッセージの改ざんを防止します。

Fernetは、暗号化と復号化のメッセージを非常に簡単にそれを作る、あなたがセキュアに保ちます。シークレットでデータを暗号化するための理想的な方法です。

を使用Fernet.generate_key()して安全な鍵を生成することをお勧めします。パスワードも使用できます(次のセクション)が、完全な32バイトの秘密鍵(暗号化に16バイト、さらに署名用に16バイト)は、考えられるほとんどのパスワードよりも安全です。

Fernetが生成するキーは、bytesURLとファイルセーフのbase64文字を持つオブジェクトなので、印刷可能です。

from cryptography.fernet import Fernet

key = Fernet.generate_key()  # store in a secure location
print("Key:", key.decode())

メッセージを暗号化または復号化するにFernet()は、指定されたキーでインスタンスを作成し、Fernet.encrypt()またはを呼び出します。Fernet.decrypt()暗号化するプレーンテキストメッセージと暗号化されたトークンの両方がbytesオブジェクトです。

encrypt()そして、decrypt()機能は次のようになります。

from cryptography.fernet import Fernet

def encrypt(message: bytes, key: bytes) -> bytes:
    return Fernet(key).encrypt(message)

def decrypt(token: bytes, key: bytes) -> bytes:
    return Fernet(key).decrypt(token)

デモ:

>>> key = Fernet.generate_key()
>>> print(key.decode())
GZWKEhHGNopxRdOHS4H4IyKhLQ8lwnyU7vRLrM3sebY=
>>> message = 'John Doe'
>>> encrypt(message.encode(), key)
'gAAAAABciT3pFbbSihD_HZBZ8kqfAj94UhknamBuirZWKivWOukgKQ03qE2mcuvpuwCSuZ-X_Xkud0uWQLZ5e-aOwLC0Ccnepg=='
>>> token = _
>>> decrypt(token, key).decode()
'John Doe'

パスワード付きのFernet –パスワードから派生したキーは、セキュリティを多少弱めます

強力な鍵導出方法使用している場合は、秘密鍵の代わりにパスワードを使用できます。次に、メッセージにソルトとHMAC反復カウントを含める必要があるため、暗号化された値は、ソルト、カウント、およびフェルネットトークンを最初に分離しない限り、フェルネット互換ではなくなります。

import secrets
from base64 import urlsafe_b64encode as b64e, urlsafe_b64decode as b64d

from cryptography.fernet import Fernet
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC

backend = default_backend()
iterations = 100_000

def _derive_key(password: bytes, salt: bytes, iterations: int = iterations) -> bytes:
    """Derive a secret key from a given password and salt"""
    kdf = PBKDF2HMAC(
        algorithm=hashes.SHA256(), length=32, salt=salt,
        iterations=iterations, backend=backend)
    return b64e(kdf.derive(password))

def password_encrypt(message: bytes, password: str, iterations: int = iterations) -> bytes:
    salt = secrets.token_bytes(16)
    key = _derive_key(password.encode(), salt, iterations)
    return b64e(
        b'%b%b%b' % (
            salt,
            iterations.to_bytes(4, 'big'),
            b64d(Fernet(key).encrypt(message)),
        )
    )

def password_decrypt(token: bytes, password: str) -> bytes:
    decoded = b64d(token)
    salt, iter, token = decoded[:16], decoded[16:20], b64e(decoded[20:])
    iterations = int.from_bytes(iter, 'big')
    key = _derive_key(password.encode(), salt, iterations)
    return Fernet(key).decrypt(token)

デモ:

>>> message = 'John Doe'
>>> password = 'mypass'
>>> password_encrypt(message.encode(), password)
b'9Ljs-w8IRM3XT1NDBbSBuQABhqCAAAAAAFyJdhiCPXms2vQHO7o81xZJn5r8_PAtro8Qpw48kdKrq4vt-551BCUbcErb_GyYRz8SVsu8hxTXvvKOn9QdewRGDfwx'
>>> token = _
>>> password_decrypt(token, password).decode()
'John Doe'

出力にソルトを含めると、ランダムなソルト値を使用できるようになり、パスワードの再利用やメッセージの繰り返しに関係なく、暗号化された出力が完全にランダムになることが保証されます。反復カウントを含めることで、古いメッセージを復号化する機能を失うことなく、時間の経過とともにCPUパフォーマンスの向上に調整できます。

同様のサイズのプールから適切にランダムなパスワードを生成すれば、パスワードだけで、Fernet 32​​バイトのランダムキーと同じくらい安全です。32バイトで256 ^ 32のキー数が得られるため、74文字のアルファベット(上26、下26、10桁、可能な記号12)を使用する場合、パスワードは少なくともmath.ceil(math.log(256 ** 32, 74))== 42文字にする必要があります。ただし、適切に選択された多数のHMAC反復により、エントロピーの欠如をある程度緩和できます。これにより、攻撃者がブルートフォース攻撃を仕掛けるのが非常に高価になるためです。

短くても適度に安全なパスワードを選択しても、このスキームが機能しなくなることはありません。ブルートフォース攻撃者が検索しなければならない可能性のある値の数が減るだけです。セキュリティ要件に対応できる十分強力なパスワードを選択してください

代替案

あいまい

代わりの方法は暗号化しないことです。Vignereは、セキュリティの低い暗号だけを使用したり、自作の実装を使用したりしないでください。これらのアプローチにはセキュリティはありませんが、コードを保守するタスクを経験の浅い開発者に与えて、セキュリティの幻想を与える可能性があります。

必要なのが不明瞭な場合は、データをbase64するだけです。URLセーフ要件の場合、base64.urlsafe_b64encode()関数は問題ありません。ここではパスワードを使用せず、エンコードするだけで完了です。せいぜい、いくつかの圧縮を追加します(などzlib):

import zlib
from base64 import urlsafe_b64encode as b64e, urlsafe_b64decode as b64d

def obscure(data: bytes) -> bytes:
    return b64e(zlib.compress(data, 9))

def unobscure(obscured: bytes) -> bytes:
    return zlib.decompress(b64d(obscured))

このターンb'Hello world!'b'eNrzSM3JyVcozy_KSVEEAB0JBF4='

完全性のみ

必要なのは、データが信頼できないクライアントに送信されて受信された後、データが変更されないように信頼できることを確認する方法だけである場合、データに署名する必要がある場合は、SHA1でこのhmacライブラリを使用できます(まだHMAC署名用に安全であると考えられている)以上:

import hmac
import hashlib

def sign(data: bytes, key: bytes, algorithm=hashlib.sha256) -> bytes:
    assert len(key) >= algorithm().digest_size, (
        "Key must be at least as long as the digest size of the "
        "hashing algorithm"
    )
    return hmac.new(key, data, algorithm).digest()

def verify(signature: bytes, data: bytes, key: bytes, algorithm=hashlib.sha256) -> bytes:
    expected = sign(data, key, algorithm)
    return hmac.compare_digest(expected, signature)

これを使用してデータに署名し、署名をデータに添付して、クライアントに送信します。データを受け取ったら、データと署名を分割して検証します。デフォルトのアルゴリズムをSHA256に設定したので、32バイトの鍵が必要になります。

key = secrets.token_bytes(32)

これをさまざまな形式でシリアル化および非シリアル化してパッケージ化したitsdangerousライブラリを確認することをお勧めします。

AES-GCM暗号化を使用して暗号化と整合性を提供する

FernetはHMAC署名付きのAEC-CBC上に構築され、暗号化されたデータの整合性を保証します。暗号文が署名されているため、悪意のある攻撃者がシステムの無意味なデータをフィードして、不正な入力のあるサークルでサービスをビジー状態に保つことはできません。

ガロア/カウンタモードでブロック暗号は、暗号文と生成タグと同じ目的を果たすために、これと同じ目的を果たすために使用することができます。欠点は、Fernetとは異なり、使いやすい万能のレシピが他のプラットフォームで再利用できないことです。AES-GCMもパディングを使用しないため、この暗号化暗号文は入力メッセージの長さと一致します(Fernet / AES-CBCはメッセージを固定長のブロックに暗号化し、メッセージの長さを多少不明瞭にします)。

AES256-GCMは、通常の32バイトの秘密をキーとして使用します。

key = secrets.token_bytes(32)

次に使用します

import binascii, time
from base64 import urlsafe_b64encode as b64e, urlsafe_b64decode as b64d

from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.backends import default_backend
from cryptography.exceptions import InvalidTag

backend = default_backend()

def aes_gcm_encrypt(message: bytes, key: bytes) -> bytes:
    current_time = int(time.time()).to_bytes(8, 'big')
    algorithm = algorithms.AES(key)
    iv = secrets.token_bytes(algorithm.block_size // 8)
    cipher = Cipher(algorithm, modes.GCM(iv), backend=backend)
    encryptor = cipher.encryptor()
    encryptor.authenticate_additional_data(current_time)
    ciphertext = encryptor.update(message) + encryptor.finalize()        
    return b64e(current_time + iv + ciphertext + encryptor.tag)

def aes_gcm_decrypt(token: bytes, key: bytes, ttl=None) -> bytes:
    algorithm = algorithms.AES(key)
    try:
        data = b64d(token)
    except (TypeError, binascii.Error):
        raise InvalidToken
    timestamp, iv, tag = data[:8], data[8:algorithm.block_size // 8 + 8], data[-16:]
    if ttl is not None:
        current_time = int(time.time())
        time_encrypted, = int.from_bytes(data[:8], 'big')
        if time_encrypted + ttl < current_time or current_time + 60 < time_encrypted:
            # too old or created well before our current time + 1 h to account for clock skew
            raise InvalidToken
    cipher = Cipher(algorithm, modes.GCM(iv, tag), backend=backend)
    decryptor = cipher.decryptor()
    decryptor.authenticate_additional_data(timestamp)
    ciphertext = data[8 + len(iv):-16]
    return decryptor.update(ciphertext) + decryptor.finalize()

Fernetがサポートするのと同じ存続時間のユースケースをサポートするために、タイムスタンプを含めました。

このページの他のアプローチ、Python 3

AES CFB- CBCに似ていますが、パディングする必要がありません

これは、正しくありませんが、AllІѕVаиітyが従うアプローチです。これはcryptographyバージョンですが、IVを暗号文含めます。IVをグローバルとして保存しないでください(IVを再利用すると、キーのセキュリティが低下します。モジュールをグローバルとして保存すると、再生成されます次のPython呼び出し、すべての暗号文を解読不能にする):

import secrets
from base64 import urlsafe_b64encode as b64e, urlsafe_b64decode as b64d

from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.backends import default_backend

backend = default_backend()

def aes_cfb_encrypt(message, key):
    algorithm = algorithms.AES(key)
    iv = secrets.token_bytes(algorithm.block_size // 8)
    cipher = Cipher(algorithm, modes.CFB(iv), backend=backend)
    encryptor = cipher.encryptor()
    ciphertext = encryptor.update(message) + encryptor.finalize()
    return b64e(iv + ciphertext)

def aes_cfb_decrypt(ciphertext, key):
    iv_ciphertext = b64d(ciphertext)
    algorithm = algorithms.AES(key)
    size = algorithm.block_size // 8
    iv, encrypted = iv_ciphertext[:size], iv_ciphertext[size:]
    cipher = Cipher(algorithm, modes.CFB(iv), backend=backend)
    decryptor = cipher.decryptor()
    return decryptor.update(encrypted) + decryptor.finalize()

これにはHMAC署名の追加のアーマーがなく、タイムスタンプはありません。それらを自分で追加する必要があります。

上記は、基本的な暗号化ビルディングブロックを誤って組み合わせることがいかに簡単かを示しています。ІѕVаиітyによるIV値の不適切な処理は、IVが失われるため、データ侵害またはすべての暗号化されたメッセージの読み取り不能につながる可能性があります。代わりにFernetを使用することで、そのような間違いからあなたを守ります。

AES ECB – 安全ではない

以前にAES ECB暗号化を実装していて、これをPython 3で引き続きサポートする必要がある場合も、同様にそれを行うことができますcryptography同じ警告が適用され、ECBは実際のアプリケーションに対して十分に安全ではありません。その答えをPython 3に再実装して、パディングの自動処理を追加します。

from base64 import urlsafe_b64encode as b64e, urlsafe_b64decode as b64d

from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.primitives import padding
from cryptography.hazmat.backends import default_backend

backend = default_backend()

def aes_ecb_encrypt(message, key):
    cipher = Cipher(algorithms.AES(key), modes.ECB(), backend=backend)
    encryptor = cipher.encryptor()
    padder = padding.PKCS7(cipher.algorithm.block_size).padder()
    padded = padder.update(msg_text.encode()) + padder.finalize()
    return b64e(encryptor.update(padded) + encryptor.finalize())

def aes_ecb_decrypt(ciphertext, key):
    cipher = Cipher(algorithms.AES(key), modes.ECB(), backend=backend)
    decryptor = cipher.decryptor()
    unpadder = padding.PKCS7(cipher.algorithm.block_size).unpadder()
    padded = decryptor.update(b64d(ciphertext)) + decryptor.finalize()
    return unpadder.update(padded) + unpadder.finalize()

繰り返しますが、これにはHMAC署名がないため、とにかくECBを使用しないでください。上記はcryptography、実際に使用してはいけないものでも、一般的な暗号化ビルディングブロックを処理できることを示すためのものです。


51

@smehmoodのVigenere暗号解答で言及されている「encoded_c」は「key_c」である必要があります。

ここにエンコード/デコード機能があります。

import base64
def encode(key, clear):
    enc = []
    for i in range(len(clear)):
        key_c = key[i % len(key)]
        enc_c = chr((ord(clear[i]) + ord(key_c)) % 256)
        enc.append(enc_c)
    return base64.urlsafe_b64encode("".join(enc))

def decode(key, enc):
    dec = []
    enc = base64.urlsafe_b64decode(enc)
    for i in range(len(enc)):
        key_c = key[i % len(key)]
        dec_c = chr((256 + ord(enc[i]) - ord(key_c)) % 256)
        dec.append(dec_c)
    return "".join(dec)

免責事項:コメントで暗示されているように、これを読んで弁護士と話しても構わないのでない限り、実際のアプリケーションのデータを保護するためにこれを使用しないでください。

XOR暗号化の何が問題になっていますか?


2
とても便利です。私は以下のPython 3バージョンを投稿しました(コメントで醜く見えました)
Ryan Barrett

1
「シュナイアーの法則」:最も無知なアマチュアから最高の暗号学者まで、誰でも彼自身が破ることができないアルゴリズムを作成できます。これを使用しないでください。安全に近づくことさえできません。
zaph 2016年

3
すごい!このバージョンはアクセント付きの文字列でも機能しますが、@ smehmoodのバージョンは機能しません。使用例:encodedmsg = encode('mypassword', 'this is the message éçàèç"') print encodedmsg print decode('mypassword', encodedmsg)、正常に動作します。
Basj

2
これは、このコードに基づくSublimeテキストプラグインで、CTRL + SHIFT + Pを押してから「Eeencode」または「Dddecode」でテキストを簡単にエンコード/デコードできます。
Basj

2
@basj例をありがとう
sk03

49

@qneillの回答からの関数のPython 3バージョンは次のとおりです。

import base64
def encode(key, clear):
    enc = []
    for i in range(len(clear)):
        key_c = key[i % len(key)]
        enc_c = chr((ord(clear[i]) + ord(key_c)) % 256)
        enc.append(enc_c)
    return base64.urlsafe_b64encode("".join(enc).encode()).decode()

def decode(key, enc):
    dec = []
    enc = base64.urlsafe_b64decode(enc).decode()
    for i in range(len(enc)):
        key_c = key[i % len(key)]
        dec_c = chr((256 + ord(enc[i]) - ord(key_c)) % 256)
        dec.append(dec_c)
    return "".join(dec)

Python 3は文字列/バイト配列を2つの異なる概念に分割し、それを反映するようにAPIを更新したため、追加のエンコード/デコードが必要です。


4
ライアン、ありがとう、@ qniellと打ち間違えた
qneill

3
不思議に思う人にとって、違いは.encode()).decode()です。の戻りencode()、および.decode()の2行目decode()
RolfBly 2016年

2
うーん、エンコードされたコードは本当に一意ではありません。テストを実行したところ、11,22,33,44、...、88,99,111,222、...のすべてのコードキーが常に以前と同じ別のコードを持っていることを示しています。しかし、私はそれを感謝しています
Hzzkygcs

1
@Ryan Barrett、デコード時にパスワードの正しさを確認することは可能ですか?キーを知っているエンコードされた文字列を1つ送信するとします。もし彼がタイプミスでキーを入力したらどうなるでしょうか?デコードによって「デコードされた」文字列がまだ提供されますが、それは正しいものではありません。
ハインツ

26

免責事項:コメントで述べたように、これ実際のアプリケーションのデータを保護するために使用すべきではありません

XOR暗号化の何が問題になっていますか?

/crypto/56281/breaking-a-xor-cipher-of-known-key-length

https://github.com/hellman/xortool


すでに述べたように、PyCryptoライブラリには一連の暗号が含まれています。自分でやりたくない場合は、XOR「暗号」を使用してダーティーな作業を行うことができます。

from Crypto.Cipher import XOR
import base64

def encrypt(key, plaintext):
  cipher = XOR.new(key)
  return base64.b64encode(cipher.encrypt(plaintext))

def decrypt(key, ciphertext):
  cipher = XOR.new(key)
  return cipher.decrypt(base64.b64decode(ciphertext))

暗号は、平文を埋め込むことなく次のように機能します。

>>> encrypt('notsosecretkey', 'Attack at dawn!')
'LxsAEgwYRQIGRRAKEhdP'

>>> decrypt('notsosecretkey', encrypt('notsosecretkey', 'Attack at dawn!'))
'Attack at dawn!'

base64エンコード/デコード関数のhttps://stackoverflow.com/a/2490376/241294へのクレジット(私はPythonの初心者です)。


注:Cryptoモジュールは、Cryptoではなく、インストールされたpycrptopによってpython3にインストールされます。sudo pip3 install pycrypto
Nikhil VJ 2018

2
注:pycryptoが私の最後のherokuappにインストールできませんでした。私はこの投稿を見つけました.. pycryptoパッケージがpycryptodome instealと呼ばれる別のパッケージに置き換えられ、XORメソッドが廃止されたことを通知し
Nikhil VJ

2
今までにこの方法を使用しないでください、この中に「暗号」の説明注意ドキュメント XORのおもちゃの暗号を、XORは1つの最も簡単なストリーム暗号です。暗号化と復号化は、キーを汚染して作成されたキーストリームとデータをXORすることによって実行されます。実際のアプリケーションには使用しないでください。
Martijn Pieters

あなたが正しい@MartijnPieters。うまくいけば、私の編集がその点を明らかにしたことでしょう。
poida

12

以下は、AES(PyCrypto)とbase64を使用したURL Safe暗号化と復号化の実装です。

import base64
from Crypto import Random
from Crypto.Cipher import AES

AKEY = b'mysixteenbytekey' # AES key must be either 16, 24, or 32 bytes long

iv = Random.new().read(AES.block_size)

def encode(message):
    obj = AES.new(AKEY, AES.MODE_CFB, iv)
    return base64.urlsafe_b64encode(obj.encrypt(message))

def decode(cipher):
    obj2 = AES.new(AKEY, AES.MODE_CFB, iv)
    return obj2.decrypt(base64.urlsafe_b64decode(cipher))

このようなhttps://bugs.python.org/issue4329TypeError: character mapping must return integer, None or unicode)のような問題が発生した場合はstr(cipher)、デコード中に次のように使用します。

return obj2.decrypt(base64.urlsafe_b64decode(str(cipher)))

テスト:

In [13]: encode(b"Hello World")
Out[13]: b'67jjg-8_RyaJ-28='

In [14]: %timeit encode("Hello World")
100000 loops, best of 3: 13.9 µs per loop

In [15]: decode(b'67jjg-8_RyaJ-28=')
Out[15]: b'Hello World'

In [16]: %timeit decode(b'67jjg-8_RyaJ-28=')
100000 loops, best of 3: 15.2 µs per loop

Windowsのx64の+ Pythonの3.6 + PyCryptodome(pycryptoは廃止される)とのバグ:TypeError: Object type <class 'str'> cannot be passed to C code
Basj

@Basj aww申し訳ありません。私はウィンドウを使用していないため、修正できません。
すべてІѕVаиітyMar

IVを生成してモジュールレベルで保存しないでください。返される暗号文メッセージにIV を含める必要があります。これで2つの問題が発生しました。Pythonプロセスを再起動すると、新しいIVによって以前に暗号化されたメッセージを復号化できなくなり、その間、IVを複数のメッセージに再利用して、セキュリティをECBレベルに効果的に戻します。
Martijn Pieters

1
@AllІѕVаиітyで解決しb'...'ました。将来の参考のために回答を編集しました!
Basj

8

python3でのエンコード/デコード関数の動作(qneillの回答からほとんど変更されていません):

def encode(key, clear):
    enc = []
    for i in range(len(clear)):
        key_c = key[i % len(key)]
        enc_c = (ord(clear[i]) + ord(key_c)) % 256
        enc.append(enc_c)
    return base64.urlsafe_b64encode(bytes(enc))

def decode(key, enc):
    dec = []
    enc = base64.urlsafe_b64decode(enc)
    for i in range(len(enc)):
        key_c = key[i % len(key)]
        dec_c = chr((256 + enc[i] - ord(key_c)) % 256)
        dec.append(dec_c)
    return "".join(dec)

8

いくつかの素晴らしい答えをありがとう。追加するオリジナルはありませんが、いくつかの便利なPython機能を使用して、qneillの回答を段階的に書き直しています。彼らがコードを単純化して明確にすることに同意してくれることを願っています。

import base64


def qneill_encode(key, clear):
    enc = []
    for i in range(len(clear)):
        key_c = key[i % len(key)]
        enc_c = chr((ord(clear[i]) + ord(key_c)) % 256)
        enc.append(enc_c)
    return base64.urlsafe_b64encode("".join(enc))


def qneill_decode(key, enc):
    dec = []
    enc = base64.urlsafe_b64decode(enc)
    for i in range(len(enc)):
        key_c = key[i % len(key)]
        dec_c = chr((256 + ord(enc[i]) - ord(key_c)) % 256)
        dec.append(dec_c)
    return "".join(dec)

enumerate()-リスト内のアイテムとインデックスをペアにします

文字列内の文字を反復する

def encode_enumerate(key, clear):
    enc = []
    for i, ch in enumerate(clear):
        key_c = key[i % len(key)]
        enc_c = chr((ord(ch) + ord(key_c)) % 256)
        enc.append(enc_c)
    return base64.urlsafe_b64encode("".join(enc))


def decode_enumerate(key, enc):
    dec = []
    enc = base64.urlsafe_b64decode(enc)
    for i, ch in enumerate(enc):
        key_c = key[i % len(key)]
        dec_c = chr((256 + ord(ch) - ord(key_c)) % 256)
        dec.append(dec_c)
    return "".join(dec)

リスト内包表記を使用してリストを作成する

def encode_comprehension(key, clear):
    enc = [chr((ord(clear_char) + ord(key[i % len(key)])) % 256)
                for i, clear_char in enumerate(clear)]
    return base64.urlsafe_b64encode("".join(enc))


def decode_comprehension(key, enc):
    enc = base64.urlsafe_b64decode(enc)
    dec = [chr((256 + ord(ch) - ord(key[i % len(key)])) % 256)
           for i, ch in enumerate(enc)]
    return "".join(dec)

多くの場合、Pythonではリストインデックスはまったく必要ありません。zipとサイクルを使用してループインデックス変数を完全に削除します。

from itertools import cycle


def encode_zip_cycle(key, clear):
    enc = [chr((ord(clear_char) + ord(key_char)) % 256)
                for clear_char, key_char in zip(clear, cycle(key))]
    return base64.urlsafe_b64encode("".join(enc))


def decode_zip_cycle(key, enc):
    enc = base64.urlsafe_b64decode(enc)
    dec = [chr((256 + ord(enc_char) - ord(key_char)) % 256)
                for enc_char, key_char in zip(enc, cycle(key))]
    return "".join(dec)

そしていくつかのテスト...

msg = 'The quick brown fox jumps over the lazy dog.'
key = 'jMG6JV3QdtRh3EhCHWUi'
print('cleartext: {0}'.format(msg))
print('ciphertext: {0}'.format(encode_zip_cycle(key, msg)))

encoders = [qneill_encode, encode_enumerate, encode_comprehension, encode_zip_cycle]
decoders = [qneill_decode, decode_enumerate, decode_comprehension, decode_zip_cycle]

# round-trip check for each pair of implementations
matched_pairs = zip(encoders, decoders)
assert all([decode(key, encode(key, msg)) == msg for encode, decode in matched_pairs])
print('Round-trips for encoder-decoder pairs: all tests passed')

# round-trip applying each kind of decode to each kind of encode to prove equivalent
from itertools import product
all_combinations = product(encoders, decoders)
assert all(decode(key, encode(key, msg)) == msg for encode, decode in all_combinations)
print('Each encoder and decoder can be swapped with any other: all tests passed')

>>> python crypt.py
cleartext: The quick brown fox jumps over the lazy dog.
ciphertext: vrWsVrvLnLTPlLTaorzWY67GzYnUwrSmvXaix8nmctybqoivqdHOic68rmQ=
Round-trips for encoder-decoder pairs: all tests passed
Each encoder and decoder can be swapped with any other: all tests passed

非常に素晴らしい@ Nick、Pythonismsの良い進行、そしてテストも起動します。私はちょうどSmehmoodのオリジナル解答のバグ固定された適切な信用を与えるためにstackoverflow.com/a/2490718/468252を
qneill

4

安全になりたい場合は、暗号的に健全なFernetを使用できます。個別に保存したくない場合は、静的な「塩」を使用できます。ディクショナリとレインボーアタックの防止だけが失われます。長いパスワードまたは短いパスワードを選択できるため、これを選択しました。これはAESでは簡単ではありません。

from cryptography.fernet import Fernet
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
import base64

#set password
password = "mysecretpassword"
#set message
message = "secretmessage"

kdf = PBKDF2HMAC(algorithm=hashes.SHA256(), length=32, salt="staticsalt", iterations=100000, backend=default_backend())
key = base64.urlsafe_b64encode(kdf.derive(password))
f = Fernet(key)

#encrypt
encrypted = f.encrypt(message)
print encrypted

#decrypt
decrypted = f.decrypt(encrypted)
print decrypted

それが複雑すぎる場合は、誰かがsimplecryptを提案しました

from simplecrypt import encrypt, decrypt
ciphertext = encrypt('password', plaintext)
plaintext = decrypt('password', ciphertext)

ソルトを生成して暗号化結果に含めるだけで、パスワードとメッセージが繰り返されてもランダムな出力が得られます。アルゴリズムの将来性を保証するために反復値も含めますが、異なる反復カウントを使用してメッセージを復号化できます。
Martijn Pieters

3

ここに来た人(そして賞金総額)は、他の回答では提供されていない、あまり設定されていないワンライナーを探しているようです。だから私はbase64を進めています。

さて、これは基本的な難読化のみであり、**セキュリティに問題はありません**ですが、次の1行に注意してください。

from base64 import urlsafe_b64encode, urlsafe_b64decode

def encode(data, key):
    return urlsafe_b64encode(bytes(key+data, 'utf-8'))

def decode(enc, key):
    return urlsafe_b64decode(enc)[len(key):].decode('utf-8')

print(encode('hi', 'there')) # b'dGhlcmVoaQ=='
print(decode(encode('hi', 'there'), 'there')) # 'hi'

注意すべきいくつかの事柄:

  • I / Oに応じて、バイト単位から文字列へのエンコード/デコードを自分で処理したい場合があります。見てbytes()bytes::decode()
  • base64は、使用される文字のタイプによって簡単に認識でき、多くの場合、=文字で終了します。私のような人々は、ウェブサイトでそれらを見るとき、JavaScriptコンソールでそれらを完全にデコードします。btoa(string)(js)と同じくらい簡単です
  • 順序はkey + dataです。b64と同様に、最後に表示される文字は、最初の文字に依存します(バイトオフセットのため、Wikipediaにいくつかの説明があります)。このシナリオでは、エンコードされた文字列の先頭は、そのキーでエンコードされたすべてのものと同じになります。プラスは、データがより難読化されることです。それを逆に行うと、キーに関係なく、データパーツは誰にとってもまったく同じになります。

ここで、必要なものがどのような種類のキーも必要とせず、単に難読化している場合でも、種類のキーなしでbase64を使用できます。

from base64 import urlsafe_b64encode, urlsafe_b64decode

def encode(data):
    return urlsafe_b64encode(bytes(data, 'utf-8'))

def decode(enc):
    return urlsafe_b64decode(enc).decode()

print(encode('hi')) # b'aGk='
print(decode(encode('hi'))) # 'hi'

2
はい。セキュリティに煩わされていない場合、base64は暗号化よりもはるかに優れています。
Martijn Pieters

ワンライナーではない他の回答について:それは問題のポイントではありません。彼らは呼び出す2つの関数を求めます。そしてFernet(key).encrypt(message)、あなたのbase64呼び出しと同じようにただ一つの式です。
Martijn Pieters

そして、あなたは完全に削除する必要がありkeyます。多くの開発者がスタックオーバーフローからコピーアンドペーストします。注意を払わずに、キーは秘密である想定します。これを含める必要がある場合は、少なくとも使用せず、とにかく使用する場合は警告または例外を発生させます。コピーアンドペーストカルチャの愚かさと、正しい機能を提供するための責任を過小評価しないでください。
Martijn Pieters

3

私は4つの解決策をあげます:

1)cryptographyライブラリでのFernet暗号化の使用

以下は、パッケージを使用したソリューションでcryptography、通常どおりインストールできますpip install cryptography

import base64
from cryptography.fernet import Fernet, InvalidToken
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC

def cipherFernet(password):
    key = PBKDF2HMAC(algorithm=hashes.SHA256(), length=32, salt=b'abcd', iterations=1000, backend=default_backend()).derive(password)
    return Fernet(base64.urlsafe_b64encode(key))

def encrypt1(plaintext, password):
    return cipherFernet(password).encrypt(plaintext)

def decrypt1(ciphertext, password):
    return cipherFernet(password).decrypt(ciphertext)

# Example:

print(encrypt1(b'John Doe', b'mypass'))  
# b'gAAAAABd53tHaISVxFO3MyUexUFBmE50DUV5AnIvc3LIgk5Qem1b3g_Y_hlI43DxH6CiK4YjYHCMNZ0V0ExdF10JvoDw8ejGjg=='
print(decrypt1(b'gAAAAABd53tHaISVxFO3MyUexUFBmE50DUV5AnIvc3LIgk5Qem1b3g_Y_hlI43DxH6CiK4YjYHCMNZ0V0ExdF10JvoDw8ejGjg==', b'mypass')) 
# b'John Doe'
try:  # test with a wrong password
    print(decrypt1(b'gAAAAABd53tHaISVxFO3MyUexUFBmE50DUV5AnIvc3LIgk5Qem1b3g_Y_hlI43DxH6CiK4YjYHCMNZ0V0ExdF10JvoDw8ejGjg==', b'wrongpass')) 
except InvalidToken:
    print('Wrong password')

あなたは、このコードは非常に遠くHCLivessの答え@からではなく、目標はすぐに使用できる持ってここにあるなど、独自の塩、反復回数、と適応することができますencryptし、decrypt機能しています。ソース:https : //cryptography.io/en/latest/fernet/#using-passwords-with-fernet

注:.encode()などのバイトの代わりに.decode()文字列が必要な場合は、andwhere whereを使用してください。'John Doe'b'John Doe'


2)Cryptoライブラリを使用した単純なAES暗号化

これはPython 3で動作します。

import base64
from Crypto import Random
from Crypto.Hash import SHA256
from Crypto.Cipher import AES

def cipherAES(password, iv):
    key = SHA256.new(password).digest()
    return AES.new(key, AES.MODE_CFB, iv)

def encrypt2(plaintext, password):
    iv = Random.new().read(AES.block_size)
    return base64.b64encode(iv + cipherAES(password, iv).encrypt(plaintext))

def decrypt2(ciphertext, password):
    d = base64.b64decode(ciphertext)
    iv, ciphertext = d[:AES.block_size], d[AES.block_size:]
    return cipherAES(password, iv).decrypt(ciphertext)

# Example:    

print(encrypt2(b'John Doe', b'mypass'))
print(decrypt2(b'B/2dGPZTD8V22cIVKfp2gD2tTJG/UfP/', b'mypass'))
print(decrypt2(b'B/2dGPZTD8V22cIVKfp2gD2tTJG/UfP/', b'wrongpass'))  # wrong password: no error, but garbled output

注:あなたが削除することができますbase64.b64encodeし、.b64decodeあなたはテキストが読める出力したくない場合、および/または、あなたはとにかくバイナリファイルとしてディスクに暗号文を保存したい場合。


3)AESは、より良いパスワードキー導出関数を使用し、Cryptoライブラリで「間違ったパスワードが入力されたか」どうかをテストする機能を備えています。

ソリューション2)でのAES "CFBモード"は問題ありませんが、2つの欠点があります。それはSHA256(password)、ルックアップテーブルで簡単にブルートフォースできること、および間違ったパスワードが入力されたかどうかをテストする方法がないことです。これは、AESで説明されているように、「GCMモード」でAESを使用することによって解決されます。不正なパスワードが入力されたことを検出する方法は?そして、この方法は「入力したパスワードが間違っています」と言って安全ですか?

import Crypto.Random, Crypto.Protocol.KDF, Crypto.Cipher.AES

def cipherAES_GCM(pwd, nonce):
    key = Crypto.Protocol.KDF.PBKDF2(pwd, nonce, count=100000)
    return Crypto.Cipher.AES.new(key, Crypto.Cipher.AES.MODE_GCM, nonce=nonce, mac_len=16)

def encrypt3(plaintext, password):
    nonce = Crypto.Random.new().read(16)
    return nonce + b''.join(cipherAES_GCM(password, nonce).encrypt_and_digest(plaintext))  # you case base64.b64encode it if needed

def decrypt3(ciphertext, password):
    nonce, ciphertext, tag = ciphertext[:16], ciphertext[16:len(ciphertext)-16], ciphertext[-16:]
    return cipherAES_GCM(password, nonce).decrypt_and_verify(ciphertext, tag)

# Example:

print(encrypt3(b'John Doe', b'mypass'))
print(decrypt3(b'\xbaN_\x90R\xdf\xa9\xc7\xd6\x16/\xbb!\xf5Q\xa9]\xe5\xa5\xaf\x81\xc3\n2e/("I\xb4\xab5\xa6ezu\x8c%\xa50', b'mypass'))
try:
    print(decrypt3(b'\xbaN_\x90R\xdf\xa9\xc7\xd6\x16/\xbb!\xf5Q\xa9]\xe5\xa5\xaf\x81\xc3\n2e/("I\xb4\xab5\xa6ezu\x8c%\xa50', b'wrongpass'))
except ValueError:
    print("Wrong password")

4)RC4の使用(ライブラリは不要)

https://github.com/bozhu/RC4-Python/blob/master/rc4.pyから適応。

def PRGA(S):
    i = 0
    j = 0
    while True:
        i = (i + 1) % 256
        j = (j + S[i]) % 256
        S[i], S[j] = S[j], S[i]
        yield S[(S[i] + S[j]) % 256]

def encryptRC4(plaintext, key, hexformat=False):
    key, plaintext = bytearray(key), bytearray(plaintext)  # necessary for py2, not for py3
    S = list(range(256))
    j = 0
    for i in range(256):
        j = (j + S[i] + key[i % len(key)]) % 256
        S[i], S[j] = S[j], S[i]
    keystream = PRGA(S)
    return b''.join(b"%02X" % (c ^ next(keystream)) for c in plaintext) if hexformat else bytearray(c ^ next(keystream) for c in plaintext)

print(encryptRC4(b'John Doe', b'mypass'))                           # b'\x88\xaf\xc1\x04\x8b\x98\x18\x9a'
print(encryptRC4(b'\x88\xaf\xc1\x04\x8b\x98\x18\x9a', b'mypass'))   # b'John Doe'

(最新の編集以降は古くなっていますが、将来の参照用に保管されています):Windows + Python 3.6 +(Windowsでは使用pycryptoできないpip install pycrypto)に関するすべての回答またはpycryptodome(このフォークでサポートされていないfrom Crypto.Cipher import XORため、ここでの回答は失敗しました)の使用に問題XORがありましたpycrypto。を使用... AESしたソリューションもTypeError: Object type <class 'str'> cannot be passed to C code)で失敗しました。また、ライブラリにsimple-cryptpycrypto依存関係があるため、オプションではありません。


1
ソルトとイテレーションのカウントをハードコーディングしたくない場合。ランダムなソルトを生成し、反復回数を暗号化で構成可能にし、その情報を暗号化結果に含め、解読時に値を抽出して使用します。ソルトは、指定されたメッセージで再利用されたパスワードの簡単な認識からユーザーを保護します。反復回数は、アルゴリズムを将来にわたって保証します。
Martijn Pieters

はい、もちろん@MartijnPietersですが、ここでの目標は、OPからの要求に応じて、単純な目的のための単純なコードを2つのパラメーター(プレーンテキスト+パスワード)で作成することです。もちろん、より複雑なシナリオ(つまり、データベース)では、これらすべての追加パラメーターを使用します。
Basj

追加のパラメーターは必要ありません。の不透明な戻り値にエンコードされた情報を含めますpassword_encrypt()
Martijn Pieters

@MartijnPieters確かに素晴らしいソリューションです。
Basj

2

これは機能しますが、パスワードの長さは正確でなければなりません8。これは簡単で、pyDesが必要です

from pyDes import *

def encode(data,password):
    k = des(password, CBC, "\0\0\0\0\0\0\0\0", pad=None, padmode=PAD_PKCS5)
    d = k.encrypt(data)
    return d

def decode(data,password):
    k = des(password, CBC, "\0\0\0\0\0\0\0\0", pad=None, padmode=PAD_PKCS5)
    d = k.decrypt(data)
    return d

x = encode('John Doe', 'mypass12')
y = decode(x,'mypass12')

print x
print y

出力:

³.\Þ\åS¾+æÅ`;Ê
John Doe

固定IVは使用しないでください。IVをランダム化して、代わりに暗号文に含めます。それ以外の場合は、ECBモードを使用することもできます。繰り返されるプレーンテキストメッセージは、それ以外の場合は簡単に認識できます。
Martijn Pieters

また、pyDesプロジェクトは死んでいるようです。ホームページがなくなり、PyPIの最後のリリースは9年前になりました。
Martijn Pieters

2

元のメッセージのCRCチェックサムを含む@qneillコードの他の実装では、チェックが失敗すると例外がスローされます。

import hashlib
import struct
import zlib

def vigenere_encode(text, key):
    text = '{}{}'.format(text, struct.pack('i', zlib.crc32(text)))

    enc = []
    for i in range(len(text)):
        key_c = key[i % len(key)]
        enc_c = chr((ord(text[i]) + ord(key_c)) % 256)
        enc.append(enc_c)

    return base64.urlsafe_b64encode("".join(enc))


def vigenere_decode(encoded_text, key):
    dec = []
    encoded_text = base64.urlsafe_b64decode(encoded_text)
    for i in range(len(encoded_text)):
        key_c = key[i % len(key)]
        dec_c = chr((256 + ord(encoded_text[i]) - ord(key_c)) % 256)
        dec.append(dec_c)

    dec = "".join(dec)
    checksum = dec[-4:]
    dec = dec[:-4]

    assert zlib.crc32(dec) == struct.unpack('i', checksum)[0], 'Decode Checksum Error'

    return dec

2

AESを使用して、パスワードで文字列を暗号化できます。ただし、ユーザーが簡単にパスワードを推測できないように、十分に強力なパスワードを選択する必要があります(申し訳ありませんが、私はそれを手伝うことができません。私はセキュリティウィニーになりたいと思っています)。

AESは強力な鍵サイズで強力ですが、PyCryptoとの使用も簡単です。


3
アラン、ありがとう。ただし、明確にするために、パスワード自体は暗号化していません。上記の例では、ソースコードで使用する単純なパスワードであるパスワード「mypass」に従って文字列「John Doe」を暗号化しています。ユーザーのパスワードは含まれず、他の非常に機密性の高い情報も含まれません。これを明確にするために質問を編集しました。
RexE 2010年

1
正しく使用すれば、AESは素晴らしいです。ただし、誤って使用するのは簡単です。安全でないブロック暗号モードを使用する答えが少なくとも1つここにあり、IV値を処理するための別の2つがあります。Fernetのような明確に定義されたレシピを備えた優れたライブラリを使用することをお勧めします!
Martijn Pieters

実際、それは非常に鋭い観察です。一度IVをいじったことがあります。
アラン

0

外部ライブラリは、秘密鍵暗号化アルゴリズムを提供します。

たとえばCypher、PyCryptoモジュールは、多くの暗号化アルゴリズムの選択肢を提供します。

  • Crypto.Cipher.AES
  • Crypto.Cipher.ARC2
  • Crypto.Cipher.ARC4
  • Crypto.Cipher.Blowfish
  • Crypto.Cipher.CAST
  • Crypto.Cipher.DES
  • Crypto.Cipher.DES3
  • Crypto.Cipher.IDEA
  • Crypto.Cipher.RC5
  • Crypto.Cipher.XOR

MeTooCryptoOpenSSLのPythonラッパーであり、(他の機能とともに)完全な強度の汎用暗号ライブラリを提供します。含まれるのは、対称暗号(AESなど)です。


0

安全な暗号化が必要な場合:

Python 2の場合、keyczar http://www.keyczar.org/を使用する必要があります

Python 3の場合、keyczarが使用可能になるまで、simple-cryptを作成しました http://pypi.python.org/pypi/simple-cryptを作成しました

これらはどちらもキー強化を使用するため、他のほとんどの回答よりも安全です。とても使いやすいので、セキュリティがそれほど重要ではない場合でも使いたいかもしれません...


Keyczarリポジトリから:重要な注意:Keyczarは非推奨です。Keyczar開発者はTinkを推奨していますが、PythonバージョンのTinkはありません。
Martijn Pieters

0

したがって、ミッションクリティカルなものは何もエンコードされておらず難読化のために暗号化したいだけです

シーザーの暗号を紹介しましょう

ここに画像の説明を入力してください

シーザーの暗号またはシーザーシフトは、最も単純で最も広く知られている暗号化技術の1つです。これは、平文の各文字がアルファベットの下の一定数の位置の文字に置き換えられる一種の置換暗号です。たとえば、左シフトが3の場合、DはAに置き換えられ、EはBになります。

あなたの参照のためのサンプルコード:

def encrypt(text,s): 
        result = "" 

        # traverse text 
        for i in range(len(text)): 
            char = text[i] 

            # Encrypt uppercase characters 
            if (char.isupper()): 
                result += chr((ord(char) + s-65) % 26 + 65) 

            # Encrypt lowercase characters 
            else: 
                result += chr((ord(char) + s - 97) % 26 + 97) 

        return result 

    def decrypt(text,s): 
        result = "" 

        # traverse text 
        for i in range(len(text)): 
            char = text[i] 

            # Encrypt uppercase characters 
            if (char.isupper()): 
                result += chr((ord(char) - s-65) % 26 + 65) 

            # Encrypt lowercase characters 
            else: 
                result += chr((ord(char) - s - 97) % 26 + 97) 

        return result 

    #check the above function 
    text = "ATTACKATONCE"
    s = 4
    print("Text  : " + text) 
    print("Shift : " + str(s)) 
    print("Cipher: " + encrypt(text,s))
    print("Original text: " + decrypt(encrypt(text,s),s))

利点:要件を満たし、シンプルであり、エンコード処理を実行します。

短所:単純なブルートフォースアルゴリズムによって解読される可能性があります(余計な結果をすべて処理しようとする可能性はほとんどありません)。


0

参照用にデコードとエンコードを行うコードをもう1つ追加する

import base64

def encode(key, string):
    encoded_chars = []
    for i in range(len(string)):
        key_c = key[i % len(key)]
        encoded_c = chr(ord(string[i]) + ord(key_c) % 128)
        encoded_chars.append(encoded_c)
    encoded_string = "".join(encoded_chars)
    arr2 = bytes(encoded_string, 'utf-8')
    return base64.urlsafe_b64encode(arr2)

def decode(key, string):
    encoded_chars = []
    string = base64.urlsafe_b64decode(string)
    string = string.decode('utf-8')
    for i in range(len(string)):
        key_c = key[i % len(key)]
        encoded_c = chr(ord(string[i]) - ord(key_c) % 128)
        encoded_chars.append(encoded_c)
    encoded_string = "".join(encoded_chars)
    return encoded_string

def main():
    answer = str(input("EorD"))
    if(answer in ['E']):
        #ENCODE
        file = open("D:\enc.txt")
        line = file.read().replace("\n", " NEWLINEHERE ")
        file.close()
        text = encode("4114458",line)
        fnew = open("D:\\new.txt","w+")
        fnew.write(text.decode('utf-8'))
        fnew.close()
    else:
        #DECODE
        file = open("D:\\new.txt",'r+')
        eline = file.read().replace("NEWLINEHERE","\n")
        file.close()
        print(eline)
        eline = eline.encode('utf-8')
        dtext=decode("4114458",eline)
        print(dtext)
        fnew = open("D:\\newde.txt","w+")
        fnew.write(dtext)
        fnew.close

if __name__ == '__main__':
    main()
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.